Objectives:
- Users can log in using LDAP only
- Admin can log in with or without LDAP
- Only username and password are verified, nothing more
- First, we need openldap and python-ldap packages.
I have created my own authenticate backend based on django.contrib.auth.backends.ModelBackend.
# coding=utf-8import ldapimport loggingfrom django.contrib.auth.models import Userfrom django.contrib.auth.backends import ModelBackend
logger = logging.getLogger('helper')
class LdapBackend(ModelBackend): def authenticate(self, username=None, password=None): if username: """ All usernames in database are lowercase. """ username = username.lower() try: user = User.objects.get(username=username) if user.has_usable_password(): """ User can log in without LDAP. """ if user.check_password(password): return user else: """ LDAP only. """ ldap_address = 'IP:PORT' domain = 'eshlox.net' l = ldap.initialize('ldaps://%s' % ldap_address) l.set_option(ldap.OPT_REFERRALS, 0) l.set_option(ldap.OPT_TIMEOUT, 5) l.set_option(ldap.OPT_NETWORK_TIMEOUT, 5) l.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3) l.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND) l.set_option(ldap.OPT_X_TLS_DEMAND, True) l.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) try: l.simple_bind_s('%s@%s' % (username.encode('utf-8'), domain), password.encode('utf-8')) return user except ldap.INVALID_CREDENTIALS as e: """ Wrong username or password. """ return None except Exception as e: """ It has not happened yet. ;-) """ logger.error(u'LDAP Error. User %s. %s' % (username, e.args[0]['desc'])) return None except User.DoesNotExist: return None
Set new authentication backend in settings.py.
AUTHENTICATION_BACKENDS = ('project.ldapbackend.LdapBackend', )
Last thing. I have set unusable password while user is creating. One admin (me). The rest have to use LDAP. Otherwise I can set a password for user manually.
from django.contrib.auth.models import Userfrom django.db.models.signals import post_savefrom django.dispatch import receiver
@receiver(post_save, sender=User)def createUserProfile(sender, instance, created, **kwargs): if created: profile, created = UserProfile.objects.get_or_create(user=instance) if created: instance.set_unusable_password() instance.save()
Improvements? ;-)