From: Rob Crittenden Date: Wed, 28 Oct 2015 20:29:57 +0000 (-0400) Subject: Add support for IdP-initiated login X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fipsilon.git;a=commitdiff_plain;h=a8994fbcbe824b784c6ccefb1acc2cf8d268b90e Add support for IdP-initiated login This uses the Redirect SSO endpoint and two new optional arguments: SPIdentifier and RelayState. SPIdentifier is the provider ID of the SP. RelayState is where on the SP the user should be sent. If the user is already authenticted then a SAMLResponse is generated and the existing HTML page is generated and sent to the user including this response and the value of RelayState (if any). This will then POST to the SP and the user will be show the page on the SP. If the user is not authenticated then they will be given the login page after which they will be sent to the SP. The link to the SP on the IdP Portal has changed to be and IdP-initiated login. If a user bookmarks this link then they will always go to that SP and be authenticated first, if needed. https://fedorahosted.org/ipsilon/ticket/138 Signed-off-by: Rob Crittenden Reviewed-by: John Dennis --- diff --git a/ipsilon/providers/saml2/auth.py b/ipsilon/providers/saml2/auth.py index 940746c..cc41bb8 100644 --- a/ipsilon/providers/saml2/auth.py +++ b/ipsilon/providers/saml2/auth.py @@ -99,23 +99,65 @@ class AuthenticateRequest(ProviderPageBase): return login - def saml2login(self, request): + def _idp_initiated_login(self, spidentifier, relaystate): + """ + Perform an Idp-initiated login - if not request: + Exceptions are handled by the caller + """ + login = self.cfg.idp.get_login_handler() + + login.initIdpInitiatedAuthnRequest(spidentifier) + + # Hardcode for now, handle Artifact later + login.request.protocolBinding = lasso.SAML2_METADATA_BINDING_POST + + login.processAuthnRequestMsg() + + if relaystate is not None: + login.msgRelayState = relaystate + else: + provider = ServiceProvider(self.cfg, login.remoteProviderId) + if provider.splink is not None: + login.msgRelayState = provider.splink + else: + login.msgRelayState = login.remoteProviderId + + return login + + def saml2login(self, request, spidentifier=None, relaystate=None): + """ + request: the SAML request + spidentifier: the provider ID for IdP-initiated login + relaystate: optional string to direct user to particular place on + the SP after sending POST. If one is not provided then + the protected site from the SP is used, otherwise it + is set to the remote provider ID. + """ + if not request and not spidentifier: raise cherrypy.HTTPError(400, 'SAML request token missing or empty') - try: - login = self._parse_request(request) - except InvalidRequest, e: - self.debug(str(e)) - raise cherrypy.HTTPError(400, 'Invalid SAML request token') - except UnknownProvider, e: - self.debug(str(e)) - raise cherrypy.HTTPError(400, 'Unknown Service Provider') - except Exception, e: # pylint: disable=broad-except - self.debug(str(e)) - raise cherrypy.HTTPError(500) + if spidentifier: + try: + login = self._idp_initiated_login(spidentifier, relaystate) + except lasso.ServerProviderNotFoundError: + raise cherrypy.HTTPError(400, 'Unknown Service Provider') + except Exception, e: # pylint: disable=broad-except + self.debug(str(e)) + raise cherrypy.HTTPError(500) + else: + try: + login = self._parse_request(request) + except InvalidRequest, e: + self.debug(str(e)) + raise cherrypy.HTTPError(400, 'Invalid SAML request token') + except UnknownProvider, e: + self.debug(str(e)) + raise cherrypy.HTTPError(400, 'Unknown Service Provider') + except Exception, e: # pylint: disable=broad-except + self.debug(str(e)) + raise cherrypy.HTTPError(500) return login diff --git a/ipsilon/providers/saml2idp.py b/ipsilon/providers/saml2idp.py index 3ed95d8..78e7778 100644 --- a/ipsilon/providers/saml2idp.py +++ b/ipsilon/providers/saml2idp.py @@ -76,7 +76,10 @@ class Redirect(AuthenticateRequest): query = cherrypy.request.query_string - login = self.saml2login(query) + spidentifier = kwargs.get('SPIdentifier') + relaystate = kwargs.get(lasso.SAML2_FIELD_RELAYSTATE) + + login = self.saml2login(query, spidentifier, relaystate) return self.auth(login) diff --git a/templates/index.html b/templates/index.html index db1339b..5215b3b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -90,7 +90,7 @@