From 02a6d2a32f64597e6954ec507f2950a4694c37b5 Mon Sep 17 00:00:00 2001 From: Sixto Martin Date: Sat, 7 Jul 2018 01:45:03 +0200 Subject: [PATCH] Improve addSign method. Support DigestMethod. On decrypt method, verify that there is encrypted data --- .../onelogin/saml2/authn/SamlResponse.java | 13 +- .../com/onelogin/saml2/settings/Metadata.java | 30 ++++- .../saml2/settings/Saml2Settings.java | 21 +++- .../java/com/onelogin/saml2/util/Util.java | 112 +++++++++++++----- .../saml2/test/settings/MetadataTest.java | 88 ++++++++++++++ .../test/settings/Saml2SettingsTest.java | 11 +- .../onelogin/saml2/test/util/UtilsTest.java | 62 +++++++++- .../resources/config/config.all.properties | 9 +- 8 files changed, 302 insertions(+), 44 deletions(-) diff --git a/core/src/main/java/com/onelogin/saml2/authn/SamlResponse.java b/core/src/main/java/com/onelogin/saml2/authn/SamlResponse.java index 5bc5bdfb..9ff710cf 100644 --- a/core/src/main/java/com/onelogin/saml2/authn/SamlResponse.java +++ b/core/src/main/java/com/onelogin/saml2/authn/SamlResponse.java @@ -1065,8 +1065,9 @@ private NodeList query(String nameQuery, Node context) throws XPathExpressionExc * @throws SAXException * @throws ParserConfigurationException * @throws SettingsException + * @throws ValidationError */ - private Document decryptAssertion(Document dom) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException { + private Document decryptAssertion(Document dom) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException, ValidationError { PrivateKey key = settings.getSPkey(); if (key == null) { @@ -1074,11 +1075,17 @@ private Document decryptAssertion(Document dom) throws XPathExpressionException, } NodeList encryptedDataNodes = Util.query(dom, "/samlp:Response/saml:EncryptedAssertion/xenc:EncryptedData"); + if (encryptedDataNodes.getLength() == 0) { + throw new ValidationError("No /samlp:Response/saml:EncryptedAssertion/xenc:EncryptedData element found", ValidationError.MISSING_ENCRYPTED_ELEMENT); + } Element encryptedData = (Element) encryptedDataNodes.item(0); Util.decryptElement(encryptedData, key); // We need to Remove the saml:EncryptedAssertion Node NodeList AssertionDataNodes = Util.query(dom, "/samlp:Response/saml:EncryptedAssertion/saml:Assertion"); + if (encryptedDataNodes.getLength() == 0) { + throw new ValidationError("No /samlp:Response/saml:EncryptedAssertion/saml:Assertion element found", ValidationError.MISSING_ENCRYPTED_ELEMENT); + } Node assertionNode = AssertionDataNodes.item(0); assertionNode.getParentNode().getParentNode().replaceChild(assertionNode, assertionNode.getParentNode()); @@ -1099,7 +1106,7 @@ public String getSAMLResponseXml() { if (encrypted) { xml = Util.convertDocumentToString(decryptedDocument); } else { - xml = samlResponseString; + xml = samlResponseString; } return xml; } @@ -1113,7 +1120,7 @@ protected Document getSAMLResponseDocument() { if (encrypted) { doc = decryptedDocument; } else { - doc = samlResponseDocument; + doc = samlResponseDocument; } return doc; } diff --git a/core/src/main/java/com/onelogin/saml2/settings/Metadata.java b/core/src/main/java/com/onelogin/saml2/settings/Metadata.java index 7b1b6044..1318e916 100644 --- a/core/src/main/java/com/onelogin/saml2/settings/Metadata.java +++ b/core/src/main/java/com/onelogin/saml2/settings/Metadata.java @@ -23,6 +23,7 @@ import com.onelogin.saml2.model.Organization; import com.onelogin.saml2.model.AttributeConsumingService; import com.onelogin.saml2.model.RequestedAttribute; +import com.onelogin.saml2.util.Constants; import com.onelogin.saml2.util.Util; /** @@ -377,9 +378,32 @@ public final String getMetadataString() { */ public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm) throws XPathExpressionException, XMLSecurityException { - Document metadataDoc = Util.loadXML(metadata); - String signedMetadata = Util.addSign(metadataDoc, key, cert, signAlgorithm); - LOGGER.debug("Signed metadata --> " + signedMetadata); + return signMetadata(metadata, key, cert, signAlgorithm, Constants.SHA1); + } + + /** + * Signs the metadata with the key/cert provided + * + * @param metadata + * SAML Metadata XML + * @param key + * Private Key + * @param cert + * x509 Public certificate + * @param signAlgorithm + * Signature Algorithm + * @param digestAlgorithm + * Digest Algorithm + * + * @return string Signed Metadata + * @throws XMLSecurityException + * @throws XPathExpressionException + */ + public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm, String digestAlgorithm) throws XPathExpressionException, XMLSecurityException + { + Document metadataDoc = Util.loadXML(metadata); + String signedMetadata = Util.addSign(metadataDoc, key, cert, signAlgorithm, digestAlgorithm); + LOGGER.debug("Signed metadata --> " + signedMetadata); return signedMetadata; } } diff --git a/core/src/main/java/com/onelogin/saml2/settings/Saml2Settings.java b/core/src/main/java/com/onelogin/saml2/settings/Saml2Settings.java index 5ea7b2d1..5f627623 100644 --- a/core/src/main/java/com/onelogin/saml2/settings/Saml2Settings.java +++ b/core/src/main/java/com/onelogin/saml2/settings/Saml2Settings.java @@ -71,6 +71,7 @@ public class Saml2Settings { private String requestedAuthnContextComparison = "exact"; private boolean wantXMLValidation = true; private String signatureAlgorithm = Constants.RSA_SHA1; + private String digestAlgorithm = Constants.SHA1; private boolean rejectUnsolicitedResponsesWithInResponseTo = false; // Compress @@ -318,6 +319,13 @@ public String getSignatureAlgorithm() { return signatureAlgorithm; } + /** + * @return the digestAlgorithm setting value + */ + public String getDigestAlgorithm() { + return digestAlgorithm; + } + /** * @return SP Contact info */ @@ -681,6 +689,16 @@ public void setSignatureAlgorithm(String signatureAlgorithm) { this.signatureAlgorithm = signatureAlgorithm; } + /** + * Set the digestAlgorithm setting value + * + * @param digestAlgorithm + * the digestAlgorithm value to be set. + */ + public void setDigestAlgorithm(String digestAlgorithm) { + this.digestAlgorithm = digestAlgorithm; + } + /** * Controls if unsolicited Responses are rejected if they contain an InResponseTo value. * @@ -951,7 +969,8 @@ public String getSPMetadata() throws CertificateEncodingException { metadataString, this.getSPkey(), this.getSPcert(), - this.getSignatureAlgorithm() + this.getSignatureAlgorithm(), + this.getDigestAlgorithm() ); } catch (Exception e) { LOGGER.debug("Error executing signMetadata: " + e.getMessage(), e); diff --git a/core/src/main/java/com/onelogin/saml2/util/Util.java b/core/src/main/java/com/onelogin/saml2/util/Util.java index 8498357f..eac23dad 100644 --- a/core/src/main/java/com/onelogin/saml2/util/Util.java +++ b/core/src/main/java/com/onelogin/saml2/util/Util.java @@ -96,6 +96,7 @@ * A class that contains several auxiliary methods related to the SAML protocol */ public final class Util { + /** * Private property to construct a logger for this class. */ @@ -109,6 +110,11 @@ public final class Util { /** Indicates if JAXP 1.5 support has been detected. */ private static boolean JAXP_15_SUPPORTED = isJaxp15Supported(); + static { + System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true"); + org.apache.xml.security.Init.init(); + } + private Util() { //not called } @@ -380,7 +386,6 @@ public static Document parseXML(InputSource inputSource) throws ParserConfigurat * @return the Document object */ public static String convertDocumentToString(Document doc, Boolean c14n) { - org.apache.xml.security.Init.init(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (c14n) { XMLUtils.outputDOMc14nWithComments(doc, baos); @@ -525,8 +530,6 @@ public static X509Certificate loadCert(String certString) throws CertificateExce * @throws GeneralSecurityException */ public static PrivateKey loadPrivateKey(String keyString) throws GeneralSecurityException { - org.apache.xml.security.Init.init(); - String extractedKey = formatPrivateKey(keyString, false); extractedKey = chunkString(extractedKey, 64); KeyFactory kf = KeyFactory.getInstance("RSA"); @@ -808,8 +811,6 @@ public static String urlDecoder(String input) { * @throws SignatureException */ public static byte[] sign(String text, PrivateKey key, String signAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - org.apache.xml.security.Init.init(); - if (signAlgorithm == null) { signAlgorithm = Constants.RSA_SHA1; } @@ -964,8 +965,6 @@ public static Boolean validateMetadataSign(Document doc, X509Certificate cert, S public static Boolean validateSignNode(Node signNode, X509Certificate cert, String fingerprint, String alg) { Boolean res = false; try { - org.apache.xml.security.Init.init(); - Element sigElement = (Element) signNode; XMLSignature signature = new XMLSignature(sigElement, "", true); @@ -1034,8 +1033,6 @@ public static boolean isAlgorithmWhitelisted(String alg) { */ public static void decryptElement(Element encryptedDataElement, PrivateKey inputKey) { try { - org.apache.xml.security.Init.init(); - XMLCipher xmlCipher = XMLCipher.getInstance(); xmlCipher.init(XMLCipher.DECRYPT_MODE, null); @@ -1111,15 +1108,36 @@ public static Document copyDocument(Document source) throws ParserConfigurationE * The public certificate * @param signAlgorithm * Signature Algorithm - * + * * @return the signed document in string format - * + * * @throws XMLSecurityException * @throws XPathExpressionException */ public static String addSign(Document document, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws XMLSecurityException, XPathExpressionException { - org.apache.xml.security.Init.init(); + return addSign(document, key, certificate, signAlgorithm, Constants.SHA1); + } + /** + * Signs the Document using the specified signature algorithm with the private key and the public certificate. + * + * @param document + * The document to be signed + * @param key + * The private key + * @param certificate + * The public certificate + * @param signAlgorithm + * Signature Algorithm + * @param digestAlgorithm + * Digest Algorithm + * + * @return the signed document in string format + * + * @throws XMLSecurityException + * @throws XPathExpressionException + */ + public static String addSign(Document document, PrivateKey key, X509Certificate certificate, String signAlgorithm, String digestAlgorithm) throws XMLSecurityException, XPathExpressionException { // Check arguments. if (document == null) { throw new IllegalArgumentException("Provided document was null"); @@ -1132,7 +1150,7 @@ public static String addSign(Document document, PrivateKey key, X509Certificate if (key == null) { throw new IllegalArgumentException("Provided key was null"); } - + if (certificate == null) { throw new IllegalArgumentException("Provided certificate was null"); } @@ -1140,10 +1158,13 @@ public static String addSign(Document document, PrivateKey key, X509Certificate if (signAlgorithm == null || signAlgorithm.isEmpty()) { signAlgorithm = Constants.RSA_SHA1; } + if (digestAlgorithm == null || digestAlgorithm.isEmpty()) { + digestAlgorithm = Constants.SHA1; + } - // document.normalizeDocument(); + document.normalizeDocument(); - String c14nMethod = Constants.C14NEXC_WC; + String c14nMethod = Constants.C14NEXC; // Signature object XMLSignature sig = new XMLSignature(document, null, signAlgorithm, c14nMethod); @@ -1155,30 +1176,42 @@ public static String addSign(Document document, PrivateKey key, X509Certificate // If Issuer, locate Signature after Issuer, Otherwise as first child. NodeList issuerNodes = Util.query(document, "//saml:Issuer", null); + Element elemToSign = null; if (issuerNodes.getLength() > 0) { Node issuer = issuerNodes.item(0); root.insertBefore(sig.getElement(), issuer.getNextSibling()); + elemToSign = (Element) issuer.getParentNode(); } else { - root.insertBefore(sig.getElement(), root.getFirstChild()); + NodeList entitiesDescriptorNodes = Util.query(document, "//md:EntitiesDescriptor", null); + if (entitiesDescriptorNodes.getLength() > 0) { + elemToSign = (Element)entitiesDescriptorNodes.item(0); + } else { + NodeList entityDescriptorNodes = Util.query(document, "//md:EntityDescriptor", null); + if (entityDescriptorNodes.getLength() > 0) { + elemToSign = (Element)entityDescriptorNodes.item(0); + } else { + elemToSign = root; + } + } + root.insertBefore(sig.getElement(), elemToSign.getFirstChild()); } - String id = root.getAttribute("ID"); + String id = elemToSign.getAttribute("ID"); String reference = id; if (!id.isEmpty()) { - root.setIdAttributeNS(null, "ID", true); + elemToSign.setIdAttributeNS(null, "ID", true); reference = "#" + id; } // Create the transform for the document Transforms transforms = new Transforms(document); transforms.addTransform(Constants.ENVSIG); - //transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS); transforms.addTransform(c14nMethod); - sig.addDocument(reference, transforms, Constants.SHA1); + sig.addDocument(reference, transforms, digestAlgorithm); // Add the certification info - sig.addKeyInfo(certificate); + sig.addKeyInfo(certificate); // Sign the document sig.sign(key); @@ -1197,14 +1230,16 @@ public static String addSign(Document document, PrivateKey key, X509Certificate * The public certificate * @param signAlgorithm * Signature Algorithm - * + * @param digestAlgorithm + * Digest Algorithm + * * @return the signed document in string format * * @throws ParserConfigurationException * @throws XMLSecurityException * @throws XPathExpressionException */ - public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException { + public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm, String digestAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException { // Check arguments. if (node == null) { throw new IllegalArgumentException("Provided node was null"); @@ -1216,9 +1251,31 @@ public static String addSign(Node node, PrivateKey key, X509Certificate certific Node newNode = doc.importNode(node, true); doc.appendChild(newNode); - return addSign(doc, key, certificate, signAlgorithm); - } - + return addSign(doc, key, certificate, signAlgorithm, digestAlgorithm); + } + + /** + * Signs a Node using the specified signature algorithm with the private key and the public certificate. + * + * @param node + * The Node to be signed + * @param key + * The private key + * @param certificate + * The public certificate + * @param signAlgorithm + * Signature Algorithm + * + * @return the signed document in string format + * + * @throws ParserConfigurationException + * @throws XMLSecurityException + * @throws XPathExpressionException + */ + public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException { + return addSign(node, key, certificate, signAlgorithm, Constants.SHA1); + } + /** * Validates signed binary data (Used to validate GET Signature). * @@ -1241,8 +1298,6 @@ public static String addSign(Node node, PrivateKey key, X509Certificate certific public static Boolean validateBinarySignature(String signedQuery, byte[] signature, X509Certificate cert, String signAlg) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException { Boolean valid = false; try { - org.apache.xml.security.Init.init(); - String convertedSigAlg = signatureAlgConversion(signAlg); Signature sig = Signature.getInstance(convertedSigAlg); //, provider); @@ -1278,7 +1333,6 @@ public static Boolean validateBinarySignature(String signedQuery, byte[] signatu public static Boolean validateBinarySignature(String signedQuery, byte[] signature, List certList, String signAlg) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException { Boolean valid = false; - org.apache.xml.security.Init.init(); String convertedSigAlg = signatureAlgConversion(signAlg); Signature sig = Signature.getInstance(convertedSigAlg); //, provider); diff --git a/core/src/test/java/com/onelogin/saml2/test/settings/MetadataTest.java b/core/src/test/java/com/onelogin/saml2/test/settings/MetadataTest.java index 59ef1890..e1da4a68 100644 --- a/core/src/test/java/com/onelogin/saml2/test/settings/MetadataTest.java +++ b/core/src/test/java/com/onelogin/saml2/test/settings/MetadataTest.java @@ -9,12 +9,20 @@ import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Calendar; import java.util.List; +import javax.xml.xpath.XPathExpressionException; + import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.apache.xml.security.exceptions.XMLSecurityException; import org.junit.Test; import com.onelogin.saml2.settings.Saml2Settings; @@ -23,6 +31,7 @@ import com.onelogin.saml2.model.AttributeConsumingService; import com.onelogin.saml2.model.RequestedAttribute; import com.onelogin.saml2.settings.Metadata; +import com.onelogin.saml2.util.Constants; import com.onelogin.saml2.util.SchemaFactory; import com.onelogin.saml2.util.Util; @@ -377,4 +386,83 @@ public void testGetAttributeConsumingServiceXmlWithMultipleAttributeValue() thro assertThat(metadataStr, containsString(reqAttr2Str)); assertThat(metadataStr, containsString(footerStr)); } + + /** + * Tests the signMetadata method of Metadata + * Case imported metadata + * + * @throws IOException + * @throws GeneralSecurityException + * @throws XMLSecurityException + * @throws XPathExpressionException + * + * @see com.onelogin.saml2.settings.Metadata#signMetadata + */ + @Test + public void testSignImportedMetadata() throws IOException, GeneralSecurityException, XPathExpressionException, XMLSecurityException { + String certString = Util.getFileAsString("data/customPath/certs/sp.crt"); + X509Certificate cert = Util.loadCert(certString); + String keyString = Util.getFileAsString("data/customPath/certs/sp.pem"); + PrivateKey key = Util.loadPrivateKey(keyString); + String signAlgorithmSha1 = Constants.RSA_SHA1; + String digestAlgorithmSha1 = Constants.SHA1; + + String metadata = Util.getFileAsString("data/metadata/metadata_settings1.xml"); + String metadataSigned = Metadata.signMetadata(metadata, key, cert, signAlgorithmSha1); + assertThat(metadataSigned, containsString("")); + Document metadataSignedDoc = Util.loadXML(metadataSigned); + assertEquals("md:EntityDescriptor", metadataSignedDoc.getFirstChild().getNodeName()); + Node ds_signature_metadata = metadataSignedDoc.getFirstChild().getFirstChild(); + assertEquals("ds:Signature", ds_signature_metadata.getNodeName()); + Node canonization_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild(); + assertEquals("ds:CanonicalizationMethod", canonization_metadata_signed.getNodeName()); + assertEquals(Constants.C14NEXC, canonization_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node signature_method_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling(); + assertEquals("ds:SignatureMethod", signature_method_metadata_signed.getNodeName()); + assertEquals(signAlgorithmSha1, signature_method_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node digest_method_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getNextSibling(); + assertEquals("ds:DigestMethod", digest_method_metadata_signed.getNodeName()); + assertEquals(digestAlgorithmSha1, digest_method_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + } + + /** + * Tests the signMetadata method of Metadata + * Case generated metadata + * + * @throws Error + * @throws IOException + * @throws GeneralSecurityException + * @throws XMLSecurityException + * @throws XPathExpressionException + * + * @see com.onelogin.saml2.settings.Metadata#signMetadata + */ + @Test + public void testSigngeneratedMetadata() throws Error, IOException, GeneralSecurityException, XPathExpressionException, XMLSecurityException { + Saml2Settings settings = new SettingsBuilder().fromFile("config/config.all.properties").build(); + String certString = Util.getFileAsString("data/customPath/certs/sp.crt"); + X509Certificate cert = Util.loadCert(certString); + String keyString = Util.getFileAsString("data/customPath/certs/sp.pem"); + PrivateKey key = Util.loadPrivateKey(keyString); + String signAlgorithmSha256 = Constants.RSA_SHA256; + String digestAlgorithmSha512 = Constants.SHA512; + + Metadata metadataObj = new Metadata(settings); + String metadata = metadataObj.getMetadataString(); + String metadataSigned = Metadata.signMetadata(metadata, key, cert, signAlgorithmSha256, digestAlgorithmSha512); + assertThat(metadataSigned, containsString("")); + Document metadataSignedDoc = Util.loadXML(metadataSigned); + assertEquals("md:EntityDescriptor", metadataSignedDoc.getFirstChild().getNodeName()); + Node ds_signature_metadata = metadataSignedDoc.getFirstChild().getFirstChild(); + assertEquals("ds:Signature", ds_signature_metadata.getNodeName()); + Node canonization_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild(); + assertEquals("ds:CanonicalizationMethod", canonization_metadata_signed.getNodeName()); + assertEquals(Constants.C14NEXC, canonization_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node signature_method_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling(); + assertEquals("ds:SignatureMethod", signature_method_metadata_signed.getNodeName()); + assertEquals(signAlgorithmSha256, signature_method_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node digest_method_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getNextSibling(); + assertEquals("ds:DigestMethod", digest_method_metadata_signed.getNodeName()); + assertEquals(digestAlgorithmSha512, digest_method_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + } } diff --git a/core/src/test/java/com/onelogin/saml2/test/settings/Saml2SettingsTest.java b/core/src/test/java/com/onelogin/saml2/test/settings/Saml2SettingsTest.java index 439a735a..65c00c90 100644 --- a/core/src/test/java/com/onelogin/saml2/test/settings/Saml2SettingsTest.java +++ b/core/src/test/java/com/onelogin/saml2/test/settings/Saml2SettingsTest.java @@ -14,11 +14,13 @@ import org.junit.Test; import org.w3c.dom.Document; +import org.w3c.dom.Node; import com.onelogin.saml2.exception.Error; import com.onelogin.saml2.settings.Metadata; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.settings.SettingsBuilder; +import com.onelogin.saml2.util.Constants; import com.onelogin.saml2.util.SchemaFactory; import com.onelogin.saml2.util.Util; @@ -279,9 +281,14 @@ public void testGetSPMetadataSigned() throws Exception { Document metadataDoc = Util.loadXML(metadataStr); assertTrue(metadataDoc instanceof Document); - - assertEquals("md:EntityDescriptor", metadataDoc.getDocumentElement().getNodeName()); assertEquals("ds:Signature", metadataDoc.getDocumentElement().getFirstChild().getNodeName()); + Node ds_signature_metadata = metadataDoc.getFirstChild().getFirstChild(); + + assertEquals(Constants.C14NEXC, ds_signature_metadata.getFirstChild().getFirstChild().getAttributes().getNamedItem("Algorithm").getNodeValue()); + + assertEquals(Constants.RSA_SHA512, ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling().getAttributes().getNamedItem("Algorithm").getNodeValue()); + assertEquals(Constants.SHA1, ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getNextSibling().getAttributes().getNamedItem("Algorithm").getNodeValue()); + assertEquals("md:SPSSODescriptor", metadataDoc.getDocumentElement().getFirstChild().getNextSibling().getNodeName()); assertTrue(Util.validateXML(metadataDoc, SchemaFactory.SAML_SCHEMA_METADATA_2_0)); diff --git a/core/src/test/java/com/onelogin/saml2/test/util/UtilsTest.java b/core/src/test/java/com/onelogin/saml2/test/util/UtilsTest.java index c4170c49..602dc7bb 100644 --- a/core/src/test/java/com/onelogin/saml2/test/util/UtilsTest.java +++ b/core/src/test/java/com/onelogin/saml2/test/util/UtilsTest.java @@ -1628,6 +1628,9 @@ public void testAddSignDoc() throws URISyntaxException, IOException, GeneralSecu String keyString = Util.getFileAsString("data/customPath/certs/sp.pem"); PrivateKey key = Util.loadPrivateKey(keyString); String signAlgorithmSha1 = Constants.RSA_SHA1; + String signAlgorithmSha256 = Constants.RSA_SHA256; + String digestAlgorithmSha1 = Constants.SHA1; + String digestAlgorithmSha512 = Constants.SHA512; // AuthNReq String authNRequest = Util.getFileAsString("data/requests/authn_request.xml"); @@ -1658,12 +1661,22 @@ public void testAddSignDoc() throws URISyntaxException, IOException, GeneralSecu // Logout Request String logoutRequest = Util.getFileAsString("data/logout_requests/logout_request.xml"); Document logoutRequestDoc = Util.loadXML(logoutRequest); - String logoutRequestSigned = Util.addSign(logoutRequestDoc, key, cert, signAlgorithmSha1); + String logoutRequestSigned = Util.addSign(logoutRequestDoc, key, cert, signAlgorithmSha256, digestAlgorithmSha512); assertThat(logoutRequestSigned, containsString("")); Document logoutRequestSignedDoc = Util.loadXML(logoutRequestSigned); - Node ds_signature_logreq = logoutRequestSignedDoc.getFirstChild().getFirstChild().getNextSibling().getNextSibling(); - assertEquals("ds:Signature", ds_signature_logreq.getNodeName()); + assertEquals("samlp:LogoutRequest", logoutRequestSignedDoc.getFirstChild().getNodeName()); + Node ds_signature_logout_request = logoutRequestSignedDoc.getFirstChild().getFirstChild().getNextSibling().getNextSibling(); + assertEquals("ds:Signature", ds_signature_logout_request.getNodeName()); + Node canonization_logout_request_signed = ds_signature_logout_request.getFirstChild().getFirstChild(); + assertEquals("ds:CanonicalizationMethod", canonization_logout_request_signed.getNodeName()); + assertEquals(Constants.C14NEXC, canonization_logout_request_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node signature_method_logout_request_signed = ds_signature_logout_request.getFirstChild().getFirstChild().getNextSibling(); + assertEquals("ds:SignatureMethod", signature_method_logout_request_signed.getNodeName()); + assertEquals(signAlgorithmSha256, signature_method_logout_request_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node digest_method_logout_request_signed = ds_signature_logout_request.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getNextSibling(); + assertEquals("ds:DigestMethod", digest_method_logout_request_signed.getNodeName()); + assertEquals(digestAlgorithmSha512, digest_method_logout_request_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); // Logout Response String logoutResponse = Util.getFileAsString("data/logout_responses/logout_response.xml"); @@ -1672,8 +1685,18 @@ public void testAddSignDoc() throws URISyntaxException, IOException, GeneralSecu assertThat(logoutResponseSigned, containsString("")); Document logoutResponseSignedDoc = Util.loadXML(logoutResponseSigned); - Node ds_signature_logres = logoutResponseSignedDoc.getFirstChild().getFirstChild().getNextSibling().getNextSibling(); - assertEquals("ds:Signature", ds_signature_logres.getNodeName()); + assertEquals("samlp:LogoutResponse", logoutResponseSignedDoc.getFirstChild().getNodeName()); + Node ds_signature_logout_response = logoutResponseSignedDoc.getFirstChild().getFirstChild().getNextSibling().getNextSibling();; + assertEquals("ds:Signature", ds_signature_logout_response.getNodeName()); + Node canonization_logout_response_signed = ds_signature_logout_response.getFirstChild().getFirstChild(); + assertEquals("ds:CanonicalizationMethod", canonization_logout_response_signed.getNodeName()); + assertEquals(Constants.C14NEXC, canonization_logout_response_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node signature_method_logout_response_signed = ds_signature_logout_response.getFirstChild().getFirstChild().getNextSibling(); + assertEquals("ds:SignatureMethod", signature_method_logout_response_signed.getNodeName()); + assertEquals(signAlgorithmSha1, signature_method_logout_response_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node digest_method_logout_response_signed = ds_signature_logout_response.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getNextSibling(); + assertEquals("ds:DigestMethod", digest_method_logout_response_signed.getNodeName()); + assertEquals(digestAlgorithmSha1, digest_method_logout_response_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); // Metadata String metadata = Util.getFileAsString("data/metadata/metadata_settings1.xml"); @@ -1682,8 +1705,37 @@ public void testAddSignDoc() throws URISyntaxException, IOException, GeneralSecu assertThat(metadataSigned, containsString("")); Document metadataSignedDoc = Util.loadXML(metadataSigned); + assertEquals("md:EntityDescriptor", metadataSignedDoc.getFirstChild().getNodeName()); Node ds_signature_metadata = metadataSignedDoc.getFirstChild().getFirstChild(); assertEquals("ds:Signature", ds_signature_metadata.getNodeName()); + Node canonization_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild(); + assertEquals("ds:CanonicalizationMethod", canonization_metadata_signed.getNodeName()); + assertEquals(Constants.C14NEXC, canonization_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node signature_method_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling(); + assertEquals("ds:SignatureMethod", signature_method_metadata_signed.getNodeName()); + assertEquals(signAlgorithmSha1, signature_method_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node digest_method_metadata_signed = ds_signature_metadata.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getNextSibling(); + assertEquals("ds:DigestMethod", digest_method_metadata_signed.getNodeName()); + assertEquals(digestAlgorithmSha1, digest_method_metadata_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + + String metadata_entities = Util.getFileAsString("data/metadata/metadata_entities.xml"); + Document metadataEntitiesDoc = Util.loadXML(metadata_entities); + String metadataEntitiesSigned = Util.addSign(metadataEntitiesDoc, key, cert, signAlgorithmSha256, digestAlgorithmSha512); + assertThat(metadataEntitiesSigned, containsString("")); + + Document metadataEntitiesSignedDoc = Util.loadXML(metadataEntitiesSigned); + assertEquals("EntitiesDescriptor", metadataEntitiesSignedDoc.getFirstChild().getNodeName()); + Node ds_signature_metadata_entities = metadataEntitiesSignedDoc.getFirstChild().getFirstChild(); + assertEquals("ds:Signature", ds_signature_metadata_entities.getNodeName()); + Node canonization_metadata_entities_signed = ds_signature_metadata_entities.getFirstChild().getFirstChild(); + assertEquals("ds:CanonicalizationMethod", canonization_metadata_entities_signed.getNodeName()); + assertEquals(Constants.C14NEXC, canonization_metadata_entities_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node signature_method_metadata_entities_signed = ds_signature_metadata_entities.getFirstChild().getFirstChild().getNextSibling(); + assertEquals("ds:SignatureMethod", signature_method_metadata_entities_signed.getNodeName()); + assertEquals(signAlgorithmSha256, signature_method_metadata_entities_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); + Node digest_method_metadata_entities_signed = ds_signature_metadata_entities.getFirstChild().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getNextSibling(); + assertEquals("ds:DigestMethod", digest_method_metadata_entities_signed.getNodeName()); + assertEquals(digestAlgorithmSha512, digest_method_metadata_entities_signed.getAttributes().getNamedItem("Algorithm").getNodeValue()); } /** diff --git a/core/src/test/resources/config/config.all.properties b/core/src/test/resources/config/config.all.properties index 25588aa6..fdc03929 100644 --- a/core/src/test/resources/config/config.all.properties +++ b/core/src/test/resources/config/config.all.properties @@ -127,6 +127,13 @@ onelogin.saml2.security.want_xml_validation = true # 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512' onelogin.saml2.security.signature_algorithm = http://www.w3.org/2001/04/xmldsig-more#rsa-sha512 +# Algorithm that the toolkit will use on signing process. Options: +# 'http://www.w3.org/2000/09/xmldsig#sha1' +# 'http://www.w3.org/2001/04/xmlenc#sha256' +# 'http://www.w3.org/2001/04/xmldsig-more#sha384' +# 'http://www.w3.org/2001/04/xmlenc#sha512' +onelogin.saml2.security.digest_algorithm = http://www.w3.org/2000/09/xmldsig#sha1 + # Organization onelogin.saml2.organization.name = SP Java onelogin.saml2.organization.displayname = SP Java Example @@ -137,4 +144,4 @@ onelogin.saml2.organization.lang = en onelogin.saml2.contacts.technical.given_name = Technical Guy onelogin.saml2.contacts.technical.email_address = technical@example.com onelogin.saml2.contacts.support.given_name = Support Guy -onelogin.saml2.contacts.support.email_address = support@example.com \ No newline at end of file +onelogin.saml2.contacts.support.email_address = support@example.com