diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py index f4b1722757..a3765ae0f1 100644 --- a/django/contrib/auth/backends.py +++ b/django/contrib/auth/backends.py @@ -39,6 +39,8 @@ class ModelBackend(BaseBackend): def authenticate(self, request, username=None, password=None, **kwargs): if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) + if username is None or password is None: + return try: user = UserModel._default_manager.get_by_natural_key(username) except UserModel.DoesNotExist: diff --git a/tests/auth_tests/test_auth_backends.py b/tests/auth_tests/test_auth_backends.py index 6447edefc9..92c60af7d6 100644 --- a/tests/auth_tests/test_auth_backends.py +++ b/tests/auth_tests/test_auth_backends.py @@ -226,6 +226,19 @@ class BaseModelBackendTest: authenticate(username='no_such_user', password='test') self.assertEqual(CountingMD5PasswordHasher.calls, 1) + @override_settings(PASSWORD_HASHERS=['auth_tests.test_auth_backends.CountingMD5PasswordHasher']) + def test_authentication_without_credentials(self): + CountingMD5PasswordHasher.calls = 0 + for credentials in ( + {}, + {'username': getattr(self.user, self.UserModel.USERNAME_FIELD)}, + {'password': 'test'}, + ): + with self.subTest(credentials=credentials): + with self.assertNumQueries(0): + authenticate(**credentials) + self.assertEqual(CountingMD5PasswordHasher.calls, 0) + class ModelBackendTest(BaseModelBackendTest, TestCase): """