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: try:
user = User.objects.get(username=username) user = User.objects.get(username=username)
except User.DoesNotExist: except User.DoesNotExist:
raise authenticate.AuthenticationFailed('No such user') raise exceptions.AuthenticationFailed('No such user')
return (user, None) return (user, None)

View File

@ -4,4 +4,4 @@ defusedxml>=0.3
django-filter>=0.5.4 django-filter>=0.5.4
django-oauth-plus>=2.0 django-oauth-plus>=2.0
oauth2>=1.5.211 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. by the authentication classes provided to the request.
""" """
if not hasattr(self, '_user'): if not hasattr(self, '_user'):
self._authenticator, self._user, self._auth = self._authenticate() self._authenticate()
return self._user return self._user
@user.setter @user.setter
@ -192,7 +192,7 @@ class Request(object):
request, such as an authentication token. request, such as an authentication token.
""" """
if not hasattr(self, '_auth'): if not hasattr(self, '_auth'):
self._authenticator, self._user, self._auth = self._authenticate() self._authenticate()
return self._auth return self._auth
@auth.setter @auth.setter
@ -210,7 +210,7 @@ class Request(object):
to authenticate the request, or `None`. to authenticate the request, or `None`.
""" """
if not hasattr(self, '_authenticator'): if not hasattr(self, '_authenticator'):
self._authenticator, self._user, self._auth = self._authenticate() self._authenticate()
return self._authenticator return self._authenticator
def _load_data_and_files(self): def _load_data_and_files(self):
@ -330,11 +330,18 @@ class Request(object):
Returns a three-tuple of (authenticator, user, authtoken). Returns a three-tuple of (authenticator, user, authtoken).
""" """
for authenticator in self.authenticators: for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self) user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if not user_auth_tuple is None: if not user_auth_tuple is None:
user, auth = user_auth_tuple self._authenticator = authenticator
return (authenticator, user, auth) self._user, self._auth = user_auth_tuple
return self._not_authenticated() return
self._not_authenticated()
def _not_authenticated(self): def _not_authenticated(self):
""" """
@ -343,17 +350,17 @@ class Request(object):
By default this will be (None, AnonymousUser, None). By default this will be (None, AnonymousUser, None).
""" """
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER: if api_settings.UNAUTHENTICATED_USER:
user = api_settings.UNAUTHENTICATED_USER() self._user = api_settings.UNAUTHENTICATED_USER()
else: else:
user = None self._user = None
if api_settings.UNAUTHENTICATED_TOKEN: if api_settings.UNAUTHENTICATED_TOKEN:
auth = api_settings.UNAUTHENTICATED_TOKEN() self._auth = api_settings.UNAUTHENTICATED_TOKEN()
else: else:
auth = None self._auth = None
return (None, user, auth)
def __getattr__(self, attr): 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 HTTP_HEADER_ENCODING
from rest_framework import exceptions from rest_framework import exceptions
from rest_framework import permissions from rest_framework import permissions
from rest_framework import renderers
from rest_framework.response import Response
from rest_framework import status from rest_framework import status
from rest_framework.authentication import ( from rest_framework.authentication import (
BaseAuthentication, BaseAuthentication,
@ -553,3 +555,40 @@ class OAuth2Tests(TestCase):
auth = self._create_authorization_header(token=read_write_access_token.token) auth = self._create_authorization_header(token=read_write_access_token.token)
response = self.csrf_client.post('/oauth2-with-scope-test/', HTTP_AUTHORIZATION=auth) response = self.csrf_client.post('/oauth2-with-scope-test/', HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 200) 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')