Search code examples
eve

how to access lookup dictionary from check_auth


I have users resource in my app and have implemented a BasicAuth scheme.

Here are my security requirements -

  • Anybody can create a new user via POST /users endpoint
  • Only the superuser can call the GET /users endpoint
  • Any authenticated user can call the GET /users/{{email}} endpoint to get their own profile. If they call it with somebody else's email, then a 404 is returned.

The simplest way to implement these requirements would be to have access to the lookup dictionary in the check_auth method, then I could compare the authenticated user with the email param. But I could not find any way to do this. Instead I came up with the following hacky solution using event hooks.

class UserAuth(BasicAuth):
    def check_auth(self, username, password, allowed_roles, resource, method):
        try:
            user = db.session.query(User).filter(User.email == username).one()
            return user.authenticate(password)
        except Exception as e:
            # TODO: Log this exception
            print('Error - {}'.format(e))
            return False


def authz(req, lookup):
    authn_user = db.session.query(User).filter(User.email == req.authorization['username']).one()
    if 'email' in lookup and lookup['email'] == req.authorization['username']:
        print('User requesting their own profile')
        return
    elif authn_user.is_superuser:
        print('Superuser requesting something')
        return
    else:
        print('Not authorized. Sabotaging request.')
        lookup['email'] = 'None'


app.on_pre_GET_users += authz

Snippet from my settings.py file -

DOMAIN['users']['public_methods'] = ['POST']
DOMAIN['users']['additional_lookup'] = {'url': 'regex("[\w]+@[\w]+\.[\w]+")', 'field': 'email'}

Is there a better way to design this?


Solution

  • One simple option is to use the request object from Flask:

    from flask import request
    
    class UserAuth(BasicAuth):
        def check_auth(self, username, password, allowed_roles, resource, method):
            # you can inspect the request object here
            print request.args, request.url, request.headers
            return True