From: Simo Sorce Date: Thu, 3 Apr 2014 19:42:35 +0000 (-0400) Subject: Add Service and Identity Provider abstraction X-Git-Tag: v0.2.2~45 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fipsilon.git;a=commitdiff_plain;h=ed5ed179806c921036cf811e1890408aac072bef;hp=c67d1a3583a6eda8c626c6d1d9cb42547d7a5b68 Add Service and Identity Provider abstraction This commit adds: - helper functions to create new providers - separate IdentityProvider class to represent the IDP. Database changes: The saml2 plugin database now contain the metadata file contents and does not rely anymore on on-disk data. Signed-off-by: Simo Sorce --- diff --git a/ipsilon/providers/saml2/auth.py b/ipsilon/providers/saml2/auth.py index ff81af6..bac73a5 100755 --- a/ipsilon/providers/saml2/auth.py +++ b/ipsilon/providers/saml2/auth.py @@ -59,7 +59,7 @@ class AuthenticateRequest(ProviderPageBase): def _parse_request(self, message): - login = lasso.Login(self.cfg.idp) + login = self.cfg.idp.get_login_handler() try: login.processAuthnRequestMsg(message) diff --git a/ipsilon/providers/saml2/provider.py b/ipsilon/providers/saml2/provider.py index d3ed5da..6339450 100755 --- a/ipsilon/providers/saml2/provider.py +++ b/ipsilon/providers/saml2/provider.py @@ -109,3 +109,62 @@ class ServiceProvider(object): if 'strip domain' in self._properties: return username.split('@', 1)[0] return username + + +class ServiceProviderCreator(object): + + def __init__(self, config): + self.cfg = config + + def create_from_buffer(self, name, metabuf): + '''Test and add data''' + + test = lasso.Server() + test.addProviderFromBuffer(lasso.PROVIDER_ROLE_SP, metabuf) + newsps = test.get_providers() + if len(newsps) != 1: + raise InvalidProviderId("Metadata must contain one Provider") + + spid = newsps.keys()[0] + data = self.cfg.get_data(name='id', value=spid) + if len(data) != 0: + raise InvalidProviderId("Provider Already Exists") + datum = {'id': spid, 'name': name, 'type': 'SP', 'metadata': metabuf} + self.cfg.new_datum(datum) + + data = self.cfg.get_data(name='id', value=spid) + if len(data) != 1: + raise InvalidProviderId("Internal Error") + idval = data.keys()[0] + data = self.cfg.get_data(idval=idval) + sp = data[idval] + self.cfg.idp.add_provider(sp) + + return ServiceProvider(self.cfg, spid) + + +class IdentityProvider(object): + def __init__(self, config): + self.server = lasso.Server(config.idp_metadata_file, + config.idp_key_file, + None, + config.idp_certificate_file) + self.server.role = lasso.PROVIDER_ROLE_IDP + + def add_provider(self, sp): + self.server.addProviderFromBuffer(lasso.PROVIDER_ROLE_SP, + sp['metadata']) + self._debug('Added SP %s' % sp['name']) + + def get_login_handler(self, dump=None): + if dump: + return lasso.Login.newFromDump(self.server, dump) + else: + return lasso.Login(self.server) + + def get_providers(self): + return self.server.get_providers() + + def _debug(self, fact): + if cherrypy.config.get('debug', False): + cherrypy.log(fact) diff --git a/ipsilon/providers/saml2idp.py b/ipsilon/providers/saml2idp.py index c70b96a..d8cbe6c 100755 --- a/ipsilon/providers/saml2idp.py +++ b/ipsilon/providers/saml2idp.py @@ -22,6 +22,7 @@ from ipsilon.providers.common import FACILITY from ipsilon.providers.saml2.auth import AuthenticateRequest from ipsilon.providers.saml2.admin import AdminPage from ipsilon.providers.saml2.certs import Certificate +from ipsilon.providers.saml2.provider import IdentityProvider from ipsilon.providers.saml2 import metadata from ipsilon.util.user import UserSession from ipsilon.util.plugin import PluginObject @@ -76,7 +77,7 @@ class Continue(AuthenticateRequest): raise cherrypy.HTTPError(400) try: - login = lasso.Login.newFromDump(self.cfg.idp, dump) + login = self.cfg.idp.get_login_handler(dump) except Exception, e: # pylint: disable=broad-except self._debug('Failed to load status from dump: %r' % e) @@ -104,32 +105,23 @@ class SAML2(ProviderPageBase): # Init IDP data try: - self.cfg.idp = lasso.Server(self.cfg.idp_metadata_file, - self.cfg.idp_key_file, - None, - self.cfg.idp_certificate_file) - self.cfg.idp.role = lasso.PROVIDER_ROLE_IDP + self.cfg.idp = IdentityProvider(self.cfg) except Exception, e: # pylint: disable=broad-except - self._debug('Failed to enable SAML2 provider: %r' % e) + self._debug('Failed to init SAML2 provider: %r' % e) return # Import all known applications data = self.cfg.get_data() for idval in data: - if 'type' not in data[idval] or data[idval]['type'] != 'SP': - continue - path = os.path.join(self.cfg.idp_storage_path, str(idval)) sp = data[idval] - if 'name' in sp: - name = sp['name'] - else: - name = str(idval) + if 'type' not in sp or sp['type'] != 'SP': + continue + if 'name' not in sp or 'metadata' not in sp: + continue try: - meta = os.path.join(path, 'metadata.xml') - self.cfg.idp.addProvider(lasso.PROVIDER_ROLE_SP, meta) - self._debug('Added SP %s' % name) + self.cfg.idp.add_provider(sp) except Exception, e: # pylint: disable=broad-except - self._debug('Failed to add SP %s: %r' % (name, e)) + self._debug('Failed to add SP %s: %r' % (sp['name'], e)) self.SSO = SSO(*args, **kwargs) @@ -139,6 +131,7 @@ class IdpProvider(ProviderBase): def __init__(self): super(IdpProvider, self).__init__('saml2', 'saml2') self.page = None + self.idp = None self.description = """ Provides SAML 2.0 authentication infrastructure. """