<?xml version=”1.0″ encoding=”UTF-8″?> <samlp:Response Destination=”https://saml.centis1504.net/sp/acs.do” ID=”r5436a7fd9a3b4b3f9dbd01e04d6ddcbc” InResponseTo=”vIV8WvY8YQyP4c8vCyzBKV47kapv” IssueInstant=”2013-08-08T06:36:12.805Z” Version=”2.0″ xmlns:saml=”urn:oasis:names:tc:SAML:2.0:assertion” xmlns:samlp=”urn:oasis:names:tc:SAML:2.0:protocol”><saml:Issuer xmlns:saml=”urn:oasis:names:tc:SAML:2.0:assertion”>https://saml.centis1504.net</saml:Issuer><samlp:Status><samlp:StatusCode Value=”urn:oasis:names:tc:SAML:2.0:status:Success”/></samlp:Status><saml:Assertion ID=”aEo-hvlDqH0qz2MnnrP2D60mmNvlz” IssueInstant=”2013-08-08T06:36:12.804Z” Version=”2.0″ xmlns:saml=”urn:oasis:names:tc:SAML:2.0:assertion”><saml:Issuer>https://saml.centis1504.net</saml:Issuer><ds:Signature xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”> <ds:SignedInfo xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”> <ds:CanonicalizationMethod Algorithm=”http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments” xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/> <ds:SignatureMethod Algorithm=”http://www.w3.org/2000/09/xmldsig#rsa-sha1″ xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/> <ds:Reference URI=”#aEo-hvlDqH0qz2MnnrP2D60mmNvlz” xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”> <ds:Transforms xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”> <ds:Transform Algorithm=”http://www.w3.org/2000/09/xmldsig#enveloped-signature” xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/> <ds:Transform Algorithm=”http://www.w3.org/2001/10/xml-exc-c14n#” xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”><ec:InclusiveNamespaces PrefixList=”ds saml xs xsi” xmlns:ec=”http://www.w3.org/2001/10/xml-exc-c14n#”/></ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm=”http://www.w3.org/2000/09/xmldsig#sha1″ xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”/> <ds:DigestValue xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>Pnp8KGJg8Ny0lyeSwvLvlRunOTg=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”>B/KgR0EFNgxjmtlInJSnXqclmVbYkZkuPZnROKAcph+98avAT4jNgutfWXIMUUSrgsyOPKoig5l+peRVNOUX5Q==</ds:SignatureValue> <ds:KeyInfo><ds:KeyValue><ds:RSAKeyValue><ds:Modulus>nEVcq+Ph3ZkXQone59guZiEYybtxDdYVAhw4JsoSQoxuzBM8BMqjYD0xmcMF1rJV+7BNKDkOJz3kdsFgS05acw==</ds:Modulus><ds:Exponent>AQAB</ds:Exponent></ds:RSAKeyValue></ds:KeyValue></ds:KeyInfo></ds:Signature><saml:Subject><saml:NameID Format=”urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified” SPNameQualifier=”https://saml.centis1504.net/sp”>RpGaj4IRLtdR2-W1-YD3jTjzHhJF</saml:NameID><saml:SubjectConfirmation Method=”urn:oasis:names:tc:SAML:2.0:cm:bearer”><saml:SubjectConfirmationData InResponseTo=”vIV8WvY8YQyP4c8vCyzBKV47kapv” NotOnOrAfter=”2013-08-09T06:36:12.805Z” Recipient=”https://saml.centis1504.net/sp/acs.do”/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore=”2013-08-08T06:36:12.805Z” NotOnOrAfter=”2013-08-09T06:36:12.805Z”><saml:AudienceRestriction><saml:Audience>https://saml.centis1504.net/sp</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant=”2013-08-08T06:36:12.805Z”><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name=”mail” NameFormat=”urn:oasis:names:tc:SAML:2.0:attrname-format:uri”><saml:AttributeValue xmlns:xs=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:type=”xs:string”>jojh@centis1504.net</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response> 위 내용을 c:/rsa-response.xml 에 저장한후에 아래와 같이 검증할 수 있다.
import java.io.FileInputStream; import java.io.StringWriter; import java.security.Key; import java.security.KeyException; import java.security.PublicKey; import java.util.Iterator; import java.util.List; import javax.xml.crypto.AlgorithmMethod; import javax.xml.crypto.KeySelector; import javax.xml.crypto.KeySelectorException; import javax.xml.crypto.KeySelectorResult; import javax.xml.crypto.XMLCryptoContext; import javax.xml.crypto.XMLStructure; import javax.xml.crypto.dsig.Reference; import javax.xml.crypto.dsig.SignatureMethod; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMValidateContext; import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.crypto.dsig.keyinfo.KeyValue; import javax.xml.parsers.DocumentBuilderFactory; import org.jcp.xml.dsig.internal.dom.DOMX509Data; import org.opensaml.xml.util.XMLHelper; import org.w3c.dom.Document; import org.w3c.dom.NodeList; /** * This is a simple example of validating an XML Signature using the JSR 105 * API. It assumes the key needed to validate the signature is contained in a * KeyValue KeyInfo. */ public class Validate { // // Synopsis: java Validate [document] // // where "document" is the name of a file containing the XML document // to be validated. // public static void main(String[] args) throws Exception { // Instantiate the document to be validated DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); Document doc = dbf.newDocumentBuilder().parse(new FileInputStream("c:/saml-response.xml")); // dbf.newDocumentBuilder().parse(new FileInputStream(args[0])); StringWriter writer = new StringWriter(); XMLHelper.writeNode(doc, writer); System.out.println(writer.toString()); // Find Signature element NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); if (nl.getLength() == 0) { throw new Exception("Cannot find Signature element"); } // Create a DOM XMLSignatureFactory that will be used to unmarshal the // document containing the XMLSignature XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); // Create a DOMValidateContext and specify a KeyValue KeySelector // and document context DOMValidateContext valContext = new DOMValidateContext(new KeyValueKeySelector(), nl.item(0)); // unmarshal the XMLSignature XMLSignature signature = fac.unmarshalXMLSignature(valContext); // Validate the XMLSignature (generated above) boolean coreValidity = signature.validate(valContext); // Check core validation status if (coreValidity == false) { System.err.println("Signature failed core validation"); boolean sv = signature.getSignatureValue().validate(valContext); System.out.println("signature validation status: " + sv); // check the validation status of each Reference Iterator이 예제에서는 Assertion내부의 Key정보가 있는데 키값 또는 X509증명서로 검증을 할 수 있다. X509증명서를 이용하여 서명을 하는 부분은 아래를 참조하라. http://www.java-only.com/LoadTutorial.javaonly?id=67]]>i = signature.getSignedInfo().getReferences().iterator(); Reference r = null; for (int j = 0; i.hasNext(); j++) { r = i.next(); System.out.println(r.getURI() + " => "+r); boolean refValid = (r).validate(valContext); System.out.println("ref[" + j + "] validity status: " + refValid); } } else { System.out.println("Signature passed core validation"); } } /** * KeySelector which retrieves the public key out of the KeyValue element * and returns it. NOTE: If the key algorithm doesn't match signature * algorithm, then the public key will be ignored. */ private static class KeyValueKeySelector extends KeySelector { public KeySelectorResult select(KeyInfo keyInfo, KeySelector.Purpose purpose, AlgorithmMethod method, XMLCryptoContext context) throws KeySelectorException { System.out.println("keyInfo="+keyInfo); System.out.println("method="+method); if (keyInfo == null) { throw new KeySelectorException("Null KeyInfo object!"); } SignatureMethod sm = (SignatureMethod) method; List list = keyInfo.getContent(); for (int i = 0; i < list.size(); i++) { XMLStructure xmlStructure = (XMLStructure) list.get(i); System.out.println(xmlStructure); if (xmlStructure instanceof KeyValue) { PublicKey pk = null; try { pk = ((KeyValue) xmlStructure).getPublicKey(); } catch (KeyException ke) { throw new KeySelectorException(ke); } // make sure algorithm is compatible with method if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) { return new SimpleKeySelectorResult(pk); } } else if (xmlStructure instanceof DOMX509Data) { sun.security.x509.X509CertImpl cert = (sun.security.x509.X509CertImpl) ((DOMX509Data)xmlStructure).getContent().get(0); PublicKey pk = cert.getPublicKey(); System.out.println("SignatureMethod => " + sm.getAlgorithm()); System.out.println("PublicKey => " + pk.getAlgorithm()); if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) { return new SimpleKeySelectorResult(pk); } } } throw new KeySelectorException("No KeyValue element found!"); } // @@@FIXME: this should also work for key types other than DSA/RSA static boolean algEquals(String algURI, String algName) { if (algName.equalsIgnoreCase("DSA") && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) { return true; } else if (algName.equalsIgnoreCase("RSA") && algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) { return true; } else { return false; } } } private static class SimpleKeySelectorResult implements KeySelectorResult { private PublicKey pk; SimpleKeySelectorResult(PublicKey pk) { this.pk = pk; } public Key getKey() { return pk; } } }