diff options
Diffstat (limited to 'ipsilon/providers')
-rw-r--r-- | ipsilon/providers/saml2/auth.py | 27 | ||||
-rw-r--r-- | ipsilon/providers/saml2idp.py | 57 |
2 files changed, 80 insertions, 4 deletions
diff --git a/ipsilon/providers/saml2/auth.py b/ipsilon/providers/saml2/auth.py index 5c00e97..611c9bf 100644 --- a/ipsilon/providers/saml2/auth.py +++ b/ipsilon/providers/saml2/auth.py @@ -6,6 +6,7 @@ from ipsilon.providers.saml2.provider import ServiceProvider from ipsilon.providers.saml2.provider import InvalidProviderId from ipsilon.providers.saml2.provider import NameIdNotAllowed from ipsilon.providers.saml2.sessions import SAMLSessionsContainer +from ipsilon.tools import saml2metadata as metadata from ipsilon.util.policy import Policy from ipsilon.util.user import UserSession from ipsilon.util.trans import Transaction @@ -29,14 +30,29 @@ class AuthenticateRequest(ProviderPageBase): super(AuthenticateRequest, self).__init__(*args, **kwargs) self.stage = 'init' self.trans = None + self.binding = None def _preop(self, *args, **kwargs): try: # generate a new id or get current one self.trans = Transaction('saml2', **kwargs) - if self.trans.cookie.value != self.trans.provider: - self.debug('Invalid transaction, %s != %s' % ( - self.trans.cookie.value, self.trans.provider)) + + self.debug('self.binding=%s, transdata=%s' % + (self.binding, self.trans.retrieve())) + if self.binding is None: + # SAML binding is unknown, try to get it from transaction + transdata = self.trans.retrieve() + self.binding = transdata.get('saml2_binding') + else: + # SAML binding known, store in transaction + data = {'saml2_binding': self.binding} + self.trans.store(data) + + # Only check for cookie for those bindings which use one + if self.binding not in (metadata.SAML2_SERVICE_MAP['sso-soap'][1]): + if self.trans.cookie.value != self.trans.provider: + self.debug('Invalid transaction, %s != %s' % ( + self.trans.cookie.value, self.trans.provider)) except Exception, e: # pylint: disable=broad-except self.debug('Transaction initialization failed: %s' % repr(e)) raise cherrypy.HTTPError(400, 'Invalid transaction id') @@ -303,5 +319,10 @@ class AuthenticateRequest(ProviderPageBase): } return self._template('saml2/post_response.html', **context) + elif login.protocolProfile == lasso.LOGIN_PROTOCOL_PROFILE_BRWS_LECP: + login.buildResponseMsg() + self.debug("Returning ECP: %s" % login.msgBody) + return login.msgBody + else: raise cherrypy.HTTPError(500) diff --git a/ipsilon/providers/saml2idp.py b/ipsilon/providers/saml2idp.py index ef31f36..6dfb03a 100644 --- a/ipsilon/providers/saml2idp.py +++ b/ipsilon/providers/saml2idp.py @@ -10,6 +10,8 @@ from ipsilon.providers.saml2.provider import IdentityProvider from ipsilon.tools.certs import Certificate from ipsilon.tools import saml2metadata as metadata from ipsilon.tools import files +from ipsilon.util.http import require_content_type +from ipsilon.util.constants import SOAP_MEDIA_TYPE, XML_MEDIA_TYPE from ipsilon.util.user import UserSession from ipsilon.util.plugin import PluginObject from ipsilon.util import config as pconfig @@ -20,9 +22,54 @@ import os import time import uuid +cherrypy.tools.require_content_type = cherrypy.Tool('before_request_body', + require_content_type) + + +def is_lasso_ecp_enabled(): + # Full ECP support appeared in lasso version 2.4.2 + return lasso.checkVersion(2, 4, 2, lasso.CHECK_VERSION_NUMERIC) + + +class SSO_SOAP(AuthenticateRequest): + + def __init__(self, *args, **kwargs): + super(SSO_SOAP, self).__init__(*args, **kwargs) + self.binding = metadata.SAML2_SERVICE_MAP['sso-soap'][1] + + @cherrypy.tools.require_content_type( + required=[SOAP_MEDIA_TYPE, XML_MEDIA_TYPE]) + @cherrypy.tools.accept(media=[SOAP_MEDIA_TYPE, XML_MEDIA_TYPE]) + @cherrypy.tools.response_headers( + headers=[('Content-Type', 'SOAP_MEDIA_TYPE')]) + def POST(self, *args, **kwargs): + self.debug("SSO_SOAP.POST() begin") + + self.debug("SSO_SOAP transaction provider=%s id=%s" % + (self.trans.provider, self.trans.transaction_id)) + + us = UserSession() + us.remote_login() + user = us.get_user() + self.debug("SSO_SOAP user=%s" % (user.name)) + + if not user: + raise cherrypy.HTTPError(403, 'No user specified for SSO_SOAP') + + soap_xml_doc = cherrypy.request.rfile.read() + soap_xml_doc = soap_xml_doc.strip() + self.debug("SSO_SOAP soap_xml_doc=%s" % soap_xml_doc) + login = self.saml2login(soap_xml_doc) + + return self.auth(login) + class Redirect(AuthenticateRequest): + def __init__(self, *args, **kwargs): + super(Redirect, self).__init__(*args, **kwargs) + self.binding = metadata.SAML2_SERVICE_MAP['sso-redirect'][1] + def GET(self, *args, **kwargs): query = cherrypy.request.query_string @@ -33,6 +80,10 @@ class Redirect(AuthenticateRequest): class POSTAuth(AuthenticateRequest): + def __init__(self, *args, **kwargs): + super(POSTAuth, self).__init__(*args, **kwargs) + self.binding = metadata.SAML2_SERVICE_MAP['sso-post'][1] + def POST(self, *args, **kwargs): request = kwargs.get(lasso.SAML2_FIELD_REQUEST) @@ -98,6 +149,7 @@ class SSO(ProviderPageBase): self.Redirect = Redirect(*args, **kwargs) self.POST = POSTAuth(*args, **kwargs) self.Continue = Continue(*args, **kwargs) + self.SOAP = SSO_SOAP(*args, **kwargs) class SLO(ProviderPageBase): @@ -118,7 +170,7 @@ class Metadata(ProviderPageBase): def GET(self, *args, **kwargs): body = self._get_metadata() - cherrypy.response.headers["Content-Type"] = "text/xml" + cherrypy.response.headers["Content-Type"] = XML_MEDIA_TYPE cherrypy.response.headers["Content-Disposition"] = \ 'attachment; filename="metadata.xml"' return body @@ -368,6 +420,9 @@ class IdpMetadataGenerator(object): '%s/saml2/SSO/POST' % url) self.meta.add_service(metadata.SAML2_SERVICE_MAP['sso-redirect'], '%s/saml2/SSO/Redirect' % url) + if is_lasso_ecp_enabled(): + self.meta.add_service(metadata.SAML2_SERVICE_MAP['sso-soap'], + '%s/saml2/SSO/SOAP' % url) self.meta.add_service(metadata.SAML2_SERVICE_MAP['logout-redirect'], '%s/saml2/SLO/Redirect' % url) self.meta.add_allowed_name_format( |