Improve password complexity messaging

Send password form instructions that include password complexity and
also send error messages back that include all parts of the
complexity instead of single parts at a time.

And clean up phrasing to be more consistent.
This commit is contained in:
Michael Terry
2018-03-20 09:58:02 -04:00
committed by Michael Terry
parent 795dda47d8
commit a576d682ff
10 changed files with 235 additions and 79 deletions

View File

@@ -1,31 +1,67 @@
"""Tests for util.password_policy_validators module."""
import mock
import unittest
from ddt import data, ddt, unpack
from django.conf import settings
from django.core.exceptions import ValidationError
from django.test.utils import override_settings
from util.password_policy_validators import validate_password_dictionary
from util.password_policy_validators import password_instructions, validate_password, _validate_password_dictionary
@ddt
class PasswordPolicyValidatorsTestCase(unittest.TestCase):
""" Tests for password validator utility functions """
@override_settings(PASSWORD_DICTIONARY_EDIT_DISTANCE_THRESHOLD=2)
@override_settings(PASSWORD_DICTIONARY=['testme'])
@mock.patch.dict(settings.FEATURES, {'ENFORCE_PASSWORD_POLICY': True})
def test_validate_password_dictionary(self):
""" Tests dictionary checks """
# Direct match
with self.assertRaises(ValidationError):
validate_password_dictionary('testme')
_validate_password_dictionary('testme')
# Off by one
with self.assertRaises(ValidationError):
validate_password_dictionary('estme')
_validate_password_dictionary('estme')
# Off by two
with self.assertRaises(ValidationError):
validate_password_dictionary('bestmet')
_validate_password_dictionary('bestmet')
# Off by three (should pass)
validate_password_dictionary('bestem')
_validate_password_dictionary('bestem')
@data(
(u'', 'at least 2 characters & 2 letters & 1 number.'),
(u'a.', 'at least 2 letters & 1 number.'),
(u'a1', 'at least 2 letters.'),
(u'aa1', None),
)
@unpack
@override_settings(PASSWORD_COMPLEXITY={'ALPHABETIC': 2, 'NUMERIC': 1})
@mock.patch.dict(settings.FEATURES, {'ENFORCE_PASSWORD_POLICY': True})
def test_validation_errors(self, password, msg):
""" Tests validate_password error messages """
if msg is None:
validate_password(password)
else:
with self.assertRaises(ValidationError) as cm:
validate_password(password)
self.assertIn(msg, cm.exception.message)
@data(
({}, 'at least 2 characters.'),
({'ALPHABETIC': 2}, 'characters, including 2 letters.'),
({'ALPHABETIC': 2, 'NUMERIC': 1}, 'characters, including 2 letters & 1 number.'),
({'NON ASCII': 2, 'NUMERIC': 1, 'UPPER': 3}, 'including 3 uppercase letters & 1 number & 2 symbols.'),
)
@unpack
@mock.patch.dict(settings.FEATURES, {'ENFORCE_PASSWORD_POLICY': True})
def test_password_instruction(self, config, msg):
""" Tests password_instruction """
with override_settings(PASSWORD_COMPLEXITY=config):
self.assertIn(msg, password_instructions())