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-->