mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #35693 -- Made password validators callable.
This commit is contained in:
parent
86661f2449
commit
92f6a713d3
@ -104,6 +104,9 @@ class MinimumLengthValidator:
|
|||||||
def __init__(self, min_length=8):
|
def __init__(self, min_length=8):
|
||||||
self.min_length = min_length
|
self.min_length = min_length
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.validate(*args, kwargs)
|
||||||
|
|
||||||
def validate(self, password, user=None):
|
def validate(self, password, user=None):
|
||||||
if len(password) < self.min_length:
|
if len(password) < self.min_length:
|
||||||
raise ValidationError(self.get_error_message(), code="password_too_short")
|
raise ValidationError(self.get_error_message(), code="password_too_short")
|
||||||
@ -175,6 +178,9 @@ class UserAttributeSimilarityValidator:
|
|||||||
raise ValueError("max_similarity must be at least 0.1")
|
raise ValueError("max_similarity must be at least 0.1")
|
||||||
self.max_similarity = max_similarity
|
self.max_similarity = max_similarity
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.validate(*args, **kwargs)
|
||||||
|
|
||||||
def validate(self, password, user=None):
|
def validate(self, password, user=None):
|
||||||
if not user:
|
if not user:
|
||||||
return
|
return
|
||||||
@ -241,6 +247,9 @@ class CommonPasswordValidator:
|
|||||||
with open(password_list_path) as f:
|
with open(password_list_path) as f:
|
||||||
self.passwords = {x.strip() for x in f}
|
self.passwords = {x.strip() for x in f}
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.validate(*args, **kwargs)
|
||||||
|
|
||||||
def validate(self, password, user=None):
|
def validate(self, password, user=None):
|
||||||
if password.lower().strip() in self.passwords:
|
if password.lower().strip() in self.passwords:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
@ -260,6 +269,9 @@ class NumericPasswordValidator:
|
|||||||
Validate that the password is not entirely numeric.
|
Validate that the password is not entirely numeric.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.validate(*args, **kwargs)
|
||||||
|
|
||||||
def validate(self, password, user=None):
|
def validate(self, password, user=None):
|
||||||
if password.isdigit():
|
if password.isdigit():
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
|
@ -91,6 +91,10 @@ Minor features
|
|||||||
now have a new method ``get_error_message()``, which can be overridden in
|
now have a new method ``get_error_message()``, which can be overridden in
|
||||||
subclasses to customize the error messages.
|
subclasses to customize the error messages.
|
||||||
|
|
||||||
|
* The :ref:`password validator classes <included-password-validators>`
|
||||||
|
now have a new method ``__call__()``, calling the password validator class
|
||||||
|
object will perform ``validate()`` method.
|
||||||
|
|
||||||
:mod:`django.contrib.contenttypes`
|
:mod:`django.contrib.contenttypes`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -158,6 +158,19 @@ class MinimumLengthValidatorTest(SimpleTestCase):
|
|||||||
with self.assertRaisesMessage(ValidationError, expected_error % 3) as cm:
|
with self.assertRaisesMessage(ValidationError, expected_error % 3) as cm:
|
||||||
CustomMinimumLengthValidator(min_length=3).validate("12")
|
CustomMinimumLengthValidator(min_length=3).validate("12")
|
||||||
|
|
||||||
|
def test_callable_validate(self):
|
||||||
|
expected_error = (
|
||||||
|
"This password is too short. It must contain at least %d characters."
|
||||||
|
)
|
||||||
|
|
||||||
|
validator = MinimumLengthValidator()
|
||||||
|
self.assertIsNone(validator("12345678"))
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError) as cm:
|
||||||
|
validator("1234567")
|
||||||
|
self.assertEqual(cm.exception.messages, [expected_error % 8])
|
||||||
|
self.assertEqual(cm.exception.error_list[0].code, "password_too_short")
|
||||||
|
|
||||||
|
|
||||||
class UserAttributeSimilarityValidatorTest(TestCase):
|
class UserAttributeSimilarityValidatorTest(TestCase):
|
||||||
def test_validate(self):
|
def test_validate(self):
|
||||||
@ -263,6 +276,24 @@ class UserAttributeSimilarityValidatorTest(TestCase):
|
|||||||
with self.assertRaisesMessage(ValidationError, expected_error):
|
with self.assertRaisesMessage(ValidationError, expected_error):
|
||||||
CustomUserAttributeSimilarityValidator().validate("testclient", user=user)
|
CustomUserAttributeSimilarityValidator().validate("testclient", user=user)
|
||||||
|
|
||||||
|
def test_callable_validate(self):
|
||||||
|
user = User.objects.create_user(
|
||||||
|
username="testclient",
|
||||||
|
password="password",
|
||||||
|
email="testclient@example.com",
|
||||||
|
first_name="Test",
|
||||||
|
last_name="Client",
|
||||||
|
)
|
||||||
|
expected_error = "The password is too similar to the %s."
|
||||||
|
|
||||||
|
validator = UserAttributeSimilarityValidator()
|
||||||
|
self.assertIsNone(validator("testclient"))
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError) as cm:
|
||||||
|
validator("testclient", user=user)
|
||||||
|
self.assertEqual(cm.exception.messages, [expected_error % "username"])
|
||||||
|
self.assertEqual(cm.exception.error_list[0].code, "password_too_similar")
|
||||||
|
|
||||||
|
|
||||||
class CommonPasswordValidatorTest(SimpleTestCase):
|
class CommonPasswordValidatorTest(SimpleTestCase):
|
||||||
def test_validate(self):
|
def test_validate(self):
|
||||||
@ -307,6 +338,15 @@ class CommonPasswordValidatorTest(SimpleTestCase):
|
|||||||
with self.assertRaisesMessage(ValidationError, expected_error):
|
with self.assertRaisesMessage(ValidationError, expected_error):
|
||||||
CustomCommonPasswordValidator().validate("godzilla")
|
CustomCommonPasswordValidator().validate("godzilla")
|
||||||
|
|
||||||
|
def test_callable_validate(self):
|
||||||
|
expected_error = "This password is too common."
|
||||||
|
validator = CommonPasswordValidator()
|
||||||
|
self.assertIsNone(validator("a-safe-password"))
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError) as cm:
|
||||||
|
validator("godzilla")
|
||||||
|
self.assertEqual(cm.exception.messages, [expected_error])
|
||||||
|
|
||||||
|
|
||||||
class NumericPasswordValidatorTest(SimpleTestCase):
|
class NumericPasswordValidatorTest(SimpleTestCase):
|
||||||
def test_validate(self):
|
def test_validate(self):
|
||||||
@ -334,6 +374,16 @@ class NumericPasswordValidatorTest(SimpleTestCase):
|
|||||||
with self.assertRaisesMessage(ValidationError, expected_error):
|
with self.assertRaisesMessage(ValidationError, expected_error):
|
||||||
CustomNumericPasswordValidator().validate("42424242")
|
CustomNumericPasswordValidator().validate("42424242")
|
||||||
|
|
||||||
|
def test_callable_validate(self):
|
||||||
|
expected_error = "This password is entirely numeric."
|
||||||
|
validator = NumericPasswordValidator()
|
||||||
|
self.assertIsNone(validator("a-safe-password"))
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError) as cm:
|
||||||
|
validator("42424242")
|
||||||
|
self.assertEqual(cm.exception.messages, [expected_error])
|
||||||
|
self.assertEqual(cm.exception.error_list[0].code, "password_entirely_numeric")
|
||||||
|
|
||||||
|
|
||||||
class UsernameValidatorsTests(SimpleTestCase):
|
class UsernameValidatorsTests(SimpleTestCase):
|
||||||
def test_unicode_validator(self):
|
def test_unicode_validator(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user