TypeError: hash must be unicode or bytes, not None

Question:

I am working on Flask project works with mongoengine. Register code hashed to password with passlib.hash when user registered. When I try to read password in login authentication I’ve got this error.

TypeError: hash must be unicode or bytes, not None

enter image description here

Traceback:

TypeError
TypeError: hash must be unicode or bytes, not appname.models.User

Traceback (most recent call last)

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)

File "/*/**/***/***/appname/views.py", line 207, in login
if sha256_crypt.verify(u''+ passW,user):

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/passlib/utils/handlers.py", line 567, in verify
self = cls.from_string(hash, **context)

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/passlib/handlers/sha2_crypt.py", line 285, in from_string
hash = to_unicode(hash, "ascii", "hash")

File "/*/**/***/***/appname/env/lib/python2.7/site-packages/passlib/utils/__init__.py", line 617, in to_unicode
raise ExpectedStringError(source, param)

TypeError: hash must be unicode or bytes, not appname.models.User
The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.

To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.

You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:

dump() shows all variables in the frame
dump(obj) dumps all that's known about the object

Here is my views.py codes:

@app.route("/login", methods=['GET','POST'])
def login():
    if current_user.is_authenticated:
        flash("You're already registered", "info")
        return redirect(url_for('profile')+('/'+current_user.slug))

    form = LoginForm()
    passW = form.password.data

    if request.method == 'POST':
        form = LoginForm()

        if form.validate_on_submit():
            user = User.objects(email=form.email.data, password=str(passW)).first()
            if sha256_crypt.verify(passW, user):
                login_user(user, form.remember_me.data)
                slug = slugify(user.name)

                flash('We are glad you came {}.'.format(user.name),'success')
                return redirect(request.args.get('next') or url_for('profile', slug=slug))

            else:
                flash('Wrong username or password.','danger')
                return render_template("login.html", form=form, title="Cp-Login")
    return render_template("login.html", form=form, title="Cp-Login")

Any help will be appreciated.

Asked By: oyilmaztekin

||

Answers:

I guess the problem is here:

user = User.objects(email=form.email.data, password=str(passW)).first()

If your database can’t find any match user, user will be none. So you’d better use if else to tell if the user exist first.

EDIT

From the doc in Passlib,

>>> # import the hash algorithm
>>> from passlib.hash import sha256_crypt

>>> # generate new salt, and hash a password
>>> hash = sha256_crypt.encrypt("toomanysecrets")
>>> hash
'$5$rounds=80000$zvpXD3gCkrt7tw.1$QqeTSolNHEfgryc5oMgiq1o8qCEAcmye3FoMSuvgToC'

>>> # verifying the password
>>> sha256_crypt.verify("toomanysecrets", hash)
True
>>> sha256_crypt.verify("joshua", hash)
False

Your code

if sha256_crypt.verify(passW, user):

should be

if sha256_crypt.verify(passW, user.password):

if you store user’s password use Passlib. But usually you should use django build-in authenticating to do something like this.

Answered By: Windsooon

Just as @aison said above I had to change objects variable with the objects field variable as user.password

if sha256_crypt.verify(passW, user.password): 

Also needed to change model queryset itself. I removed the password field in the query, beacuse the password already verifying sha256_crypt statement after the form validation above

before modifying

user = User.objects(email=form.email.data, password=str(passW)).first()

after modifying

user = User.objects(email=form.email.data).first()

Hash verify statement that @aison suggested do the rest

if sha256_crypt.verify(passW, user.password): 
Answered By: oyilmaztekin

in my case (fastAPI) i just make mistake when declare types of class in schemas.py
should be looks like
password: str
instead
password = str

Answered By: Dmytro Velenets