python flask-security: encryption error "hash could not be identified"


Question

I'm using Flask-Security in a Flask project. Basically everything works, until I try to turn on password encryption. Basically I followed this: http://packages.python.org/Flask-Security/configuration.html Which led to me adding this:

app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt'
app.config['SECURITY_PASSWORD_SALT'] = '$2a$16$PnnIgfMwkOjGX4SkHqSOPO'

This results in a error unfortunately:

File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1701, in __call__
return self.wsgi_app(environ, start_response)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1689, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1687, in wsgi_app
response = self.full_dispatch_request()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1360, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request
rv = self.dispatch_request()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask/app.py", line 1344, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/decorators.py", line 171, in wrapper
return f(*args, **kwargs)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/views.py", line 72, in login
if form.validate_on_submit():
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_wtf/form.py", line 123, in validate_on_submit
return self.is_submitted() and self.validate()
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/forms.py", line 165, in validate
if not verify_password(self.password.data, self.user.password):
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/flask_security/utils.py", line 84, in verify_password
return _pwd_context.verify(get_hmac(password), password_hash)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 2534, in verify
record = self._get_or_identify_record(hash, scheme, category)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 2258, in _get_or_identify_record
return self._identify_record(hash, category)
File "/home/geoadmin/.virtualenvs/flask/lib/python2.7/site-packages/passlib/context.py", line 1455, in identify_record
raise ValueError("hash could not be identified")
ValueError: hash could not be identified

I'm rather clueless as to what's happening. I thought i generated a good bcrypt hash, but there are no real examples on the website for password encryption and the error itself confuses me :/

Software used: - Ubuntu 12.04LTS - Python 2.7.2 - FLask 0.9 - Flask-Security 1.5.4 - Running on MongoDB 2.2 through MongoAlchemy

Thanks for your help!!

Edit: thanks to Bikeshedder, this is the likely culprit:

# Create a user to test with
@app.before_first_request
def create_user():
    user_datastore.create_user(email='test@test.net', password='testerdetest')

I assumed that the create_user method would automatically encrypt the password. But apparently it doesn't... The documentation isn't really clear here:

Class flask_security.datastore.MongoEngineUserDatastore(db, user_model, role_model)
A MongoEngine datastore implementation for Flask-Security that assumes the use of the Flask-MongoEngine extension.
create_user(**kwargs)
Creates and returns a new user from the given parameters.

Edit 2: Working further on BikeShedder's suggestion, I changed my standard user creation to this:

# Create a user to test with
@app.before_first_request
def create_user():
    user_datastore.create_user(email='test@test.net', password=bcrypt.hashpw('testerdetest', app.config['SECURITY_PASSWORD_SALT'])

So that solves the error, but it gives me an "Invalid password", meaning that flask-security does something different than I do in my encrypting... argh!

Edit 3: changed from bcrypt to passlib (which flask-security also uses)

app.config['SECURITY_PASSWORD_SALT'] = '/2aX16zPnnIgfMwkOjGX4S'

and

user_datastore.create_user(email='test@test.net', password=passlib.hash.bcrypt.encrypt('testerdetest', salt=app.config['SECURITY_PASSWORD_SALT']))

still get an invalid pw :( If i look at the source code at https://github.com/mattupstate/flask-security/blob/develop/flask_security/utils.py it seems it only uses a sha512 encryption... I don't understand the documentation then...

Edit 5: solved (thanks for putting me on the right direction!) flask.ext.security.utils.encrypt_password() did the trick. However, i'm still in doubt whether it really is bcrypt or not, but okay, it's encrypted at least...

1
2
1/28/2013 3:01:30 PM

Accepted Answer

Since you did not explain when this error occurs I have to guess that it happens when trying to log in.

If this is the case this means the password stored in the DB is in the wrong format. It is probably still plain text and Flask-Security is unable to figure out the hashing algorithm in use.

The simplest way to fix this would be resetting the passwords of the users.

3
1/28/2013 1:28:32 PM

I had the same issue, I solve it with:

from flask.ext.security.utils import encrypt_password
user_datastore.create_user(email='test@test.fr', password=encrypt_password('password'))

The advantage is that we can choose that we want for SECURITY_PASSWORD_HASH and SECURITY_PASSWORD_SALT values.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon