Home

Introduction

This library facilitates the implementation of HTTP Digest Authentication for Django projects.

It supplies a middleware (django_digest.middleware.HttpDigestMiddleware) that may installed to protect access to all URLs, a decorator (@django_digest.decorators.httpdigest) that may be applied to selected view functions, and a simple class (django_digest.HttpDigestAuthenticator) that can be used to implement custom authentication scenarios.

Installation

  1. Check it out from bitbucket or download a pre-built egg from pypi.
  2. Do the same for python-digest and, optionally, decorator, mocker, and south
  3. Add django_digest to your settings.INSTALLED_APPS.
  4. Optionally configure settings as described in the README.

Requirements

  • python-digest
  • decorator: only required if using the @httpdigest decorator
  • mocker: only for running the unit tests
  • south: optional, for maintaining your database schema using migrations

Usage

Password Management

HTTP Digest requires the server to be able to calculate a hash over the user's username, password, and your realm. Since django.contrib.auth only stores a hash of the user's password, this cannot be used to authenticate HTTP Digest sessions.

django-digest intercepts password assignments and user logins in order to capture the user's password and generate the digest it requires. Only the generated digest is stored in the database. This means that only users who have logged in or set or changed their passwords since django-digest was installed will be able to authenticate using HTTP Digest. Also, changing your realm will invalidate all stored digests.

Alternative Logins

django-digest allows users to authenticate using their username or their email address. If either is supplied in mixed or upper case, the user may authenticate using either the original case or the lower case.

Additional valid logins may be defined using the DIGEST_LOGIN_FACTORY setting. See django_digest.DefaultLoginFactory for an example.

Changing Logins

If a valid login may change over time (i.e. when the user changes their email address), you must force django-digest to regenerate its stored partial digests by calling django_digest.backend.db.update_partial_digests, passing the user and their password. In this case you will need to ask the user for their password to add or change an email address (generally a good idea, anyway).

Unconfirmed Logins

If:

  1. you allow users to log in with their email address,
  2. you allow users to change their email address,
  3. you require users to confirm their email addresses, and
  4. you wish to ask users their password when they set the email address (as opposed to when they confirm it),

You can tell django-digest about the new email address when it is added but only enable it once the user confirms it. To do so:

  1. Define the method unconfirmed_logins_for_user on your login factory.
  2. Call django_digest.backend.db.update_partial_digests with the user and his or her password after storing the user's new, unconfirmed, email address. Ensure that it is returned from the method defined in (1).
  3. Call django_digest.backend.db.review_partial_digests with the user after confirming the email address.

Middleware

Add django_digest.middleware.HttpDigestMiddleware to your middleware stack (probably near the top, after CommonMiddleware). If you are serving web browsers, you will probably want to disable nonce-count enforcement. Otherwise you will have problems when browsers start sending simultaneous requests on multiple connections (this is a problem with all HTTP Digest implementations). To disable nonce-count enforcement, add the following to your Django settings:

DIGEST_ENFORCE_NONCE_COUNT = False

Decorator

Ensure that you have installed decorator, a required dependency for the @httpdigest decorator.

Add the @django_digest.decorators.httpdigest decorator to your view. If you are authenticating web browsers or other clients who are likely to make multiple simultaneous requests, you should disable nonce-count enforcement. To disable nonce-count enforcement, add the following to your Django settings:

DIGEST_ENFORCE_NONCE_COUNT = False

The decorator can be used in any of the following ways:

# use a default-constructed authenticator
@httpdigest
def view(request):
   ...

# use a default-constructed authenticator
@httpdigest()
def view(request):
   ...

# pass in a pre-constructed authenticator
authenticator = HttpDigestAuthenticator(realm='realm', secret=...)
@httpdigest(authenticator)
def view(request):
   ...

# pass in the constructor args for an authenticator
@httpdigest(realm=..., ...)
def view(request):
   ...

Development

django-digest uses buildout so setting up a development and testing environment is easy:

erik-wrights-macbook-pro:~ erikwright$ hg clone http://bitbucket.org/akoha/django-digest/
destination directory: django-digest
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 16 changes to 16 files
updating working directory
16 files updated, 0 files merged, 0 files removed, 0 files unresolved
erik-wrights-macbook-pro:~ erikwright$ cd django-digest
erik-wrights-macbook-pro:django-digest erikwright$ /usr/bin/python bootstrap.py 
Creating directory '/Users/erikwright/django-digest/bin'.
Creating directory '/Users/erikwright/django-digest/parts'.
Creating directory '/Users/erikwright/django-digest/eggs'.
Creating directory '/Users/erikwright/django-digest/develop-eggs'.
Generated script '/Users/erikwright/django-digest/bin/buildout'.
erik-wrights-macbook-pro:django-digest erikwright$ ./bin/buildout 
Develop: '/Users/erikwright/django-digest/.'
Develop: '/Users/erikwright/django-digest/../python-digest'
Getting distribution for 'djangorecipe'.
Got djangorecipe 0.20.
Getting distribution for 'zc.recipe.egg'.
Got zc.recipe.egg 1.2.2.
Installing django.
django: Downloading Django from: http://www.djangoproject.com/download/1.1.1/tarball/
Getting distribution for 'mocker'.
zip_safe flag not set; analyzing archive contents...
Got mocker 0.10.1.
Getting distribution for 'decorator'.
warning: no previously-included files found matching 'Makefile'
Got decorator 3.1.2.
Generated script '/Users/erikwright/django-digest/bin/django'.
Generated script '/Users/erikwright/django-digest/bin/test'.
erik-wrights-macbook-pro:django-digest erikwright$ ./bin/test
Creating test database...
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_digest_usernonce
Creating table django_digest_partialdigest
Installing index for auth.Permission model
Installing index for auth.Message model
Installing index for django_digest.UserNonce model
Installing index for django_digest.PartialDigest model
..................
----------------------------------------------------------------------
Ran 18 tests in 0.211s

OK
Destroying test database...
erik-wrights-macbook-pro:django-digest erikwright$ 

If python-digest is checked out as a file-system sibling of the django-digest project that checkout will be used. Otherwise it will be retrieved from pypi.

Troubleshooting

django-digest emits debugging messages when it fails to accept Digest credentials. If authentication is not working for you, try enabling 'debug' logging for the 'django_digest' logger using the standard Python logging module. This can be done by adding the following code somewhere in your project:

import logging
logging.basicConfig(level=logging.DEBUG)

If you are experiencing problems with a web browser, the most likely issue is that you have not disabled nonce-count enforcement and the browser is making multiple simultaneous requests.

Updated

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.