diff options
| author | Tamas Szabo <tszabo@ccg.murdoch.edu.au> | 2017-05-15 06:22:58 +0800 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2017-05-15 08:15:18 -0400 |
| commit | d945b7e42a8d45cb13b1bd0420b420cf563482f1 (patch) | |
| tree | 7b171da67e0ddfdad6e7ae8a4d33e416ff9ad4ce | |
| parent | 84f6098aaf8d9cca521f7776134564b7f5ed704a (diff) | |
[1.11.x] Fixed #28207 -- Fixed contrib.auth.authenticate() if multiple auth backends don't accept a request.
Backport of 3008f30f194af386c354416be4c483f0f6b15f33 from master
| -rw-r--r-- | django/contrib/auth/__init__.py | 65 | ||||
| -rw-r--r-- | docs/releases/1.11.2.txt | 3 | ||||
| -rw-r--r-- | tests/auth_tests/test_auth_backends_deprecation.py | 18 |
3 files changed, 55 insertions, 31 deletions
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py index 426bd6982b..94153d243d 100644 --- a/django/contrib/auth/__init__.py +++ b/django/contrib/auth/__init__.py @@ -66,38 +66,8 @@ def authenticate(request=None, **credentials): If the given credentials are valid, return a User object. """ for backend, backend_path in _get_backends(return_tuples=True): - 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. - 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) + user = _authenticate_with_backend(backend, backend_path, request, **credentials) except PermissionDenied: # This backend says to stop in our tracks - this user should not be allowed in at all. break @@ -111,6 +81,39 @@ def authenticate(request=None, **credentials): 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): """ Persist a user id and a backend in the request. This way a user doesn't diff --git a/docs/releases/1.11.2.txt b/docs/releases/1.11.2.txt index 558b3e40c3..6831f60cef 100644 --- a/docs/releases/1.11.2.txt +++ b/docs/releases/1.11.2.txt @@ -20,3 +20,6 @@ Bugfixes (:ticket:`28142`). * 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`). diff --git a/tests/auth_tests/test_auth_backends_deprecation.py b/tests/auth_tests/test_auth_backends_deprecation.py index 0d45fee7a4..7ee53a0bc6 100644 --- a/tests/auth_tests/test_auth_backends_deprecation.py +++ b/tests/auth_tests/test_auth_backends_deprecation.py @@ -50,3 +50,21 @@ class AcceptsRequestBackendTest(SimpleTestCase): "In %s.authenticate(), move the `request` keyword argument to the " "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 + ) |
