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, !

  • 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. – Miguel Grinberg Mar 13 '15 at 17:21

5 Answers5

8

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

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.

sjudǝʊ
  • 1,565
  • 1
  • 23
  • 34
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.

huy mai
  • 111
  • 1
  • 5
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.

Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • 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`. –  Mar 29 '15 at 11:05
  • @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. – Miguel Grinberg Mar 29 '15 at 16:34
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')
Nav
  • 19,885
  • 27
  • 92
  • 135
Eyasu
  • 240
  • 3
  • 13