Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask middleware on abort 401 causing a 500

I have a middleware in my Flask app that is used to authenticate a JSON Web Token coming in the header of the request and is checking to verify it, below is my middleware class:

class AuthMiddleware(object):

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        path = environ.get('PATH_INFO')
        if path != '/authenticate' or path != '/token':
            token = environ.get('HTTP_X_ACCESS_TOKEN')
            verfied_token = verify_token(token)
            if verfied_token is False:
                abort(401)
            elif verfied_token is True:
                # payload = get_token_payload(token)
                # check_permissions(payload)
                pass

        return self.app(environ, start_response) 

verify_token() is a function that will return True or False, and if it returns False, I want it to abort with an error 401. However, it aborts with an error 500:

127.0.0.1 - - [25/Mar/2015 11:37:25] "POST /role HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
File "/ENV/lib/python2.7/site-packages/werkzeug/serving.py", line 180, in run_wsgi
execute(self.server.app)
File "/ENV/lib/python2.7/site-packages/werkzeug/serving.py", line 168, in execute
application_iter = app(environ, start_response)
File "/ENV/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/middleware.py", line 24, in __call__
return self.app(environ, start_response) 
File "/ENV/lib/python2.7/site-packages/werkzeug/exceptions.py", line 605, in __call__
raise self.mapping[code](*args, **kwargs)
BadRequest: 400: Bad Request

In my views, I abort a 401 like it should, but here it seems to be a problem. What should I do?

like image 917
quack_quack Avatar asked Mar 25 '15 19:03

quack_quack


People also ask

How does Python handle 500 internal server error?

Make sure debug mode is off, then try again. Here is a comment directly from the code itself: Default exception handling that kicks in when an exception occurs that is not caught. In debug mode the exception will be re-raised immediately, otherwise it is logged and the handler for a 500 internal server error is used.

What does abort do in Flask?

Flask comes with a handy abort() function that aborts a request with an HTTP error code early. It will also provide a plain black and white error page for you with a basic description, but nothing fancy. Depending on the error code it is less or more likely for the user to actually see such an error.

How do you handle exceptions in Flask?

This can be done by registering error handlers. When Flask catches an exception while handling a request, it is first looked up by code. If no handler is registered for the code, Flask looks up the error by its class hierarchy; the most specific handler is chosen.

How do I change my status code on a Flask?

The make_response() method We can set the status code using the make_response method in two ways: Pass the status code as a constructor parameter. Use the property status_code to set the status code. Here, the value set has to be an integer.


1 Answers

The middleware you've shown runs some other code and then calls the wrapped Flask application. However, abort raises exceptions that Flask handles, but aren't handled by WSGI directly. Since you're not in the Flask application yet, it can't handle the exception.

A much easier way would be to do this check inside the Flask app. Create a before_request handler that does basically the same thing as the middleware, except you can use flask.request rather than needing to parse the path and headers yourself.

from flask import request, abort

@app.before_request
def check_auth_token():
    if request.path in ('/authenticate', '/token'):
        return

    token = request.headers.get('X-ACCESS-TOKEN')

    if not verify_token(token):
        abort(401)

    check_permissions(get_token_payload(token))

If you do want to use WSGI middleware for this, you need to create the response yourself. Conveniently, Werkzeug's exceptions behave like WSGI applications, so it's straightforward to use them.

from werkzeug.exceptions import Unauthorized

# in place of abort(401) in the middleware
return Unauthorized()(environ, start_response)

You can also use abort still by catching the exceptions it raises (which, again, are WSGI applications).

from werkzeug.exceptions import abort, HTTPException
# werkzeug.exceptions.abort is the same as flask.abort

try:
    abort(401)
except HTTPException as e:
    return e(environ, start_response)
like image 195
davidism Avatar answered Oct 29 '22 12:10

davidism