diff --git a/src/signed-xml.ts b/src/signed-xml.ts index e5d80af7..4f6d11ec 100644 --- a/src/signed-xml.ts +++ b/src/signed-xml.ts @@ -252,26 +252,72 @@ export class SignedXml { this.signedXml = xml; const doc = new xmldom.DOMParser().parseFromString(xml); + // Reset the references as only references from our re-parsed signedInfo node can be trusted + this.references = []; + + const unverifiedSignedInfoCanon = this.getCanonSignedInfoXml(doc); + if (!unverifiedSignedInfoCanon) { + if (callback) { + callback(new Error("Canonical signed info cannot be empty"), false); + return; + } + + throw new Error("Canonical signed info cannot be empty"); + } + + // unsigned, verify later to keep with consistent callback behavior + const parsedUnverifiedSignedInfo = new xmldom.DOMParser().parseFromString( + unverifiedSignedInfoCanon, + "text/xml", + ); + + const unverifiedSignedInfoDoc = parsedUnverifiedSignedInfo.documentElement; + if (!unverifiedSignedInfoDoc) { + if (callback) { + callback(new Error("Could not parse unverifiedSignedInfoCanon into a document"), false); + return; + } + + throw new Error("Could not parse unverifiedSignedInfoCanon into a document"); + } + + const references = utils.findChildren(unverifiedSignedInfoDoc, "Reference"); + if (!utils.isArrayHasLength(references)) { + if (callback) { + callback(new Error("could not find any Reference elements"), false); + return; + } + + throw new Error("could not find any Reference elements"); + } + + // TODO: In a future release we'd like to load the Signature and its References at the same time, + // however, in the `.loadSignature()` method we don't have the entire document, + // which we need to to keep the inclusive namespaces + for (const reference of references) { + this.loadReference(reference); + } if (!this.getReferences().every((ref) => this.validateReference(ref, doc))) { if (callback) { - callback(new Error("Could not validate all references")); + callback(new Error("Could not validate all references"), false); return; } return false; } - const signedInfoCanon = this.getCanonSignedInfoXml(doc); + // Stage B: Take the signature algorithm and key and verify the SignatureValue against the canonicalized SignedInfo const signer = this.findSignatureAlgorithm(this.signatureAlgorithm); const key = this.getCertFromKeyInfo(this.keyInfo) || this.publicCert || this.privateKey; if (key == null) { throw new Error("KeyInfo or publicCert or privateKey is required to validate signature"); } + if (callback) { - signer.verifySignature(signedInfoCanon, key, this.signatureValue, callback); + signer.verifySignature(unverifiedSignedInfoCanon, key, this.signatureValue, callback); } else { - const verified = signer.verifySignature(signedInfoCanon, key, this.signatureValue); + const verified = signer.verifySignature(unverifiedSignedInfoCanon, key, this.signatureValue); if (verified === false) { throw new Error( @@ -295,6 +341,11 @@ export class SignedXml { if (signedInfo.length === 0) { throw new Error("could not find SignedInfo element in the message"); } + if (signedInfo.length > 1) { + throw new Error( + "could not get canonicalized signed info for a signature that contains multiple SignedInfo nodes", + ); + } if ( this.canonicalizationAlgorithm === "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" || @@ -522,11 +573,43 @@ export class SignedXml { this.signatureAlgorithm = signatureAlgorithm.value as SignatureAlgorithmType; } - this.references = []; - const references = xpath.select( - ".//*[local-name(.)='SignedInfo']/*[local-name(.)='Reference']", - signatureNode, + const signedInfoNodes = utils.findChildren(this.signatureNode, "SignedInfo"); + if (!utils.isArrayHasLength(signedInfoNodes)) { + throw new Error("no signed info node found"); + } + if (signedInfoNodes.length > 1) { + throw new Error("could not load signature that contains multiple SignedInfo nodes"); + } + + // Try to operate on the c14n version of `signedInfo`. This forces the initial `getReferences()` + // API call to always return references that are loaded under the canonical `SignedInfo` + // in the case that the client access the `.references` **before** signature verification. + + // Ensure canonicalization algorithm is exclusive, otherwise we'd need the entire document + let canonicalizationAlgorithmForSignedInfo = this.canonicalizationAlgorithm; + if ( + !canonicalizationAlgorithmForSignedInfo || + canonicalizationAlgorithmForSignedInfo === + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" || + canonicalizationAlgorithmForSignedInfo === + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" + ) { + canonicalizationAlgorithmForSignedInfo = "http://www.w3.org/2001/10/xml-exc-c14n#"; + } + + const temporaryCanonSignedInfo = this.getCanonXml( + [canonicalizationAlgorithmForSignedInfo], + signedInfoNodes[0], + ); + const temporaryCanonSignedInfoXml = new xmldom.DOMParser().parseFromString( + temporaryCanonSignedInfo, + "text/xml", ); + const signedInfoDoc = temporaryCanonSignedInfoXml.documentElement; + + this.references = []; + const references = utils.findChildren(signedInfoDoc, "Reference"); + if (!utils.isArrayHasLength(references)) { throw new Error("could not find any Reference elements"); } @@ -572,11 +655,15 @@ export class SignedXml { if (nodes.length === 0) { throw new Error(`could not find DigestValue node in reference ${refNode.toString()}`); } - const firstChild = nodes[0].firstChild; - if (!firstChild || !("data" in firstChild)) { - throw new Error(`could not find the value of DigestValue in ${nodes[0].toString()}`); + if (nodes.length > 1) { + throw new Error( + `could not load reference for a node that contains multiple DigestValue nodes: ${refNode.toString()}`, + ); + } + const digestValue = nodes[0].textContent; + if (!digestValue) { + throw new Error(`could not find the value of DigestValue in ${refNode.toString()}`); } - const digestValue = firstChild.data; const transforms: string[] = []; let inclusiveNamespacesPrefixList: string[] = []; @@ -626,11 +713,14 @@ export class SignedXml { ) { transforms.push("http://www.w3.org/TR/2001/REC-xml-c14n-20010315"); } + const refUri = isDomNode.isElementNode(refNode) + ? refNode.getAttribute("URI") || undefined + : undefined; this.addReference({ transforms, digestAlgorithm: digestAlgo, - uri: isDomNode.isElementNode(refNode) ? utils.findAttr(refNode, "URI")?.value : undefined, + uri: refUri, digestValue, inclusiveNamespacesPrefixList, isEmptyUri: false, diff --git a/test/saml-response-tests.spec.ts b/test/saml-response-tests.spec.ts index b6ee8263..7ae94bc8 100644 --- a/test/saml-response-tests.spec.ts +++ b/test/saml-response-tests.spec.ts @@ -92,4 +92,78 @@ describe("SAML response tests", function () { // This doesn't matter, just want to make sure that we don't fail due to unknown algorithm expect(() => sig.checkSignature(xml)).to.throw(/^invalid signature/); }); + + it("throws an error for a document with no `SignedInfo` node", function () { + const xml = fs.readFileSync("./test/static/invalid_saml_no_signed_info.xml", "utf-8"); + const doc = new xmldom.DOMParser().parseFromString(xml); + const node = xpath.select1( + "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + doc, + ); + + isDomNode.assertIsNodeLike(node); + const sig = new SignedXml(); + const feidePublicCert = fs.readFileSync("./test/static/feide_public.pem"); + sig.publicCert = feidePublicCert; + + expect(() => sig.loadSignature(node)).to.throw("no signed info node found"); + }); + + it("test validation ignores an additional wrapped `SignedInfo` node", function () { + const xml = fs.readFileSync("./test/static/saml_wrapped_signed_info_node.xml", "utf-8"); + const doc = new xmldom.DOMParser().parseFromString(xml); + const assertion = xpath.select1("//*[local-name(.)='Assertion']", doc); + isDomNode.assertIsNodeLike(assertion); + const signature = xpath.select1( + "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + assertion, + ); + isDomNode.assertIsNodeLike(signature); + + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/saml_external_ns.pem"); + sig.loadSignature(signature); + expect(sig.getReferences().length).to.equal(1); + const checkSignatureResult = sig.checkSignature(xml); + expect(checkSignatureResult).to.be.true; + }); + + it("test signature throws if multiple `SignedInfo` nodes are found", function () { + const xml = fs.readFileSync("./test/static/saml_multiple_signed_info_nodes.xml", "utf-8"); + const doc = new xmldom.DOMParser().parseFromString(xml); + const assertion = xpath.select1("//*[local-name(.)='Assertion'][1]", doc); + isDomNode.assertIsNodeLike(assertion); + const signature = xpath.select1( + "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + assertion, + ); + isDomNode.assertIsNodeLike(signature); + + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/saml_external_ns.pem"); + expect(() => sig.loadSignature(signature)).to.throw( + "could not load signature that contains multiple SignedInfo nodes", + ); + }); + + describe("for a SAML response with a digest value comment", () => { + it("loads digest value from text content instead of comment", function () { + const xml = fs.readFileSync("./test/static/valid_saml_with_digest_comment.xml", "utf-8"); + const doc = new xmldom.DOMParser().parseFromString(xml); + const assertion = xpath.select1("//*[local-name(.)='Assertion']", doc); + isDomNode.assertIsNodeLike(assertion); + const signature = xpath.select1( + "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']", + assertion, + ); + isDomNode.assertIsNodeLike(signature); + const sig = new SignedXml(); + sig.publicCert = fs.readFileSync("./test/static/feide_public.pem"); + + sig.loadSignature(signature); + + expect(sig.getReferences()[0].digestValue).to.equal("RnNjoyUguwze5w2R+cboyTHlkQk="); + expect(sig.checkSignature(xml)).to.be.false; + }); + }); }); diff --git a/test/static/invalid_saml_no_signed_info.xml b/test/static/invalid_saml_no_signed_info.xml new file mode 100644 index 00000000..cfc34ca1 --- /dev/null +++ b/test/static/invalid_saml_no_signed_info.xml @@ -0,0 +1,9 @@ +https://openidp.feide.no + + + dkONrkxW+LSuDvnNMG/mWYFa47d2WGyapLhXSTYqrlT9Td+tT7ciojNJ55WTaPaCMt7IrGtIxxskPAZIjdIn5pRyDxHr0joWxzZ7oZHCOI1CnQV5HjOq+rzzmEN2LctCZ6S4hbL7SQ1qJ3vp2BCXAygy4tmJOURQdnk0KLwwRS8= +MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==https://openidp.feide.no + + + RnNjoyUguwze5w2R+cboyTHlkQk=aw5711jKP7xragunjRRCAD4mT4xKHc37iohBpQDbdSomD3ksOSB96UZQp0MtaC3xlVSkMtYw85Om96T2q2xrxLLYVA50eFJEMMF7SCVPStWTVjBlaCuOPEQxIaHyJs9Sy3MCEfbBh4Pqn9IJBd1kzwdlCrWWjAmksbFFg5wHQJA= +MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==_6c5dcaa3053321ff4d63785fbc3f67c59a129cde82passport-samlurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordbergieHenriBergiusHenri Bergiushenri.bergius@nemein.combergie@rnd.feide.no8216c78fe244502efa13f62e6615c94acb7bdf3ebergieHenriBergiusHenri Bergiushenri.bergius@nemein.combergie@rnd.feide.no8216c78fe244502efa13f62e6615c94acb7bdf3e \ No newline at end of file diff --git a/test/static/saml_multiple_signed_info_nodes.xml b/test/static/saml_multiple_signed_info_nodes.xml new file mode 100644 index 00000000..aed22887 --- /dev/null +++ b/test/static/saml_multiple_signed_info_nodes.xml @@ -0,0 +1 @@ +https://app.onelogin.com/saml/metadata/164679https://app.onelogin.com/saml/metadata/164679Gx0mTydMn1k6804jZBrdUrZmbV4=jGst6BnAC9xOeqa6hKNPsoMm2TY=oHEPKtwoCbfq1QRm2pjx35zVMqAsti4nQU+3ws8EUJUXHmPG2EoX3HBkb7D2wN4m+ZFrdwARUpNJlhhOIz/eG4jES6ar0tvlNN3qE5cqcQhwZHyRARLnTlERqyZU9Qm729DnAGBeXCdMb736zi16onOIVPNA63LRTzUIxhyZqypDCf1wd6me/ur6UUgH11nYOu4JDYx0iWNkXc1Nad7vkF9oMPeO1QsMxuZSIVH4tvdJkue+qAnu2l+dFJb0LPfm+xmIC0FBo+VX1ECCWRoUZIxjotQfAM6yZpHIi5fNqPXkVyN9fYoUEa9CafqHlc4tAAdgAgGeOqA3jWeC8ZnOVA==MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UEBwwMU2FudGEgTW9uaWNhMREwDwYDVQQKDAhPbmVMb2dpbjEZMBcGA1UEAwwQYXBwLm9uZWxvZ2luLmNvbTAeFw0xMzA1MjcwODU1MTNaFw0xODA1MjcwODU1MTNaMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQHDAxTYW50YSBNb25pY2ExETAPBgNVBAoMCE9uZUxvZ2luMRkwFwYDVQQDDBBhcHAub25lbG9naW4uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoXoc7IFZQRv+SwJ15zjIl9touwY5e6b7H4vn3OtOUByjOKHUX8VX0TpbAV2ctZE2GSALx1AGuQAv6O4MVUH+qn/2IAiBY3a7zKN07UBsya7xFMQVHuGE6EiBAs9jpA9wjvYMPRkS5wYZcwjpTQSZK7zFPPtobG8K/1vDbm/tWZjNLmZmQePmXpwrQAuC0+NlzlmnjoQYB2xp2NaTUK9JnnmuB5qev3dpUwlYGSJpf+HUIoxuo8IpxAXOymq1d6tEEJgU1kR2sa7o1sSRFo31YeW/qYCP/gcLJZo3MRUDFe0g5MHeliFue9DsKYUsC6qwAD3gc+MI47buiD6Msu11cwIDAQABo4HUMIHRMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAAJFJRIlpQQSFsuNdeq7FkTJIH4MIGRBgNVHSMEgYkwgYaAFAAJFJRIlpQQSFsuNdeq7FkTJIH4oWukaTBnMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UEBwwMU2FudGEgTW9uaWNhMREwDwYDVQQKDAhPbmVMb2dpbjEZMBcGA1UEAwwQYXBwLm9uZWxvZ2luLmNvbYIBATAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADggEBAB9zN+g6N4sUBE61RaMUH2LSHWwOtfhL64i7pjHjvZa47/qcV/S0Yyd4IE44ho9i2N+AM79d34mThc30oK5aVxOKphKf+xM/cOyVaWIeqr+dCbkY/0OpLEwWOh9VSgOizRO3evLMurbtR892LbSK/Td3hG5jfwoHD23nHH87Dv/3KyZox9MkJdY2DXOHGGIcsqoIifaTyNZyhW6RgwEujQ6LjsaolP1YoeV85TZFKTLa1Ta7ZLUVUC2UJWqz+kRlsyGxf+E/ZmJ7hSq0ZBVHrVOyXjCcFn6X0/W5SrpOmN3fZYcj8Bp6vhB0cJk9qpjgWOP2RCuBdHZVawjCjIaE+bc=anyone@gmail.comForNodeJSurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportkartik.cds@gmail.comKartikCDShttps://app.onelogin.com/saml/metadata/164679kartik.cds@gmail.comForNodeJSurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportkartik.cds@gmail.comKartikCDS \ No newline at end of file diff --git a/test/static/saml_wrapped_signed_info_node.xml b/test/static/saml_wrapped_signed_info_node.xml new file mode 100644 index 00000000..b7eb19d1 --- /dev/null +++ b/test/static/saml_wrapped_signed_info_node.xml @@ -0,0 +1 @@ +https://app.onelogin.com/saml/metadata/164679https://app.onelogin.com/saml/metadata/164679jGst6BnAC9xOeqa6hKNPsoMm2TY=Gx0mTydMn1k6804jZBrdUrZmbV4=oHEPKtwoCbfq1QRm2pjx35zVMqAsti4nQU+3ws8EUJUXHmPG2EoX3HBkb7D2wN4m+ZFrdwARUpNJlhhOIz/eG4jES6ar0tvlNN3qE5cqcQhwZHyRARLnTlERqyZU9Qm729DnAGBeXCdMb736zi16onOIVPNA63LRTzUIxhyZqypDCf1wd6me/ur6UUgH11nYOu4JDYx0iWNkXc1Nad7vkF9oMPeO1QsMxuZSIVH4tvdJkue+qAnu2l+dFJb0LPfm+xmIC0FBo+VX1ECCWRoUZIxjotQfAM6yZpHIi5fNqPXkVyN9fYoUEa9CafqHlc4tAAdgAgGeOqA3jWeC8ZnOVA==MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UEBwwMU2FudGEgTW9uaWNhMREwDwYDVQQKDAhPbmVMb2dpbjEZMBcGA1UEAwwQYXBwLm9uZWxvZ2luLmNvbTAeFw0xMzA1MjcwODU1MTNaFw0xODA1MjcwODU1MTNaMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQHDAxTYW50YSBNb25pY2ExETAPBgNVBAoMCE9uZUxvZ2luMRkwFwYDVQQDDBBhcHAub25lbG9naW4uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoXoc7IFZQRv+SwJ15zjIl9touwY5e6b7H4vn3OtOUByjOKHUX8VX0TpbAV2ctZE2GSALx1AGuQAv6O4MVUH+qn/2IAiBY3a7zKN07UBsya7xFMQVHuGE6EiBAs9jpA9wjvYMPRkS5wYZcwjpTQSZK7zFPPtobG8K/1vDbm/tWZjNLmZmQePmXpwrQAuC0+NlzlmnjoQYB2xp2NaTUK9JnnmuB5qev3dpUwlYGSJpf+HUIoxuo8IpxAXOymq1d6tEEJgU1kR2sa7o1sSRFo31YeW/qYCP/gcLJZo3MRUDFe0g5MHeliFue9DsKYUsC6qwAD3gc+MI47buiD6Msu11cwIDAQABo4HUMIHRMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAAJFJRIlpQQSFsuNdeq7FkTJIH4MIGRBgNVHSMEgYkwgYaAFAAJFJRIlpQQSFsuNdeq7FkTJIH4oWukaTBnMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UEBwwMU2FudGEgTW9uaWNhMREwDwYDVQQKDAhPbmVMb2dpbjEZMBcGA1UEAwwQYXBwLm9uZWxvZ2luLmNvbYIBATAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADggEBAB9zN+g6N4sUBE61RaMUH2LSHWwOtfhL64i7pjHjvZa47/qcV/S0Yyd4IE44ho9i2N+AM79d34mThc30oK5aVxOKphKf+xM/cOyVaWIeqr+dCbkY/0OpLEwWOh9VSgOizRO3evLMurbtR892LbSK/Td3hG5jfwoHD23nHH87Dv/3KyZox9MkJdY2DXOHGGIcsqoIifaTyNZyhW6RgwEujQ6LjsaolP1YoeV85TZFKTLa1Ta7ZLUVUC2UJWqz+kRlsyGxf+E/ZmJ7hSq0ZBVHrVOyXjCcFn6X0/W5SrpOmN3fZYcj8Bp6vhB0cJk9qpjgWOP2RCuBdHZVawjCjIaE+bc=anyone@gmail.comForNodeJSurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportkartik.cds@gmail.comKartikCDShttps://app.onelogin.com/saml/metadata/164679kartik.cds@gmail.comForNodeJSurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportkartik.cds@gmail.comKartikCDS \ No newline at end of file diff --git a/test/static/valid_saml_with_digest_comment.xml b/test/static/valid_saml_with_digest_comment.xml new file mode 100644 index 00000000..d0996872 --- /dev/null +++ b/test/static/valid_saml_with_digest_comment.xml @@ -0,0 +1,7 @@ +https://openidp.feide.no +https://openidp.feide.no + + + RnNjoyUguwze5w2R+cboyTHlkQk=aw5711jKP7xragunjRRCAD4mT4xKHc37iohBpQDbdSomD3ksOSB96UZQp0MtaC3xlVSkMtYw85Om96T2q2xrxLLYVA50eFJEMMF7SCVPStWTVjBlaCuOPEQxIaHyJs9Sy3MCEfbBh4Pqn9IJBd1kzwdlCrWWjAmksbFFg5wHQJA= +MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==test@example.compassport-samlurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordbergieHenriBergiusHenri Bergiushenri.bergius@nemein.combergie@rnd.feide.no8216c78fe244502efa13f62e6615c94acb7bdf3ebergieHenriBergiusHenri Bergiushenri.bergius@nemein.combergie@rnd.feide.no8216c78fe244502efa13f62e6615c94acb7bdf3e + \ No newline at end of file