Implement urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
authorRob Crittenden <rcritten@redhat.com>
Thu, 19 Mar 2015 19:15:26 +0000 (15:15 -0400)
committerSimo Sorce <simo@redhat.com>
Mon, 23 Mar 2015 22:00:15 +0000 (18:00 -0400)
This also makes persistent the default NameID format when generating
metadata.

https://fedorahosted.org/ipsilon/ticket/27

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
ipsilon/install/ipsilon-server-install
ipsilon/providers/saml2/auth.py
ipsilon/providers/saml2idp.py
quickrun.py
tests/fconf.py

index 307f1e4..edcccb6 100755 (executable)
@@ -116,7 +116,8 @@ def install(plugins, args):
                 'transdb': args['database_url'] % {
                     'datadir': args['data_dir'], 'dbname': 'transactions'},
                 'secure': "False" if args['secure'] == "no" else "True",
-                'debugging': "True" if args['server_debugging'] else "False"}
+                'debugging': "True" if args['server_debugging'] else "False",
+               }
     # Testing database sessions
     if 'session_type' in args:
         confopts['sesstype'] = args['session_type']
index 71bfc9a..4bfbc1a 100644 (file)
@@ -28,6 +28,7 @@ import cherrypy
 import datetime
 import lasso
 import uuid
+import hashlib
 
 
 class UnknownProvider(ProviderException):
@@ -183,8 +184,16 @@ class AuthenticateRequest(ProviderPageBase):
 
         nameid = None
         if nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT:
-            # TODO map to something else ?
-            nameid = provider.normalize_username(user.name)
+            idpsalt = self.cfg.idp_nameid_salt
+            if idpsalt is None:
+                raise AuthenticationError(
+                    "idp nameid salt is not set in configuration"
+                )
+            value = hashlib.sha512()
+            value.update(idpsalt)
+            value.update(login.remoteProviderId)
+            value.update(user.name)
+            nameid = '_' + value.hexdigest()
         elif nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT:
             nameid = '_' + uuid.uuid4().hex
         elif nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_KERBEROS:
index 96a7d11..5d8aa03 100644 (file)
@@ -33,6 +33,7 @@ from datetime import timedelta
 import lasso
 import os
 import time
+import uuid
 
 
 class Redirect(AuthenticateRequest):
@@ -194,6 +195,10 @@ Provides SAML 2.0 authentication infrastructure. """
                 'idp key file',
                 'The IdP Certificate Key genearated at install time.',
                 'certificate.key'),
+            pconfig.String(
+                'idp nameid salt',
+                'The salt used for persistent Name IDs.',
+                None),
             pconfig.Condition(
                 'allow self registration',
                 'Allow authenticated users to register applications.',
@@ -253,6 +258,10 @@ Provides SAML 2.0 authentication infrastructure. """
                             self.get_config_value('idp key file'))
 
     @property
+    def idp_nameid_salt(self):
+        return self.get_config_value('idp nameid salt')
+
+    @property
     def default_allowed_nameids(self):
         return self.get_config_value('default allowed nameids')
 
@@ -324,10 +333,10 @@ class IdpMetadataGenerator(object):
         self.meta.add_service(metadata.SAML2_SERVICE_MAP['logout-redirect'],
                               '%s/saml2/SLO/Redirect' % url)
         self.meta.add_allowed_name_format(
-            lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT)
-        self.meta.add_allowed_name_format(
             lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT)
         self.meta.add_allowed_name_format(
+            lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT)
+        self.meta.add_allowed_name_format(
             lasso.SAML2_NAME_IDENTIFIER_FORMAT_EMAIL)
 
     def output(self, path=None):
@@ -379,7 +388,8 @@ class Installer(ProviderInstaller):
         config = {'idp storage path': path,
                   'idp metadata file': 'metadata.xml',
                   'idp certificate file': cert.cert,
-                  'idp key file': cert.key}
+                  'idp key file': cert.key,
+                  'idp nameid salt': uuid.uuid4().hex}
         po.save_plugin_config(config)
 
         # Update global config to add login plugin
index 0722c7b..57cdcb7 100755 (executable)
@@ -80,7 +80,8 @@ def config(workdir):
                          'sesstype': 'file',
                          'sessopt': 'path',
                          'sessval': os.path.join(workdir, 'sessions'),
-                         'secure': 'False'})
+                         'secure': 'False',
+                        })
     conf = os.path.join(workdir, 'ipsilon.conf')
     with open(conf, 'w+') as f:
         f.write(text)
index 16738cb..409c975 100755 (executable)
@@ -25,6 +25,7 @@ import os
 import pwd
 import sys
 from string import Template
+import uuid
 
 
 idpname = 'idp1'
@@ -66,6 +67,7 @@ saml2 idp key file = ${TESTDIR}/lib/${NAME}/saml2/idp.key
 saml2 idp storage path = ${TESTDIR}/lib/${NAME}/saml2
 saml2 idp metadata file = metadata.xml
 saml2 idp certificate file = ${TESTDIR}/lib/${NAME}/saml2/idp.pem
+saml2 idp nameid salt = ${IDPSALT}
 [saml2_data]
 811d0231-9362-46c9-a105-a01a64818904 id = http://${SPADDR}:${SPPORT}/saml2
 811d0231-9362-46c9-a105-a01a64818904 type = SP
@@ -116,10 +118,12 @@ def fixup_idp_conf(testdir):
 
     idpuri = "http://%s:%s/%s" % (idpaddr, idpport, idpname)
 
+    idpsalt = uuid.uuid4().hex
     t = Template(idp_file_conf)
     text = t.substitute({'NAME': idpname, 'IDPURI': idpuri,
                          'SPNAME': spname, 'SPADDR': spaddr, 'SPPORT': spport,
-                         'SPMETA': spmeta, 'TESTDIR': testdir})
+                         'SPMETA': spmeta, 'TESTDIR': testdir,
+                         'IDPSALT': idpsalt})
 
     adminconf = os.path.join(testdir, 'etc/admin.conf')
     with open(adminconf, 'w+') as f: