diff options
| author | Tom Christie | 2013-06-03 12:32:57 +0100 |
|---|---|---|
| committer | Tom Christie | 2013-06-03 12:32:57 +0100 |
| commit | 6e0567c271ca2b68b5c53778692066a799fb2df6 (patch) | |
| tree | 2f33dbc6fcc2582e137833b2dc5aae4eec4370c1 | |
| parent | 11cbf8dca2fe54ae9c27040be70157b88ec75541 (diff) | |
| download | django-rest-framework-6e0567c271ca2b68b5c53778692066a799fb2df6.tar.bz2 | |
request.user should be still be accessible in renderer context if authentication fails
| -rwxr-xr-x | docs/api-guide/authentication.md | 2 | ||||
| -rw-r--r-- | optionals.txt | 2 | ||||
| -rw-r--r-- | rest_framework/request.py | 33 | ||||
| -rw-r--r-- | rest_framework/tests/test_authentication.py | 39 |
4 files changed, 61 insertions, 15 deletions
diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index 6888ac4e..09491f02 100755 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -333,7 +333,7 @@ The following example will authenticate any incoming request as the user given b try: user = User.objects.get(username=username) except User.DoesNotExist: - raise authenticate.AuthenticationFailed('No such user') + raise exceptions.AuthenticationFailed('No such user') return (user, None) diff --git a/optionals.txt b/optionals.txt index 1853f74b..4ebfceab 100644 --- a/optionals.txt +++ b/optionals.txt @@ -4,4 +4,4 @@ defusedxml>=0.3 django-filter>=0.5.4 django-oauth-plus>=2.0 oauth2>=1.5.211 -django-oauth2-provider>=0.2.3 +django-oauth2-provider>=0.2.4 diff --git a/rest_framework/request.py b/rest_framework/request.py index a434659c..0d88ebc7 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -173,7 +173,7 @@ class Request(object): by the authentication classes provided to the request. """ if not hasattr(self, '_user'): - self._authenticator, self._user, self._auth = self._authenticate() + self._authenticate() return self._user @user.setter @@ -192,7 +192,7 @@ class Request(object): request, such as an authentication token. """ if not hasattr(self, '_auth'): - self._authenticator, self._user, self._auth = self._authenticate() + self._authenticate() return self._auth @auth.setter @@ -210,7 +210,7 @@ class Request(object): to authenticate the request, or `None`. """ if not hasattr(self, '_authenticator'): - self._authenticator, self._user, self._auth = self._authenticate() + self._authenticate() return self._authenticator def _load_data_and_files(self): @@ -330,11 +330,18 @@ class Request(object): Returns a three-tuple of (authenticator, user, authtoken). """ for authenticator in self.authenticators: - user_auth_tuple = authenticator.authenticate(self) + try: + user_auth_tuple = authenticator.authenticate(self) + except exceptions.APIException: + self._not_authenticated() + raise + if not user_auth_tuple is None: - user, auth = user_auth_tuple - return (authenticator, user, auth) - return self._not_authenticated() + self._authenticator = authenticator + self._user, self._auth = user_auth_tuple + return + + self._not_authenticated() def _not_authenticated(self): """ @@ -343,17 +350,17 @@ class Request(object): By default this will be (None, AnonymousUser, None). """ + self._authenticator = None + if api_settings.UNAUTHENTICATED_USER: - user = api_settings.UNAUTHENTICATED_USER() + self._user = api_settings.UNAUTHENTICATED_USER() else: - user = None + self._user = None if api_settings.UNAUTHENTICATED_TOKEN: - auth = api_settings.UNAUTHENTICATED_TOKEN() + self._auth = api_settings.UNAUTHENTICATED_TOKEN() else: - auth = None - - return (None, user, auth) + self._auth = None def __getattr__(self, attr): """ diff --git a/rest_framework/tests/test_authentication.py b/rest_framework/tests/test_authentication.py index 05e9fbc3..d46ac079 100644 --- a/rest_framework/tests/test_authentication.py +++ b/rest_framework/tests/test_authentication.py @@ -6,6 +6,8 @@ from django.utils import unittest from rest_framework import HTTP_HEADER_ENCODING from rest_framework import exceptions from rest_framework import permissions +from rest_framework import renderers +from rest_framework.response import Response from rest_framework import status from rest_framework.authentication import ( BaseAuthentication, @@ -553,3 +555,40 @@ class OAuth2Tests(TestCase): auth = self._create_authorization_header(token=read_write_access_token.token) response = self.csrf_client.post('/oauth2-with-scope-test/', HTTP_AUTHORIZATION=auth) self.assertEqual(response.status_code, 200) + + +class FailingAuthAccessedInRenderer(TestCase): + def setUp(self): + class AuthAccessingRenderer(renderers.BaseRenderer): + media_type = 'text/plain' + format = 'txt' + + def render(self, data, media_type=None, renderer_context=None): + request = renderer_context['request'] + if request.user.is_authenticated(): + return b'authenticated' + return b'not authenticated' + + class FailingAuth(BaseAuthentication): + def authenticate(self, request): + raise exceptions.AuthenticationFailed('authentication failed') + + class ExampleView(APIView): + authentication_classes = (FailingAuth,) + renderer_classes = (AuthAccessingRenderer,) + + def get(self, request): + return Response({'foo': 'bar'}) + + self.view = ExampleView.as_view() + + def test_failing_auth_accessed_in_renderer(self): + """ + When authentication fails the renderer should still be able to access + `request.user` without raising an exception. Particularly relevant + to HTML responses that might reasonably access `request.user`. + """ + request = factory.get('/') + response = self.view(request) + content = response.render().content + self.assertEqual(content, b'not authenticated') |
