URI的引用没有使用Apache Santuario的XMLSignatureInput

时间:2014-03-24 18:25:57

标签: java xml apache jboss

我需要将我的Web应用程序与SSO集成。我收到了具有数字签名的SAML响应。我被告知第一步是使用标准的XML签名验证技术确保签名与SAML的内容匹配。

我正在使用Apache Santuario,因为标准的Java XML API不能与JBOSS 7一起使用。 https://issues.jboss.org/browse/AS7-4248

错误:

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)

我能找到的唯一帮助是使用setIdAttributeNS()将Assertion元素ID设置为null。我不知道如何或何时这样做。我觉得我此刻可能会打破SAML。 http://comments.gmane.org/gmane.text.xml.security.devel/7609

XML代码段

<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="http://www.carrier.com" ID="da55c478-f2f6-43b7-ba2f-a130d60abbf8" IssueInstant="2013-05-31T21:33:21Z" Version="2.0">
  <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://someissuer.com/SAML2/SSO</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success">
    </samlp:StatusCode>
  </samlp:Status>
  <saml:Assertion ID="973348f8-3980-4403-bede-df6d3f2a0f10" IssueInstant="2013-05-31T21:33:21Z" Version="2.0">
    <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://someissuer.com/SAML2/SSO</saml:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
        <Reference URI="#973348f8-3980-4403-bede-df6d3f2a0f10">
          <Transforms>
            <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
            <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
          </Transforms>
          <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
          <DigestValue>DIGEST VALUE</DigestValue>
        </Reference>
      </SignedInfo>
      <SignatureValue xmlns="http://www.w3.org/2000/09/xmldsig#">BIG STRING</SignatureValue>
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>ANOTHER BIG STRING</X509Certificate>
        </X509Data>
      </KeyInfo>
    </ds:Signature>

代码:

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

    valid = signature.checkSignatureValue(pk);
}

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

1 个答案:

答案 0 :(得分:3)

修正了它!我非常接近,这就是我所做的。

我必须首先获取Assertion元素并注册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);
}