aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdocs/api-guide/authentication.md2
-rw-r--r--optionals.txt2
-rw-r--r--rest_framework/request.py33
-rw-r--r--rest_framework/tests/test_authentication.py39
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')