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

@@ -15,7 +15,9 @@ from openedx.core.djangoapps.user_api.helpers import FormDescription
from openedx.features.enterprise_support.api import enterprise_customer_for_request
from student.forms import get_registration_extension_form
from student.models import UserProfile
from util.password_policy_validators import password_max_length, password_min_length
from util.password_policy_validators import (
password_complexity, password_instructions, password_max_length, password_min_length
)
def get_password_reset_form():
@@ -415,23 +417,21 @@ class RegistrationFormFactory(object):
# meant to hold the user's password.
password_label = _(u"Password")
restrictions = {}
if settings.FEATURES.get('ENFORCE_PASSWORD_POLICY', False):
complexities = getattr(settings, 'PASSWORD_COMPLEXITY', {})
for key, value in complexities.iteritems():
api_key = key.lower().replace(' ', '_')
restrictions[api_key] = value
restrictions.update({
restrictions = {
"min_length": password_min_length(),
"max_length": password_max_length(),
})
}
complexities = password_complexity()
for key, value in complexities.iteritems():
api_key = key.lower().replace(' ', '_')
restrictions[api_key] = value
form_desc.add_field(
"password",
label=password_label,
field_type="password",
instructions=password_instructions(),
restrictions=restrictions,
required=required
)

View File

@@ -1055,6 +1055,7 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
u"type": u"password",
u"required": True,
u"label": u"Password",
u"instructions": u'Your password must contain at least {} characters.'.format(password_min_length()),
u"restrictions": {
'min_length': password_min_length(),
'max_length': password_max_length(),
@@ -1072,6 +1073,7 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
{
u'name': u'password',
u'label': u'Password',
u'instructions': u'Your password must contain at least {} characters.'.format(password_min_length()),
u'restrictions': {
'min_length': password_min_length(),
'max_length': password_max_length(),
@@ -1081,11 +1083,14 @@ class RegistrationViewTest(ThirdPartyAuthTestMixin, UserAPITestCase):
# Now with an enabled password policy
with mock.patch.dict(settings.FEATURES, {'ENFORCE_PASSWORD_POLICY': True}):
msg = u'Your password must contain at least {} characters, including '\
u'3 uppercase letters & 1 symbol.'.format(password_min_length())
self._assert_reg_field(
no_extra_fields_setting,
{
u'name': u'password',
u'label': u'Password',
u'instructions': msg,
u'restrictions': {
'min_length': password_min_length(),
'max_length': password_max_length(),

View File

@@ -172,7 +172,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
)
def test_password_empty_validation_decision(self):
msg = u'Password: Invalid Length (must be {0} characters or more)'.format(password_min_length())
msg = u'Enter a password with at least {0} characters.'.format(password_min_length())
self.assertValidationDecision(
{'password': ''},
{"password": msg}
@@ -180,7 +180,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
def test_password_bad_min_length_validation_decision(self):
password = 'p' * (password_min_length() - 1)
msg = u'Password: Invalid Length (must be {0} characters or more)'.format(password_min_length())
msg = u'Enter a password with at least {0} characters.'.format(password_min_length())
self.assertValidationDecision(
{'password': password},
{"password": msg}
@@ -188,7 +188,7 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
def test_password_bad_max_length_validation_decision(self):
password = 'p' * (password_max_length() + 1)
msg = u'Password: Invalid Length (must be {0} characters or fewer)'.format(password_max_length())
msg = u'Enter a password with at most {0} characters.'.format(password_max_length())
self.assertValidationDecision(
{'password': password},
{"password": msg}
@@ -197,5 +197,5 @@ class RegistrationValidationViewTests(test_utils.ApiTestCase):
def test_password_equals_username_validation_decision(self):
self.assertValidationDecision(
{"username": "somephrase", "password": "somephrase"},
{"username": "", "password": u"Password cannot be the same as the username"}
{"username": "", "password": u"Password cannot be the same as the username."}
)

View File

@@ -57,7 +57,7 @@ class RegistrationValidationView(APIView):
>>> {
>>> "validation_decisions": {
>>> "username": "",
>>> "password": "Password cannot be the same as the username"
>>> "password": "Password cannot be the same as the username."
>>> }
>>> }