0002-ldap-inform-user-when-password-change-has-failed-577.patch
src/authentic2/backends/ldap_backend.py | ||
---|---|---|
58 | 58 |
from authentic2.middleware import StoreRequestMiddleware |
59 | 59 |
from authentic2.models import UserExternalId |
60 | 60 |
from authentic2.user_login_failure import user_login_failure, user_login_success |
61 |
from authentic2.utils.misc import to_list |
|
61 |
from authentic2.utils.misc import PasswordChangeError, to_list
|
|
62 | 62 |
from django_rbac.utils import get_ou_model |
63 | 63 | |
64 | 64 |
# code originaly copied from by now merely inspired by |
... | ... | |
478 | 478 |
self.ldap_backend.modify_password(conn, self.block, self.dn, _current_password, new_password) |
479 | 479 |
except ldap.LDAPError as e: |
480 | 480 |
log.warning('ldap: set_password failed (%s)', type(e).__name__) |
481 |
return
|
|
481 |
raise PasswordChangeError(_('LDAP directory refused the password change.'))
|
|
482 | 482 |
self._current_password = new_password |
483 | 483 |
self.keep_password_in_session(new_password) |
484 | 484 |
if self.block['keep_password']: |
src/authentic2/utils/misc.py | ||
---|---|---|
1310 | 1310 |
path=request.path, |
1311 | 1311 |
httponly=True, |
1312 | 1312 |
) |
1313 | ||
1314 | ||
1315 |
class PasswordChangeError(Exception): |
|
1316 |
def __init__(self, message): |
|
1317 |
self.message = message |
src/authentic2/views.py | ||
---|---|---|
1414 | 1414 |
hooks.call_hooks('event', name='change-password', user=self.request.user, request=self.request) |
1415 | 1415 |
messages.info(self.request, _('Password changed')) |
1416 | 1416 |
models.PasswordReset.objects.filter(user=self.request.user).delete() |
1417 |
response = super().form_valid(form) |
|
1417 |
try: |
|
1418 |
response = super().form_valid(form) |
|
1419 |
except utils_misc.PasswordChangeError as e: |
|
1420 |
messages.error(self.request, e.message) |
|
1421 |
return utils_misc.redirect(self.request, self.post_change_redirect) |
|
1418 | 1422 |
self.request.journal.record('user.password.change', session=self.request.session) |
1419 | 1423 |
return response |
1420 | 1424 |
tests/test_ldap.py | ||
---|---|---|
37 | 37 |
from authentic2.backends import ldap_backend |
38 | 38 |
from authentic2.models import Service |
39 | 39 |
from authentic2.utils import switch_user |
40 |
from authentic2.utils.misc import authenticate |
|
40 |
from authentic2.utils.misc import PasswordChangeError, authenticate
|
|
41 | 41 |
from django_rbac.utils import get_ou_model |
42 | 42 | |
43 | 43 |
from . import utils |
... | ... | |
1056 | 1056 |
assert response['Location'].endswith('/accounts/') |
1057 | 1057 | |
1058 | 1058 | |
1059 |
def test_user_change_password_denied(slapd, settings, app, db): |
|
1060 |
settings.LDAP_AUTH_SETTINGS = [ |
|
1061 |
{ |
|
1062 |
'url': [slapd.ldap_url], |
|
1063 |
'basedn': 'o=ôrga', |
|
1064 |
'use_tls': False, |
|
1065 |
} |
|
1066 |
] |
|
1067 |
assert User.objects.count() == 0 |
|
1068 |
# first login |
|
1069 |
response = app.get('/login/') |
|
1070 |
response.form['username'] = USERNAME |
|
1071 |
response.form['password'] = PASS |
|
1072 |
response = response.form.submit('login-password-submit').follow() |
|
1073 | ||
1074 |
response = app.get('/accounts/password/change/') |
|
1075 |
response.form['old_password'] = PASS |
|
1076 |
response.form['new_password1'] = 'hopAbcde1' |
|
1077 |
response.form['new_password2'] = 'hopAbcde1' |
|
1078 |
with mock.patch( |
|
1079 |
'authentic2.backends.ldap_backend.LDAPBackend.modify_password', side_effect=ldap.UNWILLING_TO_PERFORM |
|
1080 |
): |
|
1081 |
response = response.form.submit().follow() |
|
1082 |
assert 'LDAP directory refused the password change' in response.text |
|
1083 | ||
1084 | ||
1059 | 1085 |
def test_tls(db, tls_slapd, settings, client): |
1060 | 1086 |
conn = tls_slapd.get_connection_admin() |
1061 | 1087 |
conn.modify_s( |
... | ... | |
1266 | 1292 |
with mock.patch( |
1267 | 1293 |
'authentic2.backends.ldap_backend.LDAPBackend.modify_password', side_effect=ldap.UNWILLING_TO_PERFORM |
1268 | 1294 |
): |
1269 |
user.set_password('passé') |
|
1270 |
assert 'set_password failed (UNWILLING_TO_PERFORM)' in caplog.text |
|
1295 |
with pytest.raises(PasswordChangeError): |
|
1296 |
user.set_password('passé') |
|
1297 |
assert 'set_password failed (UNWILLING_TO_PERFORM)' in caplog.text |
|
1271 | 1298 | |
1272 | 1299 | |
1273 | 1300 |
def test_login_ppolicy_pwdMaxFailure(slapd_ppolicy, settings, db, app): |
... | ... | |
1664 | 1691 |
) |
1665 | 1692 | |
1666 | 1693 |
user = authenticate(username=USERNAME, password=UPASS) |
1667 |
assert user.set_password('ogutOmyetew4') is None |
|
1668 |
assert 'STRONG_AUTH_REQUIRED' in caplog.text |
|
1694 |
with pytest.raises(PasswordChangeError): |
|
1695 |
user.set_password('ogutOmyetew4') |
|
1696 |
assert 'STRONG_AUTH_REQUIRED' in caplog.text |
|
1669 | 1697 | |
1670 | 1698 | |
1671 | 1699 |
def test_ou_selector(slapd, settings, app, ou1): |
1672 |
- |