/ programming

Django, LDAP and SSL

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-8
import ldap
import logging
from django.contrib.auth.models import User
from 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('%[email protected]%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 User
from django.db.models.signals import post_save
from 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? ;-)