Commits

Felipe Prenholato  committed c1830b1

Changing _LDAPUser position and changing calls on LDAPBackend to self.ldap_user so people who extend LDAPBackend can easily use a custom _LDAPUser without headcache of overwrite various methods.

  • Participants
  • Parent commits 544923a

Comments (0)

Files changed (1)

File django_auth_ldap/backend.py

 from django.contrib.auth.models import User, Group, SiteProfileNotAvailable
 from django.core.cache import cache
 from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
+from django.utils.datastructures import SortedDict
 import django.dispatch
 
 from django_auth_ldap.config import _LDAPConfig, LDAPSearch, LDAPGroupType
 populate_user = django.dispatch.Signal(providing_args=["user", "ldap_user"])
 populate_user_profile = django.dispatch.Signal(providing_args=["profile", "ldap_user"])
 
-
-class LDAPBackend(object):
-    """
-    The main backend class. This implements the auth backend API, although it
-    actually delegates most of its work to _LDAPUser, which is defined next.
-    """
-    supports_anonymous_user = False
-    supports_object_permissions = False
-
-    ldap = None # The cached ldap module (or mock object)
-    
-    def __init__(self):
-        self.ldap = self.ldap_module()
-    
-    def ldap_module(cls):
-        """
-        Requests the ldap module from _LDAPConfig. Under a test harness, this
-        will be a mock object. We only do this once because this is where we
-        apply AUTH_LDAP_GLOBAL_OPTIONS.
-        """
-        if cls.ldap is None:
-            cls.ldap = _LDAPConfig.get_ldap()
-            
-            for opt, value in ldap_settings.AUTH_LDAP_GLOBAL_OPTIONS.iteritems():
-                cls.ldap.set_option(opt, value)
-        
-        return cls.ldap
-    ldap_module = classmethod(ldap_module)
-
-
-    #
-    # The Django auth backend API
-    #
-
-    def authenticate(self, username, password):
-        ldap_user = _LDAPUser(self, username=username)
-        user = ldap_user.authenticate(password)
-        
-        return user
-    
-    def get_user(self, user_id):
-        user = None
-        
-        try:
-            user = User.objects.get(pk=user_id)
-            _LDAPUser(self, user=user) # This sets user.ldap_user
-        except User.DoesNotExist:
-            pass
-        
-        return user
-    
-    def has_perm(self, user, perm):
-        return perm in self.get_all_permissions(user)
-
-    def has_module_perms(self, user, app_label):
-        for perm in self.get_all_permissions(user):
-            if perm[:perm.index('.')] == app_label:
-                return True
-
-        return False
-
-    def get_all_permissions(self, user):
-        return self.get_group_permissions(user)
-
-    def get_group_permissions(self, user):
-        if not hasattr(user, 'ldap_user') and ldap_settings.AUTH_LDAP_AUTHORIZE_ALL_USERS:
-            _LDAPUser(self, user=user) # This sets user.ldap_user
-        
-        if hasattr(user, 'ldap_user'):
-            return user.ldap_user.get_group_permissions()
-        else:
-            return set()
-
-    #
-    # Bonus API: populate the Django user from LDAP without authenticating.
-    #
-
-    def populate_user(self, username):
-        ldap_user = _LDAPUser(self, username=username)
-        user = ldap_user.populate_user()
-        
-        return user
-    
-    #
-    # Hooks for subclasses
-    #
-
-    def get_or_create_user(self, username, ldap_user):
-        """
-        This must return a (User, created) 2-tuple for the given LDAP user.
-        username is the Django-friendly username of the user. ldap_user.dn is
-        the user's DN and ldap_user.attrs contains all of their LDAP attributes.
-        """
-        return User.objects.get_or_create(username__iexact=username, defaults={'username': username.lower()})
-
-    def ldap_to_django_username(self, username):
-        return username
-
-    def django_to_ldap_username(self, username):
-        return username
-
-
 class _LDAPUser(object):
     """
     Represents an LDAP user and ultimately fields all requests that the
     # Initialization
     #
     
-    def __init__(self, backend, username=None, user=None):
+    def __init__(self, backend, using, username=None, user=None):
         """
         A new LDAPUser must be initialized with either a username or an
         authenticated User object. If a user is given, the username will be
         ignored.
         """
         self.backend = backend
+        self.using = using
         self.ldap = backend.ldap_module()
         self._username = username
         self._user_dn = None
 
     def __deepcopy__(self, memo):
         obj = object.__new__(self.__class__)
+        obj.using = self.using
         obj.backend = self.backend
         obj.ldap = self.ldap
         obj._user = copy.deepcopy(self._user, memo)
         obj._user_attrs = self._user_attrs
         obj._groups = self._groups
         obj._group_permissions = self._group_permissions
-        
+
         # The connection couldn't be copied even if we wanted to
         obj._connection = self._connection
         obj._connection_bound = self._connection_bound
 
             user = self._user
         except self.AuthenticationFailed, e:
+            print u"Authentication failed for %s" % self._username
             logger.debug(u"Authentication failed for %s" % self._username)
         except self.ldap.LDAPError, e:
+            print u"Caught LDAPError while authenticating %s: %s" % (self._username, pprint.pformat(e))
             logger.warning(u"Caught LDAPError while authenticating %s: %s",
                 self._username, pprint.pformat(e))
         except Exception, e:
+            print u"Caught Exception while authenticating %s: %s" % (self._username, pprint.pformat(e))
+            print ''.join(traceback.format_tb(sys.exc_info()[2]))
             logger.error(u"Caught Exception while authenticating %s: %s",
                 self._username, pprint.pformat(e))
             logger.error(''.join(traceback.format_tb(sys.exc_info()[2])))
             raise
-
         return user
 
     def get_group_permissions(self):
         Searches the directory for a user matching AUTH_LDAP_USER_SEARCH.
         Populates self._user_dn and self._user_attrs.
         """
-        search = ldap_settings.AUTH_LDAP_USER_SEARCH
+        search = ldap_settings.get_search_for(self.using)
         if search is None:
             raise ImproperlyConfigured('AUTH_LDAP_USER_SEARCH must be an LDAPSearch instance.')
         
         Binds to the LDAP server with AUTH_LDAP_BIND_DN and
         AUTH_LDAP_BIND_PASSWORD.
         """
-        self._bind_as(ldap_settings.AUTH_LDAP_BIND_DN,
-            ldap_settings.AUTH_LDAP_BIND_PASSWORD)
+        self._bind_as(ldap_settings.get_conn_for(self.using)['USER'],
+            ldap_settings.get_conn_for(self.using)['PASSWORD'])
 
         self._connection_bound = True
 
         Returns our cached LDAPObject, which may or may not be bound.
         """
         if self._connection is None:
-            self._connection = self.ldap.initialize(ldap_settings.AUTH_LDAP_SERVER_URI)
-            
+            self._connection = self.ldap.initialize(ldap_settings.get_conn_for(self.using)['NAME'])
+
             for opt, value in ldap_settings.AUTH_LDAP_CONNECTION_OPTIONS.iteritems():
                 self._connection.set_option(opt, value)
 
 
         return self._connection
 
-
-
 class _LDAPUserGroups(object):
     """
     Represents the set of groups that a user belongs to.
     def _cache_key(self, attr_name):
         return u'auth_ldap.%s.%s.%s' % (self.__class__.__name__, attr_name, self._ldap_user.dn)
 
+class LDAPBackend(object):
+    """
+    The main backend class. This implements the auth backend API, although it
+    actually delegates most of its work to _LDAPUser, which is defined next.
+    """
+    supports_anonymous_user = False
+    supports_object_permissions = False
+
+    ldap = None # The cached ldap module (or mock object)
+    ldap_user = _LDAPUser
+    
+    def __init__(self):
+        self.ldap = self.ldap_module()
+    
+    def ldap_module(cls):
+        """
+        Requests the ldap module from _LDAPConfig. Under a test harness, this
+        will be a mock object. We only do this once because this is where we
+        apply AUTH_LDAP_GLOBAL_OPTIONS.
+        """
+        if cls.ldap is None:
+            cls.ldap = _LDAPConfig.get_ldap()
+            
+            for opt, value in ldap_settings.AUTH_LDAP_GLOBAL_OPTIONS.iteritems():
+                cls.ldap.set_option(opt, value)
+        
+        return cls.ldap
+    ldap_module = classmethod(ldap_module)
+
+
+    #
+    # The Django auth backend API
+    #
+
+    def authenticate(self, username, password):
+        for name in ldap_settings.AUTH_LDAP_CONNECTIONS:
+            ldap_user = self.ldap_user(self, using=name, username=username)
+            user = ldap_user.authenticate(password)
+            if user is not None:
+                self.using = name
+                break
+
+        return user
+
+    def get_user(self, user_id):
+        user = None
+
+        try:
+            user = User.objects.get(pk=user_id)
+            for name in ldap_settings.AUTH_LDAP_CONNECTIONS:
+                _LDAPUser(self, using=name, user=user) # This sets user.ldap_user
+                if user is not None:
+                    self.using = name
+                    break
+        except User.DoesNotExist:
+            pass
+        
+        return user
+    
+    def has_perm(self, user, perm):
+        return perm in self.get_all_permissions(user)
+
+    def has_module_perms(self, user, app_label):
+        for perm in self.get_all_permissions(user):
+            if perm[:perm.index('.')] == app_label:
+                return True
+
+        return False
+
+    def get_all_permissions(self, user):
+        return self.get_group_permissions(user)
+
+    def get_group_permissions(self, user):
+        if not hasattr(user, 'ldap_user') and ldap_settings.AUTH_LDAP_AUTHORIZE_ALL_USERS:
+            self.ldap_user(self, self.using, user=user) # This sets user.ldap_user
+        
+        if hasattr(user, 'ldap_user'):
+            return user.ldap_user.get_group_permissions()
+        else:
+            return set()
+
+    #
+    # Bonus API: populate the Django user from LDAP without authenticating.
+    #
+
+    def populate_user(self, username):
+        ldap_user = self.ldap_user(self, using=self.using, username=username)
+        user = ldap_user.populate_user()
+        
+        return user
+    
+    #
+    # Hooks for subclasses
+    #
+
+    def get_or_create_user(self, username, ldap_user):
+        """
+        This must return a (User, created) 2-tuple for the given LDAP user.
+        username is the Django-friendly username of the user. ldap_user.dn is
+        the user's DN and ldap_user.attrs contains all of their LDAP attributes.
+        """
+        return User.objects.get_or_create(username__iexact=username, defaults={'username': username.lower()})
+
+    def ldap_to_django_username(self, username):
+        return username
+
+    def django_to_ldap_username(self, username):
+        return username
 
 class LDAPSettings(object):
     """
         'AUTH_LDAP_BIND_PASSWORD': '',
         'AUTH_LDAP_CACHE_GROUPS': False,
         'AUTH_LDAP_CONNECTION_OPTIONS': {},
+        'AUTH_LDAP_CONNECTIONS': [],
         'AUTH_LDAP_FIND_GROUP_PERMS': False,
         'AUTH_LDAP_GLOBAL_OPTIONS': {},
         'AUTH_LDAP_GROUP_CACHE_TIMEOUT': None,
         'AUTH_LDAP_USER_FLAGS_BY_GROUP': {},
         'AUTH_LDAP_USER_SEARCH': None,
     }
+
+    connections = SortedDict()
     
     def __init__(self):
         """
             value = getattr(settings, name, default)
             setattr(self, name, value)
 
+        if not self.AUTH_LDAP_CONNECTIONS:
+            self.AUTH_LDAP_CONNECTIONS = ['ldap']
+            self.connections['ldap'] = {
+                'NAME': self.AUTH_LDAP_SERVER_URI,
+                'USER': self.AUTH_LDAP_BIND_DN,
+                'PASSWORD': self.AUTH_LDAP_BIND_PASSWORD,
+                'USER_SEARCH': self.AUTH_LDAP_USER_SEARCH,
+                'BASE_DN': self.AUTH_LDAP_USER_SEARCH.base_dn,
+            }
+        else:
+            for name in self.AUTH_LDAP_CONNECTIONS:
+                s = settings.DATABASES.get(name,None)
+                if not s:
+                    raise ImproperlyConfigured,u"Connection %s not found in settings.DATABASES" % name
+                self.connections[name] = settings.DATABASES[name]
+
+    def get_conn_for(self,alias):
+        return self.connections[alias]
+
+    def get_search_for(self,alias):
+        return self.connections[alias]['USER_SEARCH']
 
 # Our global settings object
 ldap_settings = LDAPSettings()
+# LDAPBackend().authenticate('teste.ad01.pdgr@pdg.com.br','jmEiEywxPx4io')