Eduard Gamonal
Eduard Gamonal

Reputation: 8031

django test doesn't populate request.auth

I made an endpoint called /cars. A person can create cars with a frontend, but devices read cars using an SDK, which has an API Key. This way, 2 rent-a-car companies can use the API without getting the cars mixed-up. Each app has its own API Key and its own person managing the contents.

This is being implemented with django restframework 3.x and django-oauth-toolkit.

I'm writing a test for a human retrieving cars, and another for a device.

This is failing:

def test_get_list(self):
    # devices have a django user (AUTH_USER_MODEL ---onetoone--- Device)
    self.client.force_authenticate(user=self.user_device)
    self._get_list()
    self.client.force_authenticate(user=None)

force_authentication sets request.auth to None. However, with postman or httpie, request.auth contains the Application object.

The queryset is:

def get_queryset(self):
    if hasattr(self.request.user, 'device'):
        # get the cars created by the owner of the API Key
        return self.request.auth.application.user.cars.all()
    return self.request.user.cars.all() # get my cars
  1. Does this approach in the queryset make sense?
  2. Am I testing it in the wrong way?
  3. Why is request.auth empty? Is force_authentication using BasicAuthentication?

Upvotes: 0

Views: 888

Answers (2)

Linovia
Linovia

Reputation: 20996

As pointed in the documentation force_authenticate bypass authentication therefore it's your job to simulate the missing authentication part, including filling the request.auth.

Otherwise, you'll need to configure a data set and call either login or credential on the APIClient instance.

Upvotes: 1

DevilPinky
DevilPinky

Reputation: 558

  1. I would recommend going with check_object_permission for this kind of checks. You can read more here.

  2. DRF documentation states that you need to force_authenticate the request if you are using APIRequestFactory. From the documentation:

    from rest_framework.test import force_authenticate
    
    factory = APIRequestFactory()
    user = User.objects.get(username='olivia')
    view = AccountDetail.as_view()
    
    # Make an authenticated request to the view...
    request = factory.get('/accounts/django-superstars/')
    force_authenticate(request, user=user)
    response = view(request)
    

    To authenticate with APIClient try using credentials. Example from the documentation:

    from rest_framework.authtoken.models import Token
    from rest_framework.test import APIClient
    
    # Include an appropriate `Authorization:` header on all requests.
    token = Token.objects.get(user__username='lauren')
    client = APIClient()
    client.credentials(HTTP_AUTHORIZATION='Token ' + token.key)
    
  3. The same is the second question.

Upvotes: 2

Related Questions