From 354ae73ffb37494016f377527a52ea51ed4c29f7 Mon Sep 17 00:00:00 2001 From: willbeaufoy Date: Thu, 15 Sep 2022 09:35:48 +0100 Subject: [PATCH] Make `APIClient.force_authenticate()` work with `user=None` (#8212) * Fix testing with token * Add unit test * Split unit test into 3 * Fix linting error --- rest_framework/test.py | 2 +- tests/test_testing.py | 54 +++++++++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/rest_framework/test.py b/rest_framework/test.py index 07df743c8e..04409f9621 100644 --- a/rest_framework/test.py +++ b/rest_framework/test.py @@ -277,7 +277,7 @@ def force_authenticate(self, user=None, token=None): """ self.handler._force_user = user self.handler._force_token = token - if user is None: + if user is None and token is None: self.logout() # Also clear any possible session info if required def request(self, **kwargs): diff --git a/tests/test_testing.py b/tests/test_testing.py index b6579e3690..196319a29e 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -10,6 +10,7 @@ from django.urls import path from rest_framework import fields, serializers +from rest_framework.authtoken.models import Token from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework.test import ( @@ -19,10 +20,12 @@ @api_view(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS']) def view(request): - return Response({ - 'auth': request.META.get('HTTP_AUTHORIZATION', b''), - 'user': request.user.username - }) + data = {'auth': request.META.get('HTTP_AUTHORIZATION', b'')} + if request.user: + data['user'] = request.user.username + if request.auth: + data['token'] = request.auth.key + return Response(data) @api_view(['GET', 'POST']) @@ -78,14 +81,46 @@ def test_credentials(self): response = self.client.get('/view/') assert response.data['auth'] == 'example' - def test_force_authenticate(self): + def test_force_authenticate_with_user(self): """ - Setting `.force_authenticate()` forcibly authenticates each request. + Setting `.force_authenticate()` with a user forcibly authenticates each + request with that user. """ user = User.objects.create_user('example', 'example@example.com') - self.client.force_authenticate(user) + + self.client.force_authenticate(user=user) + response = self.client.get('/view/') + + assert response.data['user'] == 'example' + assert 'token' not in response.data + + def test_force_authenticate_with_token(self): + """ + Setting `.force_authenticate()` with a token forcibly authenticates each + request with that token. + """ + user = User.objects.create_user('example', 'example@example.com') + token = Token.objects.create(key='xyz', user=user) + + self.client.force_authenticate(token=token) response = self.client.get('/view/') + + assert response.data['token'] == 'xyz' + assert 'user' not in response.data + + def test_force_authenticate_with_user_and_token(self): + """ + Setting `.force_authenticate()` with a user and token forcibly + authenticates each request with that user and token. + """ + user = User.objects.create_user('example', 'example@example.com') + token = Token.objects.create(key='xyz', user=user) + + self.client.force_authenticate(user=user, token=token) + response = self.client.get('/view/') + assert response.data['user'] == 'example' + assert response.data['token'] == 'xyz' def test_force_authenticate_with_sessions(self): """ @@ -102,8 +137,9 @@ def test_force_authenticate_with_sessions(self): response = self.client.get('/session-view/') assert response.data['active_session'] is True - # Force authenticating as `None` should also logout the user session. - self.client.force_authenticate(None) + # Force authenticating with `None` user and token should also logout + # the user session. + self.client.force_authenticate(user=None, token=None) response = self.client.get('/session-view/') assert response.data['active_session'] is False