Authenticating and populating users in Django using a Windows Active Directory and SASL

I’ve been trying to get some Django stuff running that can securely authenticate users against Windows Active Directory and also populate some info (first/last name, email address, maybe groups etc.). There are lots of resources out there but nothing was fully complete or modern and it took me some figuring/hacking to get it done.

Resources I found include:

  • django-auth-ldap — the normal LDAP plugin. Problem: It does not natively support SASL and simple binds would send clear-text passwords. I think normal people would just activate TLS in this case but I didn’t want to do that
  • A relevant SO post — with an answer linking to a useful snippet that no longer works on recent django versions.
  • django-auth-ldap-ad — Someone’s entire different ldap plugin made specifically for this purpose. But it isn’t being maintained, is GPL-2, and doesn’t work directly in Python 3 or recent django.

I worked hard on that last one and actually got it running in Python 3, Django 2.1. But it still needed work (Needed a different signature in the authenticate method, bytes vs. strings issues, etc.).

In the end I made a custom subclass of the LDAPBackend in django-auth-ldap.

Activate the custom subclass and specify some settings:

Make the custom authenticator subclass in auth.py. Note that this is heavily based on the original class in the library. I did a few things with this that weren’t awesome but worked:

  • Copy/pasted lots of code with _LDAPUser switched to my new subclass of that user. A better solution would be to change the library code to use a factory method and just update that. This subclass would shrink dramatically with that change.
  • Overrode the attempt to know the DN before authenticating. SASL works fine with just the username.
  • Eliminated re-binding when getting the connection. It was grabbing that through a property and failing authentication all the time because the auth_tokens weren’t cached anywhere. Another option would have been to cache the auth tokens.

And boom, it works! Users get authenticated and name/email gets populated. Quite glorious. I haven’t messed with groups much but that’s the next step.

Moving forward, I’ll consider cleaning this up and contributing it to django-auth-ldap.

 

Leave a Reply

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