Skip to content

Commit 5618b65

Browse files
authored
Resolve XML-encoded carriage returns during signature validation (#576)
1 parent 0798e4d commit 5618b65

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/node-saml/saml.ts

+8
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,8 @@ class SAML {
738738
if (totalReferencedNodes.length > 1) {
739739
return false;
740740
}
741+
// normalize XML to replace XML-encoded carriage returns with actual carriage returns
742+
fullXml = this.normalizeXml(fullXml);
741743
fullXml = this.normalizeNewlines(fullXml);
742744
return sig.checkSignature(fullXml);
743745
}
@@ -1465,6 +1467,12 @@ class SAML {
14651467
// https://github.com/node-saml/passport-saml/issues/431#issuecomment-718132752
14661468
return xml.replace(/\r\n?/g, "\n");
14671469
}
1470+
1471+
normalizeXml(xml: string): string {
1472+
// we can use this utility to parse and re-stringify XML
1473+
// `DOMParser` will take care of normalization tasks, like replacing XML-encoded carriage returns with actual carriage returns
1474+
return new xmldom.DOMParser({}).parseFromString(xml).toString();
1475+
}
14681476
}
14691477

14701478
export { SAML };

test/node-saml/test-signatures.spec.ts

+22
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,26 @@ describe("Signatures", function () {
279279
await testOneResponseBody(body, false, 1);
280280
});
281281
});
282+
283+
describe("Signature on saml:Response with XML-encoded carriage returns", () => {
284+
const samlResponseXml = fs
285+
.readFileSync(
286+
__dirname + "/../static/signatures/valid/response.root-unsigned.assertion-signed.xml"
287+
)
288+
.toString();
289+
const makeBody = (str: string) => ({ SAMLResponse: Buffer.from(str).toString("base64") });
290+
291+
const insertChars = (str: string, where: string, chars: string) =>
292+
str.replace(new RegExp(`(<ds:${where}>)(.{10})(.{10})`), `$1$2${chars}$3`);
293+
294+
it("SignatureValue with &#13;", async () => {
295+
const body = makeBody(insertChars(samlResponseXml, "SignatureValue", "&#13;"));
296+
await testOneResponseBody(body, false, 2);
297+
});
298+
299+
it("SignatureValue with &#xd;", async () => {
300+
const body = makeBody(insertChars(samlResponseXml, "SignatureValue", "&#xd;"));
301+
await testOneResponseBody(body, false, 2);
302+
});
303+
});
282304
});

0 commit comments

Comments
 (0)