From 52a393789911237a5cf576a586e9fc571525f78f Mon Sep 17 00:00:00 2001 From: Rob Gijsens Date: Wed, 18 Mar 2020 11:45:31 +0100 Subject: [PATCH 1/4] feat(authorize request): add idp scoping add idpScopingProviderId as an option which will assume the configured idp is a proxying idp and the passed provider id is the idp to target. --- README.md | 1 + lib/passport-saml/saml.js | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index 649cf5b84..f35f32614 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ type Profile = { * `skipRequestCompression`: if set to true, the SAML request from the service provider won't be compressed. * `authnRequestBinding`: if set to `HTTP-POST`, will request authentication from IDP via HTTP POST binding, otherwise defaults to HTTP Redirect * `disableRequestACSUrl`: if truthy, SAML AuthnRequest from the service provider will not include the optional AssertionConsumerServiceURL. Default is falsy so it is automatically included. + * `idpScopingProviderId`: if set to a string, expects the IDP to be a proxying identity provider. The passed provider ID is the specific IDP the proxy idp should communicatie with. Useful for targeting a specific IDP from the application. * **InResponseTo Validation** * `validateInResponseTo`: if truthy, then InResponseTo will be validated from incoming SAML responses * `requestIdExpirationPeriodMs`: Defines the expiration time when a Request ID generated for a SAML request will not be valid if seen in a SAML response in the `InResponseTo` field. Default is 8 hours. diff --git a/lib/passport-saml/saml.js b/lib/passport-saml/saml.js index 519d22ae0..0ba2d727b 100644 --- a/lib/passport-saml/saml.js +++ b/lib/passport-saml/saml.js @@ -213,6 +213,19 @@ SAML.prototype.generateAuthorizeRequest = function (req, isPassive, isHttpPostBi request['samlp:AuthnRequest']['@ProviderName'] = this.options.providerName; } + if (this.options.idpScopingProviderId) { + request['samlp:AuthnRequest']['samlp:Scoping'] = { + '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + 'samlp:IDPList': { + '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + 'samlp:IDPEntry': { + '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + '@ProviderID': this.options.scopingProviderId, + } + } + }; + } + var stringRequest = xmlbuilder.create(request).end(); if (isHttpPostBinding && this.options.privateCert) { stringRequest = signAuthnRequestPost(stringRequest, this.options); From 26489fba7a3e4fe73650e8e8e81ba6ebc3f257bd Mon Sep 17 00:00:00 2001 From: Rob Gijsens Date: Wed, 18 Mar 2020 11:51:39 +0100 Subject: [PATCH 2/4] fix(authorize request): fix variable name idp scoping --- lib/passport-saml/saml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/passport-saml/saml.js b/lib/passport-saml/saml.js index 0ba2d727b..5798f387a 100644 --- a/lib/passport-saml/saml.js +++ b/lib/passport-saml/saml.js @@ -220,7 +220,7 @@ SAML.prototype.generateAuthorizeRequest = function (req, isPassive, isHttpPostBi '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', 'samlp:IDPEntry': { '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', - '@ProviderID': this.options.scopingProviderId, + '@ProviderID': this.options.idpScopingProviderId, } } }; From aa04ba25e359795ae5eebba9a8505324c873739c Mon Sep 17 00:00:00 2001 From: Rob Gijsens Date: Fri, 30 Oct 2020 15:37:53 +0100 Subject: [PATCH 3/4] chore(test): add test for authnrequest with idp scoping --- test/tests.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/test/tests.js b/test/tests.js index ab1860511..2c1482466 100644 --- a/test/tests.js +++ b/test/tests.js @@ -524,7 +524,79 @@ describe( 'passport-saml /', function() { 'saml:Issuer': [ { _: 'onelogin_saml', '$': { 'xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion' } } ] } } - } + }, + { name: "Config with idpScopingProviderId", + config: { + issuer: 'http://exampleSp.com/saml', + identifierFormat: 'alternateIdentifier', + idpScopingProviderId: 'myScopingProviderId' + }, + result: { + 'samlp:AuthnRequest': { + '$': { + AssertionConsumerServiceURL: 'http://localhost:3033/login', + Destination: 'https://wwwexampleIdp.com/saml', + ProtocolBinding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + Version: '2.0', + 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol' + }, + 'saml:Issuer': [ + { + '$': { + 'xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion', + }, + '_': 'http://exampleSp.com/saml', + } + ], + 'samlp:NameIDPolicy': [ + { + '$': { + AllowCreate: 'true', + Format: 'alternateIdentifier', + 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + } + } + ], + 'samlp:RequestedAuthnContext': [ + { + '$': { + Comparison: 'exact', + 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol' + }, + 'saml:AuthnContextClassRef': [ + { + '$': { + 'xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion' + }, + '_': 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport' + } + ] + } + ], + 'samlp:Scoping': [ + { + '$': { + 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + }, + 'samlp:IDPList': [ + { + '$': { + 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol' + }, + 'samlp:IDPEntry': [ + { + '$': { + ProviderID: 'myScopingProviderId', + 'xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol' + } + } + ] + } + ] + } + ] + } + } } ]; var server; @@ -1354,7 +1426,7 @@ describe( 'passport-saml /', function() { const nameQualifier = 'https://idp.example.org/idp/saml' const spNameQualifier = 'https://sp.example.org/sp/entity' const format = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' - const xml = + const xml = '' + '' + '' + @@ -1385,7 +1457,7 @@ describe( 'passport-saml /', function() { }); it( 'An undefined value given with an object should still be undefined', function( done ) { - const xml = + const xml = '' + '' + '' + From d0702e6faa68a5ee6823e1bcbf94ba8bbe19c33a Mon Sep 17 00:00:00 2001 From: Rob Gijsens Date: Fri, 30 Oct 2020 15:48:16 +0100 Subject: [PATCH 4/4] chore(merge): merge in master and add changes to typescript files --- src/passport-saml/saml.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/passport-saml/saml.ts b/src/passport-saml/saml.ts index 54a381a5d..dc1748567 100644 --- a/src/passport-saml/saml.ts +++ b/src/passport-saml/saml.ts @@ -305,6 +305,19 @@ class SAML { request['samlp:AuthnRequest']['@ProviderName'] = this.options.providerName; } + if (this.options.idpScopingProviderId) { + request['samlp:AuthnRequest']['samlp:Scoping'] = { + '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + 'samlp:IDPList': { + '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + 'samlp:IDPEntry': { + '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol', + '@ProviderID': this.options.idpScopingProviderId, + } + } + }; + } + let stringRequest = xmlbuilder.create(request).end(); if (isHttpPostBinding && this.options.privateCert) { stringRequest = signAuthnRequestPost(stringRequest, this.options);