LDAP(Lightweight Directory Access Protocol) is a popular way to  control access in enterprise environments. In this post,   I will demonstrate how this can be used with django.

Setup

Forumsys LDAP Directory

 

Demo Project

The demo project will have two views; one public view and a private view. Only authenticated users  are allowed to see the private view.  It  also contain two additional apps to demonstrate access control in admin. Code for our views looks like this:

from django.contrib.auth.decorators import login_required

def public(request):
    return HttpResponse("Welcome to public page")

@login_required
def private(request):
    return HttpResponse("Welcome to private page")

you may download the source code for this project from my github page.

 

Basic Authentication with LDAP

Add following lines to your settings.py for basic authentication.

import ldap
AUTH_LDAP_SERVER_URI = "ldap://ldap.forumsys.com"
AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,dc=example,dc=com"
AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Vist http://127.0.0.1:8000/private/ and django will show a login form. You can use user name ‘euler’ and password ‘password’. (All user passwords are ‘password’)

 

Troubleshooting with Logging

If you are able to get the above steps working, congratulations, but if it is not, don’t worry,  here are the the  common troubleshooting steps.

First step is to enable logging. You can enable logging by adding following lines to settings.py

import logging
logger = logging.getLogger('django_auth_ldap')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

Are you seeing any error in the log? What does the error say?  Does it say “”Can’t contact LDAP server” ? Occasionally, the LDAP server may go down, so please make sure that you are able to connect to the LDAP server using  Apache Directory Studio.  It will be worthwhile to test your AUTH_LDAP_USER_DN_TEMPLATE variable using  Apache Directory Studio as well. Below error is caused by LDAP server not responding(Confirmed using Apache Studio)

 

Django admin access using LDAP

In order to handle admin access using LDAP, group level settings are required. Add following lines to your settings.py

from django_auth_ldap.config import LDAPSearch,GroupOfUniqueNamesType

#Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("dc=example,dc=com",
ldap.SCOPE_SUBTREE, "(objectClass=GroupOfUniqueNames)"
)

AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType()

AUTH_LDAP_USER_FLAGS_BY_GROUP = {
 "is_active": ("ou=mathematicians,dc=example,dc=com",
 "ou=scientists,dc=example,dc=com", ),
 "is_staff": ("ou=mathematicians,dc=example,dc=com",
 "ou=scientists,dc=example,dc=com", )
}

This will give ‘staff’ access to groups ‘mathematicians’ and ‘scientists’. You can confirm this by logging in to admin as ‘newton’ who is a member of ‘scientists’ group.

Logging is much more useful to troubleshoot group level access.

Even though the users have staff access now, they don’t have any permissions yet. We will fix it in a moment.

Add below line to settings.py

AUTH_LDAP_MIRROR_GROUPS = True

This option will create the groups for the user in django admin. (If you are logging in as user ‘newton’, it will create the ‘scientists’ group).

Log in to admin as a superuser and add all ‘Science’ app permissions to group ‘scientists’.

Now, if you login as a user from ‘scientists’ group, you will have access to the ‘science app models.

Repeat the same process for ‘Mathematicians’ group with permissions only granted for ‘mathematics’ app. This way,  scientists will have access only to science app and mathematicians only have access to mathematics app.

 

Additional Settings

If your LDAP server does not support anonymous binds, you have to provide below additional details. Here is the settings for Forumsys server.

AUTH_LDAP_BIND_DN = "cn=read-only-admin,dc=example,dc=com"
AUTH_LDAP_BIND_PASSWORD = "password"

You can allow or disallow certain user groups using below lines

AUTH_LDAP_REQUIRE_GROUP = "ou=scientists,dc=example,dc=com"
AUTH_LDAP_DENY_GROUP = "ou=chemists,dc=example,dc=com"

You can map the django user attributes to LDAP like this:

AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "cn",
"last_name": "sn",
"email": "mail"
}

Instead of AUTH_LDAP_USER_DN_TEMPLATE, you can use a LDAP search object.

AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=example,dc=com",
ldap.SCOPE_SUBTREE, "(uid=%(user)s)"
)

You can cache LDAP group memberships to reduce LDAP traffic in production.

AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

 

A word of caution

LDAP configurations can vary a lot between organizations. If you are having trouble, please use a LDAP browser like  Apache Directory Studio  to understand the directory structure.

 

Source Code

Leave a Reply

Your email address will not be published. Required fields are marked *