I had some trouble getting other peoples code to work for AD support, so I wrote my own which authenticates against LDAP and will also use SSL and cert if required. It will also verify that an autheticated user has specific group membership before authorizing.
This will also debug to a file, which is really helpful when trying to figure out problems.
One thing that really got me when getting python-ldap to work was that you must have "ldap.set_option(ldap.OPT_REFERRALS,0)" set or any ldap search will not work.
Also, this will add group permissions to a user.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157  | In settings:
AD_DNS_NAME='your-ldap-server.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_SEARCH_DN='dc=mygroup,dc=net,dc=com'
AD_NT4_DOMAIN='YOURDOMAIN'
AD_SEARCH_FIELDS= ['mail','givenName','sn','sAMAccountName','memberOf']
AD_MEMBERSHIP_REQ=['Group_Required','Alternative_Group']
AD_CERT_FILE='/path/to/your/cert.txt'
AUTHENTICATION_BACKENDS = ('reviewboard.accounts.backends.ActiveDirectoryGroupMembershipSSLBackend',
'django.contrib.auth.backends.ModelBackend')
AD_DEBUG=True
AD_DEBUG_FILE='/path/to/writable/log/file/ldap.debug'
In accounts/backends.py:
class ActiveDirectoryGroupMembershipSSLBackend:
  def authenticate(self,username=None,password=None):
      try:
         if len(password) == 0:
            return None
         ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,settings.AD_CERT_FILE)
         l = ldap.initialize(settings.AD_LDAP_URL)
         l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
         binddn = "%s@%s" % (username,settings.AD_NT4_DOMAIN)
         l.simple_bind_s(binddn,password)
         l.unbind_s()
         return self.get_or_create_user(username,password)
      except ImportError:
         pass
      except ldap.INVALID_CREDENTIALS:
         pass
  def get_or_create_user(self, username, password):
      try:
         user = User.objects.get(username=username)
      except User.DoesNotExist:
         try:
            # debug info
            debug=0
            if len(settings.AD_DEBUG_FILE) > 0:
               if settings.AD_DEBUG:
                   debug=open(settings.AD_DEBUG_FILE,'w')
                   print >>debug, "create user %s" % username
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,settings.AD_CERT_FILE)
            ldap.set_option(ldap.OPT_REFERRALS,0) # DO NOT TURN THIS OFF OR SEARCH WON'T WORK!      
            # initialize
            if debug:
               print >>debug, 'ldap.initialize...'
            l = ldap.initialize(settings.AD_LDAP_URL)
            l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
            # bind
            if debug:
               print >>debug, 'bind...'
            binddn = "%s@%s" % (username,settings.AD_NT4_DOMAIN)
            l.bind_s(binddn,password)
            # search
            if debug:
               print >>debug, 'search...'
            result = l.search_ext_s(settings.AD_SEARCH_DN,ldap.SCOPE_SUBTREE,"sAMAccountName=%s" % username,settings.AD_SEARCH_FIELDS)[0][1]
            if debug:
               print >>debug, result
            # Validate that they are a member of review board group
            if result.has_key('memberOf'):
                membership = result['memberOf']
            else:
                membership = None
            if debug:
               print >>debug, "required:%s" % settings.AD_MEMBERSHIP_REQ
            bValid=0
            for req_group in settings.AD_MEMBERSHIP_REQ:
               if debug:
                  print >>debug, "Check for %s group..." % req_group
               for group in membership:
                   group_str="CN=%s," % req_group
                   if group.find(group_str) >= 0:
                        if debug:
                           print >>debug, "User authorized: group_str membership found!"
                        bValid=1
                        break
            if bValid == 0:
               if debug:
                   print >>debug, "User not authorized, correct group membership not found!"
               return None
            # get email
            if result.has_key('mail'):
                mail = result['mail'][0]
            else:
                mail = None
            if debug:
                print >>debug, "mail=%s" % mail
            # get surname
            if result.has_key('sn'):
                last_name = result['sn'][0]
            else:
                last_name = None
            if debug:
                print >>debug, "sn=%s" % last_name
            # get display name
            if result.has_key('givenName'):
                first_name = result['givenName'][0]
            else:
                first_name = None
            if debug:
               print >>debug, "first_name=%s" % first_name
            l.unbind_s()
            user = User(username=username,first_name=first_name,last_name=last_name,email=mail)
         except Exception, e:
            if debug:
               print >>debug, "exception caught!"
               print >>debug, e
            return None
         user.is_staff = False
         user.is_superuser = False
         user.set_password('ldap authenticated')
         user.save()
         # add user to default group
         group=Group.objects.get(pk=1)
         if debug:
             print >>debug, group
         if debug:
             print >>debug, "add %s to group %s" % (username,group)
         user.groups.add(group)
         user.save()
         if debug:
             print >>debug, "successful group add"
         if debug:
            debug.close()
      return user
  def get_user(self, user_id):
      try:
        return User.objects.get(pk=user_id)
      except User.DoesNotExist:
        return None
 | 
More like this
- Add Toggle Switch Widget to Django Forms by OgliariNatan 1 month, 4 weeks ago
 - get_object_or_none by azwdevops 5 months, 2 weeks ago
 - Mask sensitive data from logger by agusmakmun 7 months, 2 weeks ago
 - Template tag - list punctuation for a list of items by shapiromatron 1 year, 9 months ago
 - JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 1 year, 9 months ago
 
Comments
Two questions about the certificate you used:
#
Just to note, this snippet is very useful, but you really need to make sure that you have the groups in your django db. Otherwise you will see errors like:
So, I patched the script to catch these errors with:
#
Beware to change line 133
user.set_password('ldap authenticated')to a random number like:Otherwise, anyone can log in as a user with password "ldap authenticated".
#
Please login first before commenting.