Django Authentication Module

This is the implementation of a Django authentication backend for OpenID, based on the openid2rp package. It is automatically installed together with openid2rp.

In contrast to most (all ?) other Django OpenID authentication packages, this one does not try to cover any view aspects. All error cases are reported by exceptions, which you can render in whatever way you prefer.

Using the authentication backend

It is assumed that you have a working Django app with standard login functionality.

Add openid2rp.django to INSTALLED_APPS. Example:

INSTALLED_APPS = (
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.admin',
        'openid2rp.django',
        '<yourapp>.front' )

Add openid2rp.django.auth.Backend to AUTHENTICATION_BACKENDS.Example:

AUTHENTICATION_BACKENDS = (
        'django.contrib.auth.backends.ModelBackend',
        'openid2rp.django.auth.Backend' )

Do once a python manage.py syncdb to create the relevant tables.

The next step is to modify your existing login view. You need accept an OpenID URI as alternative to username / password. There are JavaScript support libraries available to help you with the URIs for the different providers and their logos.

Add a second view, which will receive the answer from the OpenID authentication provider.

In your original login view code, call openid2rp_django.auth.preAuthenticate instead of Django’s authenticate if you want to perform an OpenID authentication. Input parameters are the user-provided OpenID URI, and the (absolute !) URL of the newly created view. The result of this call is an HttpResponse object you must return as view result.

After authentication, the provider will send the users browser back to your newly created second login view. Call Django’s authenticate in there with one keyword arguments openidrequest for the request object. The result is a Django User object (if a user record in the database has this claim attached), a Django AnonymousUser object (if the claim could not be found, but OpenID authentication was ok), or an Exception if anything went wrong. In the second case, you might offer some user registration facility. You can use openid2rp_django.auth.linkOpenID to assign claims to Django user objects, so that authenticate is successfull the next time.

Functions

The Django application can use the following API:

openid2rp_django.auth.preAuthenticate(uri, answer_url, sreg = (('nickname', 'email'), ()), ax = ((openid2rp.AX.email, openid2rp.AX.first, openid2rp.AX.last), ()), reuse_session = True) → response

uri is the OpenID URI input from the user. answer_url is the absolute address of the view that will later call authenticate(). You can realize this view in whatever way you prefer, for example also by using the original login view with another GET parameter. sreg resp. ax allow you to request a set of information attributes from the authentication provider. Check the openid2rp and OpenID documentation for details.

reuse_session is intended as possibility for the application to work around broken OpenID providers. It disables the re-using of OpenID sessions for the given claim. If your provider sends an ‘openid.invalidate_handle’ parameter in the returning request, and the OpenID authentication ends with a session error, try to set this to ‘False’. Normally, you don’t need to touch this parameter.

The result is the HttpResponse object you should directly return from the view code after calling preAuthenticate. It contains a 307 redirection to the authentication provider URL, so that the user’s browser goes forward to the actual provider authentication screen.

If something goes wrong, one of the following errors is raised:

  • IncorrectURIError: The provided URI couldn’t be normalized.
  • IncorrectClaimError: The OpenID discovery step for this claim failed. This might be a typo, but can also be reasoned by an unavailable provider.
django.contrib.auth.authenticate(openidrequest=None) → user

In the handling of the providers redirection back to your site, you need to call Django’s authenticate function with a keyword parameter. request is the HttpRequest input object for your view code. The authentication provider fetches all relevant information from it.

The result of this call is either:

  • A Django User object. In this case, the OpenID claim was successfully authenticated, and the backend found a user in the database with this claim attached. The object as additional attributes:

    • openid_claim: The claim that was finally authenticated. Depending on the OpenID provider, this might or might not be the original input. In a later call to linkOpenID, use this one.
    • openid_ax: A dictionary of received AX values. The django.contrib.auth.AX dictionary contains a list of standardized key names. Check the openid2rp documentation for more information.
    • openid_sreg: A dictionary of received SREG values.
  • A Django AnonymousUser object. In this case, the claim could not be related to any user in the database, but the OpenID authentication was ok. The object has the same additional attributes as above. In this situation, you should normally proceed with some new user registration functionality. You can use the AX / SREG data to pre-fill some registration form.

  • One of the following exceptions:

    • MissingSessionError: There is no stored session for this result. This typically means that you forgot to start with preAuthenticate.
    • AuthenticationError: Something went wrong in the OpenID authentication process. The exception message contains more information.
    • IncompleteAnswerError: This is normally the providers fault.
    • MultipleClaimUsageError: The authenticated claim was linked to multiple users, which is not valid. You need to correct your database.
    • ReplayAttackError: The nonce checking mechanisms identified an answer that was already given before.
    • TookTooLongError: The authentication at the provider side took too long. You can override the default value (5 min) in your settings file with the parameter OPENID2RP_MAXLOGINDELAY.
openid2rp_django.auth.getOpenIDs(user) → ids

Returns a string list of stored OpenID claim URIs for this Django user object. This is intended for your user settings view.

openid2rp_django.auth.linkOpenID(user, claim)

Links the given Django user object to the given OpenID claim.

openid2rp_django.auth.unlinkOpenID(user, claim)

Unlinks the given Django user object from the given OpenID claim. This is intended for your user settings view.

Time, clocks, and the ordering of events

For the different timestamp checks, the authentication backend allows a maximum derivation of authentication provider clock and relaying party clock of 5 min. You can override this default value in your Django settings file with the parameter OPENID2RP_MAXTIMESHIFT.

Table Of Contents

Previous topic

Welcome to openid2rp!

Next topic

WSGI Middleware

This Page