request.user should be still be accessible in renderer context if authentication fails

This commit is contained in:
Tom Christie 2013-06-03 12:32:57 +01:00
parent 11cbf8dca2
commit 6e0567c271
4 changed files with 61 additions and 15 deletions

View File

@ -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)

View File

@ -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

View File

@ -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):
"""

View File

@ -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')