Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export function extract(context: string, fields) {
const shortcut = field.shortcut;
// get optional fields
const index = field.index;
const excludeAttribute = field.excludeAttribute;
const attributePath = field.attributePath;

// set allowing overriding if there is a shortcut injected
Expand Down Expand Up @@ -361,6 +362,30 @@ export function extract(context: string, fields) {
[key]: attributeValues[0]
};
}

// case: single excluded attribute
/*
{
key: 'sharedCertificate',
excludeAttribute: 'use',
localPath: ['EntityDescriptor', '~SSODescriptor', 'KeyDescriptor'],
attributePath: ['KeyInfo', 'X509Data', 'X509Certificate'],
attributes: [],
}
*/
if (excludeAttribute) {
const fullPath = `${baseXPath}[not(@${excludeAttribute})]${buildAbsoluteXPath(attributePath)}`;
const node = select(fullPath, targetDoc);
return {
...result,
[key]: node.length > 0
? node
.filter((n: Node) => n.firstChild)
.map((n: Node) => n.firstChild!.nodeValue)
: undefined
};
}

// case: zero attribute
/*
{
Expand Down
3 changes: 3 additions & 0 deletions src/libsaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,9 @@ const libSaml = () => {
const certificateNode = select(".//*[local-name(.)='X509Certificate']", signatureNode) as any;
// certificate in metadata
let metadataCert: any = opts.metadata.getX509Certificate(certUse.signing);
if (!metadataCert) {
throw new Error('INVALID_CERTIFICATE_PROVIDED')
}
// flattens the nested array of Certificates from each KeyDescriptor
if (Array.isArray(metadataCert)) {
metadataCert = flattenDeep(metadataCert);
Expand Down
14 changes: 11 additions & 3 deletions src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ export default class Metadata implements MetadataInterface {
{
// shared certificate for both encryption and signing
key: 'sharedCertificate',
localPath: ['EntityDescriptor', '~SSODescriptor', 'KeyDescriptor', 'KeyInfo', 'X509Data', 'X509Certificate'],
excludeAttribute: 'use',
localPath: ['EntityDescriptor', '~SSODescriptor', 'KeyDescriptor'],
attributePath: ['KeyInfo', 'X509Data', 'X509Certificate'],
attributes: []
},
{
Expand All @@ -72,8 +74,14 @@ export default class Metadata implements MetadataInterface {
const sharedCertificate = this.meta.sharedCertificate;
if (typeof sharedCertificate === 'string') {
this.meta.certificate = {
signing: sharedCertificate,
encryption: sharedCertificate
signing: this.meta.certificate.signing || sharedCertificate,
encryption: this.meta.certificate.encryption || sharedCertificate
};
delete this.meta.sharedCertificate;
} else if (Array.isArray(sharedCertificate)) {
this.meta.certificate = {
signing: this.meta.certificate.signing || sharedCertificate[0],
encryption: this.meta.certificate.encryption || sharedCertificate[0]
};
delete this.meta.sharedCertificate;
}
Expand Down
28 changes: 27 additions & 1 deletion test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,13 @@ test('getAssertionConsumerService with two bindings', t => {
t.is(libsaml.verifySignature(responseSignedByCert2, { metadata: idpRollingCert.entityMeta, signatureAlgorithm: signatureAlgorithms.RSA_SHA256 })[0], true);

});

test('verify a XML signature with metadata but with multiple anonymous certificates, where some of them are incorrect', t => {
const responseSignedByCert1 = String(readFileSync('./test/misc/response_signed_cert1.xml'));
const metadata = idpMetadata(
readFileSync("./test/misc/idpmeta_multiple_anonymous_certs.xml")
);
t.is(libsaml.verifySignature(responseSignedByCert1, { metadata: metadata, signatureAlgorithm: signatureAlgorithms.RSA_SHA256 })[0], true);
});
test('verify a XML signature signed by RSA-SHA1 with .cer keyFile', t => {
const xml = String(readFileSync('./test/misc/signed_request_sha1.xml'));
t.is(libsaml.verifySignature(xml, { keyFile: './test/key/sp/cert.cer' })[0], true);
Expand Down Expand Up @@ -441,3 +447,23 @@ test('contains explicit certificate declaration for signing and encryption in me
t.not(encryptionCertificate, null);
t.not(signingCertificate, encryptionCertificate);
});

test('returns different certificates for signing and encryption when metadata contains one signing and one anonymous certificate', t => {
const metadata = idpMetadata(
readFileSync("./test/misc/idpmeta_one_signing_and_one_anonymous_cert.xml")
);
const signingCertificate = metadata.getX509Certificate("signing");
const encryptionCertificate = metadata.getX509Certificate("encryption");
t.not(signingCertificate, encryptionCertificate);
});

test('returns the same certificate for signing and encryption when multiple anonymous certificates are present', t => {
const metadata = idpMetadata(
readFileSync("./test/misc/idpmeta_multiple_anonymous_certs.xml")
);
const signingCertificate = metadata.getX509Certificate("signing");
const encryptionCertificate = metadata.getX509Certificate("encryption");
t.not(signingCertificate, null);
t.not(encryptionCertificate, null);
t.is(signingCertificate, encryptionCertificate);
});
111 changes: 111 additions & 0 deletions test/libsaml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import test from "ava";
import { SignedXml } from "xml-crypto";
import libSaml from "../src/libsaml";

const fakeMetadataInvalid = {
getX509Certificate: (_usage: string) => null,
};

const fakeMetadataValid = {
getX509Certificate: (_usage: string) => "VALIDCERT",
};

test("throws ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS when neither keyFile nor metadata provided", (t) => {
const xml = "<Response><Signature></Signature></Response>";
const error = t.throws(() => {
libSaml.verifySignature(xml, { signatureAlgorithm: "dummy" } as any);
});
t.is(error!.message, "ERR_UNDEFINED_SIGNATURE_VERIFIER_OPTIONS");
});

test("throws ERR_ZERO_SIGNATURE when no signature element exists", (t) => {
const xml = "<Response></Response>";
const error = t.throws(() => {
libSaml.verifySignature(xml, {
keyFile: "dummy.pem",
signatureAlgorithm: "dummy",
} as any);
});
t.is(error!.message, "ERR_ZERO_SIGNATURE");
});

test("throws ERR_POTENTIAL_WRAPPING_ATTACK when wrapping element is present", (t) => {
// Construct XML with a wrapping assertion inside SubjectConfirmationData
const xml = `
<Response>
<Signature>
<X509Data>
<X509Certificate>VALIDCERT</X509Certificate>
</X509Data>
</Signature>
<Assertion ID="ID">
<Subject>
<SubjectConfirmation>
<SubjectConfirmationData>
<Assertion></Assertion>
</SubjectConfirmationData>
</SubjectConfirmation>
</Subject>
</Assertion>
</Response>
`;
const error = t.throws(() => {
libSaml.verifySignature(xml, {
keyFile: "dummy.pem",
signatureAlgorithm: "dummy",
} as any);
});
t.is(error!.message, "ERR_POTENTIAL_WRAPPING_ATTACK");
});

test("throws INVALID_CERTIFICATE_PROVIDED when metadata returns no certificate", (t) => {
// Signature element is present and metadata returns null certificate.
const xml = `
<Response>
<Signature>
<X509Data>
<X509Certificate>ANOTHERCERT</X509Certificate>
</X509Data>
</Signature>
<Assertion ID="ID">Content</Assertion>
</Response>
`;
const error = t.throws(() => {
libSaml.verifySignature(xml, {
metadata: fakeMetadataInvalid,
signatureAlgorithm: "dummy",
} as any);
});
t.is(error!.message, "INVALID_CERTIFICATE_PROVIDED");
});

test("returns valid verification result when signature is valid", (t) => {
// Override SignedXml methods to simulate valid signature checking
const origCheckSignature = SignedXml.prototype.checkSignature;
const origLoadSignature = SignedXml.prototype.loadSignature;
SignedXml.prototype.checkSignature = () => true;
SignedXml.prototype.loadSignature = () => {};

// Create a minimal XML with a Signature element containing a valid certificate node
const xml = `
<Response>
<Signature>
<X509Data>
<X509Certificate>VALIDCERT</X509Certificate>
</X509Data>
</Signature>
<Assertion ID="ID">AssertionContent</Assertion>
</Response>
`;
const result = libSaml.verifySignature(xml, {
metadata: fakeMetadataValid,
signatureAlgorithm: "dummy",
} as any);
t.true(Array.isArray(result));
t.true(result[0] === true);
t.regex(typeof result[1] === "string" ? result[1] : "", /Assertion/);

// Restore the original methods
SignedXml.prototype.checkSignature = origCheckSignature;
SignedXml.prototype.loadSignature = origLoadSignature;
});
41 changes: 41 additions & 0 deletions test/misc/idpmeta_multiple_anonymous_certs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<EntityDescriptor ID="SMa4fd5378c57fa016d03c6b27a8e0cf6f99ed2073b" entityID="https://idp.example.com/metadata"
xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
<IDPSSODescriptor WantAuthnRequestsSigned="true" ID="SM14a93e72cb19411b4fc4eec882c98b12dbf55cea68e" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor>
<KeyInfo ID="SM4cee9750ee17bb2f60ddbe556a2798218f7a5bbed"
xmlns:ns1="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIIDlzCCAn+gAwIBAgIJAO1ymQc33+bWMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDAeFw0xNTA3MDUxODAyMjdaFw0xODA3MDQxODAyMjdaMGIxCzAJBgNVBAYTAkhLMRMwEQYDVQQIDApTb21lLVN0YXRlMRowGAYDVQQKDBFJZGVudGl0eSBQcm92aWRlcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxDDAKBgNVBAMMA0lEUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAODZsWhCe+yG0PalQPTUoD7yko5MTWMCRxJ8hSm2k7mG3Eg/Y2v0EBdCmTw7iDCevRqUmbmFnq7MROyV4eriJzh0KabAdZf7/k6koghst3ZUtWOwzshyxkBtWDwGmBpQGTGsKxJ8M1js3aSqNRXBT4OBWM9w2Glt1+8ty30RhYv3pSF+/HHLH7Ac+vLSIAlokaFW34RWTcJ/8rADuRWlXih4GfnIu0W/ncm5nTSaJiRAvr3dGDRO/khiXoJdbbOj7dHPULxVGbH9IbPK76TCwLbF7ikIMsPovVbTrpyL6vsbVUKeEl/5GKppTwp9DLAOeoSYpCYkkDkYKu9TRQjF02MCAwEAAaNQME4wHQYDVR0OBBYEFP2ut2AQdy6D1dwdwK740IHmbh38MB8GA1UdIwQYMBaAFP2ut2AQdy6D1dwdwK740IHmbh38MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBANMZUoPNmHzgja2PYkbvBYMHmpvUkVoiuvQ9cJPlqGTB2CRfG68BNNs/Clz8P7cIrAdkhCUwi1rSBhDuslGFNrSaIpv6B10FpBuKwef3G7YrPWFNEN6khY7aHNWSTHqKgs1DrGef2B9hvkrnHWbQVSVXrBFKe1wTCqcgGcOpYoSK7L8C6iX6uIA/uZYnVQ4NgBrizJ0azkjdegz3hwO/gt4malEURy8D85/AAVt6PAzhpb9VJUGxSXr/EfntVUEz3L2gUFWWk1CnZFyz0rIOEt/zPmeAY8BLyd/Tjxm4Y+gwNazKq5y9AJS+m858b/nM4QdCnUE4yyoWAJDUHiAmvFA=</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<KeyDescriptor>
<KeyInfo ID="SM4cee9750ee17cc2f60ddbe777a2798218f7a5bbef"
xmlns:ns1="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIIFLjCCAxYCCQCqGHhTssya9jANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJISzESMBAGA1UECAwJSG9uZyBLb25nMRIwEAYDVQQHDAlIb25nIEtvbmcxEDAOBgNVBAoMB3NhbWxpZnkxEDAOBgNVBAMMB3NhbWxpZnkwHhcNMjAwNTEwMTUyNjIzWhcNMzAwNTA4MTUyNjIzWjBZMQswCQYDVQQGEwJISzESMBAGA1UECAwJSG9uZyBLb25nMRIwEAYDVQQHDAlIb25nIEtvbmcxEDAOBgNVBAoMB3NhbWxpZnkxEDAOBgNVBAMMB3NhbWxpZnkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQG+abAeeWjwsOZt5SkcNcw/XSJcjSyJykEbEU2iguErRuOIyBfgj0p1UVBv33uL2igeYJT3OSXmSjvMO8KvqtYN2tJAjoFjghGr8NbIEZjYS4ukMZUbwxd2bRycD9OMI9g44AUB1sfQ0UyFwzEOseW3lcW1FnhcizA8TgI0GN4NpdVruNlpgoWdP3w+Syhtq0rWebY8g/HGFruEKn8VwbUblOZdP7jNVXsd1aUMScpuMa0khzzXPDN+Q0rwl79fO4ychSeKAAERdPXA1UfDfbh9W7pcYBP0ABXd91Bf9akplmbbVOIsNbuRIcVS7WvLwCr613JuJ+EtGDcUkrSpbuRvDW85DQRHBGuoKlcSG+imHQtHqRwMwMc8P54hIEBvaFW0RfwPfzdFNe8wARtmvIeX84iwq5Yey15Ly1rdopi7t2g7qyF7C/B9gZ3tJ/gPKp2NrdCGFBcahl93Lj56WWmI0jNHn7+7Y3x6isJ3KTRXIliSrAwiK7/7UezOlWzs1k8mGQWZTD3AGGKu1cBVwuC+rh4wkLsDeHfzxavbXxVEok9p/1P28M4GiHfS0POE3Hl4RT3Q6AiYWnmFYyZ+smY97SgPwB4tTNYFjC6+9d/BllNoQb8wsPjqp6ZDn1OeY668hp+ZAcE13AFdiTBMVrcdEECCPLxg1kFk5wZdHrGwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCyA/14hKTqfdeOVl+MQ2SLPWi7pC/t/Zv4kc361xP26FAVSSrxgXq9kVLZeJIAqCwjGHkl/DTUlA8hfLfuZx5z+NI/qIodsXAjCzsCe7paEbjvR6OQjYkR0UY4u/AOO7x2op2KDFKNuWT9KZNm8bh1mxwNKep1fJP2O5M0nMYAGYbPsLAOn7mzZyufQl8hsJwIV2s8sbft7s8vmEYZbuueQDOJCMTt+eC08LONrovYChyYmj3i5RIk8kcaodeSDo811F1B1gDvO/dmVxgrHEgoai7X6LUoiAiLkigP7udNEZxbXsRlOhBRv9w+rRXFurVFlUPkQ9UF+QB0BoyIcUxo+fZ8vCA4xEVBenVBadpFbwum6+XeTkvDoRc4sSCpm8v2qtprc8aU/0F82EzxSybYvstc5lDv7wuwCwNwfoAQ+/16kTpJvoYbOXUPv5yCA3mIuqYeA1woaWPXsE4jNOzTqv1qOZQTvXProEgK5B0FR5ILc4mfNrD2p9VGbiYf2GjCfeEzDFg174dvSn2MMp1yK5pvZEp7yFE8z1eduYN6W/7qdtss9BGpnyS5X7LuYfDvd1dHP6/JuqJDbfSVG9prYWcaMRd3FzSC7jBeetJgMyj4dunfqw8R16aONhwvICtzdFa93hYrDvTyo3ae80KFi0WGgApKeoqO5t3l1PAcaA==</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<KeyDescriptor>
<KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIID6TCCAtGgAwIBAgIJAPQQPsolUypeMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFTATBgNVBAoTDGV4cHJlc3Mtc2FtbDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQDEwVlc2FtbDAeFw0xNTEwMDMwMzU3MzRaFw0xODEwMDIwMzU3MzRaMFYxCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxFTATBgNVBAoTDGV4cHJlc3Mtc2FtbDEMMAoGA1UECxMDZGV2MQ4wDAYDVQQDEwVlc2FtbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7dF1gUNu8en0fHMSbzf192uB8m2CTeHeEeYrmq5rau6t1WzaHwbSStd9tJ/11Arm8f8zfefFqEBA0EYbp/DMqHb9ZiLGgIff08679NOYeK/d9EAs5DzvTMTR6QqG7a4vH3jKOksIbjM35h5RVitVDxo+xWDKyvOpuNE64bJlWHOEiNxvwmcHfJ2hAd1EozaRLcJOojFHg51alUqiNIZ+vpkMAM8s3lUlcYETKqTpcnsE7c1QX60cCrFN4m3SNS98HGBEdotch8+2Myzz957cBiwg9CR05PtEfjH0gGXJbL56JmpPyY+TkEiNMtMqJ7RNkK92gZfoY2i3RdjLKOHDUCAwEAAaOBuTCBtjAdBgNVHQ4EFgQUm4zK2qBtDMICekupt3LnRBdbP9UwgYYGA1UdIwR/MH2AFJuMytqgbQzCAnpLqbdy50QXWz/VoVqkWDBWMQswCQYDVQQGEwJISzESMBAGA1UECBMJSG9uZyBLb25nMRUwEwYDVQQKEwxleHByZXNzLXNhbWwxDDAKBgNVBAsTA2RldjEOMAwGA1UEAxMFZXNhbWyCCQD0ED7KJVMqXjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA9t7VMtX93yIYIGFC20GCsMYZeZpTedxpxpjqom2dOuOUaDQgrZcGF3FVbFqTEpPtOnsKXYaCg7FJvUjxv7FIuix5H7JO6DALoJ792pfG2wwS2PvDiGFxMfGnNvb3aLnB/s6wTyWBpDYRdwlB5nj37KPk6kpFJj3N9x5BD1oTdmQqeVuacjoiemIulkc33P28tGl6Datth4WpE0LwmrwREQ1NWixi2j1Ti3mjYkyqGVY8XphWKEIIWmheqLnYCXRXhbxZ4E+FGg81ZYG8TKYC/IjzV8p0rLnAI1qS7wdwv5UJ9vQJt6KcxdHHZsUlpIfaJC6N5DvAL/qUY8DoIymgz</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:entity</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</NameIDFormat>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.example.org/sso/SingleSignOnService" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.example.org/sso/SingleSignOnService" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://idp.example.org/sso/SingleSignOnService" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.example.org/sso/SingleLogoutService" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.example.org/sso/SingleLogoutService" />
</IDPSSODescriptor>
</EntityDescriptor>
44 changes: 44 additions & 0 deletions test/misc/idpmeta_one_signing_and_one_anonymous_cert.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<EntityDescriptor ID="SMa4fd5378c57fa016d03c6b27a8e0cf6f99ed2073b"
entityID="https://idp.example.com/metadata"
xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
<IDPSSODescriptor WantAuthnRequestsSigned="true"
ID="SM14a93e72cb19411b4fc4eec882c98b12dbf55cea68e"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
cert 1
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<KeyDescriptor>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
cert 2
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:entity</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</NameIDFormat>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://idp.example.org/sso/SingleSignOnService" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://idp.example.org/sso/SingleSignOnService" />
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
Location="https://idp.example.org/sso/SingleSignOnService" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://idp.example.org/sso/SingleLogoutService" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://idp.example.org/sso/SingleLogoutService" />
</IDPSSODescriptor>
</EntityDescriptor>