11
11
from __future__ import unicode_literals
12
12
13
13
import sys
14
+ from contextlib import contextmanager
14
15
15
16
from django .conf import settings
16
17
from django .http import QueryDict
@@ -61,6 +62,24 @@ def __exit__(self, *args, **kwarg):
61
62
self .view .action = self .action
62
63
63
64
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
+
64
83
class Empty (object ):
65
84
"""
66
85
Placeholder for unset attributes.
@@ -193,7 +212,8 @@ def user(self):
193
212
by the authentication classes provided to the request.
194
213
"""
195
214
if not hasattr (self , '_user' ):
196
- self ._authenticate ()
215
+ with wrap_attributeerrors ():
216
+ self ._authenticate ()
197
217
return self ._user
198
218
199
219
@user .setter
@@ -216,7 +236,8 @@ def auth(self):
216
236
request, such as an authentication token.
217
237
"""
218
238
if not hasattr (self , '_auth' ):
219
- self ._authenticate ()
239
+ with wrap_attributeerrors ():
240
+ self ._authenticate ()
220
241
return self ._auth
221
242
222
243
@auth .setter
@@ -235,7 +256,8 @@ def successful_authenticator(self):
235
256
to authenticate the request, or `None`.
236
257
"""
237
258
if not hasattr (self , '_authenticator' ):
238
- self ._authenticate ()
259
+ with wrap_attributeerrors ():
260
+ self ._authenticate ()
239
261
return self ._authenticator
240
262
241
263
def _load_data_and_files (self ):
@@ -317,7 +339,7 @@ def _parse(self):
317
339
318
340
try :
319
341
parsed = parser .parse (stream , media_type , self .parser_context )
320
- except :
342
+ except Exception :
321
343
# If we get an exception during parsing, fill in empty data and
322
344
# re-raise. Ensures we don't simply repeat the error when
323
345
# attempting to render the browsable renderer response, or when
@@ -380,11 +402,6 @@ def __getattribute__(self, attr):
380
402
try :
381
403
return super (Request , self ).__getattribute__ (attr )
382
404
except AttributeError :
383
- # Do not proxy attribute access for `user` and `auth`, as this
384
- # potentially hides AttributeError's raised in `_authenticate`.
385
- if attr in ['user' , 'auth' ]:
386
- raise
387
-
388
405
info = sys .exc_info ()
389
406
try :
390
407
return getattr (self ._request , attr )
0 commit comments