From 3df3c5e67070949887e08282a332cc34c1f05184 Mon Sep 17 00:00:00 2001 From: Baptiste Mispelon Date: Mon, 9 Dec 2019 17:50:28 +0100 Subject: [PATCH] Fixed #26480 -- Fixed crash of contrib.auth.authenticate() on decorated authenticate() methods of authentication backends. The Signature API (PEP 362) has better support for decorated functions (by default, it follows the __wrapped__ attribute set by functools.wraps for example). --- django/contrib/auth/__init__.py | 3 ++- tests/auth_tests/test_auth_backends.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py index 6d99aa0c9b..09db690b5c 100644 --- a/django/contrib/auth/__init__.py +++ b/django/contrib/auth/__init__.py @@ -63,8 +63,9 @@ 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): + backend_signature = inspect.signature(backend.authenticate) try: - inspect.getcallargs(backend.authenticate, request, **credentials) + backend_signature.bind(request, **credentials) except TypeError: # This backend doesn't accept these credentials as arguments. Try the next one. continue diff --git a/tests/auth_tests/test_auth_backends.py b/tests/auth_tests/test_auth_backends.py index 92c60af7d6..b6aa1a2833 100644 --- a/tests/auth_tests/test_auth_backends.py +++ b/tests/auth_tests/test_auth_backends.py @@ -13,6 +13,7 @@ from django.http import HttpRequest from django.test import ( SimpleTestCase, TestCase, modify_settings, override_settings, ) +from django.views.decorators.debug import sensitive_variables from .models import ( CustomPermissionsUser, CustomUser, CustomUserWithoutIsActiveField, @@ -642,6 +643,12 @@ class SkippedBackend: pass +class SkippedBackendWithDecoratedMethod: + @sensitive_variables() + def authenticate(self): + pass + + class AuthenticateTests(TestCase): @classmethod def setUpTestData(cls): @@ -664,6 +671,13 @@ class AuthenticateTests(TestCase): """ self.assertEqual(authenticate(username='test', password='test'), self.user1) + @override_settings(AUTHENTICATION_BACKENDS=( + 'auth_tests.test_auth_backends.SkippedBackendWithDecoratedMethod', + 'django.contrib.auth.backends.ModelBackend', + )) + def test_skips_backends_with_decorated_method(self): + self.assertEqual(authenticate(username='test', password='test'), self.user1) + class ImproperlyConfiguredUserModelTest(TestCase): """