Skip to content

Commit 08c626c

Browse files
authored
Resolve XML-encoded carriage returns during signature validation (#578)
1 parent 8114d4c commit 08c626c

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

src/passport-saml/saml.ts

+8
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,8 @@ class SAML {
730730
if (totalReferencedNodes.length > 1) {
731731
return false;
732732
}
733+
// normalize XML to replace XML-encoded carriage returns with actual carriage returns
734+
fullXml = this.normalizeXml(fullXml);
733735
fullXml = this.normalizeNewlines(fullXml);
734736
return sig.checkSignature(fullXml);
735737
}
@@ -1418,6 +1420,12 @@ class SAML {
14181420
// https://github.com/node-saml/passport-saml/issues/431#issuecomment-718132752
14191421
return xml.replace(/\r\n?/g, "\n");
14201422
}
1423+
1424+
normalizeXml(xml: string): string {
1425+
// we can use this utility to parse and re-stringify XML
1426+
// `DOMParser` will take care of normalization tasks, like replacing XML-encoded carriage returns with actual carriage returns
1427+
return new xmldom.DOMParser({}).parseFromString(xml).toString();
1428+
}
14211429
}
14221430

14231431
export { SAML };

test/test-signatures.js

+23
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,27 @@ describe('Signatures', function() {
100100

101101
});
102102

103+
describe("Signature on saml:Response with XML-encoded carriage returns", () => {
104+
const samlResponseXml = fs
105+
.readFileSync(
106+
__dirname + "/static/signatures/valid/response.root-unsigned.assertion-signed.xml"
107+
)
108+
.toString();
109+
const makeBody = (str) => ({ SAMLResponse: Buffer.from(str).toString("base64") });
110+
111+
const insertChars = (str, where, chars) =>
112+
str.replace(new RegExp(`(<ds:${where}>)(.{10})(.{10})`), `$1$2${chars}$3`);
113+
114+
it("SignatureValue with &#13;", async () => {
115+
const body = makeBody(insertChars(samlResponseXml, "SignatureValue", "&#13;"));
116+
await testOneResponseBody(body, false, 2);
117+
});
118+
119+
it("SignatureValue with &#xd;", async () => {
120+
const body = makeBody(insertChars(samlResponseXml, "SignatureValue", "&#xd;"));
121+
await testOneResponseBody(body, false, 2);
122+
});
123+
124+
});
125+
103126
});

0 commit comments

Comments
 (0)