我需要将我的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);
}
答案 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);
}