Skip to content

Commit 01f5ef5

Browse files
author
Ryan P Kilby
committed
Re-raise/wrap auth attribute errors
1 parent 22ec160 commit 01f5ef5

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

rest_framework/request.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from __future__ import unicode_literals
1212

1313
import sys
14+
from contextlib import contextmanager
1415

1516
from django.conf import settings
1617
from django.http import QueryDict
@@ -61,6 +62,24 @@ def __exit__(self, *args, **kwarg):
6162
self.view.action = self.action
6263

6364

65+
class WrappedAttributeError(Exception):
66+
pass
67+
68+
69+
@contextmanager
70+
def wrap_attributeerrors():
71+
"""
72+
Used to re-raise AttributeErrors caught during authentication, preventing
73+
these errors from otherwise being handled by the attribute access protocol.
74+
"""
75+
try:
76+
yield
77+
except AttributeError:
78+
info = sys.exc_info()
79+
exc = WrappedAttributeError(str(info[1]))
80+
six.reraise(type(exc), exc, info[2])
81+
82+
6483
class Empty(object):
6584
"""
6685
Placeholder for unset attributes.
@@ -193,7 +212,8 @@ def user(self):
193212
by the authentication classes provided to the request.
194213
"""
195214
if not hasattr(self, '_user'):
196-
self._authenticate()
215+
with wrap_attributeerrors():
216+
self._authenticate()
197217
return self._user
198218

199219
@user.setter
@@ -216,7 +236,8 @@ def auth(self):
216236
request, such as an authentication token.
217237
"""
218238
if not hasattr(self, '_auth'):
219-
self._authenticate()
239+
with wrap_attributeerrors():
240+
self._authenticate()
220241
return self._auth
221242

222243
@auth.setter
@@ -235,7 +256,8 @@ def successful_authenticator(self):
235256
to authenticate the request, or `None`.
236257
"""
237258
if not hasattr(self, '_authenticator'):
238-
self._authenticate()
259+
with wrap_attributeerrors():
260+
self._authenticate()
239261
return self._authenticator
240262

241263
def _load_data_and_files(self):
@@ -317,7 +339,7 @@ def _parse(self):
317339

318340
try:
319341
parsed = parser.parse(stream, media_type, self.parser_context)
320-
except:
342+
except Exception:
321343
# If we get an exception during parsing, fill in empty data and
322344
# re-raise. Ensures we don't simply repeat the error when
323345
# attempting to render the browsable renderer response, or when

tests/test_request.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from rest_framework import status
2020
from rest_framework.authentication import SessionAuthentication
2121
from rest_framework.parsers import BaseParser, FormParser, MultiPartParser
22-
from rest_framework.request import Request
22+
from rest_framework.request import Request, WrappedAttributeError
2323
from rest_framework.response import Response
2424
from rest_framework.test import APIClient, APIRequestFactory
2525
from rest_framework.views import APIView
@@ -227,10 +227,10 @@ def authenticate(self, request):
227227

228228
# The DRF request object does not have a user and should run authenticators
229229
expected = r"no attribute 'MISSPELLED_NAME_THAT_DOESNT_EXIST'"
230-
with pytest.raises(AttributeError, match=expected):
230+
with pytest.raises(WrappedAttributeError, match=expected):
231231
request.user
232232

233-
with pytest.raises(AttributeError, match=expected):
233+
with pytest.raises(WrappedAttributeError, match=expected):
234234
login(request, self.user)
235235

236236

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy