Skip to content

Commit 8ac6118

Browse files
ahacker1-securesamlparallels999mattgdblairworkos
authoredMar 14, 2025
Merge commit from fork
* Exports C14nCanonicalization, ExclusiveCanonicalization (#471) * Ensure that they agree on loading References from canon XML * Fix specific exploits * Clarify Comments * Add tests and multiple SignedInfo check. * Only allow exclusive canon. * Updates based on feedback. * Update signedInfo naming. * Remove unnecessary comment. * Apply suggested changes * Iterate on error behavior * Edit * Adding back the edit --------- Co-authored-by: parallels999 <[email protected]> Co-authored-by: mattgd <[email protected]> Co-authored-by: Blair Weber <[email protected]>
1 parent 0ed7ab2 commit 8ac6118

6 files changed

+195
-13
lines changed
 

‎src/signed-xml.ts

+103-13
Original file line numberDiff line numberDiff line change
@@ -252,26 +252,72 @@ export class SignedXml {
252252
this.signedXml = xml;
253253

254254
const doc = new xmldom.DOMParser().parseFromString(xml);
255+
// Reset the references as only references from our re-parsed signedInfo node can be trusted
256+
this.references = [];
257+
258+
const unverifiedSignedInfoCanon = this.getCanonSignedInfoXml(doc);
259+
if (!unverifiedSignedInfoCanon) {
260+
if (callback) {
261+
callback(new Error("Canonical signed info cannot be empty"), false);
262+
return;
263+
}
264+
265+
throw new Error("Canonical signed info cannot be empty");
266+
}
267+
268+
// unsigned, verify later to keep with consistent callback behavior
269+
const parsedUnverifiedSignedInfo = new xmldom.DOMParser().parseFromString(
270+
unverifiedSignedInfoCanon,
271+
"text/xml",
272+
);
273+
274+
const unverifiedSignedInfoDoc = parsedUnverifiedSignedInfo.documentElement;
275+
if (!unverifiedSignedInfoDoc) {
276+
if (callback) {
277+
callback(new Error("Could not parse unverifiedSignedInfoCanon into a document"), false);
278+
return;
279+
}
280+
281+
throw new Error("Could not parse unverifiedSignedInfoCanon into a document");
282+
}
283+
284+
const references = utils.findChildren(unverifiedSignedInfoDoc, "Reference");
285+
if (!utils.isArrayHasLength(references)) {
286+
if (callback) {
287+
callback(new Error("could not find any Reference elements"), false);
288+
return;
289+
}
290+
291+
throw new Error("could not find any Reference elements");
292+
}
293+
294+
// TODO: In a future release we'd like to load the Signature and its References at the same time,
295+
// however, in the `.loadSignature()` method we don't have the entire document,
296+
// which we need to to keep the inclusive namespaces
297+
for (const reference of references) {
298+
this.loadReference(reference);
299+
}
255300

256301
if (!this.getReferences().every((ref) => this.validateReference(ref, doc))) {
257302
if (callback) {
258-
callback(new Error("Could not validate all references"));
303+
callback(new Error("Could not validate all references"), false);
259304
return;
260305
}
261306

262307
return false;
263308
}
264309

265-
const signedInfoCanon = this.getCanonSignedInfoXml(doc);
310+
// Stage B: Take the signature algorithm and key and verify the SignatureValue against the canonicalized SignedInfo
266311
const signer = this.findSignatureAlgorithm(this.signatureAlgorithm);
267312
const key = this.getCertFromKeyInfo(this.keyInfo) || this.publicCert || this.privateKey;
268313
if (key == null) {
269314
throw new Error("KeyInfo or publicCert or privateKey is required to validate signature");
270315
}
316+
271317
if (callback) {
272-
signer.verifySignature(signedInfoCanon, key, this.signatureValue, callback);
318+
signer.verifySignature(unverifiedSignedInfoCanon, key, this.signatureValue, callback);
273319
} else {
274-
const verified = signer.verifySignature(signedInfoCanon, key, this.signatureValue);
320+
const verified = signer.verifySignature(unverifiedSignedInfoCanon, key, this.signatureValue);
275321

276322
if (verified === false) {
277323
throw new Error(
@@ -295,6 +341,11 @@ export class SignedXml {
295341
if (signedInfo.length === 0) {
296342
throw new Error("could not find SignedInfo element in the message");
297343
}
344+
if (signedInfo.length > 1) {
345+
throw new Error(
346+
"could not get canonicalized signed info for a signature that contains multiple SignedInfo nodes",
347+
);
348+
}
298349

299350
if (
300351
this.canonicalizationAlgorithm === "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" ||
@@ -522,11 +573,43 @@ export class SignedXml {
522573
this.signatureAlgorithm = signatureAlgorithm.value as SignatureAlgorithmType;
523574
}
524575

525-
this.references = [];
526-
const references = xpath.select(
527-
".//*[local-name(.)='SignedInfo']/*[local-name(.)='Reference']",
528-
signatureNode,
576+
const signedInfoNodes = utils.findChildren(this.signatureNode, "SignedInfo");
577+
if (!utils.isArrayHasLength(signedInfoNodes)) {
578+
throw new Error("no signed info node found");
579+
}
580+
if (signedInfoNodes.length > 1) {
581+
throw new Error("could not load signature that contains multiple SignedInfo nodes");
582+
}
583+
584+
// Try to operate on the c14n version of `signedInfo`. This forces the initial `getReferences()`
585+
// API call to always return references that are loaded under the canonical `SignedInfo`
586+
// in the case that the client access the `.references` **before** signature verification.
587+
588+
// Ensure canonicalization algorithm is exclusive, otherwise we'd need the entire document
589+
let canonicalizationAlgorithmForSignedInfo = this.canonicalizationAlgorithm;
590+
if (
591+
!canonicalizationAlgorithmForSignedInfo ||
592+
canonicalizationAlgorithmForSignedInfo ===
593+
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315" ||
594+
canonicalizationAlgorithmForSignedInfo ===
595+
"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
596+
) {
597+
canonicalizationAlgorithmForSignedInfo = "http://www.w3.org/2001/10/xml-exc-c14n#";
598+
}
599+
600+
const temporaryCanonSignedInfo = this.getCanonXml(
601+
[canonicalizationAlgorithmForSignedInfo],
602+
signedInfoNodes[0],
603+
);
604+
const temporaryCanonSignedInfoXml = new xmldom.DOMParser().parseFromString(
605+
temporaryCanonSignedInfo,
606+
"text/xml",
529607
);
608+
const signedInfoDoc = temporaryCanonSignedInfoXml.documentElement;
609+
610+
this.references = [];
611+
const references = utils.findChildren(signedInfoDoc, "Reference");
612+
530613
if (!utils.isArrayHasLength(references)) {
531614
throw new Error("could not find any Reference elements");
532615
}
@@ -572,11 +655,15 @@ export class SignedXml {
572655
if (nodes.length === 0) {
573656
throw new Error(`could not find DigestValue node in reference ${refNode.toString()}`);
574657
}
575-
const firstChild = nodes[0].firstChild;
576-
if (!firstChild || !("data" in firstChild)) {
577-
throw new Error(`could not find the value of DigestValue in ${nodes[0].toString()}`);
658+
if (nodes.length > 1) {
659+
throw new Error(
660+
`could not load reference for a node that contains multiple DigestValue nodes: ${refNode.toString()}`,
661+
);
662+
}
663+
const digestValue = nodes[0].textContent;
664+
if (!digestValue) {
665+
throw new Error(`could not find the value of DigestValue in ${refNode.toString()}`);
578666
}
579-
const digestValue = firstChild.data;
580667

581668
const transforms: string[] = [];
582669
let inclusiveNamespacesPrefixList: string[] = [];
@@ -626,11 +713,14 @@ export class SignedXml {
626713
) {
627714
transforms.push("http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
628715
}
716+
const refUri = isDomNode.isElementNode(refNode)
717+
? refNode.getAttribute("URI") || undefined
718+
: undefined;
629719

630720
this.addReference({
631721
transforms,
632722
digestAlgorithm: digestAlgo,
633-
uri: isDomNode.isElementNode(refNode) ? utils.findAttr(refNode, "URI")?.value : undefined,
723+
uri: refUri,
634724
digestValue,
635725
inclusiveNamespacesPrefixList,
636726
isEmptyUri: false,

‎test/saml-response-tests.spec.ts

+74
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,78 @@ describe("SAML response tests", function () {
9292
// This doesn't matter, just want to make sure that we don't fail due to unknown algorithm
9393
expect(() => sig.checkSignature(xml)).to.throw(/^invalid signature/);
9494
});
95+
96+
it("throws an error for a document with no `SignedInfo` node", function () {
97+
const xml = fs.readFileSync("./test/static/invalid_saml_no_signed_info.xml", "utf-8");
98+
const doc = new xmldom.DOMParser().parseFromString(xml);
99+
const node = xpath.select1(
100+
"/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
101+
doc,
102+
);
103+
104+
isDomNode.assertIsNodeLike(node);
105+
const sig = new SignedXml();
106+
const feidePublicCert = fs.readFileSync("./test/static/feide_public.pem");
107+
sig.publicCert = feidePublicCert;
108+
109+
expect(() => sig.loadSignature(node)).to.throw("no signed info node found");
110+
});
111+
112+
it("test validation ignores an additional wrapped `SignedInfo` node", function () {
113+
const xml = fs.readFileSync("./test/static/saml_wrapped_signed_info_node.xml", "utf-8");
114+
const doc = new xmldom.DOMParser().parseFromString(xml);
115+
const assertion = xpath.select1("//*[local-name(.)='Assertion']", doc);
116+
isDomNode.assertIsNodeLike(assertion);
117+
const signature = xpath.select1(
118+
"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
119+
assertion,
120+
);
121+
isDomNode.assertIsNodeLike(signature);
122+
123+
const sig = new SignedXml();
124+
sig.publicCert = fs.readFileSync("./test/static/saml_external_ns.pem");
125+
sig.loadSignature(signature);
126+
expect(sig.getReferences().length).to.equal(1);
127+
const checkSignatureResult = sig.checkSignature(xml);
128+
expect(checkSignatureResult).to.be.true;
129+
});
130+
131+
it("test signature throws if multiple `SignedInfo` nodes are found", function () {
132+
const xml = fs.readFileSync("./test/static/saml_multiple_signed_info_nodes.xml", "utf-8");
133+
const doc = new xmldom.DOMParser().parseFromString(xml);
134+
const assertion = xpath.select1("//*[local-name(.)='Assertion'][1]", doc);
135+
isDomNode.assertIsNodeLike(assertion);
136+
const signature = xpath.select1(
137+
"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
138+
assertion,
139+
);
140+
isDomNode.assertIsNodeLike(signature);
141+
142+
const sig = new SignedXml();
143+
sig.publicCert = fs.readFileSync("./test/static/saml_external_ns.pem");
144+
expect(() => sig.loadSignature(signature)).to.throw(
145+
"could not load signature that contains multiple SignedInfo nodes",
146+
);
147+
});
148+
149+
describe("for a SAML response with a digest value comment", () => {
150+
it("loads digest value from text content instead of comment", function () {
151+
const xml = fs.readFileSync("./test/static/valid_saml_with_digest_comment.xml", "utf-8");
152+
const doc = new xmldom.DOMParser().parseFromString(xml);
153+
const assertion = xpath.select1("//*[local-name(.)='Assertion']", doc);
154+
isDomNode.assertIsNodeLike(assertion);
155+
const signature = xpath.select1(
156+
"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']",
157+
assertion,
158+
);
159+
isDomNode.assertIsNodeLike(signature);
160+
const sig = new SignedXml();
161+
sig.publicCert = fs.readFileSync("./test/static/feide_public.pem");
162+
163+
sig.loadSignature(signature);
164+
165+
expect(sig.getReferences()[0].digestValue).to.equal("RnNjoyUguwze5w2R+cboyTHlkQk=");
166+
expect(sig.checkSignature(xml)).to.be.false;
167+
});
168+
});
95169
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx94e4a319-b6f7-4a40-25d1-01fcb642e4c5" Version="2.0" IssueInstant="2012-07-03T11:32:20Z" Destination="http://localhost:3000/login/callback" InResponseTo="_d766d16611ac0d14121b"><saml:Issuer>https://openidp.feide.no</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
2+
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
3+
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
4+
<ds:SignatureValue>dkONrkxW+LSuDvnNMG/mWYFa47d2WGyapLhXSTYqrlT9Td+tT7ciojNJ55WTaPaCMt7IrGtIxxskPAZIjdIn5pRyDxHr0joWxzZ7oZHCOI1CnQV5HjOq+rzzmEN2LctCZ6S4hbL7SQ1qJ3vp2BCXAygy4tmJOURQdnk0KLwwRS8=</ds:SignatureValue>
5+
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==</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="pfx66496e6c-3c29-230d-6d47-b245434b872d" Version="2.0" IssueInstant="2012-07-03T11:32:20Z"><saml:Issuer>https://openidp.feide.no</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
6+
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
7+
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
8+
<ds:Reference URI="#pfx66496e6c-3c29-230d-6d47-b245434b872d"><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>RnNjoyUguwze5w2R+cboyTHlkQk=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>aw5711jKP7xragunjRRCAD4mT4xKHc37iohBpQDbdSomD3ksOSB96UZQp0MtaC3xlVSkMtYw85Om96T2q2xrxLLYVA50eFJEMMF7SCVPStWTVjBlaCuOPEQxIaHyJs9Sy3MCEfbBh4Pqn9IJBd1kzwdlCrWWjAmksbFFg5wHQJA=</ds:SignatureValue>
9+
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml:Subject><saml:NameID SPNameQualifier="passport-saml" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_6c5dcaa3053321ff4d63785fbc3f67c59a129cde82</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2012-07-03T11:37:20Z" Recipient="http://localhost:3000/login/callback" InResponseTo="_d766d16611ac0d14121b"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2012-07-03T11:31:50Z" NotOnOrAfter="2012-07-03T11:37:20Z"><saml:AudienceRestriction><saml:Audience>passport-saml</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2012-07-03T11:32:20Z" SessionNotOnOrAfter="2012-07-03T19:32:20Z" SessionIndex="_c8e6823fe38ddbce125f9be6e5118b8c352d04bcae"><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:uri"><saml:AttributeValue xsi:type="xs:string">bergie</saml:AttributeValue></saml:Attribute><saml:Attribute Name="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri</saml:AttributeValue></saml:Attribute><saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="cn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">henri.bergius@nemein.com</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonPrincipalName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">bergie@rnd.feide.no</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonTargetedID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">8216c78fe244502efa13f62e6615c94acb7bdf3e</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">bergie</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:2.5.4.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">Henri Bergius</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">henri.bergius@nemein.com</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">bergie@rnd.feide.no</saml:AttributeValue></saml:Attribute><saml:Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"><saml:AttributeValue xsi:type="xs:string">8216c78fe244502efa13f62e6615c94acb7bdf3e</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response>

0 commit comments

Comments
 (0)
Please sign in to comment.