Fixed #20760 -- Reduced timing variation in ModelBackend.
Thanks jpaglier and erikr.
This commit is contained in:
parent
e716518ad2
commit
5dbca13f3b
|
@ -17,7 +17,9 @@ class ModelBackend(object):
|
|||
if user.check_password(password):
|
||||
return user
|
||||
except UserModel.DoesNotExist:
|
||||
return None
|
||||
# Run the default password hasher once to reduce the timing
|
||||
# difference between an existing and a non-existing user (#20760).
|
||||
UserModel().set_password(password)
|
||||
|
||||
def get_group_permissions(self, user_obj, obj=None):
|
||||
"""
|
||||
|
|
|
@ -12,6 +12,17 @@ from django.contrib.auth import authenticate, get_user
|
|||
from django.http import HttpRequest
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.contrib.auth.hashers import MD5PasswordHasher
|
||||
|
||||
|
||||
class CountingMD5PasswordHasher(MD5PasswordHasher):
|
||||
"""Hasher that counts how many times it computes a hash."""
|
||||
|
||||
calls = 0
|
||||
|
||||
def encode(self, *args, **kwargs):
|
||||
type(self).calls += 1
|
||||
return super(CountingMD5PasswordHasher, self).encode(*args, **kwargs)
|
||||
|
||||
|
||||
class BaseModelBackendTest(object):
|
||||
|
@ -107,10 +118,22 @@ class BaseModelBackendTest(object):
|
|||
self.assertEqual(user.get_all_permissions(), set(['auth.test']))
|
||||
|
||||
def test_get_all_superuser_permissions(self):
|
||||
"A superuser has all permissions. Refs #14795"
|
||||
"""A superuser has all permissions. Refs #14795."""
|
||||
user = self.UserModel._default_manager.get(pk=self.superuser.pk)
|
||||
self.assertEqual(len(user.get_all_permissions()), len(Permission.objects.all()))
|
||||
|
||||
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.tests.test_auth_backends.CountingMD5PasswordHasher',))
|
||||
def test_authentication_timing(self):
|
||||
"""Hasher is run once regardless of whether the user exists. Refs #20760."""
|
||||
CountingMD5PasswordHasher.calls = 0
|
||||
username = getattr(self.user, self.UserModel.USERNAME_FIELD)
|
||||
authenticate(username=username, password='test')
|
||||
self.assertEqual(CountingMD5PasswordHasher.calls, 1)
|
||||
|
||||
CountingMD5PasswordHasher.calls = 0
|
||||
authenticate(username='no_such_user', password='test')
|
||||
self.assertEqual(CountingMD5PasswordHasher.calls, 1)
|
||||
|
||||
|
||||
@skipIfCustomUser
|
||||
class ModelBackendTest(BaseModelBackendTest, TestCase):
|
||||
|
|
Loading…
Reference in New Issue