创建 QName 异常时,Opensaml unmarshallMessage 给出的 opensaml 本地部分不能为“null”
Posted
技术标签:
【中文标题】创建 QName 异常时,Opensaml unmarshallMessage 给出的 opensaml 本地部分不能为“null”【英文标题】:Opensaml unmarshallMessage giving opensaml local part cannot be "null" when creating a QName Exception 【发布时间】:2021-07-30 17:49:54 【问题描述】:我正在使用 Spring SAML,来自 IDP 响应我收到 issuer 作为属性 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)
对于下面的代码,如上所述,它会抛出异常。
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);
throw new MessageDecodingException("Encountered error unmarshalling message from its DOM representation", e);
但对于下面的代码,它工作正常,因为在这里我再次转换为字符串并创建输入流,然后获取传递给解组的 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, 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);
throw new MessageDecodingException("Encountered error unmarshalling message from its DOM representation", e);
【问题讨论】:
【参考方案1】:您的问题可能与您的解析器配置有关,可能未配置为支持命名空间。
请在初始化 parserPool
时使用类似于以下代码的代码:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder parserPool = documentBuilderFactory.newDocumentBuilder();
我的猜测是第二个测试成功运行,因为在后台 XMLHelper
nodeToString
正在使用 writeNode
,而 writeNode
又使用 LSSerializer
来执行实际的 XML 序列化。由于解析器被声明为非命名空间感知,因此生成的 XML 输出和对应的解析 Document
将不包含命名空间信息,或者至少,它包含的信息以这样一种方式,即随后由 Unmarshaller
执行的解析过程认为合适。
此外,请注意,问题可能与您创建新 Element
的方式有关,因为您也没有提供命名空间信息:当您使用 createElement
时,生成的 @987654333 @ 将不包含localName
、prefix
或namespaceURI
,都设置为null
。请尝试以下代码:
Document messageDoc = parserPool.parse(messageStream);
Element messageElem = messageDoc.getDocumentElement();
Element assertionElem = (Element) messageElem.getElementsByTagName("saml2:Assertion").item(0);
Element issuerElement = messageDoc.createElementNS("urn:oasis:names:tc:SAML:2.0:assertion", "saml2:Issuer");
Attr formatAttr = messageDoc.createAttributeNS("urn:oasis:names:tc:SAML:2.0:assertion", "saml2:Format");
formatAttr.setNodeValue("urn:oasis:names:tc:SAML:2.0:nameid-format:entity");
issuerElement.setAttributeNode(formatAttr);
Text text = messageDoc.createTextNode("emIDAM");
issuerElement.appendChild(text);
assertionElem.appendChild(issuerElement);
【讨论】:
以上是关于创建 QName 异常时,Opensaml unmarshallMessage 给出的 opensaml 本地部分不能为“null”的主要内容,如果未能解决你的问题,请参考以下文章
在 Java 中从给定的 XML 创建 OpenSAML 断言
OpenSAML / Spring 安全设置,因此在 Tomcat 上重新部署有效
Worklight javax/xml/名称空间/QName