summaryrefslogtreecommitdiff
path: root/coip/apps/utils/saml.py
diff options
context:
space:
mode:
authorJohan Berggren <jbn@klutt.se>2012-09-19 16:27:23 +0200
committerJohan Berggren <jbn@klutt.se>2012-09-19 16:27:23 +0200
commitc676429509d83b9a2d89a85260eb8968fe06a926 (patch)
treea64836b691929ea994adfa1e482c4bfac3d1b9b1 /coip/apps/utils/saml.py
parenta08a1f509e5118f0dab647f20854c581ffdce5c7 (diff)
Make pysaml work in asgard
Diffstat (limited to 'coip/apps/utils/saml.py')
-rw-r--r--coip/apps/utils/saml.py160
1 files changed, 160 insertions, 0 deletions
diff --git a/coip/apps/utils/saml.py b/coip/apps/utils/saml.py
new file mode 100644
index 0000000..bad3d60
--- /dev/null
+++ b/coip/apps/utils/saml.py
@@ -0,0 +1,160 @@
+from django.contrib.auth.backends import ModelBackend
+from django.contrib.auth.models import SiteProfileNotAvailable, User
+from django.core.exceptions import ObjectDoesNotExist
+import logging
+from saml2.saml import name_id_type__from_string
+
+logger = logging.getLogger('djangosaml2')
+
+__author__ = 'leifj'
+
+class Saml2Backend(ModelBackend):
+
+ """This backend is added automatically by the assertion_consumer_service
+ view.
+
+ Don't add it to settings.AUTHENTICATION_BACKENDS.
+ """
+
+ def _set(self,o,django_attr,saml_attrs,attributes):
+ for saml_attr in saml_attrs:
+ if attributes.has_key(saml_attr):
+ setattr(o, django_attr, attributes[saml_attr][0])
+ return True
+ return False
+
+ def get_saml_user(self,session_info,attributes,attribute_mapping):
+ for saml_attr, django_fields in attribute_mapping.items():
+ if 'username' in django_fields and saml_attr in attributes:
+ return attributes[saml_attr][0]
+ return None
+
+ def authenticate(self, session_info=None, attribute_mapping=None,
+ create_unknown_user=True):
+ if session_info is None or attribute_mapping is None:
+ logger.error('Session info or attribute mapping are None')
+ return None
+
+ if not 'ava' in session_info:
+ logger.error('"ava" key not found in session_info')
+ return None
+
+ print session_info
+
+ attributes = session_info['ava']
+ if not attributes:
+ logger.error('The attributes dictionary is empty')
+
+ saml_user = self.get_saml_user(session_info,attributes,attribute_mapping)
+
+ if saml_user is None:
+ logger.error('Could not find saml_user value')
+ return None
+
+ user = None
+ username = self.clean_username(saml_user)
+
+ # Note that this could be accomplished in one try-except clause, but
+ # instead we use get_or_create when creating unknown users since it has
+ # built-in safeguards for multiple threads.
+ if create_unknown_user:
+ logger.debug('Check if the user "%s" exists or create otherwise' % username)
+ user, created = User.objects.get_or_create(username=username)
+ if created:
+ logger.debug('New user created')
+ user = self.configure_user(user, attributes, attribute_mapping)
+ else:
+ logger.debug('User updated')
+ user = self.update_user(user, attributes, attribute_mapping)
+ else:
+ logger.debug('Retrieving existing user "%s"' % username)
+ try:
+ user = User.objects.get(username=username)
+ user = self.update_user(user, attributes, attribute_mapping)
+ except User.DoesNotExist:
+ logger.error('The user "%s" does not exist' % username)
+ pass
+
+ return user
+
+ def clean_username(self, username):
+ """Performs any cleaning on the "username" prior to using it to get or
+ create the user object. Returns the cleaned username.
+
+ By default, returns the username unchanged.
+ """
+ return username
+
+ def configure_user(self, user, attributes, attribute_mapping):
+ """Configures a user after creation and returns the updated user.
+
+ By default, returns the user with his attributes updated.
+ """
+ user.set_unusable_password()
+ return self.update_user(user, attributes, attribute_mapping,
+ force_save=True)
+
+ def update_user(self, user, attributes, attribute_mapping, force_save=False):
+ """Update a user with a set of attributes and returns the updated user.
+
+ By default it uses a mapping defined in the settings constant
+ SAML_ATTRIBUTE_MAPPING. For each attribute, if the user object has
+ that field defined it will be set, otherwise it will try to set
+ it in the profile object.
+ """
+ if not attribute_mapping:
+ return user
+
+ try:
+ profile = user.get_profile()
+ except ObjectDoesNotExist:
+ profile = None
+ except SiteProfileNotAvailable:
+ profile = None
+
+ user_modified = False
+ profile_modified = False
+ for django_attr,saml_attrs in attribute_mapping.items():
+ try:
+ if hasattr(user, django_attr):
+ user_modified = self._set(user,django_attr,saml_attrs,attributes)
+
+ elif profile is not None and hasattr(profile, django_attr):
+ profile_modified = self._set(profile,django_attr,saml_attrs,attributes)
+
+ except KeyError:
+ # the saml attribute is missing
+ pass
+
+ if user_modified or force_save:
+ user.save()
+
+ if profile_modified or force_save:
+ profile.save()
+
+ return user
+
+class TargetedUsernameSamlBackend(Saml2Backend):
+ def get_saml_user(self,session_info,attributes,attribute_mapping):
+
+ eptid = attributes.get('eduPersonTargetedID',None)
+ if eptid is not None:
+ try:
+ name_id_o = name_id_type__from_string(eptid)
+ return "%s!%s!%s" % (name_id_o.name_qualifier,name_id_o.sp_name_qualifier,name_id_o.text)
+ except Exception,ex:
+ logger.error(ex)
+ pass
+
+ username = None
+ print attribute_mapping
+ if attribute_mapping.has_key('username'):
+ for saml_attr in attribute_mapping['username']:
+ if attributes.has_key(saml_attr):
+ username = attributes[saml_attr][0]
+
+ if username is None:
+ return None
+
+ return username
+ #return "%s!%s!%s" % (session_info['issuer'],session_info.get('entity_id',""),username) \ No newline at end of file