ldap: redirect /password/change if it is about to expire (#51268)

Fixes: #51268

License: MIT
This commit is contained in:
Loïc Dachary 2021-02-18 18:12:22 +01:00 committed by Valentin Deniaud
parent 409305831c
commit 2048d0d004
3 changed files with 68 additions and 13 deletions

View File

@ -132,6 +132,10 @@ class LoginPasswordAuthenticator(BaseAuthenticator):
if 'ou' in form.fields:
utils.prepend_remember_cookie(request, response, 'preferred-ous', form.cleaned_data['ou'].pk)
if hasattr(request, 'needs_password_change'):
del request.needs_password_change
return utils.redirect(request, 'password_change', params={'next': response.url}, resolve=True)
return response
else:
username = form.cleaned_data.get('username', '').strip()

View File

@ -585,6 +585,8 @@ class LDAPBackend(object):
message = ' '.join(password_policy_control_messages(c))
if request is not None:
messages.add_message(request, messages.WARNING, message)
if c.graceAuthNsRemaining or c.timeBeforeExpiration:
request.needs_password_change = True
else:
message = str(vars(c))
log.info('ldap: bind error with authz_id "%s" -> "%s"', authz_id, message)

View File

@ -750,14 +750,7 @@ def test_no_connect_with_user_credentials(slapd_strict_acl, db, settings, app):
assert force_bytes('Étienne Michu') in response.body
def test_reset_password_ldap_user(slapd, settings, app, db):
settings.LDAP_AUTH_SETTINGS = [{
'url': [slapd.ldap_url],
'binddn': force_text(slapd.root_bind_dn),
'bindpw': force_text(slapd.root_bind_password),
'basedn': u'o=ôrga',
'use_tls': False,
}]
def reset_password_ldap_user(settings, app):
assert User.objects.count() == 0
# first login
response = app.get('/login/')
@ -769,11 +762,7 @@ def test_reset_password_ldap_user(slapd, settings, app, db):
user = User.objects.get()
assert user.email == EMAIL
# logout
response = response.click('Logout')
if response.status_code == 200: # Django 1.7, same_origin is bugged; testserver != localhost:80
response = response.form.submit().maybe_follow()
else:
response = response.maybe_follow()
response = response.click('Logout').maybe_follow()
response = response.click('Reset it!')
response.form['email'] = EMAIL
assert len(mail.outbox) == 0
@ -789,6 +778,20 @@ def test_reset_password_ldap_user(slapd, settings, app, db):
response.form['new_password1'] = new_password
response.form['new_password2'] = new_password
response = response.form.submit(status=302).maybe_follow()
# logout
response = response.click('Logout').maybe_follow()
return new_password
def test_reset_password_ldap_user(slapd, settings, app, db):
settings.LDAP_AUTH_SETTINGS = [{
'url': [slapd.ldap_url],
'binddn': force_text(slapd.root_bind_dn),
'bindpw': force_text(slapd.root_bind_password),
'basedn': u'o=ôrga',
'use_tls': False,
}]
new_password = reset_password_ldap_user(settings, app)
# verify password has changed
slapd.get_connection().bind_s(DN, new_password)
with pytest.raises(ldap.INVALID_CREDENTIALS):
@ -1138,6 +1141,52 @@ pwdSafeModify: FALSE
assert 'password will expire' in caplog.text
def test_login_ppolicy_pwdExpireWarning(slapd_ppolicy, settings, app, db, caplog):
settings.LDAP_AUTH_SETTINGS = [{
'url': [slapd_ppolicy.ldap_url],
'binddn': force_text(slapd_ppolicy.root_bind_dn),
'bindpw': force_text(slapd_ppolicy.root_bind_password),
'basedn': u'o=ôrga',
'use_tls': False,
}]
pwdMaxAge = 3600
slapd_ppolicy.add_ldif('''
dn: cn=default,ou=ppolicies,o=ôrga
cn: default
objectclass: top
objectclass: device
objectclass: pwdPolicy
objectclass: pwdPolicyChecker
pwdAttribute: userPassword
pwdMinAge: 0
pwdMaxAge: {pwdMaxAge}
pwdInHistory: 1
pwdCheckQuality: 0
pwdMinLength: 0
pwdExpireWarning: {pwdMaxAge}
pwdGraceAuthnLimit: 0
pwdLockout: TRUE
pwdLockoutDuration: 0
pwdMaxFailure: 0
pwdMaxRecordedFailure: 0
pwdFailureCountInterval: 0
pwdMustChange: FALSE
pwdAllowUserChange: TRUE
pwdSafeModify: FALSE
'''.format(pwdMaxAge=pwdMaxAge))
password = reset_password_ldap_user(settings, app)
time.sleep(2)
response = app.get('/login/')
response.form['username'] = USERNAME
response.form['password'] = password
response = response.form.submit('login-password-submit')
assert '/password/change/' in response['Location']
def test_authenticate_ppolicy_pwdAllowUserChange(slapd_ppolicy, settings, db, caplog):
settings.LDAP_AUTH_SETTINGS = [{
'url': [slapd_ppolicy.ldap_url],