Skip to content

Commit

Permalink
fix for signature checks failing with 
 chars (#748)
Browse files Browse the repository at this point in the history
* Add test case for issue (#747)

Co-authored-by: Riley Wills <[email protected]>

* fix for signature checks failing with &#13; chars

---------

Co-authored-by: Riley Wills <[email protected]>
  • Loading branch information
deepakprabhakara and rileyw authored Dec 19, 2024
1 parent 6c0575a commit 2f89ad9
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/validateSignature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const _hasValidSignature = (xml, cert, certThumbprint) => {
idAttribute: 'AssertionID',
});

signed.loadSignature(signature.toString());
signed.loadSignature(signature);

let valid;
let id, calculatedThumbprint;
Expand Down
54 changes: 54 additions & 0 deletions test/assets/saml20.validResponseSignedMessage-unsanitized.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfxfd74aca6-c440-d8a1-827c-0d30840315a9" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#pfxfd74aca6-c440-d8a1-827c-0d30840315a9"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>o2gfRtA1O8EEy6J8Sl7L4dKsQts=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>xk5Z0neBXyFACKQztJC5EXMiFCNSFyjlwkwaB8fdz5n4TnwKstzwUianBxCtmMM2dMYjzENnPL3jigcikJawkNrfmV6JP+9VXoK54C/Bb0nH69zwp/Am8VuvJZShgzAjHJ0L34o2l5QcW14qSeKR9+OPhenbyp/Uhxxe/eEGECE=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQ0FADBSMQswCQYDVQQGEwJ1czET&#13;
MBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMT25lbG9naW4gSW5jMRcwFQYD&#13;
VQQDDA5zcC5leGFtcGxlLmNvbTAeFw0xNDA3MTcxNDEyNTZaFw0xNTA3MTcxNDEy&#13;
NTZaMFIxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQK&#13;
DAxPbmVsb2dpbiBJbmMxFzAVBgNVBAMMDnNwLmV4YW1wbGUuY29tMIGfMA0GCSqG&#13;
SIb3DQEBAQUAA4GNADCBiQKBgQDZx+ON4IUoIWxgukTb1tOiX3bMYzYQiwWPUNMp&#13;
+Fq82xoNogso2bykZG0yiJm5o8zv/sd6pGouayMgkx/2FSOdc36T0jGbCHuRSbti&#13;
a0PEzNIRtmViMrt3AeoWBidRXmZsxCNLwgIV6dn2WpuE5Az0bHgpZnQxTKFek0BM&#13;
KU/d8wIDAQABo1AwTjAdBgNVHQ4EFgQUGHxYqZYyX7cTxKVODVgZwSTdCnwwHwYD&#13;
VR0jBBgwFoAUGHxYqZYyX7cTxKVODVgZwSTdCnwwDAYDVR0TBAUwAwEB/zANBgkq&#13;
hkiG9w0BAQ0FAAOBgQByFOl+hMFICbd3DJfnp2Rgd/dqttsZG/tyhILWvErbio/D&#13;
Ee98mXpowhTkC04ENprOyXi7ZbUqiicF89uAGyt1oqgTUCD1VsLahqIcmrzgumNy&#13;
TwLGWo17WDAa1/usDhetWAMhgzF/Cnf5ek0nK00m0YZGyc4LzgD0CROMASTWNg==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
<saml:Subject>
<saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf2014<!-- a comment? -->6dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
<saml:AudienceRestriction>
<saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">te<!-- a comment? -->[email protected]</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue>
<saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
84 changes: 84 additions & 0 deletions test/lib/saml20.responseSignedMessage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import fs from 'fs';

// Tests Configuration
const validResponse = fs.readFileSync('./test/assets/saml20.validResponseSignedMessage.xml').toString();
const validResponseUnsanitized = fs
.readFileSync('./test/assets/saml20.validResponseSignedMessage-unsanitized.xml')
.toString();

const issuerName = 'http://idp.example.com/metadata.php';
const thumbprint = 'e606eced42fa3abd0c5693456384f5931b174707';
Expand Down Expand Up @@ -92,3 +95,84 @@ describe('saml20.responseSignedMessage', function () {
}
});
});

describe('saml20.validResponseSignedMessageUnsanitized', function () {
it('Should validate saml 2.0 token using thumbprint', async function () {
const response = await validate(validResponseUnsanitized, {
thumbprint: thumbprint,
bypassExpiration: true,
inResponseTo: inResponseTo,
});

assert.strictEqual(response.issuer, issuerName);
assert.strictEqual(
response.claims['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'],
'_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7'
);
});

it('Should validate saml 2.0 token using certificate', async function () {
const response = await validate(validResponseUnsanitized, {
publicKey: certificate,
bypassExpiration: true,
inResponseTo: inResponseTo,
});

assert.strictEqual(response.issuer, issuerName);
assert.strictEqual(
response.claims['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'],
'_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7'
);
});

it('Should validate saml 2.0 token and check audience', async function () {
const response = await validate(validResponseUnsanitized, {
publicKey: certificate,
audience: audience,
bypassExpiration: true,
inResponseTo: inResponseTo,
});
assert.strictEqual(response.issuer, issuerName);
});

it('Should fail with invalid audience', async function () {
try {
await validate(validResponseUnsanitized, {
publicKey: certificate,
audience: 'http://any-other-audience.com/',
bypassExpiration: true,
inResponseTo: inResponseTo,
});
} catch (error) {
const result = (error as Error).message;
assert.strictEqual(result, 'Invalid audience.');
}
});

it('Should fail with missing root element', async function () {
try {
await validate('invalid-assertion', {
publicKey: certificate,
bypassExpiration: true,
inResponseTo: inResponseTo,
});
} catch (error) {
const result = (error as Error).message;
assert.strictEqual(result, 'missing root element');
}
});

it('Should fail with invalid inResponseTo', async function () {
try {
await validate(validResponseUnsanitized, {
publicKey: certificate,
audience: audience,
bypassExpiration: true,
inResponseTo: 'not-the-right-response-to',
});
} catch (error) {
const result = (error as Error).message;
assert.strictEqual(result, 'Invalid InResponseTo.');
}
});
});

0 comments on commit 2f89ad9

Please sign in to comment.