Fixed #28207 -- Fixed contrib.auth.authenticate() if multiple auth backends don't accept a request.
This commit is contained in:
parent
a7975260b5
commit
3008f30f19
|
@ -66,38 +66,8 @@ def authenticate(request=None, **credentials):
|
||||||
If the given credentials are valid, return a User object.
|
If the given credentials are valid, return a User object.
|
||||||
"""
|
"""
|
||||||
for backend, backend_path in _get_backends(return_tuples=True):
|
for backend, backend_path in _get_backends(return_tuples=True):
|
||||||
args = (request,)
|
|
||||||
# Does the backend accept a request argument?
|
|
||||||
try:
|
try:
|
||||||
inspect.getcallargs(backend.authenticate, request, **credentials)
|
user = _authenticate_with_backend(backend, backend_path, request, **credentials)
|
||||||
except TypeError:
|
|
||||||
args = ()
|
|
||||||
# Does the backend accept a request keyword argument?
|
|
||||||
try:
|
|
||||||
inspect.getcallargs(backend.authenticate, request=request, **credentials)
|
|
||||||
except TypeError:
|
|
||||||
# Does the backend accept credentials without request?
|
|
||||||
try:
|
|
||||||
inspect.getcallargs(backend.authenticate, **credentials)
|
|
||||||
except TypeError:
|
|
||||||
# This backend doesn't accept these credentials as arguments. Try the next one.
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
warnings.warn(
|
|
||||||
"Update %s.authenticate() to accept a positional "
|
|
||||||
"`request` argument." % backend_path,
|
|
||||||
RemovedInDjango21Warning
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
credentials['request'] = request
|
|
||||||
warnings.warn(
|
|
||||||
"In %s.authenticate(), move the `request` keyword argument "
|
|
||||||
"to the first positional argument." % backend_path,
|
|
||||||
RemovedInDjango21Warning
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
user = backend.authenticate(*args, **credentials)
|
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
# This backend says to stop in our tracks - this user should not be allowed in at all.
|
# This backend says to stop in our tracks - this user should not be allowed in at all.
|
||||||
break
|
break
|
||||||
|
@ -111,6 +81,39 @@ def authenticate(request=None, **credentials):
|
||||||
user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)
|
user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)
|
||||||
|
|
||||||
|
|
||||||
|
def _authenticate_with_backend(backend, backend_path, request, **credentials):
|
||||||
|
args = (request,)
|
||||||
|
# Does the backend accept a request argument?
|
||||||
|
try:
|
||||||
|
inspect.getcallargs(backend.authenticate, request, **credentials)
|
||||||
|
except TypeError:
|
||||||
|
args = ()
|
||||||
|
# Does the backend accept a request keyword argument?
|
||||||
|
try:
|
||||||
|
inspect.getcallargs(backend.authenticate, request=request, **credentials)
|
||||||
|
except TypeError:
|
||||||
|
# Does the backend accept credentials without request?
|
||||||
|
try:
|
||||||
|
inspect.getcallargs(backend.authenticate, **credentials)
|
||||||
|
except TypeError:
|
||||||
|
# This backend doesn't accept these credentials as arguments. Try the next one.
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
warnings.warn(
|
||||||
|
"Update %s.authenticate() to accept a positional "
|
||||||
|
"`request` argument." % backend_path,
|
||||||
|
RemovedInDjango21Warning
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
credentials['request'] = request
|
||||||
|
warnings.warn(
|
||||||
|
"In %s.authenticate(), move the `request` keyword argument "
|
||||||
|
"to the first positional argument." % backend_path,
|
||||||
|
RemovedInDjango21Warning
|
||||||
|
)
|
||||||
|
return backend.authenticate(*args, **credentials)
|
||||||
|
|
||||||
|
|
||||||
def login(request, user, backend=None):
|
def login(request, user, backend=None):
|
||||||
"""
|
"""
|
||||||
Persist a user id and a backend in the request. This way a user doesn't
|
Persist a user id and a backend in the request. This way a user doesn't
|
||||||
|
|
|
@ -20,3 +20,6 @@ Bugfixes
|
||||||
(:ticket:`28142`).
|
(:ticket:`28142`).
|
||||||
|
|
||||||
* Fixed regression causing pickling of model fields to crash (:ticket:`28188`).
|
* Fixed regression causing pickling of model fields to crash (:ticket:`28188`).
|
||||||
|
|
||||||
|
* Fixed ``django.contrib.auth.authenticate()`` when multiple authentication
|
||||||
|
backends don't accept a positional ``request`` argument (:ticket:`28207`).
|
||||||
|
|
|
@ -50,3 +50,21 @@ class AcceptsRequestBackendTest(SimpleTestCase):
|
||||||
"In %s.authenticate(), move the `request` keyword argument to the "
|
"In %s.authenticate(), move the `request` keyword argument to the "
|
||||||
"first positional argument." % self.request_not_positional_backend
|
"first positional argument." % self.request_not_positional_backend
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@override_settings(AUTHENTICATION_BACKENDS=[request_not_positional_backend, no_request_backend])
|
||||||
|
def test_both_types_of_deprecation_warning(self):
|
||||||
|
with warnings.catch_warnings(record=True) as warns:
|
||||||
|
warnings.simplefilter('always')
|
||||||
|
authenticate(mock_request, username='username', password='pass')
|
||||||
|
|
||||||
|
self.assertEqual(len(warns), 2)
|
||||||
|
self.assertEqual(
|
||||||
|
str(warns[0].message),
|
||||||
|
"In %s.authenticate(), move the `request` keyword argument to the "
|
||||||
|
"first positional argument." % self.request_not_positional_backend
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
str(warns[1].message),
|
||||||
|
"Update %s.authenticate() to accept a positional `request` "
|
||||||
|
"argument." % self.no_request_backend
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue