-
Notifications
You must be signed in to change notification settings - Fork 344
Description
Summary
When using Self-Service Password with the Password Modify extended operation, if OpenLDAP’s password policy rejects the change (e.g., password is in history), the web UI still displays “Password changed” even though the server returned an error. Looking at slapd
logs shows the EXOP fails with err=19
, then SSP performs a subsequent MOD
that succeeds; the UI takes that as overall success.
Environment
-
Self-Service Password 1.7.x (Debian package)
-
Debian 13
-
OpenLDAP with ppolicy overlay and ppolicy-check-password (ppm)
-
TLS/StartTLS
-
Relevant SSP config:
$who_change_password = "user"; $ldap_use_exop_passwd = true; $ldap_use_ppolicy_control= true; $show_extended_error = true; $hash = "clear";
Steps to Reproduce
-
Configure OpenLDAP ppolicy to enforce password history (e.g.,
pwdInHistory > 0
). -
In SSP, try to change a user’s password to a previously used value.
-
Observe:
slapd
logs show Password Modify EXOP rejected by ppolicy (err=19
“Password is in history of old passwords”).- Immediately after, SSP issues a
MOD
on the same DN that returns success. - The SSP UI displays “Your password has been changed.”
Observed Behavior
- UI shows success even though the EXOP failed due to ppolicy.
Example slapd
excerpt:
PASSMOD id="cn=prueba,ou=users,dc=..." old new
... ppm/ppolicy evaluation ...
RESULT err=19 text=Password is in history of old passwords
MOD dn="cn=prueba,ou=users,dc=..."
RESULT tag=103 err=0
Expected Behavior
- If the Password Modify EXOP fails (non-zero LDAP error or ppolicy control indicates failure), SSP should not perform follow-up modifications and the UI should show an error explaining why the change was rejected.
Likely Cause
In lib/functions.inc.php
, function change_password(...)
:
-
In the
$use_exop_passwd
branch, SSP calls:list($error_code, $error_msg, $ppolicy_error_code) = $ldapInstance->change_password_with_exop(...); if ($error_code == 0) { list($error_code, $error_msg) = $ldapInstance->modify_attributes($dn, $userdata); }
-
In some cases the wrapper returns
$error_code == 0
while signaling failure through$ppolicy_error_code
(history, complexity, etc.). SSP then proceeds tomodify_attributes()
and later reports success.
Proposed Fix
Immediately after change_password_with_exop(...)
, if ppolicy_error_code
indicates failure, skip any modify_attributes()
and return an error (optionally force a non-zero LDAP error code like 19). Minimal patch:
--- a/lib/functions.inc.php
+++ b/lib/functions.inc.php
@@ -... +...
} elseif ($use_exop_passwd) {
- list($error_code, $error_msg, $ppolicy_error_code) =
- $ldapInstance->change_password_with_exop($dn, $oldpassword, $password, $use_ppolicy_control);
- if( $error_code == 0 )
- {
- list($error_code, $error_msg) = $ldapInstance->modify_attributes($dn, $userdata);
- }
+ list($error_code, $error_msg, $ppolicy_error_code) =
+ $ldapInstance->change_password_with_exop($dn, $oldpassword, $password, $use_ppolicy_control);
+
+ // Stop if ppolicy reports an error (e.g., history/quality). Do not proceed to modify_attributes().
+ if ($ppolicy_error_code !== false && $ppolicy_error_code > 4) {
+ if ($error_code === 0) {
+ $error_code = 19; // constraintViolation, so the caller/UI reports failure
+ }
+ } elseif ($error_code == 0) {
+ // Only update auxiliary attributes if EXOP truly succeeded and no ppolicy error was signaled
+ list($error_code, $error_msg) = $ldapInstance->modify_attributes($dn, $userdata);
+ }
}
This prevents false “success” messages and aligns UI behavior with LDAP’s EXOP/ppolicy result. I’m happy to open a PR with this change (or adjust it to match your error-handling conventions).