summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2016-11-10 06:30:38 -0500
committerTim Graham <timograham@gmail.com>2016-11-16 17:40:37 -0500
commit0d9ff873d9f93efbba875efbf582db88bb0e30ce (patch)
treeeefc9f9c29b24b9482d39efb6c0d9d40ee3977cb
parent45e01df37353324c3ca9cca1b330bc2841468f82 (diff)
Fixed #27467 -- Made UserAttributeSimilarityValidator max_similarity=0/1 work as documented.
Thanks goblinJoel for the report and feedback.
-rw-r--r--django/contrib/auth/password_validation.py2
-rw-r--r--docs/topics/auth/passwords.txt9
-rw-r--r--tests/auth_tests/test_validators.py17
3 files changed, 21 insertions, 7 deletions
diff --git a/django/contrib/auth/password_validation.py b/django/contrib/auth/password_validation.py
index 12cf29cb9b..4ff2c409ec 100644
--- a/django/contrib/auth/password_validation.py
+++ b/django/contrib/auth/password_validation.py
@@ -147,7 +147,7 @@ class UserAttributeSimilarityValidator(object):
continue
value_parts = re.split(r'\W+', value) + [value]
for value_part in value_parts:
- if SequenceMatcher(a=password.lower(), b=value_part.lower()).quick_ratio() > self.max_similarity:
+ if SequenceMatcher(a=password.lower(), b=value_part.lower()).quick_ratio() >= self.max_similarity:
try:
verbose_name = force_text(user._meta.get_field(attribute_name).verbose_name)
except FieldDoesNotExist:
diff --git a/docs/topics/auth/passwords.txt b/docs/topics/auth/passwords.txt
index da2bc57df8..7015e65404 100644
--- a/docs/topics/auth/passwords.txt
+++ b/docs/topics/auth/passwords.txt
@@ -545,11 +545,10 @@ Django includes four validators:
is used: ``'username', 'first_name', 'last_name', 'email'``.
Attributes that don't exist are ignored.
- The maximum similarity the password can have, before it is rejected, can
- be set with the ``max_similarity`` parameter, on a scale of 0 to 1.
- A setting of 0 will cause all passwords to be rejected, whereas a setting
- of 1 will cause it to only reject passwords that are identical to an
- attribute's value.
+ The minimum similarity of a rejected password can be set on a scale of 0 to
+ 1 with the ``max_similarity`` parameter. A setting of 0 rejects all
+ passwords, whereas a setting of 1 rejects only passwords that are identical
+ to an attribute's value.
.. class:: CommonPasswordValidator(password_list_path=DEFAULT_PASSWORD_LIST_PATH)
diff --git a/tests/auth_tests/test_validators.py b/tests/auth_tests/test_validators.py
index 97cf396b1a..e074716f46 100644
--- a/tests/auth_tests/test_validators.py
+++ b/tests/auth_tests/test_validators.py
@@ -124,7 +124,22 @@ class UserAttributeSimilarityValidatorTest(TestCase):
max_similarity=0.3,
).validate('testclient', user=user)
self.assertEqual(cm.exception.messages, [expected_error % "first name"])
-
+ # max_similarity=1 doesn't allow passwords that are identical to the
+ # attribute's value.
+ with self.assertRaises(ValidationError) as cm:
+ UserAttributeSimilarityValidator(
+ user_attributes=['first_name'],
+ max_similarity=1,
+ ).validate(user.first_name, user=user)
+ self.assertEqual(cm.exception.messages, [expected_error % "first name"])
+ # max_similarity=0 rejects all passwords.
+ with self.assertRaises(ValidationError) as cm:
+ UserAttributeSimilarityValidator(
+ user_attributes=['first_name'],
+ max_similarity=0,
+ ).validate('XXX', user=user)
+ self.assertEqual(cm.exception.messages, [expected_error % "first name"])
+ # Passes validation.
self.assertIsNone(
UserAttributeSimilarityValidator(user_attributes=['first_name']).validate('testclient', user=user)
)