From a6f07faca09ffd351f2e6485984bf08be77fa408 Mon Sep 17 00:00:00 2001 From: Benjamin Renard Date: Tue, 12 May 2020 19:23:24 +0200 Subject: [PATCH] LSauth: Add possibility to configure more than one LSobject type as user --- doc/conf/srv-ldap.docbook | 139 +++++---- src/conf/config.inc.php | 19 +- .../LSaddons.LSaccessRightsMatrixView.php | 6 +- src/includes/class/class.LSauth.php | 99 ++++++- src/includes/class/class.LSauthMethod.php | 35 +-- .../class/class.LSauthMethod_basic.php | 48 ++- src/includes/class/class.LSsession.php | 280 +++++++++++------- 7 files changed, 398 insertions(+), 228 deletions(-) diff --git a/doc/conf/srv-ldap.docbook b/doc/conf/srv-ldap.docbook index 8828b41b..a143895c 100644 --- a/doc/conf/srv-ldap.docbook +++ b/doc/conf/srv-ldap.docbook @@ -18,7 +18,14 @@ serveur LDAP. ), 'useUserCredentials' => [boolean], 'LSauth' => array ( - 'method' => [LSauth method] + 'method' => [LSauth method], + 'LSobjects' => array( + '[object type 1]', + '[object type 2]' => array( + 'filter' => '[LDAP filter]', + 'password_attribute' => '[attribute name]', + ) + ) ), 'LSprofiles' => array ( // Définition des LSprofiles @@ -26,9 +33,6 @@ serveur LDAP. 'cacheLSprofiles' => [boolean], 'cacheSearch' => [boolean], 'globalSearch' => [boolean], - 'authObjectType' => [LSobject], - 'authObjectFilter' => [LSformat], - 'authObjectTypeAttrPwd' => [attribut], 'LSaccess' => array ( [Type LSobject 1], [Type LSobject 2], @@ -50,7 +54,7 @@ serveur LDAP. ... - + Paramètres de configuration @@ -66,8 +70,8 @@ serveur LDAP. ldap_config - Informations de connexion au serveur LDAP. Ces informations sont - structurées selon les attentes de la librairie &netldap;. + Informations de connexion au serveur LDAP. Ces informations sont + structurées selon les attentes de la librairie &netldap;. Plus d'informations @@ -102,12 +106,71 @@ serveur LDAP. LSauth - Définition de la méthode d'authentification &LSauthMethod;. Pour le - moment ce tableau associatif ne contient qu'un paramètre - method qui correpond au nom de la librairie d'authentification. - Exemple : pour utiliser la classe LSauthMethod_HTTP, la - valeur du paramètre method sera HTTP. - + Ce tableau défini les paramètres d'authentification à l'application. + + Paramètres de configuration de l'authentification + + + method + + Nom de la méthode d'authentification &LSauthMethod;. Exemple : pour utiliser la classe + LSauthMethod_HTTP, la valeur de ce paramètre sera HTTP. + Paramètre facultatif, méthode par défaut : basic. + + + + + + LSobjects + + Tableau listant les types &LSobjects; pouvant se connecter à l'application. Les valeurs + de ce tableau peuvent être un nom de type d'objet ou bien tableau détaillant les paramètres de + connexion de ce type d'objet. + + Paramètres de configuration d'un type d'object + + + filter + + &LSformat; du filtre de recherche de l'utilisateur à sa connexion. + Ce format sera composé avec l'identifiant fourni par l'utilisateur. Cela peut + par exemple permettre à l'utilisateur de se connecter en fournissant son login + ou son email comme identifiant. Exemple de valeur : + (|(uid=%{user})(mail=%{user})). Paramètre facultatif, + filtre par défaut composé à l'aide de l'attribut RDN. + + + + + password_attribute + + Nom de l'attribut stockant le mot de passe de ce type d'&LSobject;. + Paramètre facultatif, valeur par défaut : userPassword. + C'est cet attribut de l'utilisateur qui sera modifié par la fonctionnalité + de récupération de mot de passe. + + + + + + + + + allow_multi_match + + Booléen permettant de définir si un doublon d'identifiant utilisateur est autorisé. + Si c'est le cas et lorsqu'un identifiant fourni par l'utilisateur a sa connexion a permi + de trouver plus d'un utilisateur possible correspondant, l'application tentera de déterminer + lequel de ces utilisateurs correspond à la tentative d'authentification. La méthodologie + employée dépendra de la &LSauthMethod; configurée. Par exemple, la &LSauthMethod; + basic tentera de s'identifier avec le mot de passe. Dans tous les cas, si cette + méthode n'a pas permi d'identifier un seul utilisateur, l'authentification échoura. + Paramètre facultatif, valeur par défaut : Faux. + + + + + @@ -115,7 +178,7 @@ serveur LDAP. cacheLSprofiles - Activation/Désactivation de la mise en cache des &LSprofiles; des + Activation/Désactivation de la mise en cache des &LSprofiles; des utilisateurs connectés à ce serveur. @@ -124,7 +187,7 @@ serveur LDAP. cacheSearch - Activation/Désactivation de la mise en cache du résultat des + Activation/Désactivation de la mise en cache du résultat des recherches sur ce serveur. @@ -140,42 +203,12 @@ serveur LDAP. - - authObjectType - - Nom du type d'&LSobject; pouvant être utilisé pour authentifier un - utilisateur se connectant à l'interface. - - - - - - authObjectFilter - - &LSformat; du filtre de recherche de l'utilisateur à sa connexion. - Le LSformat sera composé avec la valeur de l'information fourni par l'utilisateur. - Cela peut pemettre par exemple de permettre à l'utilisateur de se connecter en - fournissant soit son login, soit son email. Exemple de valeur : - (|(uid=%{user})(mail=%{user})) - - - - - - authObjectTypeAttrPwd - - Nom de l'attribut "mot de passe" du type d'&LSobject; utilisé pour - l'authentification des utilisateurs se connectant à l'interface. - - - - LSaccess - Définition des types d'&LSobjects; devant apparaître dans le menu de + Définition des types d'&LSobjects; devant apparaître dans le menu de l'interface. - Ce paramètre n'est utilisé que pour les annuaires n'ayant + Ce paramètre n'est utilisé que pour les annuaires n'ayant pas de sous-niveaux (&subDn;). @@ -186,8 +219,8 @@ serveur LDAP. Définition des sous-niveaux de connexion à l'annuaire. Voir section concernée. - Ce paramètre remplace le paramètre - LSaccess dans le cas d'un annuaire + Ce paramètre remplace le paramètre + LSaccess dans le cas d'un annuaire multi-niveaux. @@ -198,7 +231,7 @@ serveur LDAP. Définition du label utilisé pour qualifier les sous-niveaux de connexion. - Ce paramètre est utile uniquement dans le cas d'un annuaire + Ce paramètre est utile uniquement dans le cas d'un annuaire multi-niveaux. @@ -238,8 +271,8 @@ serveur LDAP. emailSender - Adresse mail utilisée par &LdapSaisie; pour envoyer des e-mails en - relation avec cet annuaire. Cette adresse est celle utilisée par défaut. + Adresse mail utilisée par &LdapSaisie; pour envoyer des e-mails en + relation avec cet annuaire. Cette adresse est celle utilisée par défaut. L'adresse utilisée peut également être configurée dans le contexte de configuration du module devant envoyer des e-mails. @@ -249,7 +282,7 @@ serveur LDAP. keepLSsessionActive Activation/Désactivation du maintient de la LSsession active. - Valeurs possibles : True ou + Valeurs possibles : True ou False diff --git a/src/conf/config.inc.php b/src/conf/config.inc.php index 570ce6bb..00189bf1 100644 --- a/src/conf/config.inc.php +++ b/src/conf/config.inc.php @@ -48,11 +48,16 @@ $GLOBALS['LSconfig'] = array( 'filter' => '(objectClass=*)', 'scope' => 'sub' ), -/* 'LSauth' => array ( - 'method' => 'HTTP' + //'method' => 'basic', // Auth method : basic(default), HTTP, CAS or anonymous + 'LSobjects' => array( + 'LSpeople' => array( + 'filter' => '(|(uid=%{user})(mail=%{user}))', + 'password_attribute' => 'userPassword', + ), + ), + //'allow_multi_match' => false, // Allow username multiple match (default: false) ), -*/ 'LSprofiles' => array ( 'admin' => array ( 'label' => 'Administrator', @@ -82,9 +87,6 @@ $GLOBALS['LSconfig'] = array( ), 'cacheLSprofiles' => true, 'cacheSearch' => true, - 'authObjectType' => 'LSpeople', - 'authObjectFilter' => '(|(uid=%{user})(mail=%{user}))', - 'authObjectTypeAttrPwd' => 'userPassword', 'LSaccess' => array( 'LSpeople', 'LSgroup' @@ -118,6 +120,9 @@ $GLOBALS['LSconfig'] = array( 'filter' => '(objectClass=*)', 'scope' => 'sub' ), + 'LSauth' => array ( + 'LSobjects' => array('LSpeople'), + ), 'LSprofiles' => array( 'admin' => array ( 'o=ls' => array ( @@ -134,7 +139,6 @@ $GLOBALS['LSconfig'] = array( ) ) ), - 'authObjectType' => 'LSpeople', 'subDnLabel' => 'Company', 'subDn' => array( '== All ==' => array( @@ -157,7 +161,6 @@ $GLOBALS['LSconfig'] = array( 'cacheLSprofiles' => true, 'cacheSearch' => true, 'globalSearch' => true, - 'authObjectTypeAttrPwd' => 'userPassword', 'recoverPassword' => array( 'mailAttr' => 'mail', 'recoveryHashAttr' => 'lsRecoveryHash', diff --git a/src/includes/addons/LSaddons.LSaccessRightsMatrixView.php b/src/includes/addons/LSaddons.LSaccessRightsMatrixView.php index 7d491e13..60cc58be 100644 --- a/src/includes/addons/LSaddons.LSaccessRightsMatrixView.php +++ b/src/includes/addons/LSaddons.LSaccessRightsMatrixView.php @@ -74,7 +74,7 @@ function LSaccessRightsMatrixView() { foreach(LSconfig :: get("LSobjects.$LSobject.attrs", array()) as $attr_name => $attr_config) { $raw_attr_rights = LSconfig :: get('rights', array(), 'array', $attr_config); $attr_rights = array(); - if ($LSobject == LSsession :: $ldapServer["authObjectType"]) + if ($LSobject == LSsession :: get('authenticated_user_type')) $attr_rights['self'] = LSconfig :: get('self', False, null, $raw_attr_rights); foreach(array_keys($LSprofiles) as $LSprofile) { $attr_rights[$LSprofile] = LSconfig :: get($LSprofile, False, null, $raw_attr_rights); @@ -90,7 +90,7 @@ function LSaccessRightsMatrixView() { foreach(LSconfig :: get("LSobjects.$LSobject.LSrelation", array()) as $relation_name => $relation_config) { $raw_relation_rights = LSconfig :: get('rights', array(), 'array', $relation_config); $relation_rights = array(); - if ($LSobject == LSsession :: $ldapServer["authObjectType"]) + if ($LSobject == LSsession :: get('authenticated_user_type')) $relation_rights['self'] = LSconfig :: get('self', False, null, $raw_relation_rights); foreach(array_keys($LSprofiles) as $LSprofile) { $relation_rights[$LSprofile] = LSconfig :: get($LSprofile, False, null, $raw_relation_rights); @@ -112,7 +112,7 @@ function LSaccessRightsMatrixView() { reset($LSobjects); $LSobject = (isset($_REQUEST['LSobject']) && array_key_exists($_REQUEST['LSobject'], $LSobjects)?$_REQUEST['LSobject']:key($LSobjects)); - if ($LSobject == LSsession :: $ldapServer["authObjectType"]) + if ($LSobject == LSsession :: get('authenticated_user_type')) $LSprofiles = array_merge(array('self' => _('The user him-self')), $LSprofiles); LSlog :: get_logger('LSaddon_LSaccessRightsMatrixView') -> debug($LSobjects); diff --git a/src/includes/class/class.LSauth.php b/src/includes/class/class.LSauth.php index 18078608..b89594d1 100644 --- a/src/includes/class/class.LSauth.php +++ b/src/includes/class/class.LSauth.php @@ -87,6 +87,103 @@ class LSauth extends LSlog_staticLoggerClass { return; } + /** + * Return a configuration parameter (or default value) + * + * @param[] $param The configuration parameter + * @param[] $default The default value (default : null) + * @param[] $cast Cast resulting value in specific type (default : disabled) + * + * @retval mixed The configuration parameter value or default value if not set + **/ + private static function getConfig($param, $default=null, $cast=null) { + return LSconfig :: get($param, $default, $cast, self :: $config); + } + + /** + * Retreive auth object types info + * @return array Array of auth object type with type as key and type's parameters as value + */ + public static function getAuthObjectTypes() { + $objTypes = array(); + foreach(self :: getConfig('LSobjects', array()) as $objType => $objParams) { + if (is_int($objType) && is_string($objParams)) { + // We just have the object type + $objTypes[$objType] = array('filter' => null, 'password_attribute' => 'userPassword'); + continue; + } + $objTypes[$objType] = array( + 'filter' => self :: getConfig("LSobjects.$objType.filter", null, 'string'), + 'password_attribute' => self :: getConfig("LSobjects.$objType.password_attribute", 'userPassword', 'string'), + ); + } + // For retro-compatibility, also retreived old parameters: + $oldAuthObjectType = LSconfig :: get('authObjectType', null, 'string', LSsession :: $ldapServer); + if ($oldAuthObjectType && !array_key_exists($oldAuthObjectType, $objTypes)) { + $objTypes[$oldAuthObjectType] = array( + 'filter' => LSconfig :: get('authObjectFilter', null, 'string', LSsession :: $ldapServer), + 'password_attribute' => LSconfig :: get('authObjectTypeAttrPwd', 'userPassword', 'string', LSsession :: $ldapServer), + ); + } + return $objTypes; + } + + /** + * Retreived LSobjects corresponding to a username + * + * @retval array|false Array of corresponding LSldapObject with object DN as key, or false in case of error + */ + public static function username2LSobjects($username) { + $user_objects = array(); + foreach (self :: getAuthObjectTypes() as $objType => $objParams) { + if (!LSsession :: loadLSobject($objType)) { + LSerror :: addErrorCode('LSauth_03', $objType); + return false; + } + $authobject = new $objType(); + $result = $authobject -> searchObject( + $username, + LSsession :: getTopDn(), + $objParams['filter'], + array('withoutCache' => true, 'onlyAccessible' => false) + ); + for($i=0; $i getDn()] = $result[$i]; + } + + $nbresult = count($user_objects); + if ($nbresult == 0) { + // incorrect login + self :: log_debug('Invalid username'); + LSerror :: addErrorCode('LSauth_01'); + return false; + } + else if ($nbresult > 1) { + // duplication of identity + self :: log_debug("More than one user detected for username '$username': ".implode(', ', array_keys($user_objects))); + if (!self :: getConfig('allow_multi_match', false, 'bool')) { + LSerror :: addErrorCode('LSauth_02'); + return false; + } + } + return $user_objects; + } + + /** + * Get user password attribute name + * + * @param[in] &object LSldapObject The user object + * + * @retval string|false The user password attribute name or false if not configured + */ + public static function getUserPasswordAttribute(&$object) { + $authObjectTypes = self :: getAuthObjectTypes(); + $objType = $object -> getType(); + if (array_key_exists($objType, $authObjectTypes)) + return $authObjectTypes[$objType]['password_attribute']; + return false; + } + /** * Get LDAP credentials * @@ -188,7 +285,7 @@ LSerror :: defineError('LSauth_02', _("LSauth : Impossible to identify you : Duplication of identities.") ); LSerror :: defineError('LSauth_03', -_("LSauth : Could not load type of identifiable objects.") +_("LSauth : Could not load type of identifiable objects %{type}.") ); LSerror :: defineError('LSauth_04', _("LSauth : Can't load authentication method %{method}.") diff --git a/src/includes/class/class.LSauthMethod.php b/src/includes/class/class.LSauthMethod.php index 4a53d883..9b0247b8 100644 --- a/src/includes/class/class.LSauthMethod.php +++ b/src/includes/class/class.LSauthMethod.php @@ -60,33 +60,18 @@ class LSauthMethod extends LSlog_staticLoggerClass { * @retval LSldapObject|false The LSldapObject of the user authificated or false */ public function authenticate() { - if (LSsession :: loadLSobject(LSsession :: $ldapServer['authObjectType'])) { - $authobject = new LSsession :: $ldapServer['authObjectType'](); - $result = $authobject -> searchObject( - $this -> authData['username'], - LSsession :: getTopDn(), - (isset(LSsession :: $ldapServer['authObjectFilter'])?LSsession :: $ldapServer['authObjectFilter']:NULL), - array('withoutCache' => true, 'onlyAccessible' => false) - ); - $nbresult=count($result); - - if ($nbresult==0) { - // incorrect login - LSdebug('identifiant incorrect'); - LSerror :: addErrorCode('LSauth_01'); - } - else if ($nbresult>1) { - // duplication of identity - LSerror :: addErrorCode('LSauth_02'); - } - else { - return $result[0]; - } + $authobjects = LSauth :: username2LSobjects($this -> authData['username']); + if (!$authobjects) { + LSerror :: addErrorCode('LSauth_01'); + self :: log_debug("No user found for provided username '".$this -> authData['username']."'"); } - else { - LSerror :: addErrorCode('LSauth_03'); + elseif (count($authobjects) > 1) { + self :: log_debug('Multiple users match with provided username: '.implode(', ', array_keys($authobjects))); + LSerror :: addErrorCode('LSauth_02'); + return false; } - return; + // Authentication succeeded + return $authobjects[$matched[0]]; } /** diff --git a/src/includes/class/class.LSauthMethod_basic.php b/src/includes/class/class.LSauthMethod_basic.php index 54c40490..0466f3de 100644 --- a/src/includes/class/class.LSauthMethod_basic.php +++ b/src/includes/class/class.LSauthMethod_basic.php @@ -51,32 +51,28 @@ class LSauthMethod_basic extends LSauthMethod { * @retval LSldapObject|false The LSldapObject of the user authificated or false */ public function authenticate() { - $authobject = parent :: authenticate(); - if ($authobject) { - if ( $this -> checkUserPwd($authobject,$this -> authData['password']) ) { - // Authentication succeeded - return $authobject; - } - else { - LSerror :: addErrorCode('LSauth_01'); - LSdebug('mdp incorrect'); - } - } - return; - } - - /** - * Test un couple LSobject/pwd - * - * Test un bind sur le serveur avec le dn de l'objet et le mot de passe fourni. - * - * @param[in] LSobject L'object "user" pour l'authentification - * @param[in] string Le mot de passe à tester - * - * @retval boolean True si l'authentification a reussi, false sinon. - **/ - public static function checkUserPwd($object,$pwd) { - return LSldap :: checkBind($object -> getValue('dn'),$pwd); + $authobjects = LSauth :: username2LSobjects($this -> authData['username']); + if (!$authobjects) { + LSerror :: addErrorCode('LSauth_01'); + self :: log_debug('Invalid username'); + return false; + } + $matched = array(); + foreach(array_keys($authobjects) as $dn) + if ( LSldap :: checkBind($dn, $this -> authData['password']) ) + $matched[] = $dn; + if (!$matched) { + LSerror :: addErrorCode('LSauth_01'); + self :: log_debug('Invalid password'); + return false; + } + elseif (count($matched) > 1) { + self :: log_debug('Multiple users match with provided username and password: '.implode(', ', $matched)); + LSerror :: addErrorCode('LSauth_02'); + return false; + } + // Authentication succeeded + return $authobjects[$matched[0]]; } } diff --git a/src/includes/class/class.LSsession.php b/src/includes/class/class.LSsession.php index b7914dfe..f91d4c7d 100644 --- a/src/includes/class/class.LSsession.php +++ b/src/includes/class/class.LSsession.php @@ -84,9 +84,12 @@ class LSsession { // Libs CSS files to load on page private static $LibsCssFiles = array(); - // L'objet de l'utilisateur connecté + // The LSldapObject of connected user private static $LSuserObject = NULL; + // The LSldapObject type of connected user + private static $LSuserObjectType = NULL; + // The LSauht object of the session private static $LSauthObject = false; @@ -96,6 +99,39 @@ class LSsession { // Initialized telltale private static $initialized = false; + /** + * Get session info by key + * + * @param[in] $key string The info + * + * @retval mixed The info or null + */ + public static function get($key) { + switch($key) { + case 'top_dn': + return self :: getTopDn(); + case 'root_dn': + return self :: getRootDn(); + case 'sub_dn_name': + return self :: getSubDnName(); + case 'sub_dn_label': + return self :: getSubDnLabel(); + case 'authenticated_user_dn': + return self :: $dn; + case 'authenticated_user_type': + return self :: $LSuserObjectType; + case 'authenticated_user': + return self :: getLSuserObject(); + case 'is_connected': + return self :: isConnected(); + case 'global_search_enabled': + return self :: globalSearch(); + case 'email_sender': + return self :: getEmailSender(); + } + return null; + } + /** * Include PHP file * @@ -569,15 +605,16 @@ class LSsession { return; } - if(isset($_SESSION['LSsession']['dn']) && !isset($_GET['LSsession_recoverPassword'])) { + if(isset($_SESSION['LSsession']['LSuserObjectType']) && isset($_SESSION['LSsession']['dn']) && !isset($_GET['LSsession_recoverPassword'])) { self :: log_debug('existing session'); // --------------------- Session existante --------------------- // - self :: $topDn = $_SESSION['LSsession']['topDn']; - self :: $dn = $_SESSION['LSsession']['dn']; - self :: $rdn = $_SESSION['LSsession']['rdn']; - self :: $ldapServerId = $_SESSION['LSsession']['ldapServerId']; - self :: $tmp_file = $_SESSION['LSsession']['tmp_file']; - self :: $userLDAPcreds = $_SESSION['LSsession']['userLDAPcreds']; + self :: $topDn = $_SESSION['LSsession']['topDn']; + self :: $dn = $_SESSION['LSsession']['dn']; + self :: $LSuserObjectType = $_SESSION['LSsession']['LSuserObjectType']; + self :: $rdn = $_SESSION['LSsession']['rdn']; + self :: $ldapServerId = $_SESSION['LSsession']['ldapServerId']; + self :: $tmp_file = $_SESSION['LSsession']['tmp_file']; + self :: $userLDAPcreds = $_SESSION['LSsession']['userLDAPcreds']; if ( self :: cacheLSprofiles() && !isset($_REQUEST['LSsession_refresh']) ) { self :: setLdapServer(self :: $ldapServerId); @@ -606,7 +643,7 @@ class LSsession { self :: $_subDnLdapServer = ((isset($_SESSION['LSsession_subDnLdapServer']))?$_SESSION['LSsession_subDnLdapServer']:NULL); } - if (!self :: loadLSobject(self :: $ldapServer['authObjectType'])) { + if (!self :: loadLSobject(self :: $LSuserObjectType)) { return; } @@ -694,6 +731,7 @@ class LSsession { if ($LSuserObject) { // Authentication successful self :: $LSuserObject = $LSuserObject; + self :: $LSuserObjectType = $LSuserObject -> getType(); self :: $dn = $LSuserObject->getValue('dn'); self :: $rdn = $LSuserObject->getValue('rdn'); if (isset(self :: $ldapServer['useUserCredentials']) && self :: $ldapServer['useUserCredentials']) { @@ -760,83 +798,95 @@ class LSsession { * * @retval array The recoveryPassword infos for template **/ - private static function recoverPasswd($username,$recoveryHash) { - $recoveryPasswordInfos=array(); - if ( self :: loadLSobject(self :: $ldapServer['authObjectType']) ) { - $authobject = new self :: $ldapServer['authObjectType'](); - if (!empty($recoveryHash)) { - $filter=Net_LDAP2_Filter::create( - self :: $ldapServer['recoverPassword']['recoveryHashAttr'], - 'equals', - $recoveryHash + private static function recoverPasswd($username, $recoveryHash) { + // Check feature is enabled and LSmail available + if (!isset(self :: $ldapServer['recoverPassword']) || !self :: loadLSaddon('mail')) { + LSerror :: addErrorCode('LSsession_18'); + return; + } + + // Start LSauth + if (!LSauth :: start()) { + self :: log_error("recoverPasswd(): can't start LSauth -> stop"); + return; + } + + // Search user by recoveryHash or username + if (!empty($recoveryHash)) { + $users = array(); + $filter = Net_LDAP2_Filter::create( + self :: $ldapServer['recoverPassword']['recoveryHashAttr'], + 'equals', + $recoveryHash + ); + foreach (LSauth :: getAuthObjectTypes() as $objType => $objParams) { + if (!self :: loadLSobject($objType)) + return false; + $authobject = new $objType(); + $users = array_merge( + $users, + $authobject -> listObjects($filter, self :: $topDn, array('onlyAccessible' => false)) ); - $result = $authobject -> listObjects($filter,self :: $topDn,array('onlyAccessible' => false)); - } - elseif (!empty($username)) { - $result = $authobject -> searchObject( - $username, - self :: $topDn, - self :: $ldapServer['authObjectFilter'], - array('onlyAccessible' => false) - ); - } - else { - return $recoveryPasswordInfos; } + } + elseif (!empty($username)) { + $users = LSauth :: username2LSobjects($username); + } + else { + self :: log_debug('recoverPasswd(): no username or recoveryHash provided.'); + return; + } - $nbresult=count($result); + // Check user found (and not duplicated) + $nbresult = count($users); + if ($nbresult == 0) { + self :: log_debug('recoverPasswd(): incorrect hash/username'); + LSerror :: addErrorCode('LSsession_06'); + return; + } + elseif ($nbresult > 1) { + self :: log_debug("recoverPasswd(): duplicated user found with hash='$recoveryHash' / username='$username'"); + LSerror :: addErrorCode('LSsession_07'); + return; + } - if ($nbresult==0) { - self :: log_debug('recoverPasswd(): incorrect hash/username'); - LSerror :: addErrorCode('LSsession_06'); - } - elseif ($nbresult>1) { - self :: log_debug("recoverPasswd(): duplicated user found with hash/username '$username'"); - LSerror :: addErrorCode('LSsession_07'); - } - else { - $rdn = $result[0] -> getValue('rdn'); - $username = $rdn[0]; - self :: log_debug("recoverPasswd(): user found, username = '$username'"); - if (self :: $ldapServer['recoverPassword']) { - if (self :: loadLSaddon('mail')) { - self :: log_debug("recoverPasswd(): start recovering password"); - $user=$result[0]; - $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']); - $emailAddress = $emailAddress[0]; + $user = array_pop($users); + $rdn = $user -> getValue('rdn'); + $username = $rdn[0]; + self :: log_debug("recoverPasswd(): user found, username = '$username'"); - if (checkEmail($emailAddress)) { - self :: log_debug("recoverPasswd(): Email = '$emailAddress'"); - self :: $dn = $user -> getDn(); - // 1ère étape : envoie du recoveryHash - if (empty($recoveryHash)) { - $hash=self :: recoverPasswdFirstStep($user); - if ($hash) { - if (self :: recoverPasswdSendMail($emailAddress,1,$hash)) { - // Mail a bien été envoyé - $recoveryPasswordInfos['recoveryHashMail']=$emailAddress; - } - } - } - // 2nd étape : génération du mot de passe + envoie par mail - else { - $pwd=self :: recoverPasswdSecondStep($user); - if ($pwd) { - if (self :: recoverPasswdSendMail($emailAddress,2,$pwd)){ - // Mail a bien été envoyé - $recoveryPasswordInfos['newPasswordMail']=$emailAddress; - } - } - } - } - else { - LSerror :: addErrorCode('LSsession_19'); - } - } + self :: log_debug("recoverPasswd(): start recovering password"); + $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']); + $emailAddress = $emailAddress[0]; + + if (!checkEmail($emailAddress)) { + LSerror :: addErrorCode('LSsession_19'); + return; + } + self :: log_debug("recoverPasswd(): Email = '$emailAddress'"); + self :: $dn = $user -> getDn(); + + // + $recoveryPasswordInfos = array(); + + // First step : send recoveryHash + if (empty($recoveryHash)) { + $hash = self :: recoverPasswdFirstStep($user); + if ($hash) { + if (self :: recoverPasswdSendMail($emailAddress, 1, $hash)) { + // Recovery hash sent + $recoveryPasswordInfos['recoveryHashMail'] = $emailAddress; } - else { - LSerror :: addErrorCode('LSsession_18'); + } + } + // Second step : generate and send new password + else { + $pwd = self :: recoverPasswdSecondStep($user); + if ($pwd) { + if (self :: recoverPasswdSendMail($emailAddress, 2, $pwd)) { + // New password sent + $recoveryPasswordInfos['newPasswordMail'] = $emailAddress; } } } @@ -931,24 +981,25 @@ class LSsession { * @retval string|False The new password on success or False **/ private static function recoverPasswdSecondStep($user) { - $attr = $user -> attrs[self :: $ldapServer['authObjectTypeAttrPwd']]; - if ($attr instanceof LSattribute) { - $mdp = generatePassword( - $attr -> config['html_options']['chars'], - $attr -> config['html_options']['lenght'] + $pwd_attr_name = LSauth :: getUserPasswordAttribute($user); + if (array_key_exists($pwd_attr_name, $user -> attrs)) { + $pwd_attr = $user -> attrs[$pwd_attr_name]; + $pwd = generatePassword( + $pwd_attr -> getConfig('html_options.chars'), + $pwd_attr -> getConfig('html_options.lenght'), ); - self :: log_debug("recoverPasswdSecondStep($user): new password = '$mdp'."); + self :: log_debug("recoverPasswdSecondStep($user): new password = '$pwd'."); $lostPasswdForm = $user -> getForm('lostPassword'); $lostPasswdForm -> setPostData( array( self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''), - self :: $ldapServer['authObjectTypeAttrPwd'] => array($mdp) + $pwd_attr_name => array($pwd) ) ,true ); if($lostPasswdForm -> validate()) { if ($user -> updateData('lostPassword')) { - return $mdp; + return $pwd; } else { // Erreur durant la mise à jour de l'objet @@ -964,7 +1015,7 @@ class LSsession { } else { // l'attribut password n'existe pas - self :: log_error("recoverPasswdSecondStep($user): password attribute '$attr' does not exists."); + self :: log_error("recoverPasswdSecondStep($user): password attribute '$pwd_attr_name' does not exists."); LSerror :: addErrorCode('LSsession_20',1); } return; @@ -983,6 +1034,7 @@ class LSsession { 'topDn' => self :: $topDn, 'dn' => self :: $dn, 'rdn' => self :: $rdn, + 'LSuserObjectType' => self :: $LSuserObjectType, 'userLDAPcreds' => self :: $userLDAPcreds, 'ldapServerId' => self :: $ldapServerId, 'ldapServer' => self :: $ldapServer, @@ -1000,14 +1052,17 @@ class LSsession { * @retval mixed L'objet de l'utilisateur connecté ou false si il n'a pas put * être créé */ - public static function getLSuserObject($dn=null) { + public static function &getLSuserObject($dn=null) { if ($dn) { self :: $dn = $dn; } if (!self :: $LSuserObject) { - if (self :: loadLSobject(self :: $ldapServer['authObjectType'])) { - self :: $LSuserObject = new self :: $ldapServer['authObjectType'](); - self :: $LSuserObject -> loadData(self :: $dn); + if (self :: $LSuserObjectType && self :: loadLSobject(self :: $LSuserObjectType)) { + self :: $LSuserObject = new self :: $LSuserObjectType(); + if (!self :: $LSuserObject -> loadData(self :: $dn)) { + self :: $LSuserObject = null; + return; + } } else { return; @@ -1024,7 +1079,7 @@ class LSsession { * @retval boolean True if user connected, false instead */ public static function isConnected() { - if (self :: $LSuserObject) + if (self :: getLSuserObject()) return true; return false; } @@ -1041,30 +1096,31 @@ class LSsession { } /** - * Modifie l'utilisateur connecté à la volé + * Live change of the connected user * - * @param[in] $object Mixed L'objet Ldap du nouvel utilisateur - * le type doit correspondre à - * self :: $ldapServer['authObjectType'] + * @param[in] $object LSldapObject The new connected user object * - * @retval boolean True en cas de succès, false sinon + * @retval boolean True on succes, false otherwise */ public static function changeAuthUser($object) { - if ($object instanceof self :: $ldapServer['authObjectType']) { - self :: $dn = $object -> getDn(); - $rdn = $object -> getValue('rdn'); - if(is_array($rdn)) { - $rdn = $rdn[0]; - } - self :: $rdn = $rdn; - self :: $LSuserObject = $object; + if($object instanceof LSldapObject) + return; + if(!in_array($object -> getType(), LSauth :: getAuthObjectTypes())) + return; + self :: $dn = $object -> getDn(); + $rdn = $object -> getValue('rdn'); + if(is_array($rdn)) { + $rdn = $rdn[0]; + } + self :: $rdn = $rdn; + self :: $LSuserObject = $object; + self :: $LSuserObjectType = $object -> getType(); - if(self :: loadLSprofiles()) { - self :: loadLSaccess(); - self :: loadLSaddonsViewsAccess(); - $_SESSION['LSsession']=self :: getContextInfos(); - return true; - } + if(self :: loadLSprofiles()) { + self :: loadLSaccess(); + self :: loadLSaddonsViewsAccess(); + $_SESSION['LSsession']=self :: getContextInfos(); + return true; } return; }