I have used Django before (version 1.2) and generally I like it... it is especially good at getting a brand new project up and running quickly. But, in this case, I'm rewriting and existing system and moving it to Python/Django. So, I already have a MySQL database that has a "users" table in it... this table stores the user's password with the MySQL SHA1 function (no salt, etc).
As part of the migration, I'm going to fix some of the data modeling flaws and port to PostgreSQL.
I would really like to use django.contrib.auth, but I'm unclear what I need to do. I have read the documentation, and know that I can separate the required user information and the "extra" information I have and put it into UserProfile.
But, how to handle the passwords stored in the MySQL db?
Has anyone handled this before? What approach did you take?
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_model
from django.contrib.auth.models import User
from hashlib import sha1
class 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With