Ticket #2507: backends.py.2.diff

File backends.py.2.diff, 6.3 KB (added by spr@…, 18 years ago)

update to allow ldap options, and custom bind string functions. Also fixes a typo.

  • django/contrib/auth/backends.py

     
    11from django.contrib.auth.models import User
     2from django.conf import settings
    23
    34class ModelBackend:
    45    """
     
    1920            return User.objects.get(pk=user_id)
    2021        except User.DoesNotExist:
    2122            return None
     23
     24class LDAPBackend(object):
     25    """
     26    Authenticate a user against LDAP.
     27    Requires python-ldap to be installed.
     28
     29    Requires the following things to be in settings.py:
     30    LDAP_BINDDN -- string of the LDAP dn to use for binding
     31    LDAP_SEARCHDN -- string of the LDAP dn to use for searching
     32    LDAP_BIND_ATTRIBUTE -- string of the LDAP attribute to use in binding
     33        also used to search for a user.
     34    LDAP_SERVER_URI -- string, ldap uri
     35    LDAP_SCOPE -- one of: ldap.SCOPE_*, used for searching
     36        ldap.SCOPE_BASE = 0
     37        ldap.SCOPE_ONELEVEL = 1
     38        ldap.SCOPE_SUBTREE = 2
     39        see python-ldap docs for the search function
     40    LDAP_UPDATE_FIELDS -- boolean, do we sync the db with ldap with each auth
     41
     42    Required unless LDAP_FULL_NAME is set:
     43    LDAP_FIRST_NAME -- string, LDAP attribute to get the given name from
     44    LDAP_LAST_NAME -- string, LDAP attribute to get the last name from
     45
     46    Optional Settings:
     47    LDAP_FULL_NAME -- string, LDAP attribute to get name from, splits on ' '
     48    LDAP_GID -- string, LDAP attribute to get group name/number from
     49    LDAP_SU_GIDS -- list of strings, group names/numbers that are superusers
     50    LDAP_STAFF_GIDS -- list of strings, group names/numbers that are staff
     51    LDAP_EMAIL -- string, LDAP attribute to get email from
     52    LDAP_DEFAULT_EMAIL_SUFFIX -- string, appened to username if no email found
     53    LDAP_OPTIONS -- hash, python-ldap global options and their values
     54        {ldap.OPT_X_TLS_CACERTDIR: '/etc/ldap/ca/'}
     55    LDAP_BIND_STRING_FUNC -- Function to produce the string for binding the user
     56
     57    How Binds Work:
     58    LDAP_BINDDN = 'ou=people,dc=example,dc=com'
     59    LDAP_BIND_ATTRIBUTE = 'uid'
     60    # The bind would be performed via:
     61    # uid=username,ou=people,dc=example,dc=com
     62    """
     63    import ldap
     64
     65    def authenticate(self, username=None, password=None):
     66        if not username and password is not None: # we need a user/pass
     67            l.unbind_s()
     68            return None
     69
     70        if hasattr(settings, 'LDAP_OPTIONS'):
     71            for k, v in settings.LDAP_OPTIONS:
     72                ldap.set_option(k, v)
     73
     74        l = ldap.initialize(settings.LDAP_SERVER_URI)
     75
     76        if hasattr(settings, 'LDAP_BIND_STRING_FUNC'):
     77            bind_string = settings.LDAP_BIND_STRING_FUNC
     78        else:
     79            bind_string = "%s=%s,%s" % (settings.LDAP_BIND_ATTRIBUTE,
     80                    username, settings.LDAP_BINDDN)
     81        try:
     82            l.bind_s(bind_string, password)
     83        except ldap.INVALID_CREDENTIALS: # Failed user/pass
     84            l.unbind_s()
     85            return None
     86
     87        try:
     88            user = User.objects.get(username=username)
     89        except User.DoesNotExist:
     90            user = None
     91
     92        if user is not None:
     93            if settings.LDAP_UPDATE_FIELDS:
     94                LDAPBackend.update_user(l, user)
     95        else:
     96            user = LDAPBackend.get_ldap_user(l, username)
     97
     98        l.unbind_s()
     99        return user
     100
     101    def get_user(self, user_id):
     102        try:
     103            return User.objects.get(pk=user_id)
     104        except:
     105            return None
     106
     107    def get_ldap_user(l, username):
     108        """
     109        Helper method, makes a user object and call update_user to populate
     110        """
     111
     112        user = User(username=username, password='Made by LDAP')
     113        LDAPBackend.update_user(l, user)
     114        return user
     115    get_ldap_user = staticmethod(get_ldap_user)
     116
     117    def update_user(l, user):
     118        """
     119        Helper method, populates a user object with various attributes from
     120        LDAP
     121        """
     122
     123        username = user.username
     124        filter_str = "%s=%s" % (settings.LDAP_BIND_ATTRIBUTE, username)
     125        attrs = l.search_s(settings.LDAP_SEARCHDN, settings.LDAP_SCOPE,
     126                filterstr=filter_str)[0][1]
     127
     128        if (hasattr(settings, 'LDAP_FIRST_NAME')
     129                and hasattr(settings, 'LDAP_LAST_NAME')):
     130            if (settings.LDAP_FIRST_NAME in attrs
     131                    and settings.LDAP_LAST_NAME in attrs):
     132                user.first_name = attrs[settings.LDAP_FIRST_NAME][0]
     133                user.last_name = attrs[settings.LDAP_LAST_NAME][0]
     134            else:
     135                raise NameError('Missing needed fields %s or %s in LDAP'
     136                        % (settings.LDAP_FIRST_NAME, settings.LDAP_LAST_NAME))
     137        elif hasattr(settings, 'LDAP_FULL_NAME'):
     138                if settings.LDAP_FULL_NAME in attrs:
     139                    tmp = attrs[settings.FULL_NAME_FIELD][0]
     140                    user.first_name = tmp.split(' ')[0]
     141                    user.last_name = ' '.join(tmp.split(' ')[1:])
     142                else:
     143                    raise NameError('Required field %s missing in LDAP'
     144                            % (settings.LDAP_FULL_NAME))
     145        else:
     146            raise NameError('Name fields not defined in settings.py')
     147
     148        if hasattr(settings, 'LDAP_EMAIL') and settings.LDAP_EMAIL in attrs:
     149            user.email = attrs[settings.EMAIL_FIELD][0]
     150        elif hasattr(settings, 'LDAP_DEFAULT_EMAIL_SUFFIX'):
     151            user.email = username + settings.LDAP_DEFAULT_EMAIL_SUFFIX
     152
     153        if (hasattr(settings, 'LDAP_GID')
     154                and settings.LDAP_GID in attrs
     155                and hasattr(settings, 'LDAP_SU_GIDS')
     156                and attrs[settings.LDAP_GID][0] in settings.LDAP_SU_GIDS):
     157            user.is_superuser = True
     158            user.is_staff = True
     159        elif (hasattr(settings, 'LDAP_GID')
     160                and settings.LDAP_GID in attrs
     161                and hasattr(settings, 'LDAP_STAFF_GIDS')
     162                and attrs[settings.LDAP_GID][0] in settings.LDAP_STAFF_GIDS):
     163            user.is_superuser = False
     164            user.is_staff = True
     165        else:
     166            user.is_superuser = False
     167            user.is_staff = False
     168
     169        user.save()
     170    update_user = staticmethod(update_user)
Back to Top