Commits

Frank Becker committed 4aefffe

added AD auth and user creation
- added auth against Django and Active Directory
- User has to be in the settings.AD_DEPARTMENT_REQ list
- User() is created if not existent in Django DB

  • Participants
  • Parent commits 72bee93

Comments (0)

Files changed (4)

File src/accounts/__init__.py

+# -*- coding: utf-8 -*-

File src/accounts/backends.py

+# -*- coding: utf-8 -*-
+
+"""
+Authentication Backends
+
+http://djangosnippets.org/snippets/901/
+"""
+import os
+
+from django.contrib.auth.models import User, Group
+from django.conf import settings
+import ldap
+
+class ActiveDirectoryGroupMembershipSSLBackend(object):
+
+    def __init__(self):
+        ldap.set_option(ldap.OPT_REFERRALS,0) # DO NOT TURN THIS OFF OR SEARCH WON'T WORK!
+        self.ldap_server = ldap.initialize(settings.AD_LDAP_URL)
+        # after successful authentication self.ldap_server will be un-bound
+        if hasattr(settings, 'AD_CERT_FILE'):
+            try:
+                ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, settings.AD_CERT_FILE)
+            except IOError:
+                raise("Did not find AD certificate file at {0}".format(settings.AD_CERT_FILE))
+        #self.ldap_server.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
+
+    def authenticate(self,username=None,password=None):
+        """
+        authenticate the user
+
+        :param username:
+        :param password:
+        :return: User() or None if not successful
+        """
+        try:
+            if len(password) == 0:
+                return None
+            bind_dn = "%s@%s" % (username, settings.AD_NT4_DOMAIN)
+            self.ldap_server.simple_bind_s(bind_dn, password)
+            #self.ldap_server.unbind_s()
+            return self.get_or_create_user(username, password)
+        except ImportError:
+            # fall through authentication if no ldap module there
+            pass
+        except ldap.INVALID_CREDENTIALS:
+            pass
+
+    def get_or_create_user(self, username, password):
+        """
+        return user obj or create user and copy data from active directory
+        :param username: login name
+        :param password: the password
+        :return: user obj
+        """
+        try:
+            user = User.objects.get(username=username)
+        except User.DoesNotExist:
+
+            try:
+                # search
+                #result = self.ldap_server.search_ext_s(settings.AD_SEARCH_DN, ldap.SCOPE_SUBTREE,"sAMAccountName=%s" % username,settings.AD_SEARCH_FIELDS)[0][1]
+                result = self.ldap_server.search_s(settings.AD_SEARCH_DN, ldap.SCOPE_SUBTREE,"sAMAccountName={0}".format(username))[0][1]
+                user_attrs = dict([(key, val[0]) for (key, val) in result.iteritems()])
+
+                # Validate that they are a member of the right department
+                if not (user_attrs.has_key('department') and
+                   user_attrs['department'] in settings.AD_DEPARTMENT_REQ):
+                    return None
+
+                # get email
+                if user_attrs.has_key('mail'):
+                    mail = result['mail'][0]
+                else:
+                    mail = None
+                if user_attrs.has_key('sn'):
+                    last_name = result['sn'][0]
+                else:
+                    last_name = None
+
+                # get display name
+                if result.has_key('givenName'):
+                    first_name = result['givenName'][0]
+                else:
+                    first_name = None
+
+
+                user = User.objects.create_user(username, email=mail)
+                user.first_name=first_name
+                user.last_name=last_name
+
+            except Exception, e:
+                return None
+
+            user.is_staff = True
+            user.is_superuser = False
+            # a random password is set automatically
+            #user.set_password('ldap authenticated')
+            user.save()
+
+
+            # add user to default group
+            #group=Group.objects.get(pk=1)
+            #user.groups.add(group)
+            #user.save()
+
+        self.ldap_server.unbind_s()
+        return user
+
+    def get_user(self, user_id):
+        try:
+            return User.objects.get(pk=user_id)
+        except User.DoesNotExist:
+            return None
+

File src/project/auth.py

+# -*- coding: utf-8 -*-
+"""
+Authenticate against AD
+
+http://djangosnippets.org/snippets/501/
+"""
+from django.contrib.auth.models import User
+from django.conf import settings
+import ldap
+
+class ActiveDirectoryBackend:
+
+    def authenticate(self,username=None,password=None):
+        if not self.is_valid(username,password):
+            return None
+        try:
+            user = User.objects.get(username=username)
+        except User.DoesNotExist:
+            l = ldap.initialize(settings.AD_LDAP_URL)
+            l.set_option(ldap.OPT_REFERRALS, 0)
+            l.simple_bind_s(username,password)
+            result = l.search_ext_s(settings.AD_SEARCH_DN,ldap.SCOPE_SUBTREE,
+                "sAMAccountName=%s" % username,settings.AD_SEARCH_FIELDS)[0][1]
+            l.unbind_s()
+
+            # givenName == First Name
+            if result.has_key('givenName'):
+                first_name = result['givenName'][0]
+            else:
+                first_name = None
+
+            # sn == Last Name (Surname)
+            if result.has_key('sn'):
+                last_name = result['sn'][0]
+            else:
+                last_name = None
+
+            # mail == Email Address
+            if result.has_key('mail'):
+                email = result['mail'][0]
+            else:
+                email = None
+
+            user = User(username=username,first_name=first_name,last_name=last_name,email=email)
+            user.is_staff = False
+            user.is_superuser = False
+            user.set_password(password)
+            user.save()
+        return user
+
+    def get_user(self,user_id):
+        try:
+            return User.objects.get(pk=user_id)
+        except User.DoesNotExist:
+            return None
+
+    def is_valid (self,username=None,password=None):
+        ## Disallowing null or blank string as password
+        ## as per comment: http://www.djangosnippets.org/snippets/501/#c868
+        if password == None or password == '':
+            return False
+        binddn = "%s@%s" % (username,settings.AD_NT4_DOMAIN)
+        try:
+            l = ldap.initialize(settings.AD_LDAP_URL)
+            l.simple_bind_s(binddn,password)
+            l.unbind_s()
+            return True
+        except ldap.LDAPError:
+            return False

File src/project/settings.py

-# Django settings for djweb project.
+# -*- coding: utf-8 -*-
+# Django settings for myhost project.
 import os
 import pytz
 
 DEFAULT_TIMEZONE = pytz.timezone('Europe/Berlin')
 
 CRISPY_TEMPLATE_PACK = 'bootstrap'
+
+# Active Directory authentication
+# http://djangosnippets.org/snippets/901/
+AD_DNS_NAME='smundc2.amd.com'
+# If using non-SSL use these
+#AD_LDAP_PORT=389
+#AD_LDAP_URL='ldap://%s:%s' %
+#(AD_DNS_NAME,AD_LDAP_PORT)
+# If using SSL use these:
+AD_LDAP_PORT=636
+#AD_LDAP_URL='ldaps://%s:%s' % (AD_DNS_NAME,AD_LDAP_PORT)
+AD_LDAP_URL='ldaps://%s:%s' % (AD_DNS_NAME,AD_LDAP_PORT)
+AD_SEARCH_DN='DC=amd,DC=com'
+AD_NT4_DOMAIN='AMD.COM'
+AD_SEARCH_FIELDS= ['mail','givenName','sn','sAMAccountName','memberOf']
+AD_MEMBERSHIP_REQ=['Group_Required','Alternative_Group']
+AD_DEPARTMENT_REQ=['OSRC Munich']
+#AD_CERT_FILE='/path/to/your/cert.txt'
+#AUTHENTICATION_BACKENDS = ('reviewboard.accounts.backends.ActiveDirectoryGroupMembershipSSLBackend',
+#                           'django.contrib.auth.backends.ModelBackend')
+AUTHENTICATION_BACKENDS = (
+    'django.contrib.auth.backends.ModelBackend',
+    'accounts.backends.ActiveDirectoryGroupMembershipSSLBackend',
+    #'project.auth.ActiveDirectoryBackend',
+    )
+AD_DEBUG = True
+AD_DEBUG_FILE= BASEDIR + 'log/ldap.debug'
+