LSldap: add LDAP password policy

This commit is contained in:
Emmanuel Saracco 2022-06-14 16:06:55 +02:00
parent c4e9a33d2d
commit 38d5fd5094
4 changed files with 4640 additions and 4448 deletions

View file

@ -271,6 +271,44 @@ class LSldap extends LSlog_staticLoggerClass {
return false; return false;
} }
/**
* Return a attribute value
*
* It performs a case-insensitive search.
*
* @author Emmanuel Saracco <esaracco@easter-eggs.com>
*
* @param[in] $attrs array Array of LDAP attributes
* @param[in] $name array Name of a attribute
*
* @retval boolean true if found
*/
public static function attrExists($attrs, $name) {
return array_key_exists(strtolower($name), array_change_key_case($attrs));
}
/**
* Return a attribute value
*
* It performs a case-insensitive search.
*
* @author Emmanuel Saracco <esaracco@easter-eggs.com>
*
* @param[in] $attrs array Array of LDAP attributes
* @param[in] $name array Name of a attribute
*
* @retval mixed Found value or null
*/
public static function getAttr($attrs, $name) {
$name = strtolower($name);
foreach ($attrs as $k => $v) {
if (strtolower($k) === $name) {
return $v;
}
}
return null;
}
/** /**
* Return an existing or new LDAP entry * Return an existing or new LDAP entry
* *
@ -423,8 +461,17 @@ class LSldap extends LSlog_staticLoggerClass {
// Set an error flag to false // Set an error flag to false
$error = false; $error = false;
// Handle special case: user password change
if ($changed_attrs && self :: attrExists($changed_attrs, 'userPassword')) {
$changed_attrs = self :: updateUserPassword($object_type, $changed_attrs, $dn);
if ($changed_attrs === false) {
return false;
}
}
// Handle attributes changes (if need) // Handle attributes changes (if need)
if ($changed_attrs) { if ($changed_attrs) {
$entry -> replace($changed_attrs); $entry -> replace($changed_attrs);
if ($entry -> isNew()) { if ($entry -> isNew()) {
self :: log_debug("update($object_type, $dn): add new entry"); self :: log_debug("update($object_type, $dn): add new entry");
@ -607,6 +654,56 @@ class LSldap extends LSlog_staticLoggerClass {
} }
return; return;
} }
/**
* Update userPassword attribute
*
* This method uses LDAP controls when possible (Net_LDAP2 does not).
*
* @param[in] $object_type string The object type
* @param[in] $changed_attrs array Array of changed attributes
* @param[in] $dn string DN of the LDAP object
*
* @author Emmanuel Saracco <esaracco@easter-eggs.com>
*
* @retval mixed New array of changed attributes or false
**/
private static function updateUserPassword($object_type, $changed_attrs, $dn) {
if (self :: getConfig('version') < 3 || !function_exists('ldap_mod_replace_ext')) {
return $changed_attrs;
}
$ppolicyErrorMsg = array(
_('The password expired'),
_('The account is locked'),
_('The password was reset and must be changed'),
_('It is not possible to modify the password'),
_('The old password must be supplied'),
_('The password does not meet the quality requirements'),
_('The password is too short'),
_('It is too soon to change the password'),
_('This password was recently used and cannot be used again'),
);
self :: log_debug("update($object_type, $dn): update entry for userPassword");
$ldap = self :: $cnx->getLink();
$attr = array('userPassword' => self :: getAttr($changed_attrs, 'userPassword'));
$ctrlRequest = array(array('oid' => LDAP_CONTROL_PASSWORDPOLICYREQUEST));
$r = ldap_mod_replace_ext($ldap, $dn, $attr, $ctrlRequest);
if ($r && ldap_parse_result($ldap, $r, $errcode, $matcheddn, $errmsg, $ref, $ctrlResponse)) {
if ($errcode !== 0 && isset($ctrlResponse[LDAP_CONTROL_PASSWORDPOLICYRESPONSE])) {
LSerror :: addErrorCode('LSldap_10', $ppolicyErrorMsg[$ctrlResponse[LDAP_CONTROL_PASSWORDPOLICYRESPONSE]['value']['error']]);
return false;
}
// If everything OK, remove userPassword to prevent it from being processed by Net_LDAP2
unset($changed_attrs['userPassword']);
} else {
if (ldap_errno($ldap) !== 0) {
LSerror :: addErrorCode('LSldap_10', ldap_error($ldap));
} else {
LSerror :: addErrorCode('LSldap_11');
}
return false;
}
return $changed_attrs;
}
/** /**
* Return a configuration parameter (or default value) * Return a configuration parameter (or default value)
@ -652,3 +749,9 @@ LSerror :: defineError('LSldap_08',
LSerror :: defineError('LSldap_09', LSerror :: defineError('LSldap_09',
___("LSldap: Fail to set authz proxy option on LDAP server connection.") ___("LSldap: Fail to set authz proxy option on LDAP server connection.")
); );
LSerror :: defineError('LSldap_10',
___("LSldap: Error while changing the user password: %{msg}.")
);
LSerror :: defineError('LSldap_11',
___("LSldap: Unknown LDAP error while updating user password")
);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff