ltb-project / self-service-password

Web interface to change and reset password in an LDAP directory
https://self-service-password.readthedocs.io/en/latest/
GNU General Public License v3.0
1.18k stars 327 forks source link

How to honor password history restriction (Active Directory + password change as manager) #927

Open ianharrier opened 5 months ago

ianharrier commented 5 months ago

I just wanted to put this out there, as I've seen password history mentioned in previous issues, and in case the maintainers have any interset in making this an official feature.


In Self Service Password v1.5 and below, I was able to replace this (https://github.com/ltb-project/self-service-password/blob/1.5/lib/functions.inc.php#L523-L527):

        } else {
            ldap_mod_replace($ldap, $dn, $userdata);
            $error_code = ldap_errno($ldap);
            $error_msg = ldap_error($ldap);
        }

with this:

        } else {
            # LDAP_SERVER_POLICY_HINTS_OID for Windows 2012 and above
            # Enforces password history and minimum age
            $histctrl = array(
                "oid" => "1.2.840.113556.1.4.2239",
                "value" => sprintf("%c%c%c%c%c", 48, 3, 2, 1, 1)
            );
            $sethistctrl = ldap_set_option($ldap, LDAP_OPT_SERVER_CONTROLS, array($histctrl));

            ldap_mod_replace($ldap, $dn, $userdata);
            $error_code = ldap_errno($ldap);
            $error_msg = ldap_error($ldap);
        }

which would allow me to use $who_change_password = "manager"; while still enforcing Active Directory's password history restrictions.


In SSP v1.6, the password change code has been moved into https://github.com/ltb-project/ltb-ldap, so replacing this (https://github.com/ltb-project/ltb-ldap/blob/main/src/Ltb/Ldap.php#L349-L354):

    function modify_attributes($dn, $userdata): array {
        \Ltb\PhpLDAP::ldap_mod_replace($this->ldap, $dn, $userdata);
        $error_code = \Ltb\PhpLDAP::ldap_errno($this->ldap);
        $error_msg = \Ltb\PhpLDAP::ldap_error($this->ldap);
        return array($error_code, $error_msg);
    }

with this:

    function modify_attributes($dn, $userdata): array {
        # LDAP_SERVER_POLICY_HINTS_OID for Windows 2012 and above
        # Enforces password history and minimum age
        $histctrl = array(
            "oid" => "1.2.840.113556.1.4.2239",
            "value" => sprintf("%c%c%c%c%c", 48, 3, 2, 1, 1)
        );
        $sethistctrl = ldap_set_option($this->ldap, LDAP_OPT_SERVER_CONTROLS, array($histctrl));

        \Ltb\PhpLDAP::ldap_mod_replace($this->ldap, $dn, $userdata);
        $error_code = \Ltb\PhpLDAP::ldap_errno($this->ldap);
        $error_msg = \Ltb\PhpLDAP::ldap_error($this->ldap);
        return array($error_code, $error_msg);
    }

now seems to accomplish the same thing.

coudot commented 5 months ago

Interesting page on LDAP controls for Active Directory : https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/3c5e87db-4728-4f29-b164-01dd7d7391ea?redirectedfrom=MSDN

coudot commented 5 months ago

See https://github.com/ltb-project/ltb-ldap/issues/16

coudot commented 2 months ago

See also https://blog.joeware.net/2012/02/10/2425/

bmphbWV0 commented 2 months ago

Hello @coudot,

I recently upgraded from v1.6.1 to v1.7.0 and it seems that the implementation to honor password history in an Active directory context hasn't been added in this version. I have tested to set the same "Old" and "New" password in the main form, and it is blocking since the password is the same. I then tried to update my password, store it as the N -1 password, and then update back my password to set the N -1 password. Our Active Directory policy is to not reuse the last 12 previous password. It should be blocked by the tool, but renew has been possible with my N -1 password.

Do you have any idea of when it will be implemented ? As I can see, scope of this issue is currently 1.7.0, and the following issue is now closed : https://github.com/ltb-project/ltb-common/issues/16.

Thanks by advance :)

Regards.

coudot commented 2 months ago

Hello,

indeed, the current issue is still opened.

It requires an evolution in ltb-common to use this control in AD and an option in SSP to enable this feature.

You can propose PR on these two projects or contact us for professional services so we can work on it in next release.