Search code examples
djangopython-3.xdjango-2.1

Django check_password() always returning False


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>

Solution

  • 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.