Ray Toal
Ray Toal

Reputation: 88378

Testing authenticated endpoints in Flask

I have a Flask application using LDAP for authentication, with several endpoints managed with flask-restful, but I want to unit test authenticated endpoints without actually hitting the LDAP server. I was hoping to do this by faking flask-login's current_user but I have not been able to get this trick to work. Here is what I've tried:

Endpoints are authenticated because I derive all resources from my own class (this works fine in practice and manual testing, and is what flask-restful recommends):

def authenticate(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        if not getattr(func, 'authenticated', True):
            return func(*args, **kwargs)
        if flask.ext.login.current_user and flask.ext.login.current_user.is_authenticated():
            return func(*args, **kwargs)
        flask.ext.restful.abort(401)
    return wrapper

class AuthenticatedResource(flask.ext.restful.Resource ):
    method_decorators = [authenticate]

Here is a simple endpoint:

class RootResource(AuthenticatedResource):
    def get(self):
        return {'message':'Hello'}

Now in my unit test, I figured I should be able to mock an authenticated user by writing to flask-login's current_user:

from flask.ext.login import UserMixin, current_user

class AuthenticatedUser(UserMixin):
    def is_authenticated(self):
        return True
    def is_active(self):
        return True
    def is_anonymous(self):
        return False
    def get_id(self):
        return "Test User"

class TestMyAPI(unittest.TestCase):
    def test_root_endpoint_responds_properly(self):
        with app.test_client() as client:
            current_user = AuthenticatedUser()
            response = client.get('/')
            self.assertEqual(response.status_code, 200)
            body = json.loads(response.data)
            self.assertEqual(body, {'message':'Hello'})

Unfortunately the test responds with a failure:

==================================================================
FAIL: test_root_endpoint_responds_properly (test_my_api.TestMyAPI)
------------------------------------------------------------------
Traceback (most recent call last):
  File "xxxx/test_graph_api.py", line xxx, in test_root_endpoint_responds_properly
    self.assertEqual(response.status_code, 200)
AssertionError: 401 != 200

Other notes: I am using flask 0.9, not 0.10. I am aware of Miguel Grinberg's answer to a similar problem but I don't actually want to invoke a login; I want to bypass the use of LDAP (or any test database) completely.

Why does the current_user override trick not work? Is there some other approach I should be using?

Upvotes: 0

Views: 1137

Answers (1)

Ray Toal
Ray Toal

Reputation: 88378

The reason why the code in the question does not work is that the line

current_user = AuthenticatedUser()

creates a new local variable called current_user. This is not the same as flask.ext.login.current_user.

That line should be changed to:

flask.ext.login.current_user = AuthenticatedUser()

Upvotes: 2

Related Questions