Reference for URI has no XMLSignatureInput using Apache Santuario

Reference for URI has no XMLSignatureInput using Apache Santuario

I need to integrate my web application with SSO. I’m getting a SAML response that has a digital signature. I’ve been told the first step is to make sure the signature matches that content of the SAML by using a standard XML signature verification technique.
I’m using Apache Santuario because the standard Java XML API doesn’t work with JBOSS 7.
https://issues.jboss.org/browse/AS7-4248
Error:
org.apache.xml.security.signature.MissingResourceFailureException: The Reference for URI #973348f8-3980-4403-bede-df6d3f2a0f10 has no XMLSignatureInput
Original Exception was org.apache.xml.security.signature.ReferenceNotInitializedException: Cannot resolve element with ID 973348f8-3980-4403-bede-df6d3f2a0f10
Original Exception was org.apache.xml.security.signature.ReferenceNotInitializedException: Cannot resolve element with ID 973348f8-3980-4403-bede-df6d3f2a0f10
Original Exception was org.apache.xml.security.signature.ReferenceNotInitializedException: Cannot resolve element with ID 973348f8-3980-4403-bede-df6d3f2a0f10
Original Exception was org.apache.xml.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID 973348f8-3980-4403-bede-df6d3f2a0f10
at org.apache.xml.security.signature.Manifest.verifyReferences(Manifest.java:414)
at org.apache.xml.security.signature.SignedInfo.verify(SignedInfo.java:259)
at org.apache.xml.security.signature.XMLSignature.checkSignatureValue(XMLSignature.java:724)
at org.apache.xml.security.signature.XMLSignature.checkSignatureValue(XMLSignature.java:656)

The only help I could find was to set the Assertion element ID to null with setIdAttributeNS(). I dont know how or when to do so. I feel like I could be breaking SAML at this point.
http://comments.gmane.org/gmane.text.xml.security.devel/7609
XML snippet:

https://someissuer.com/SAML2/SSO





https://someissuer.com/SAML2/SSO










DIGEST VALUE


BIG STRING


ANOTHER BIG STRING


Code:
// load XML from string
InputSource inputSource = new InputSource( new StringReader(saml) );

DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setNamespaceAware(true);
Document doc = f.newDocumentBuilder().parse(inputSource);

// new xpath
xpath = XPathFactory.newInstance().newXPath();

NodeList signatureNodes = doc.getElementsByTagNameNS(Constants.SignatureSpecNS, “Signature”);
if (signatureNodes.getLength() == 0) {
throw new Exception(“Signature NOT found!”);
}

Element sigElement = (Element) signatureNodes.item(0);
if (sigElement == null) {
throw new Exception(“Signature element is null!”);
}

XMLSignature signature = new XMLSignature(sigElement, “”);

// key
KeyInfo ki = signature.getKeyInfo();
if (ki == null) {
throw new Exception(“Did not find KeyInfo”);
}

// validate
X509Certificate cert = signature.getKeyInfo().getX509Certificate();
if (cert == null) {
PublicKey pk = signature.getKeyInfo().getPublicKey();
if (pk == null) {
throw new Exception(“Did not find Certificate or Public Key”);
}

Related:  Apache (xampp) doesn't run on Win 10 - W3SVC not running

valid = signature.checkSignatureValue(pk);
}

else {
valid = signature.checkSignatureValue(cert);
}

Solutions/Answers:

Solution 1:

Fixed it! I was super close, here is what I did.

I had to first get the Assertion element and register the ID.

// load XML from string
InputSource inputSource = new InputSource( new StringReader(saml) );

// load document
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setNamespaceAware(true);
document = docFactory.newDocumentBuilder().parse(inputSource);

// create xpath with appropriate namespace context
xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new SAMLNamespaceContext());

// load assertion to get signed ID
NodeList assertionNodes = (NodeList) xpath.evaluate("samlp:Response/saml:Assertion", document, XPathConstants.NODESET);
if (assertionNodes.getLength() == 0) {
    throw new Exception("Cannot find Assertion element");
} 

// register ID
Element assertionElement = (Element) assertionNodes.item(0);
assertionElement.setIdAttributeNS(null, "ID", true);

// load signature
NodeList signatureNodes = document.getElementsByTagNameNS(Constants.SignatureSpecNS, "Signature");
if (signatureNodes.getLength() == 0)
    throw new Exception("Signature NOT found!");

Element sigElement = (Element) signatureNodes.item(0);
if (sigElement == null) 
    throw new Exception("Signature element is null!");

XMLSignature signature = new XMLSignature(sigElement, "");

// check for key
KeyInfo ki = signature.getKeyInfo();
if (ki == null) {
    throw new Exception("Did not find KeyInfo");
}

// get cert and validate 
X509Certificate cert = signature.getKeyInfo().getX509Certificate();
if (cert == null) {
    PublicKey pk = signature.getKeyInfo().getPublicKey();
    if (pk == null) {
        throw new Exception("Did not find Certificate or Public Key");
    }

    valid = signature.checkSignatureValue(pk);
}
else {
    valid = signature.checkSignatureValue(cert);
}

References