Understanding Django-LDAP authentication
Asked Answered
P

2

39

I am new to Django and have been assigned the task of implementing a user authentication system with LDAP as the backend. I guess the documentation assumes that the end developer has enough experience in Django to be able to understand and implement such a system. This is where I fail to understand how to implement a simple django application with LDAP based authentication. Here is what I have understood so far:

Only posting the changes to a file:

settings.py
....
import ldap
from django_auth_ldap.config import LDAPSearch

AUTH_LDAP_SERVER_URI = "ldap://<my url>" 
AUTHENTICATION_BACKENDS = ('django_auth_ldap.backend.LDAPBackend')

AUTH_LDAP_CONNECTION_OPTIONS = { 
    ldap.OPT_REFERRALS: 0
}

MIDDLEWARE_CLASSES = ( 
     ....
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    ...
)

INSTALLED_APPS = ( 
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    ....
)

auth.html

<html>
    <head>
        <title>Login</title>
    </head>
    <body>
        {{state}}
        <form action="" method="post"> {% csrf_token %}
            Email address: <input type="text" name="email" value="{{ email }}" />
            Password: <input type="password" name="password" value="" />
            <input type="submit" value="Log in" />
        </form>
    </body>
</html>

models.py:

??

views.py:

from django.shortcuts import render_to_response
from django.contrib.auth import authenticate, login
from django.template import RequestContext


def login_user(request):

    username = password = ""
    state = ""

    if request.POST:
        username = request.POST.get('username')
        password = request.POST.get('password')

        print username, password

        user = authenticate(username=username, password=password)
        if user is not None:
            login(request, user)
            state = "Valid account"
        else:
            state = "Inactive account"
    return render_to_response('auth_user/auth.html', RequestContext(request, {'state': state, 'username': username}))

What I am not able to understand?

1> I am pretty sure I would have to implement a function in views.py to get the POST values for email and password and validate it, e.g: [SO]. The documentation specifies to either implement a Search/Bind or Direct Bind. Why? If the views.py would contain the actual piece of authentication code, what is the code doing specified in the documentation?

2> If the views.py would perform the actual auth, then why do we need the variable specified in the documentation?

3> The author has done a great job with the library, but the documentation does not provide with a simple barebones example of how to implement the entire authentication system with LDAP. Can anyone please point to such a resource, if it exists? It is not easy to understand the files that need to be added/modified to implement such a system.

Pinzler answered 12/11, 2013 at 21:40 Comment(1)
Your documentation link needs to be updated to django-auth-ldap.readthedocs.io/en/latestBono
J
35

This page might have what you are looking for: https://pypi.python.org/pypi/django-auth-ldap concerning the LDAP backend. You are lucky that one exists, so you don't have to code an auth backend yourself :-)

Basically django.contrib.auth.models already has a User object that contains everything you need about the user. So you don't need to create a new models.py.

You just need to authenticate yourself in your views.py, in a login function, using

from django.contrib.auth import authenticate, login
user = authenticate(username=request.REQUEST.get('email'), password=request.REQUEST.get('password'))
# handle error cases, inactive users, ...
login(request, user)

If user is None, then authentication failed. If not, you can explore this object to see what has the backend pulled for you.

Then, you can elect to create another model with User as a foreignKey if you want to keep Preferences linked to this User for this application but nor part of the LDAP.

In this case, you will need:

Models.py

The definition of the data that is important to you based on your application. You are going to pull the user data from the LDAP, and fill up this model with it and other preferences linked to the User:

from django.contrib.auth.models import User    

class Profile(models.Model):
    """User profile.  Contains some basic configurable settings"""
    user = models.ForeignKey(User, unique=True)
    phone_number = models.CharField(max_length=256, blank=True, default='')
    ...

Views.py

  • in the login function, if request.method == 'POST', then get_or_create the user profile using the user your just got from authenticate.

    profile, profile_is_new = Profile.objects.get_or_create(user=user)
    
Jerid answered 12/11, 2013 at 22:12 Comment(4)
Thank you for feedback. While I can authenticate credentials from command line using django-auth-ldap library, the same fails in django app. I am guessing the configuration details are either not being picked up or authenticate is not really authenticating it against the LDAP server. Do you think I am missing something in my settings.py?Pinzler
I honestly can't really say, as I never used LDAP Django auth. However, your settings look good, imho. Maybe you just want to add django.contrib.auth.backends.ModelBackend as a second member of the AUTHENTICATION_BACKENDS tuple, but I don't think it will really help for your particular issue. Sorry.Jerid
I did forget something important in my code above concerning the view ... after the authenticate, use django.contrib.auth.login(request, user) to tell Django to save the user into the session. Updated my answer above.Jerid
Your documentation link needs to be updated to django-auth-ldap.readthedocs.io/en/latestBono
A
7

The django-auth-ldap docs are indeed written for developers who are familiar with Django. Also LDAP. If you're starting from scratch, I would recommend taking it one step at a time:

  1. The Django tutorial
  2. Django authentication
  3. Some kind of LDAP tutorial, if you're not already familiar.
  4. django-auth-ldap
Adytum answered 13/11, 2013 at 3:16 Comment(6)
Thank you for the reply. I guess you are the author of the library? The intent of my question is to understand how to authenticate using the AUTH_LDAP_ variables and other changes in a django project? While I did create a simple django app with a form for email and password, checking for the auth using conn = ldap.initialize("<url>"), then use the entered email and password from the UI to do: conn.bind_s(email, password) and this works fine. However, it is not clear and I guess the reason for people asking on how to make it work.Pinzler
Got it to work, found out that AUTH_LDAP_USER_DN_TEMPLATE should be set to the exact email address that is entered and there is no need to include the entire dn value i.e. just AUTH_LDAP_USER_DN_TEMPLATE=%(user)sPinzler
Glad it's working. LDAP configurations can vary quite a bit, so there are some questions that only you or the LDAP administrator can answer.Adytum
I understand. Though, I still feel that the documentation is missing examples for the most common scenarios. i.e. 1> using django-auth-ldap to authenticate against LDAP with email and password. 2> populating additional fields(like is_staff). How do I use the dispatcher to populate these fields?Pinzler
Your documentation link needs to be updated to django-auth-ldap.readthedocs.io/en/latestBono
So the solution is go figure it out yourself?Whiteside

© 2022 - 2024 — McMap. All rights reserved.