[Django]-Token Based Authentication in Django

21👍

Before searching for code, be sure you read the documentation. http://docs.djangoproject.com/en/1.2/topics/auth/#other-authentication-sources
Also read the supplied Django source.

You want to create three things.

  1. Middleware to capture the token. This is where most of the work happens. It checks for the token, authenticates it (by confirming it with the identity manager) and then logs in the user.

  2. Authentication backend to find Users. This is a stub. All it does is create users as needed. Your identity manager has the details. You’re just caching the current version of the user on Django’s local DB.

Here’s the middleware (edited).

from django.contrib.auth import authenticate, login

class CookieMiddleware( object ):
    """Authentication Middleware for OpenAM using a cookie with a token.
    Backend will get user.
    """
    def process_request(self, request):
        if not hasattr(request, 'user'):
            raise ImproperlyConfigured() 
        if "thecookiename" not in request.COOKIES:
            return
        token= request.COOKIES["thecookiename"]
        # REST request to OpenAM server for user attributes.
        token, attribute, role = identity_manager.get_attributes( token )
        user = authenticate(remote_user=attribute['uid'][0])
        request.user = user
        login(request, user)

The identity_manager.get_attributes is a separate class we wrote to validate the token and get details on the user from the IM source. This, of course, has to be mocked for testing purposes.

Here’s a backend (edited)

class Backend( RemoteUserBackend ):
    def authenticate(**credentials):
        """We could authenticate the token by checking with OpenAM
        Server.  We don't do that here, instead we trust the middleware to do it.
        """
        try:
            user= User.objects.get(username=credentials['remote_user'])
        except User.DoesNotExist:
            user= User.objects.create(username=credentials['remote_user'] )
        # Here is a good place to map roles to Django Group instances or other features.
        return user

This does not materially change the decorators for authentication or authorization.

To make sure of this, we actually refresh the User and Group information from our
identity manager.

Note that the middleware runs for every single request. Sometimes, it’s okay to pass the token to the backed authenticate method. If the token exists in the local user DB, the request can proceed without contacting the identity manager.

We, however, have complex rules and timeouts in the identity manager, so we have to examine every token to be sure it’s valid. Once the middleware is sure the token is valid, we can then allow the backend to do any additional processing.

This isn’t our live code (it’s a little too complex to make a good example.)

👤S.Lott

Leave a comment