创建 QName 异常时,Opensaml unmarshallMessage 给出 opensaml 本地部分不能为“null”

问题描述

我正在使用 Spring SAML,从 IDP 响应我接收颁发者作为属性 ID,所以我想在 spring saml 接收后更改响应,所以我重写了 unmarshall 方法,该方法将解析消息并为此目的更改 xml 元素。在执行此操作时,如果我在解析后直接使用 Element 来解组它正在工作,但是如果我进行 dom 操作,则会给出以下异常。我不明白为什么它在第一个代码中抛出异常,但在下面附加的第二个代码中没有。如何在不再次转换为字符串并获取 dom 对象的情况下使其工作。

Exception in thread "main" java.lang.IllegalArgumentException: local part cannot be "null" when creating a QName
    at java.xml/javax.xml.namespace.QName.<init>(QName.java:185)
    at java.xml/javax.xml.namespace.QName.<init>(QName.java:129)
    at org.opensaml.xml.util.XMLHelper.constructQName(XMLHelper.java:433)
    at org.opensaml.xml.util.XMLHelper.getNodeQName(XMLHelper.java:171)
    at org.opensaml.xml.io.UnmarshallerFactory.getUnmarshaller(UnmarshallerFactory.java:81)
    at org.opensaml.xml.io.AbstractXMLObjectUnmarshaller.unmarshallChildElement(AbstractXMLObjectUnmarshaller.java:334)
    at org.opensaml.xml.io.AbstractXMLObjectUnmarshaller.unmarshall(AbstractXMLObjectUnmarshaller.java:127)
    at org.opensaml.xml.io.AbstractXMLObjectUnmarshaller.unmarshallChildElement(AbstractXMLObjectUnmarshaller.java:355)
    at org.opensaml.xml.io.AbstractXMLObjectUnmarshaller.unmarshall(AbstractXMLObjectUnmarshaller.java:127)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.unmarshallMessage(unmarshallMessage.java:208)
  1. 对于下面的代码,它抛出异常,如上所述。

    protected XMLObject unmarshallMessage(InputStream messageStream) throws MessageDecodingException {
         log.debug("Parsing message stream into DOM document");
    
         try {
             Document messageDoc = parserPool.parse(messageStream);
             Element messageElem = messageDoc.getDocumentElement();
             Element elementsByTagName = (Element) messageElem.getElementsByTagName("saml2:Assertion").item(0);
             Element issuer = messageDoc.createElement("saml2:Issuer");
             issuer.setTextContent("emIdam");
             issuer.setAttribute("Format","urn:oasis:names:tc:SAML:2.0:nameid-format:entity");
             log.debug("Unmarshalling message DOM");
             Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem);
             if (unmarshaller == null) {
                 log.debug("Unable to unmarshall message,no unmarshaller registered for message element "
                         + XMLHelper.getNodeQName(messageElem));
                 throw new MessageDecodingException(
                         "Unable to unmarshall message,no unmarshaller registered for message element "
                                 + XMLHelper.getNodeQName(messageElem));
             }
             XMLObject message = unmarshaller.unmarshall(messageElem);
    
             return message;
         } catch (XMLParserException e) {
             log.error("Encountered error parsing message into its DOM representation",e);
             throw new MessageDecodingException("Encountered error parsing message into its DOM representation",e);
         } catch (UnmarshallingException e) {
             log.error("Encountered error unmarshalling message from its DOM representation",e);
             throw new MessageDecodingException("Encountered error unmarshalling message from its DOM representation",e);
         }
         catch (Exception e) {
             log.warn("Encountered error unmarshalling message from its DOM representation --->",e);
         }
     }
    
  2. 但是对于下面的代码,它工作正常,因为在这里我再次转换为字符串并创建了输入流,然后获取了用于解组的 dom。

    protected XMLObject unmarshallMessage(InputStream messageStream) throws MessageDecodingException {
         log.debug("Parsing message stream into DOM document");
    
         try {
             Document messageDoc = parserPool.parse(messageStream);
             Element messageElem = messageDoc.getDocumentElement();
             Element elementsByTagName = (Element) messageElem.getElementsByTagName("saml2:Assertion").item(0);
             Element issuer = messageDoc.createElement("saml2:Issuer");
             issuer.setTextContent("emIdam");
             issuer.setAttribute("Format","urn:oasis:names:tc:SAML:2.0:nameid-format:entity");
    
             //converting again to string and getting dom
             String xml = XMLHelper.nodetoString(messageElem);
             messageStream = new ByteArrayInputStream(xml.getBytes());
             messageDoc = parserPool.parse(messageStream);
             messageElem = messageDoc.getDocumentElement();
    
    
             log.debug("Unmarshalling message DOM");
             Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem);
             if (unmarshaller == null) {
                 log.debug("Unable to unmarshall message,e);
         }
     }
    

解决方法

你的问题可能与你的解析器配置有关,可能没有配置为命名空间感知。

请在初始化您的 parserPool 时使用类似于以下代码的内容:

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder parserPool = documentBuilderFactory.newDocumentBuilder();

我的猜测是第二个测试成功运行,因为在幕后 XMLHelper nodeToString 正在使用 writeNode,而 https://help.poralix.com/articles/mysql-access-denied-you-need-the-super-privilege-for-this-operation 又使用 LSSerializer 来执行实际的 XML 序列化。由于解析器被声明为非命名空间感知的,因此生成的 XML 输出和相应的解析 Document 将不包含命名空间信息,或者至少,它包含的信息使得解析过程随后由 { {1}} 认为合适。

此外,请注意该问题也可能与您创建新 Unmarshaller 的方式有关,因为您没有提供命名空间信息:当您使用 Element 时,生成的 createElement 将不包含 ElementlocalNameprefix,所有这些都设置为 namespaceURI。请改为尝试以下代码:

null

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...