« Back to Index

[Python Tornado Header Authorization Check]

View original Gist on GitHub

Tags: #python #tornado #authorization #access

Python Tornado Header Authorization Check.py

"""
Explanation:
    tornado.web.RequestHandler calls an internal `_execute` method before
    calling any other method such as `get` or `post` etc.
    
    we wrap the internal `_execute` method so that it either returns
    a 403 or 401 exception depending on the situation.
    
    note: you can't raise a tornado.web.HTTPError from outside of the handler,
    otherwise tornado will fail with an unhandled exception. so instead we set
    the status and simply return the function.
    
Tutorial:
    http://kevinsayscode.tumblr.com/post/7362319243/easy-basic-http-authentication-with-tornado
    
See also "Python Tornado Basic Auth Middleware":
    https://gist.github.com/Integralist/911252f81830ff0ed650145c4d52f58e
"""

import tornado.ioloop
import tornado.web


def require_basic_auth(handler_class):
    def wrap_execute(handler_execute):
        def serve_error(handler, status):
            handler._transforms = []  # necessary
            handler.set_status(status)
            handler.finish()

        def _execute(self, transforms, *args, **kwargs):
            expected_header = self.request.headers.get('X-User-Auth')

            if expected_header is None:
                return serve_error(self, 403)

            # beepboop should be pulled from somewhere, not hardcoded!
            if expected_header != 'beepboop':
                return serve_error(self, 401)

            return handler_execute(self, transforms, *args, **kwargs)

        return _execute

    handler_class._execute = wrap_execute(handler_class._execute)

    return handler_class

 
@require_basic_auth
class MainHandler(tornado.web.RequestHandler):
    # use !s inside format syntax to control string conversion
    # https://docs.python.org/3.6/library/string.html#formatstrings
    def get(self, basicauth_user, basicauth_pass):
        msg = 'Hi there, {0!s}!  Your password is {1}.'
        body = msg.format(basicauth_user, basicauth_pass)
        self.write(body)
        
    def post(self, **kwargs):
        basicauth_user = kwargs['basicauth_user']
        basicauth_pass = kwargs['basicauth_pass']
        msg = 'Hi there, {0!s}!  Your password is {1}.'
        body = msg.format(basicauth_user, basicauth_pass)
        self.write(body)
        
def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])
  
if __name__ == "__main__":
    app = make_app()
    app.listen(9000)
    tornado.ioloop.IOLoop.current().start()