Migrating a password field to Django Migrating a password field to Django postgresql postgresql

Migrating a password field to Django


Here is what I did to get things working. I created a custom authentication backend. Note: I'm using the email address as the username.

Here is my code:

from django.db.models import get_modelfrom django.contrib.auth.models import Userfrom hashlib import sha1class MyUserAuthBackend(object):    def check_legacy_password(self, db_password, supplied_password):        return constant_time_compare(sha1(supplied_password).hexdigest(), db_password)    def authenticate(self, username=None, password=None):        """ Authenticate a user based on email address as the user name. """        try:            user = User.objects.get(email=username)            if '$' not in user.password:                if self.check_legacy_password(user.password, password):                    user.set_password(password)                    user.save()                    return user                else:                    return None            else:                if user.check_password(password):                    return user        except User.DoesNotExist:            return None    def get_user(self, user_id):        """ Get a User object from the user_id. """        try:            return User.objects.get(pk=user_id)        except User.DoesNotExist:            return None

Then I added the following to settings.py:

AUTHENTICATION_BACKENDS = (    'my_website.my_app.my_file.MyUserAuthBackend',)

The suggestion from @Dougal appears to be for the next release of Django and was not available for me (I'm using 1.3.1). However, it seems like it will be a better solution.


You can probably put it straight into the user_password field - see the Django docs. Since you don't have a salt, try using the format sha1$$password_hash. I haven't investigated to see that it'll work with a blank salt, but that's probably the only way you're going to be able to migrate it without hacking django.contrib.auth or writing your own authentication backend.

Otherwise, you could just set an unusable password (the canonical thing to do is set the field to !) for users and point them to the forgot-password system.


Recent versions of Django provide a hasher for unsalted legacy passwords. Just add this to your settings file:

PASSWORD_HASHERS = (  ...  'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher',)