diff options
| -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') | 
