Add Service and Identity Provider abstraction
authorSimo Sorce <simo@redhat.com>
Thu, 3 Apr 2014 19:42:35 +0000 (15:42 -0400)
committerSimo Sorce <simo@redhat.com>
Fri, 4 Apr 2014 16:58:24 +0000 (12:58 -0400)
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 <simo@redhat.com>
ipsilon/providers/saml2/auth.py
ipsilon/providers/saml2/provider.py
ipsilon/providers/saml2idp.py

index ff81af6..bac73a5 100755 (executable)
@@ -59,7 +59,7 @@ class AuthenticateRequest(ProviderPageBase):
 
     def _parse_request(self, message):
 
 
     def _parse_request(self, message):
 
-        login = lasso.Login(self.cfg.idp)
+        login = self.cfg.idp.get_login_handler()
 
         try:
             login.processAuthnRequestMsg(message)
 
         try:
             login.processAuthnRequestMsg(message)
index d3ed5da..6339450 100755 (executable)
@@ -109,3 +109,62 @@ class ServiceProvider(object):
         if 'strip domain' in self._properties:
             return username.split('@', 1)[0]
         return username
         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)
index c70b96a..d8cbe6c 100755 (executable)
@@ -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.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
 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:
             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)
 
         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:
 
         # 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
         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:
             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]
             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:
             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
             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)
 
 
         self.SSO = SSO(*args, **kwargs)
 
@@ -139,6 +131,7 @@ class IdpProvider(ProviderBase):
     def __init__(self):
         super(IdpProvider, self).__init__('saml2', 'saml2')
         self.page = None
     def __init__(self):
         super(IdpProvider, self).__init__('saml2', 'saml2')
         self.page = None
+        self.idp = None
         self.description = """
 Provides SAML 2.0 authentication infrastructure. """
 
         self.description = """
 Provides SAML 2.0 authentication infrastructure. """