Kaydet (Commit) 5e31be1b authored tarafından Tim Graham's avatar Tim Graham

Refs #25187 -- Required the authenticate() method of authentication backends to…

Refs #25187 -- Required the authenticate() method of authentication backends to have request as the first positional argument.

Per deprecation timeline.
üst 578711c3
import inspect
import re
import warnings
from django.apps import apps as django_apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.middleware.csrf import rotate_token
from django.utils.crypto import constant_time_compare
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.module_loading import import_string
from django.utils.translation import LANGUAGE_SESSION_KEY
......@@ -67,7 +65,12 @@ def authenticate(request=None, **credentials):
"""
for backend, backend_path in _get_backends(return_tuples=True):
try:
user = _authenticate_with_backend(backend, backend_path, request, credentials)
inspect.getcallargs(backend.authenticate, request, **credentials)
except TypeError:
# This backend doesn't accept these credentials as arguments. Try the next one.
continue
try:
user = backend.authenticate(request, **credentials)
except PermissionDenied:
# This backend says to stop in our tracks - this user should not be allowed in at all.
break
......@@ -81,40 +84,6 @@ 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 = ()
credentials.pop('request', None)
# 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
......
......@@ -246,3 +246,6 @@ how to remove usage of these features.
tag is removed.
* ``DatabaseIntrospection.get_indexes()`` is removed.
* The ``authenticate()`` method of authentication backends requires ``request``
as the first positional argument.
......@@ -167,11 +167,6 @@ object the first time a user authenticates::
except User.DoesNotExist:
return None
.. versionchanged:: 1.11
The ``request`` parameter was added to ``authenticate()`` and support for
backends that don't accept it will be removed in Django 2.1.
.. _authorization_methods:
Handling authorization in custom backends
......
import warnings
from django.contrib.auth import authenticate
from django.test import SimpleTestCase, override_settings
mock_request = object()
mock_backend = object()
class NoRequestBackend:
def authenticate(self, username=None, password=None):
# Doesn't accept a request parameter.
pass
class RequestNotPositionArgBackend:
def authenticate(self, username=None, password=None, request=None):
assert username == 'username'
assert password == 'pass'
assert request is mock_request
class RequestNotPositionArgWithUsedKwargBackend:
def authenticate(self, username=None, password=None, request=None, backend=None):
assert username == 'username'
assert password == 'pass'
assert request is mock_request
assert backend is mock_backend
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__
request_not_positional_with_used_kwarg_backend = '%s.RequestNotPositionArgWithUsedKwargBackend' % __name__
@override_settings(AUTHENTICATION_BACKENDS=[no_request_backend])
def test_no_request_deprecation_warning(self):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always')
authenticate(username='test', password='test')
self.assertEqual(len(warns), 1)
self.assertEqual(
str(warns[0].message),
"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
)
@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
)
@override_settings(AUTHENTICATION_BACKENDS=[request_not_positional_with_used_kwarg_backend])
def test_handles_backend_in_kwargs(self):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always')
authenticate(username='username', password='pass', request=mock_request, backend=mock_backend)
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_with_used_kwarg_backend
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment