summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/auth/__init__.py26
-rw-r--r--docs/internals/deprecation.txt4
-rw-r--r--docs/releases/1.11.txt3
-rw-r--r--tests/auth_tests/test_auth_backends_deprecation.py24
4 files changed, 47 insertions, 10 deletions
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
index 04a7f7ddcb..426bd6982b 100644
--- a/django/contrib/auth/__init__.py
+++ b/django/contrib/auth/__init__.py
@@ -67,21 +67,35 @@ def authenticate(request=None, **credentials):
"""
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, **credentials)
+ inspect.getcallargs(backend.authenticate, request=request, **credentials)
except TypeError:
- # This backend doesn't accept these credentials as arguments. Try the next one.
- continue
+ # 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:
- args = ()
+ credentials['request'] = request
warnings.warn(
- "Update authentication backend %s to accept a "
- "positional `request` argument." % backend_path,
+ "In %s.authenticate(), move the `request` keyword argument "
+ "to the first positional argument." % backend_path,
RemovedInDjango21Warning
)
+
try:
user = backend.authenticate(*args, **credentials)
except PermissionDenied:
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 42db85127f..f679ad9256 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -38,8 +38,8 @@ details on these changes.
* ``DatabaseIntrospection.get_indexes()`` will be removed.
-* The ``authenticate()`` method of authentication backends will require a
- ``request`` argument.
+* The ``authenticate()`` method of authentication backends will require
+ ``request`` as the first positional argument.
* The ``django.db.models.permalink()`` decorator will be removed.
diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt
index 3fb4968e23..eb983de0dc 100644
--- a/docs/releases/1.11.txt
+++ b/docs/releases/1.11.txt
@@ -796,7 +796,8 @@ Miscellaneous
* :func:`~django.contrib.auth.authenticate` now passes a ``request`` argument
to the ``authenticate()`` method of authentication backends. Support for
- methods that don't accept ``request`` will be removed in Django 2.1.
+ methods that don't accept ``request`` as the first positional argument will
+ be removed in Django 2.1.
* The ``USE_ETAGS`` setting is deprecated in favor of
:class:`~django.middleware.http.ConditionalGetMiddleware` which now adds the
diff --git a/tests/auth_tests/test_auth_backends_deprecation.py b/tests/auth_tests/test_auth_backends_deprecation.py
index 6178936535..0d45fee7a4 100644
--- a/tests/auth_tests/test_auth_backends_deprecation.py
+++ b/tests/auth_tests/test_auth_backends_deprecation.py
@@ -3,6 +3,8 @@ import warnings
from django.contrib.auth import authenticate
from django.test import SimpleTestCase, override_settings
+mock_request = object()
+
class NoRequestBackend(object):
def authenticate(self, username=None, password=None):
@@ -10,12 +12,20 @@ class NoRequestBackend(object):
pass
+class RequestNotPositionArgBackend:
+ def authenticate(self, username=None, password=None, request=None):
+ assert username == 'username'
+ assert password == 'pass'
+ assert request is mock_request
+
+
class AcceptsRequestBackendTest(SimpleTestCase):
"""
A deprecation warning is shown for backends that have an authenticate()
method without a request parameter.
"""
no_request_backend = '%s.NoRequestBackend' % __name__
+ request_not_positional_backend = '%s.RequestNotPositionArgBackend' % __name__
@override_settings(AUTHENTICATION_BACKENDS=[no_request_backend])
def test_no_request_deprecation_warning(self):
@@ -25,6 +35,18 @@ class AcceptsRequestBackendTest(SimpleTestCase):
self.assertEqual(len(warns), 1)
self.assertEqual(
str(warns[0].message),
- "Update authentication backend %s to accept a positional `request` "
+ "Update %s.authenticate() to accept a positional `request` "
"argument." % self.no_request_backend
)
+
+ @override_settings(AUTHENTICATION_BACKENDS=[request_not_positional_backend])
+ def test_request_keyword_arg_deprecation_warning(self):
+ with warnings.catch_warnings(record=True) as warns:
+ warnings.simplefilter('always')
+ authenticate(username='username', password='pass', request=mock_request)
+ self.assertEqual(len(warns), 1)
+ self.assertEqual(
+ str(warns[0].message),
+ "In %s.authenticate(), move the `request` keyword argument to the "
+ "first positional argument." % self.request_not_positional_backend
+ )