1

I need to import a list of users and hashed passwords from an old PHP site that used password_hash() to a new django site. The stored passwords look like this: $2y$10$ZnxKDPbqOfACnGmQeN76o.UtdwWBFBCCLTiGnvCSvl/zqIBeVxhai

I found Django password hasher using php format of function password_hash() on here when trying to look this up, and I think that will help for the NEXT step.

But currently I can't setup an import process that will correctly bring over the old passwords. When I try to manually create the users during the import process it refuses the password stating "Invalid password format or unknown hashing algorithm." when I look at the users after the import runs. I think I am just going about this totally incorrectly, here is an example snippet where I create the users.

usertest = User(username='testguy',email='testguy@test.com',password='$2y$10$ZnxKDPbqOfACnGmQeN76o.UtdwWBFBCCLTiGnvCSvl/zqIBeVxhai')

That results in no password being store. Using the create_user function results in the user being created but with that hashed password output as their password: User.objects.create_user(username='testguy',email='testguy@test.com',password='$2y$10$ZnxKDPbqOfACnGmQeN76o.UtdwWBFBCCLTiGnvCSvl/zqIBeVxhai')

How can I just get these passwords stored properly in the new database so I can move onto the next step of actually checking against those passwords?

user2300846
  • 155
  • 2
  • 10
  • 1
    Devil's advocate. Can you have a very lightweight PHP script that sits around for the next 6 or 12 months? Or however long is acceptable to your team? Have that code run the very simple `password_verify` function, and then you rehash locally. You get way less edge cases in this scenario, and it is more provable. You could even wrap it into a self-contained phar – Chris Haas Dec 21 '21 at 04:36
  • So you mean when someone logs in, have it check with that PHP script, and then if its correct, rehash it and store it in the new location normally? That could be feasible, feels pretty gross to do that though haha. I'd like to do it in a more "clean" fashion so we don't have to have a PHP script hanging out but might try that if I run out of time/patience. – user2300846 Dec 22 '21 at 06:35
  • I’ve built similar systems in the past (.Net to PHP I’m my case), and although it feels weird, it is pretty much guaranteed to work. That said, although the Python path might not have the greatest of answers here, there is a [JS version](https://stackoverflow.com/a/27341808/231316) that you might be able to rewrite in Python. – Chris Haas Dec 22 '21 at 13:04
  • OK I actually ended up with a much simpler solution that you helped me think of. I've just setup a new field in my users database to store the old password and stored the imported hashed password there. Then upon user signin, if they enter an incorrect password it uses bcrypt to check against the old password I brought over and if its a match uses django's normal password setting functionality to set it to what was entered and we are good to go. Thanks for getting me on the right path! – user2300846 Dec 22 '21 at 22:54

1 Answers1

0

I managed to find a workaround that works for me, it doesn't quite do EXACTLY what I originally intended but works well enough. For anyone that might be looking to do something similar here is what I ended up doing.

Instead of importing it into the actual Django Auth User password field, add a new old_password field to your users and import the old hashed passwords into there.

Then edit your authenticate function (likely in backends.py) to check the old_password field with bcrypt if the password check fails on login:

            if user.check_password(password):
                return user
            else: #didnt match check if its an old user
                if user.old_password != "":
                    if bcrypt.checkpw(bytes(password, 'utf-8'), bytes(user.old_password, 'utf-8')):
                        user.set_password(password)
                        user.save()
                        return user
user2300846
  • 155
  • 2
  • 10