Flask-HTTPAuth verify_password function not receiving username or password
Asked Answered
D

5

8

When I try access a route with the @auth.login_required decorator, I am prompted with a window to enter my username and password. After entering this info, the parameters username_or_token and password for the verify_password function are ''. Why is the data empty?

@auth.verify_password
def verify_password(username_or_token, password):
    # first try to authenticate by token
    user = USER.verify_auth_token(username_or_token)
    logger.debug("user = %r", user)
    logger.debug("Entered USEREMAIL = %r" ,  username_or_token)
    logger.debug("entered password = %r" ,  password)

    if not user:
        # try to authenticate with username/password
        user = session.query(USER).filter_by(USEREMAIL=username_or_token).first()   
        if not user or not user.verify_password(password):
            return False
    g.user = user
    return True

UPDATE

I've simplified the code to this:

@auth.verify_password
def verify_password(username, password):
    logger.debug("username = %s" % username)
    logger.debug("password = %s" % password)
    return true


@app.route('/api/token')
@auth.login_required
def get_auth_token():
    return "Hello, %s!" % auth.username()

I'm testing this function by using Advanced Rest Client.

http://localhost:8081/myapp/api/token

I also attached an Authorization header.

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36
Authorization: Basic YXNkOmFzZA==
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh-TW;q=0.4

This results in the output:

Hello, !

Log File:

username = 
password = 

I am also never prompted to enter my security credentials anymore.

Another strange thing is that even if I change return to false in verify_password, I still get the same output: Hello, !

Derek answered 13/3, 2015 at 3:28 Comment(1)
It would be helpful if you provide a complete example that reproduces the problem. The username and password are set to empty strings only when the client does not send the Authorization header, so this could be a client-side issue.Pendergast
V
9

I experienced similar to OP. If you're running with mod_wsgi, make sure to set WSGIPassAuthorization On as documented here.

Vala answered 17/4, 2015 at 16:37 Comment(0)
T
5

I was able to get username and password with this minimal example:

from flask import Flask
from flask.ext.httpauth import HTTPBasicAuth

app = Flask(__name__)
auth = HTTPBasicAuth()

@auth.verify_password
def foo(username, password):
    print "verifying...."
    print username
    print password
    return False

@app.route('/')
@auth.login_required
def index():
    return "Hello, %s!" % auth.username()

if __name__ == '__main__':
    app.run()

However, while working on it, chrome saved cookies and I had to remove all cache including cookies, because I was getting automatically authenticated. Maybe this could cause you problems.

Also, don't forget to mark @app.route("/") with @auth.login_required decorator. Otherwise, the verify_password callback doesn't get called.

Turbinate answered 13/3, 2015 at 9:10 Comment(1)
It also helps to add a sample HTML form that submits data to such an app.Gunlock
D
1

I got the same problem when running my Flask app on EC2. So I guess you're running your app behind a wsgi service. The point is wsgi will intercept every request header for different purposes so we need to do some configurations to make sure authentication header will be intact until it reach our app. Thanks for the answer from Erik Stephens helped me solve this. I put WSGIPassAuthorization On to /etc/httpd/conf.d/wsgi.conf on my EC2 instance and restart httpd service. You guys may want to have that update for only your app wsgi config file up to your configuration. Hope this help someone with same problem when launching app to aws.

Drench answered 19/3, 2017 at 16:39 Comment(0)
P
0

The @verify_password callback should return True if you allow the user or False if you don't. In this function, an anonymous user (i.e. one that does not send authentication) is represented with empty strings for both the username and password fields.

In your code you are not verifying that the user credentials are valid. Instead, try something like this:

@auth.verify_password
def verify_password(username, password):
    logger.debug("username = %s" % username)
    logger.debug("password = %s" % password)
    if username == '':
        return False
    return true

The above will allow any combination of username/password, but will not let anonymous users in.

Pendergast answered 21/3, 2015 at 21:6 Comment(2)
Thanks @Miguel. Using this does stop anonymous users. However, I still have the same issue with the username being ''. This is how I send my request (need Chrome Advanced Rest Client): chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo/RestClient.html#RequestPlace:default. When I send this, I am prompted with an authorisation screen. No matter what I type here and then click Log In, the box constantly reappears. When I finally press Cancel, I get the message Unauthorised Access.Derek
@Giri: that's a behavior of the browser, anytime the server responds with a 401 status code the browser displays the login dialog box. An easy way to avoid this is to return a 403 status code instead of 401. You can do this in your Flask-HTTPAuth error handler.Pendergast
C
0

Basic authentication example. This example demonstrates how to protect Flask endpoints with basic authentication, using secure hashed passwords. After running this example, visit http://localhost:5000 in your browser. To gain access, you can use (username=john, password=hello) or (username=susan, password=bye).

from flask import Flask 
from flask_httpauth import HTTPBasicAuth 
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(name) 
auth = HTTPBasicAuth()

users = { "john": generate_password_hash("hello"), "susan": generate_password_hash("bye") }

@auth.verify_password 
def verify_password(username, password): 
    if username in users: return check_password_hash(users.get(username), password) 
    else: return False

@app.route('/') 
@auth.login_required def index(): 
    return "Hello, %s!" % auth.username()

if name == 'main': 
    app.run(debug=True, host='0.0.0.0')
Colas answered 3/4, 2019 at 14:11 Comment(1)
you might want to format the code, especially for python.Ravin

© 2022 - 2024 — McMap. All rights reserved.