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.
Intro
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,
username@INTERNAL_DOMAIN
Scenario
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:
# 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.
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 get_full_name
and get_short_name
, and is_active
which defaults to True
.
Just a few variables should be set within settings.py
file to make Django a team player:
# 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 RemoteUserMiddleware
.
If want to use user
from the Kerberos’ user@REALM
as the username, you can simply extend RemoteUserBackend
:
# 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("@")[0]
and settings.py
for your custom backend defined above:
# 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:
# 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:
# synergizerApp/views.py
from django.contrib.auth import get_user_model
User = get_user_model()
# <--snip-->
Other resources
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