3

I am trying to write some REST APIs in python, to begin with I started to write Authenticate code. I found sample code for authenticate on one of the site:

from functools import wraps
from flask import request, Response

def check_auth(username, password):
    """This function is called to check if a username /
    password combination is valid.
    """
    return username == 'admin' and password == 'secret'

def authenticate():
    """Sends a 401 response that enables basic auth"""
    return Response(
    'Could not verify your access level for that URL.\n'
    'You have to login with proper credentials', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(username, password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

I have used the above piece of code to secure my sample app:

@app.route('/student/<studentid>', methods = ['GET'])
@requires_auth
def api_users(studentid):
    students = {'1':'ABC', '2':'XYZ', '3':'TEST'}

    if studentid in students:
        return jsonify({studentid:students[studentid]})
    else:
        return not_found()

Now, I am trying to call this url through python requests/pycurl module. But, everytime it returns the 401 error irrespective of valid username/password.

using requests:

import requests, base64
usrPass = "admin:secret"
b64Val = base64.b64encode(usrPass)
from requests.auth import HTTPBasicAuth
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
res = requests.get('https://<abc.com>/student/1', auth=HTTPBasicAuth('admin','secret'), headers={'Authorization': 'Basic %s' % b64Val}, data={}, verify=False)
print res

using curl:

myCurlPut = pycurl.Curl()
myCurlPut.setopt(pycurl.URL, "https://<abc.com>/student/1")
myCurlPut.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC)
myCurlPut.setopt(pycurl.USERPWD, "%s:%s" % ('admin', 'secret'))
myCurlPut.setopt(pycurl.SSL_VERIFYPEER, 0)
myCurlPut.setopt(pycurl.HTTPHEADER, ['X-HTTP-Method-Override: GET'])
myCurlPut.perform()

Can, anyone please help me why everytime it returns the 401 error. Please suggest.

2
  • Did you try to put some debug output into @requires_auth@? What is the value of request.authorization when you make the request? Commented Jun 22, 2016 at 6:45
  • value for request.authorization is coming as None Commented Jun 22, 2016 at 6:55

2 Answers 2

1

This is a working example of flask-authorization.

from functools import wraps

from flask import Flask,Response,request, abort


app = Flask(__name__)

def check_auth(name,passw):
    return (name=='admin' and passw=='pass')

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            abort(401)
        return f(*args, **kwargs)
    return decorated


@app.route('/')
@requires_auth
def hello():
    return "Hello World"


if __name__ == "__main__":
    app.run(debug=True)

My requests file:

import requests, base64
usrPass = "admin:pass"
b64Val = base64.b64encode(usrPass)
from requests.auth import HTTPBasicAuth
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
res = requests.get('http://127.0.0.1:5000/', auth=HTTPBasicAuth('admin','pass'), headers={'Authorization': 'Basic %s' % b64Val}, data={}, verify=False)
print res

If you are running this on localhost you should use the localhost address.
What is <abc.com> in your code.Probably that is the error.

EDIT 2

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired


def gen_token(name,passw, expiration=None):
    s = Serializer(app.config['SECRET_KEY'], expires_in = expiration)
    return s.dumps(name, passw)

def verify_token(token):
    serial = Serializer(app.config['SECRET_KEY'])
    try:
        data = serial.loads(token)
    except BadSignature:
        return "Error"
    except SignatureExpired:
        return "Error"

    name = data[0]
    passw = data[1]

    return name,passw

These are couple of methods that will help you get started with the token based auth.

What I did was

  1. User requests token from the server by sending a request with username and password in Auth headers
  2. After you check that the username and password is correct you can generate the token using gen_token method. You can modify this method according to your requirments. Read Here
  3. Now the user sends the token it recieved from method 2 in the Auth header in the place of username. password can be left blank or send None in that place.
  4. When you recieve the token you need to load it using the SECRET_KEY.Exceptions can be handled as per your requirements. If the token is valid you will be able to obtain the user who sent the request and thus carry your procedure.

Hope it helps!

Check out this link for a more detailed explanation.

Sign up to request clarification or add additional context in comments.

5 Comments

Looks like some issue with my server. When I am trying to execute the above piece of cod eon my localhost.. its working fine. But, when I am executing same code my server, request.authorization is coming as none.
Where have you deployed your script ? Your script is fine and I have one of my app deployed on heroku which uses token based auth and works just fine.
Is it possible for you to help me out to develop token based auth. I have just started working on python.. still getting familiar with authentication in python.
Thanks @siddhant. I am able to do the authentication using the SECRET_KEY. I have one doubt regarding this, suppose I have given the expiration time for 600 seconds, in that case that token will work for 10 minutes. Now, to make authentication more secure, I wanted to check that that token generated from same system or not. I mean to verify that user's machine , to avoid any security loop holes (if token got hacked, then anyone can access that data until its expiration). How we can verify this scenario.
I don't know much about this but you may use User-Agent header. but it can be faked.
0

Looks like you are not passing username and password correctly to authenticate. Value of username and password you should get from the auth variable. So try changing the requires_auth funtion as:

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

1 Comment

Thanks for your comment. I tried with your suggested changes, but it didn't help. I think issue is with the auth = request.authorization. It coming as None.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.