简体   繁体   中英

Opensaml unmarshallMessage giving opensaml local part cannot be "null" when creating a QName Exception

I am using Spring SAML , from IDP response I am receiving issuer as an attribute ID, So I wanted to change the response after receiving in spring saml, so I have overridden method unmarshall which will parse the message and changed the xml elements for this purpose. While doing this if I directly use the Element after parsing to unmarshall it is working but if I do dom manipulation it is giving the below exception. I am not getting why it is throwing exception in first code but not in second code attached below. How to make it work without converting again to string and get dom object.

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. For the below code it is throwing exception as explained above.

     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); } }
  2. But for the below code it is working fine, because here I have again converted to string and created the input stream and then get the dom which is passed for unmarshalling.

     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); } }

Your problem may be related to your parser configuration, probably not configured as namespace aware.

Please, use something similar to the following code when initializing your parserPool :

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

My guess is that the second test runs successfully because under the hood XMLHelper nodeToString is using writeNode which in turn uses LSSerializer for performing the actual XML serialization. Since the parser is declared to be non-namespace aware, the resulting XML output and corresponding parsed Document will not contain namespace information or at least, it contains the information in such a way that the parsing process subsequently carried out by Unmarshaller deems it appropriate.

In addition, please, be aware that the problem may be related with the way you are creating your new Element as well because you are not providing namespace information as well: when you use createElement , the resulting Element will not contain localName , prefix , or namespaceURI , all are set to null . Please, try the following code instead:

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM