3

I have an existing database that is used with NodeJs application, now same database will be used for new application that is built with Django. I have an user_account table, which stores user login credentials, and for password encryption bcrypt module has been used.Password is stored in field user_password

I have extended the Django Users model and overrides its authencticate method, which is working fine. For password varification I'm using bcrypt method bcrypt.checkpw(password, hashed) which is working fine too.

Problem: I want to use django user.check_password(password) instead of bcrypt.checkpw(password, hashed). Since it will save the pain of generating salt and encoding before password match and most of all it's a built in method for sole purpose.

import bcrypt
from django.contrib.auth.hashers import check_password

#password = plain text password entered by user at login
#hashedPassword = Password stored in db (fieldName: user_password)
check_password(password, hashedPassword) #It returns False

user.check_password(password) # It also returns False

#for same password
bcrypt.checkpw(password, hashedPassword) # returns True

#hashedPassword format $2b$12$NNVaNL2Zla0E/WwC6Mkjjer6Qh3zIBCN6kMl9qxLE/xxyt4NAgXMq

I am using Django 2.1 and Python 3.6

I have already checked related questions, but all of them had issue with forms and I am not using any django form.

My settings.py hashers are as follows

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.Argon2PasswordHasher',
]

Input method is a simple django template

<div class='col-md-12'>
  <form action='/auth/login' method='post'>
    {% csrf_token %}
    <div class='form-group row'>
      <label for='email'>Email</label>
      <input type='email' class='form-control' id='email' name='username'>
    </div>
    <div class='form-group row'>
      <label for='password'>Password</label>
      <input type='password' class='form-control' id='password' name='password'>
    </div>
    <div class='form-group row'>
      <button class='btn btn-outline-secondary' type='submit'>Log in</button>
    </div>
  </form>
</div>
Khurshid
  • 458
  • 1
  • 5
  • 20

3 Answers3

4

Django does not store the raw hashes, they are prefixed with the algorithm (see documentation).

Without the prefix, Django will be unable to identify the correct hasher. If you look at the source of check_password, you will see that it returns False if it fails to identify a password hashers.

The cleanest solution would probably be a custom authentication backend with uses bcrypt.checkpw directly.

Daniel Hepper
  • 28,981
  • 10
  • 72
  • 75
  • That also means, I shouldn't store new passwords with django's method `user.set_password`, since it will break the consistency, as existing passwords are saved without any prefix and i think djnago will save with prefix. – Khurshid Apr 09 '19 at 05:19
0

I fixed the issue with:

from django.contrib.auth.hashers import make_password
password = make_password('yourpassword')

check_password

and

has_usable_password

returns proper values now

Seyhak Ly
  • 107
  • 2
0

This problem can be solved by installing bcrypt package using "pip install bcrypt" cmd

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 17 '23 at 08:30