May 16, 2013
This is part 1 of a series of posts on setting up Django to use external authentication. This post explains how to setup Django with custom user models for corporate/internal authentication methods.
Everyone has or has had a Pointy-haired boss or client, right? micromanagement, incompetence, unaware? Maybe you’re lucky?
So your Pointy-haired boss/client needs an web application. Perhaps it’s an internal web app that supposed to capitalize on synergy, streamline costs, leverage assets, all those other effing buzzwords.
You hope to use postgres and Django’s default auth mechanism, but no – you have to use the corporate/internal authentication system, a.k.a - single sign-on. We’re trying to avoid managing separate user credentials and needing to login to the required mission-critical synergy app.
Not to despair, my Djangonauts - you can leverage Django’s new custom user models!
Problem: Make an internal Web App
So an overview of problem:
- need to integrate into internal authentication like Kerberos, LDAP, Active Directory
- can’t use Postgres for authentication - BUMMER
- leverage single sign-on within your app
Crap. What is this single sign-on magic?!
- Enter: the new custom user model introduced in Django 1.5
- allows for a different identifier than the basic User Model with username greater than 30 chars
- username can be email, twitter, etc, or add those elements as requirements
- great for Kerberos/LDAP/Active Directory authentication because often the username for those identity management systems is similar to email,
Let’s create a dummy application:
./manage.py startapp synergizerApp. Just for the sake of simplicity, this is just a single django project with a single app.
Creating your custom user model
While you’re hooking into a pre-defined user database that will take care of authentication, and perhaps authorization, you can still define your own custom model by inheriting from
AbstractUserBase with your own additions, like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# synergizerApp/models.py from django.contrib.auth.models import AbstractBaseUser from django.db import models class KerbUser(AbstractBaseUser): username = models.CharField(max_length=254, unique=True) first_name = models.CharField(max_length=30, blank=True) last_name = models.CharField(max_length=30, blank=True) email = models.EmailField(blank=True) synergy_level = models.IntegerField() is_team_player = models.BooleanField(default=False) USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email', 'synergy_level']
Because you defined a custom user model – requiring a
synergy_level for the user – you’ll need to define a user manager to take care of creating users & superusers within Django.
The key parts here are just defining what a user/superuser should have, and referring to the UserManager within the user model itself.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
from django.contrib.auth.models import ( AbstractBaseUser, BaseUserManager) from django.db import models class KerbUserManager(BaseUserManager): def create_user(self, email, synergy_level, password=None): user = self.model(email=email, synergy_level=synergy_level) # <--snip--> return user def create_superuser(self, email, synergy_level, password): user = self.create_user(email, synergy_level, password=password) user.is_team_player = True user.save() return user class KerbUser(AbstractBaseUser): username = models.CharField(max_length=254, ...) # <--snip--> objects = KerbUserManager()
Within your custom user model,
KerbUser, you will also need to define
is_active which defaults to
Just a few variables should be set within
settings.py file to make Django a team player:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# settings.py # <--snip--> AUTH_USER_MODEL = 'synergizerApp.KerbUser' MIDDLEWARE_CLASSES = ( ... 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.RemoteUserMiddleware', ... ) AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.RemoteUserBackend', ) # <--snip-->
Note: The order of middleware is very important: the
AuthenticationMiddleware must precede
If want to use
user from the Kerberos'
user@REALM as the username, you can simply extend
1 2 3 4 5 6 7 8
# synergizerApp/krb5.py from django.contrib.auth.backends import RemoteUserBackend class Krb5RemoteUserBackend(RemoteUserBackend): def clean_username(self, username): # remove @REALM from username return username.split("@")
settings.py for your custom backend defined above:
1 2 3 4 5 6 7
# settings.py # <--snip--> AUTHENTICATION_BACKENDS = ( 'appname.krb5.Krb5RemoteUserBackend', ) # <--snip-->
To access the user within the models for your application, you’ll refer to the custom user model like so:
1 2 3 4 5 6 7 8
# synergizerApp/models.py from django.conf import settings from django.db import models class Synergy(models.Model): money_sink = models.ForeignKey(settings.AUTH_USER_MODEL) # <--snip-->
To access within your views:
1 2 3 4 5 6 7
# synergizerApp/views.py from django.contrib.auth import get_user_model User = get_user_model() # <--snip-->
- Part 0: How Kerberos Works
- Part 2: Apache and Kerberos for Django Authentication + Authorization
- Part 3: Setting up a Kerberos test environment
- Using configurable user models in Django