diff --git a/src/binding-post.ts b/src/binding-post.ts index 06d333aa..8f3040cc 100644 --- a/src/binding-post.ts +++ b/src/binding-post.ts @@ -90,7 +90,7 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any const nameIDFormat = idpSetting.nameIDFormat; const selectedNameIDFormat = Array.isArray(nameIDFormat) ? nameIDFormat[0] : nameIDFormat; if (metadata && metadata.idp && metadata.sp) { - const base = metadata.sp.getAssertionConsumerService(binding.post); + const base = metadata.sp.getAssertionConsumerService(binding.post, requestInfo.extract.request.assertionConsumerServiceIndex); let rawSamlResponse: string; const nowTime = new Date(); const spEntityID = metadata.sp.getEntityID(); @@ -98,7 +98,7 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any fiveMinutesLaterTime.setMinutes(fiveMinutesLaterTime.getMinutes() + 5); const fiveMinutesLater = fiveMinutesLaterTime.toISOString(); const now = nowTime.toISOString(); - const acl = metadata.sp.getAssertionConsumerService(binding.post); + const acl = metadata.sp.getAssertionConsumerService(binding.post, requestInfo.extract.request.assertionConsumerServiceIndex); const tvalue: any = { ID: id, AssertionID: idpSetting.generateID(), diff --git a/src/binding-redirect.ts b/src/binding-redirect.ts index 4ff402d9..46d78dab 100644 --- a/src/binding-redirect.ts +++ b/src/binding-redirect.ts @@ -144,7 +144,7 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {}, let id: string = idpSetting.generateID(); if (metadata && metadata.idp && metadata.sp) { - const base = metadata.sp.getAssertionConsumerService(binding.redirect); + const base = metadata.sp.getAssertionConsumerService(binding.redirect, requestInfo.extract.request.assertionConsumerServiceIndex); let rawSamlResponse: string; // const nameIDFormat = idpSetting.nameIDFormat; diff --git a/src/binding-simplesign.ts b/src/binding-simplesign.ts index e40cc0d1..83e01622 100644 --- a/src/binding-simplesign.ts +++ b/src/binding-simplesign.ts @@ -145,7 +145,7 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any const nameIDFormat = idpSetting.nameIDFormat; const selectedNameIDFormat = Array.isArray(nameIDFormat) ? nameIDFormat[0] : nameIDFormat; if (metadata && metadata.idp && metadata.sp) { - const base = metadata.sp.getAssertionConsumerService(binding.simpleSign); + const base = metadata.sp.getAssertionConsumerService(binding.simpleSign, requestInfo.extract.request.assertionConsumerServiceIndex); let rawSamlResponse: string; const nowTime = new Date(); // Five minutes later : nowtime + 5 * 60 * 1000 (in milliseconds) diff --git a/src/entity-idp.ts b/src/entity-idp.ts index 2ebcfb97..bb50b3b5 100644 --- a/src/entity-idp.ts +++ b/src/entity-idp.ts @@ -119,7 +119,7 @@ export class IdentityProvider extends Entity { return { ...context, relayState, - entityEndpoint: (sp.entityMeta as ServiceProviderMetadata).getAssertionConsumerService(binding) as string, + entityEndpoint: (sp.entityMeta as ServiceProviderMetadata).getAssertionConsumerService(binding, requestInfo.extract.request.assertionConsumerServiceIndex) as string, type: 'SAMLResponse' }; } diff --git a/src/extractor.ts b/src/extractor.ts index 104eaedf..57343fb2 100644 --- a/src/extractor.ts +++ b/src/extractor.ts @@ -45,7 +45,7 @@ export const loginRequestFields: ExtractorFields = [ { key: 'request', localPath: ['AuthnRequest'], - attributes: ['ID', 'IssueInstant', 'Destination', 'AssertionConsumerServiceURL'] + attributes: ['ID', 'IssueInstant', 'Destination', 'AssertionConsumerServiceURL', 'AssertionConsumerServiceIndex'] }, { key: 'issuer', diff --git a/src/metadata-sp.ts b/src/metadata-sp.ts index a6fc20e8..e839d73d 100644 --- a/src/metadata-sp.ts +++ b/src/metadata-sp.ts @@ -180,11 +180,15 @@ export class SpMetadata extends Metadata { * @param {string} binding protocol binding (e.g. redirect, post) * @return {string/[string]} URL of endpoint(s) */ - public getAssertionConsumerService(binding: string): string | string[] { + public getAssertionConsumerService(binding: string, index?: number): string | string[] { if (isString(binding)) { let location; const bindName = namespace.binding[binding]; if (isNonEmptyArray(this.meta.assertionConsumerService)) { + if(index != undefined && this.meta.assertionConsumerService.length >= index + 1) { + return this.meta.assertionConsumerService[index].location; + } + this.meta.assertionConsumerService.forEach(obj => { if (obj.binding === bindName) { location = obj.location; diff --git a/test/issues.ts b/test/issues.ts index 3c768f01..23653c5a 100644 --- a/test/issues.ts +++ b/test/issues.ts @@ -164,4 +164,13 @@ test('#31 query param for sso/slo returns error', t => { const index = Object.keys(authnRequest.attributes).find((i: string) => authnRequest.attributes[i].nodeName === 'AssertionConsumerServiceURL') as any; t.is(authnRequest.attributes[index].nodeValue, 'https://example.org/response'); }); + + const spACSIndex = serviceProvider({ metadata: fs.readFileSync('./test/misc/sp_metadata_437.xml') }); + test('#437 return acl for sp metadata with acs index', t => { + const urlIndex0 = spACSIndex.entityMeta.getAssertionConsumerService('urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', 0); + const urlIndex1 = spACSIndex.entityMeta.getAssertionConsumerService('urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', 1); + t.is(urlIndex0,'https://example.org/responseForIndex0'); + t.is(urlIndex1,'https://example.org/responseForIndex1'); + }); + })(); \ No newline at end of file diff --git a/test/misc/sp_metadata_437.xml b/test/misc/sp_metadata_437.xml new file mode 100644 index 00000000..1faed778 --- /dev/null +++ b/test/misc/sp_metadata_437.xml @@ -0,0 +1,7 @@ + + + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + + + + \ No newline at end of file