Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the proper way to test token-based auth using APIRequestFactory?

Tags:

The query to my endpoint works fine (as long as I pass it a valid token), it returns the json representation of my response data.

The code in the service api that calls my endpoint, passing an auth token in the header:

headers = {'content-type': 'application/json',            'Authorization': 'Token {}'.format(myToken)} url = 'http://localhost:8000/my_endpoint/' r = session.get(url=url, params=params, headers=headers) 

In views.py, I have a method decorator that wraps the dispatch method on the view (viewsets.ReadOnlyModelViewSet):

def login_required(f):     def check_login_and_call(request, *args, **kwargs):         authentication = request.META.get('HTTP_AUTHORIZATION', b'')         if isinstance(authentication, str):             authentication = authentication.encode(HTTP_HEADER_ENCODING)         key = authentication.split()         if not key or len(key) != 2:             raise PermissionDenied('Authentication failed.')         user, token = authenticate_credentials(key[1])         return f(request, *args, **kwargs)     return check_login_and_call 

I'm trying to write a test to authenticate the request using a token:

from rest_framework.authtoken.models import Token from rest_framework.test import APIRequestFactory from rest_framework.test import APITestCase from rest_framework.test import force_authenticate  class EndpointViewTest(APITestCase):     def setUp(self):         self.factory = APIRequestFactory()         self.user = User.objects.create_user(             username='[email protected]', email='[email protected]', password='top_secret')         self.token = Token.objects.create(user=self.user)         self.token.save()      def test_token_auth(self):         request = self.factory.get('/my_endpoint')         force_authenticate(request, token=self.token.key)         view = views.EndpointViewSet.as_view({'get': 'list'})         response = view(request)         self.assertEqual(response.status_code, 200)         json_response = json.loads(response.render().content)['results'] 

For some reason, I cannot get the request to properly pass the token for this test. Using force_authenticate doesn't seem to change the header that I'm using for validating the token. The current output is raising "PermissionDenied: Authentication failed." because the token isn't being set on the request.

Is there a proper way to set this in the request header in my test or to refactor the way I'm using it in the first place?

like image 960
punkrockpolly Avatar asked Aug 27 '14 18:08

punkrockpolly


People also ask

How do I use token based authentication?

Token-based authentication works through this five-step process: Request: The user logs in to a service using their login credentials, which issues an access request to a server or protected resource. Verification: The server verifies the login information to determine that the user should have access.

Which statement is applicable for CSRF validation in REST framework?

As usual CSRF validation will only apply to any session authenticated views. This means CSRF validation will only occur if the client has been logged in by calling login() .

What is APIRequestFactory?

APIRequestFactory : This is similar to Django's RequestFactory . It allows you to create requests with any http method, which you can then pass on to any view method and compare responses. APIClient : similar to Django's Client . You can GET or POST a URL, and test responses.


1 Answers

I found a way to get the test to pass, but please post if you have a better idea of how to handle any of this.

request = self.factory.get('/my_endpoint', HTTP_AUTHORIZATION='Token {}'.format(self.token)) force_authenticate(request, user=self.user) 

After changing the above two lines of the test, it seems to authenticate based on the token properly.

like image 64
punkrockpolly Avatar answered Sep 30 '22 19:09

punkrockpolly