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
django_digest.HttpDigestAuthenticator) that can be used to implement custom authentication scenarios.
- Check it out from bitbucket or download a pre-built egg from pypi.
- Do the same for
- Optionally configure settings as described in the README.
- decorator: only required if using the @httpdigest decorator
- mocker: only for running the unit tests
- south: optional, for maintaining your database schema using migrations
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.
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.
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).
- you allow users to log in with their email address,
- you allow users to change their email address,
- you require users to confirm their email addresses, and
- 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:
- Define the method
unconfirmed_logins_for_useron your login factory.
django_digest.backend.db.update_partial_digestswith 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).
django_digest.backend.db.review_partial_digestswith the user after confirming the email address.
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
Ensure that you have installed decorator, a required dependency for 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): ...
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.
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.