dom level 3 and id attributes in saml

Tue, Jan 20, 2009

I had word from the interweb that the Guanxi SP Engine was having a bit of trouble trusting Internet2 Shibboleth IdPs, throwing the error:

org.apache.xml.security.signature.XMLSignatureException:
The Reference for URI #_1f08ed98488ed7e4f602628fa9d194cb has no XMLSignatureInput
That’s a pretty garbled message but I’d previously come across this in the Engine to Guard comms: XMLBeans and DOM3. The problem is, the I2 IdP is signing the SAML Response using a “non standard” ID attribute, which is only supported in DOM3 and XMLBeans does not support DOM3 and there are no plans to do so. So the only way round it is to break out into DOM land. However, if you’re dealing with signature verification, toString() breaks everything, when injecting the SAMLResponseDocument into a DocumentBuilderFactory. The improved solution is to use an InputStream:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
…
DocumentBuilder db = dbf.newDocumentBuilder();
…
Document doc = db.parse(samlResponse.newInputStream());
This gets you out of XMLBeans and into DOM via JAXP. The next problem is to find out whether the Response is signed in conjunction with an ID attribute. You can do this by looking at the signature Reference:
<Response …>
 <ds:Signature xmlns:ds=“http://www.w3.org/2000/09/xmldsig#">
   <ds:SignedInfo>
     …
     <ds:Reference URI=“#_1f08ed98488ed7e4f602628fa9d194cb”>
You can now see where the exception is coming from. XMLSignature can’t find an attribute with the value of URI, as it uses DOM3 to find the ID attribute. Various guesses are made, such as “id”, “ID” etc but not “ResponseID”, which is the attribute used in SAML:
<Response … ResponseID=”_1f08ed98488ed7e4f602628fa9d194cb”>
so the only way round this is to mark ResponseID as an ID attribute:
((Element)doc.getFirstChild()).setIdAttribute(“ResponseID”, true);
but first you’ve got to find the Reference node, in order to check if it has a value other than “” and here you can use the new Java 5 built-in XPath functionality:
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new SAMLNamespaceContext());
XPathExpression expr = xpath.compile(“//ds:Signature/ds:SignedInfo/ds:Reference”);
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList sigReference = (NodeList)result;
To resolve the ds namespace at runtime, you need to provide an implementation of the NamespaceContext interface but that’s easy. The entire code is in the Guanxi::Common module on CVS if you’re interested. The reason I check the Reference URI is the Guanxi IdP does not use it. It signs the SAML Response as-is, without recourse to DOM3, so there’s no need to set an ID attribute.

comments powered by Disqus