LSauth: Add possibility to configure more than one LSobject type as user

This commit is contained in:
Benjamin Renard 2020-05-12 19:23:24 +02:00
parent 5660804ef7
commit a6f07faca0
7 changed files with 398 additions and 228 deletions

View file

@ -18,7 +18,14 @@ serveur LDAP.</para>
), ),
'useUserCredentials' => [boolean], 'useUserCredentials' => [boolean],
'LSauth' => array ( '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 ( 'LSprofiles' => array (
// Définition des LSprofiles // Définition des LSprofiles
@ -26,9 +33,6 @@ serveur LDAP.</para>
'cacheLSprofiles' => [boolean], 'cacheLSprofiles' => [boolean],
'cacheSearch' => [boolean], 'cacheSearch' => [boolean],
'globalSearch' => [boolean], 'globalSearch' => [boolean],
'authObjectType' => [LSobject],
'authObjectFilter' => [LSformat],
'authObjectTypeAttrPwd' => [attribut],
'LSaccess' => array ( 'LSaccess' => array (
[Type LSobject 1], [Type LSobject 1],
[Type LSobject 2], [Type LSobject 2],
@ -50,7 +54,7 @@ serveur LDAP.</para>
... ...
</programlisting> </programlisting>
<!-- Début Paramètres Configuration --> <!-- Début Paramètres Configuration -->
<variablelist> <variablelist>
<title>Paramètres de configuration</title> <title>Paramètres de configuration</title>
@ -66,8 +70,8 @@ serveur LDAP.</para>
<varlistentry> <varlistentry>
<term>ldap_config</term> <term>ldap_config</term>
<listitem> <listitem>
<simpara>Informations de connexion au serveur LDAP. Ces informations sont <simpara>Informations de connexion au serveur LDAP. Ces informations sont
structurées selon les attentes de la librairie &netldap;. structurées selon les attentes de la librairie &netldap;.
<ulink url='http://pear.php.net/manual/fr/package.networking.net-ldap.connecting.php'> <ulink url='http://pear.php.net/manual/fr/package.networking.net-ldap.connecting.php'>
Plus d'informations</ulink> Plus d'informations</ulink>
</simpara> </simpara>
@ -102,12 +106,71 @@ serveur LDAP.</para>
<varlistentry> <varlistentry>
<term>LSauth</term> <term>LSauth</term>
<listitem> <listitem>
<simpara>Définition de la méthode d'authentification &LSauthMethod;. Pour le <simpara>Ce tableau défini les paramètres d'authentification à l'application.</simpara>
moment ce tableau associatif ne contient qu'un paramètre <parameter> <variablelist>
method</parameter> qui correpond au nom de la librairie d'authentification. <title>Paramètres de configuration de l'authentification</title>
Exemple : pour utiliser la classe <literal>LSauthMethod_HTTP</literal>, la
valeur du paramètre <parameter>method</parameter> sera <literal>HTTP</literal>. <varlistentry>
</simpara> <term>method</term>
<listitem>
<simpara>Nom de la méthode d'authentification &LSauthMethod;. Exemple : pour utiliser la classe
<literal>LSauthMethod_HTTP</literal>, la valeur de ce paramètre sera <literal>HTTP</literal>.
<emphasis>Paramètre facultatif, méthode par défaut : <literal>basic</literal>.</emphasis>
</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>LSobjects</term>
<listitem>
<simpara>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.</simpara>
<variablelist>
<title>Paramètres de configuration d'un type d'object</title>
<varlistentry>
<term>filter</term>
<listitem>
<simpara>&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 :
<literal>(|(uid=%{user})(mail=%{user}))</literal>. <emphasis>Paramètre facultatif,
filtre par défaut composé à l'aide de l'attribut RDN.</emphasis></simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>password_attribute</term>
<listitem>
<simpara>Nom de l'attribut stockant le mot de passe de ce type d'&LSobject;. <emphasis>
Paramètre facultatif, valeur par défaut : <literal>userPassword</literal>.</emphasis></simpara>
<note><simpara>C'est cet attribut de l'utilisateur qui sera modifié par la fonctionnalité
de récupération de mot de passe.</simpara></note>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry>
<term>allow_multi_match</term>
<listitem>
<simpara>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; <literal>
basic</literal> 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. <emphasis>
Paramètre facultatif, valeur par défaut : <literal>Faux</literal>.</emphasis>
</simpara>
</listitem>
</varlistentry>
</variablelist>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -115,7 +178,7 @@ serveur LDAP.</para>
<varlistentry> <varlistentry>
<term>cacheLSprofiles</term> <term>cacheLSprofiles</term>
<listitem> <listitem>
<simpara>Activation/Désactivation de la mise en cache des &LSprofiles; des <simpara>Activation/Désactivation de la mise en cache des &LSprofiles; des
utilisateurs connectés à ce serveur.</simpara> utilisateurs connectés à ce serveur.</simpara>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -124,7 +187,7 @@ serveur LDAP.</para>
<varlistentry> <varlistentry>
<term>cacheSearch</term> <term>cacheSearch</term>
<listitem> <listitem>
<simpara>Activation/Désactivation de la mise en cache du résultat des <simpara>Activation/Désactivation de la mise en cache du résultat des
recherches sur ce serveur.</simpara> recherches sur ce serveur.</simpara>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -140,42 +203,12 @@ serveur LDAP.</para>
</varlistentry> </varlistentry>
<varlistentry>
<term>authObjectType</term>
<listitem>
<simpara>Nom du type d'&LSobject; pouvant être utilisé pour authentifier un
utilisateur se connectant à l'interface.</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>authObjectFilter</term>
<listitem>
<simpara>&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 :
<literal>(|(uid=%{user})(mail=%{user}))</literal></simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>authObjectTypeAttrPwd</term>
<listitem>
<simpara>Nom de l'attribut "mot de passe" du type d'&LSobject; utilisé pour
l'authentification des utilisateurs se connectant à l'interface.</simpara>
</listitem>
</varlistentry>
<varlistentry id="config-LSaccess"> <varlistentry id="config-LSaccess">
<term>LSaccess</term> <term>LSaccess</term>
<listitem> <listitem>
<simpara>Définition des types d'&LSobjects; devant apparaître dans le menu de <simpara>Définition des types d'&LSobjects; devant apparaître dans le menu de
l'interface.</simpara> l'interface.</simpara>
<important><simpara>Ce paramètre n'est utilisé que pour les annuaires n'ayant <important><simpara>Ce paramètre n'est utilisé que pour les annuaires n'ayant
pas de sous-niveaux (&subDn;).</simpara></important> pas de sous-niveaux (&subDn;).</simpara></important>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -186,8 +219,8 @@ serveur LDAP.</para>
<listitem> <listitem>
<simpara>Définition des sous-niveaux de connexion à l'annuaire. <simpara>Définition des sous-niveaux de connexion à l'annuaire.
<link linkend="config-subDn">Voir section concernée</link>.</simpara> <link linkend="config-subDn">Voir section concernée</link>.</simpara>
<important><simpara>Ce paramètre remplace le paramètre <important><simpara>Ce paramètre remplace le paramètre
<link linkend="config-LSaccess">LSaccess</link> dans le cas d'un annuaire <link linkend="config-LSaccess">LSaccess</link> dans le cas d'un annuaire
multi-niveaux.</simpara></important> multi-niveaux.</simpara></important>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -198,7 +231,7 @@ serveur LDAP.</para>
<listitem> <listitem>
<simpara>Définition du label utilisé pour qualifier les sous-niveaux de <simpara>Définition du label utilisé pour qualifier les sous-niveaux de
connexion.</simpara> connexion.</simpara>
<important><simpara>Ce paramètre est utile uniquement dans le cas d'un annuaire <important><simpara>Ce paramètre est utile uniquement dans le cas d'un annuaire
multi-niveaux.</simpara></important> multi-niveaux.</simpara></important>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -238,8 +271,8 @@ serveur LDAP.</para>
<varlistentry> <varlistentry>
<term>emailSender</term> <term>emailSender</term>
<listitem> <listitem>
<simpara>Adresse mail utilisée par &LdapSaisie; pour envoyer des e-mails en <simpara>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. 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 L'adresse utilisée peut également être configurée dans le contexte de
configuration du module devant envoyer des e-mails.</simpara> configuration du module devant envoyer des e-mails.</simpara>
</listitem> </listitem>
@ -249,7 +282,7 @@ serveur LDAP.</para>
<term>keepLSsessionActive</term> <term>keepLSsessionActive</term>
<listitem> <listitem>
<simpara>Activation/Désactivation du maintient de la LSsession active.</simpara> <simpara>Activation/Désactivation du maintient de la LSsession active.</simpara>
<simpara>Valeurs possibles : <emphasis>True</emphasis> ou <simpara>Valeurs possibles : <emphasis>True</emphasis> ou
<emphasis>False</emphasis></simpara> <emphasis>False</emphasis></simpara>
</listitem> </listitem>
</varlistentry> </varlistentry>

View file

@ -48,11 +48,16 @@ $GLOBALS['LSconfig'] = array(
'filter' => '(objectClass=*)', 'filter' => '(objectClass=*)',
'scope' => 'sub' 'scope' => 'sub'
), ),
/*
'LSauth' => array ( '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 ( 'LSprofiles' => array (
'admin' => array ( 'admin' => array (
'label' => 'Administrator', 'label' => 'Administrator',
@ -82,9 +87,6 @@ $GLOBALS['LSconfig'] = array(
), ),
'cacheLSprofiles' => true, 'cacheLSprofiles' => true,
'cacheSearch' => true, 'cacheSearch' => true,
'authObjectType' => 'LSpeople',
'authObjectFilter' => '(|(uid=%{user})(mail=%{user}))',
'authObjectTypeAttrPwd' => 'userPassword',
'LSaccess' => array( 'LSaccess' => array(
'LSpeople', 'LSpeople',
'LSgroup' 'LSgroup'
@ -118,6 +120,9 @@ $GLOBALS['LSconfig'] = array(
'filter' => '(objectClass=*)', 'filter' => '(objectClass=*)',
'scope' => 'sub' 'scope' => 'sub'
), ),
'LSauth' => array (
'LSobjects' => array('LSpeople'),
),
'LSprofiles' => array( 'LSprofiles' => array(
'admin' => array ( 'admin' => array (
'o=ls' => array ( 'o=ls' => array (
@ -134,7 +139,6 @@ $GLOBALS['LSconfig'] = array(
) )
) )
), ),
'authObjectType' => 'LSpeople',
'subDnLabel' => 'Company', 'subDnLabel' => 'Company',
'subDn' => array( 'subDn' => array(
'== All ==' => array( '== All ==' => array(
@ -157,7 +161,6 @@ $GLOBALS['LSconfig'] = array(
'cacheLSprofiles' => true, 'cacheLSprofiles' => true,
'cacheSearch' => true, 'cacheSearch' => true,
'globalSearch' => true, 'globalSearch' => true,
'authObjectTypeAttrPwd' => 'userPassword',
'recoverPassword' => array( 'recoverPassword' => array(
'mailAttr' => 'mail', 'mailAttr' => 'mail',
'recoveryHashAttr' => 'lsRecoveryHash', 'recoveryHashAttr' => 'lsRecoveryHash',

View file

@ -74,7 +74,7 @@ function LSaccessRightsMatrixView() {
foreach(LSconfig :: get("LSobjects.$LSobject.attrs", array()) as $attr_name => $attr_config) { foreach(LSconfig :: get("LSobjects.$LSobject.attrs", array()) as $attr_name => $attr_config) {
$raw_attr_rights = LSconfig :: get('rights', array(), 'array', $attr_config); $raw_attr_rights = LSconfig :: get('rights', array(), 'array', $attr_config);
$attr_rights = array(); $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); $attr_rights['self'] = LSconfig :: get('self', False, null, $raw_attr_rights);
foreach(array_keys($LSprofiles) as $LSprofile) { foreach(array_keys($LSprofiles) as $LSprofile) {
$attr_rights[$LSprofile] = LSconfig :: get($LSprofile, False, null, $raw_attr_rights); $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) { foreach(LSconfig :: get("LSobjects.$LSobject.LSrelation", array()) as $relation_name => $relation_config) {
$raw_relation_rights = LSconfig :: get('rights', array(), 'array', $relation_config); $raw_relation_rights = LSconfig :: get('rights', array(), 'array', $relation_config);
$relation_rights = array(); $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); $relation_rights['self'] = LSconfig :: get('self', False, null, $raw_relation_rights);
foreach(array_keys($LSprofiles) as $LSprofile) { foreach(array_keys($LSprofiles) as $LSprofile) {
$relation_rights[$LSprofile] = LSconfig :: get($LSprofile, False, null, $raw_relation_rights); $relation_rights[$LSprofile] = LSconfig :: get($LSprofile, False, null, $raw_relation_rights);
@ -112,7 +112,7 @@ function LSaccessRightsMatrixView() {
reset($LSobjects); reset($LSobjects);
$LSobject = (isset($_REQUEST['LSobject']) && array_key_exists($_REQUEST['LSobject'], $LSobjects)?$_REQUEST['LSobject']:key($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); $LSprofiles = array_merge(array('self' => _('The user him-self')), $LSprofiles);
LSlog :: get_logger('LSaddon_LSaccessRightsMatrixView') -> debug($LSobjects); LSlog :: get_logger('LSaddon_LSaccessRightsMatrixView') -> debug($LSobjects);

View file

@ -87,6 +87,103 @@ class LSauth extends LSlog_staticLoggerClass {
return; 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<count($result); $i++)
$user_objects[$result[$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 * Get LDAP credentials
* *
@ -188,7 +285,7 @@ LSerror :: defineError('LSauth_02',
_("LSauth : Impossible to identify you : Duplication of identities.") _("LSauth : Impossible to identify you : Duplication of identities.")
); );
LSerror :: defineError('LSauth_03', 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', LSerror :: defineError('LSauth_04',
_("LSauth : Can't load authentication method %{method}.") _("LSauth : Can't load authentication method %{method}.")

View file

@ -60,33 +60,18 @@ class LSauthMethod extends LSlog_staticLoggerClass {
* @retval LSldapObject|false The LSldapObject of the user authificated or false * @retval LSldapObject|false The LSldapObject of the user authificated or false
*/ */
public function authenticate() { public function authenticate() {
if (LSsession :: loadLSobject(LSsession :: $ldapServer['authObjectType'])) { $authobjects = LSauth :: username2LSobjects($this -> authData['username']);
$authobject = new LSsession :: $ldapServer['authObjectType'](); if (!$authobjects) {
$result = $authobject -> searchObject( LSerror :: addErrorCode('LSauth_01');
$this -> authData['username'], self :: log_debug("No user found for provided username '".$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];
}
} }
else { elseif (count($authobjects) > 1) {
LSerror :: addErrorCode('LSauth_03'); 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]];
} }
/** /**

View file

@ -51,32 +51,28 @@ class LSauthMethod_basic extends LSauthMethod {
* @retval LSldapObject|false The LSldapObject of the user authificated or false * @retval LSldapObject|false The LSldapObject of the user authificated or false
*/ */
public function authenticate() { public function authenticate() {
$authobject = parent :: authenticate(); $authobjects = LSauth :: username2LSobjects($this -> authData['username']);
if ($authobject) { if (!$authobjects) {
if ( $this -> checkUserPwd($authobject,$this -> authData['password']) ) { LSerror :: addErrorCode('LSauth_01');
// Authentication succeeded self :: log_debug('Invalid username');
return $authobject; return false;
} }
else { $matched = array();
LSerror :: addErrorCode('LSauth_01'); foreach(array_keys($authobjects) as $dn)
LSdebug('mdp incorrect'); if ( LSldap :: checkBind($dn, $this -> authData['password']) )
} $matched[] = $dn;
} if (!$matched) {
return; LSerror :: addErrorCode('LSauth_01');
} self :: log_debug('Invalid password');
return false;
/** }
* Test un couple LSobject/pwd elseif (count($matched) > 1) {
* self :: log_debug('Multiple users match with provided username and password: '.implode(', ', $matched));
* Test un bind sur le serveur avec le dn de l'objet et le mot de passe fourni. LSerror :: addErrorCode('LSauth_02');
* return false;
* @param[in] LSobject L'object "user" pour l'authentification }
* @param[in] string Le mot de passe à tester // Authentication succeeded
* return $authobjects[$matched[0]];
* @retval boolean True si l'authentification a reussi, false sinon.
**/
public static function checkUserPwd($object,$pwd) {
return LSldap :: checkBind($object -> getValue('dn'),$pwd);
} }
} }

View file

@ -84,9 +84,12 @@ class LSsession {
// Libs CSS files to load on page // Libs CSS files to load on page
private static $LibsCssFiles = array(); private static $LibsCssFiles = array();
// L'objet de l'utilisateur connecté // The LSldapObject of connected user
private static $LSuserObject = NULL; private static $LSuserObject = NULL;
// The LSldapObject type of connected user
private static $LSuserObjectType = NULL;
// The LSauht object of the session // The LSauht object of the session
private static $LSauthObject = false; private static $LSauthObject = false;
@ -96,6 +99,39 @@ class LSsession {
// Initialized telltale // Initialized telltale
private static $initialized = false; 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 * Include PHP file
* *
@ -569,15 +605,16 @@ class LSsession {
return; 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'); self :: log_debug('existing session');
// --------------------- Session existante --------------------- // // --------------------- Session existante --------------------- //
self :: $topDn = $_SESSION['LSsession']['topDn']; self :: $topDn = $_SESSION['LSsession']['topDn'];
self :: $dn = $_SESSION['LSsession']['dn']; self :: $dn = $_SESSION['LSsession']['dn'];
self :: $rdn = $_SESSION['LSsession']['rdn']; self :: $LSuserObjectType = $_SESSION['LSsession']['LSuserObjectType'];
self :: $ldapServerId = $_SESSION['LSsession']['ldapServerId']; self :: $rdn = $_SESSION['LSsession']['rdn'];
self :: $tmp_file = $_SESSION['LSsession']['tmp_file']; self :: $ldapServerId = $_SESSION['LSsession']['ldapServerId'];
self :: $userLDAPcreds = $_SESSION['LSsession']['userLDAPcreds']; self :: $tmp_file = $_SESSION['LSsession']['tmp_file'];
self :: $userLDAPcreds = $_SESSION['LSsession']['userLDAPcreds'];
if ( self :: cacheLSprofiles() && !isset($_REQUEST['LSsession_refresh']) ) { if ( self :: cacheLSprofiles() && !isset($_REQUEST['LSsession_refresh']) ) {
self :: setLdapServer(self :: $ldapServerId); self :: setLdapServer(self :: $ldapServerId);
@ -606,7 +643,7 @@ class LSsession {
self :: $_subDnLdapServer = ((isset($_SESSION['LSsession_subDnLdapServer']))?$_SESSION['LSsession_subDnLdapServer']:NULL); self :: $_subDnLdapServer = ((isset($_SESSION['LSsession_subDnLdapServer']))?$_SESSION['LSsession_subDnLdapServer']:NULL);
} }
if (!self :: loadLSobject(self :: $ldapServer['authObjectType'])) { if (!self :: loadLSobject(self :: $LSuserObjectType)) {
return; return;
} }
@ -694,6 +731,7 @@ class LSsession {
if ($LSuserObject) { if ($LSuserObject) {
// Authentication successful // Authentication successful
self :: $LSuserObject = $LSuserObject; self :: $LSuserObject = $LSuserObject;
self :: $LSuserObjectType = $LSuserObject -> getType();
self :: $dn = $LSuserObject->getValue('dn'); self :: $dn = $LSuserObject->getValue('dn');
self :: $rdn = $LSuserObject->getValue('rdn'); self :: $rdn = $LSuserObject->getValue('rdn');
if (isset(self :: $ldapServer['useUserCredentials']) && self :: $ldapServer['useUserCredentials']) { if (isset(self :: $ldapServer['useUserCredentials']) && self :: $ldapServer['useUserCredentials']) {
@ -760,83 +798,95 @@ class LSsession {
* *
* @retval array The recoveryPassword infos for template * @retval array The recoveryPassword infos for template
**/ **/
private static function recoverPasswd($username,$recoveryHash) { private static function recoverPasswd($username, $recoveryHash) {
$recoveryPasswordInfos=array(); // Check feature is enabled and LSmail available
if ( self :: loadLSobject(self :: $ldapServer['authObjectType']) ) { if (!isset(self :: $ldapServer['recoverPassword']) || !self :: loadLSaddon('mail')) {
$authobject = new self :: $ldapServer['authObjectType'](); LSerror :: addErrorCode('LSsession_18');
if (!empty($recoveryHash)) { return;
$filter=Net_LDAP2_Filter::create( }
self :: $ldapServer['recoverPassword']['recoveryHashAttr'],
'equals', // Start LSauth
$recoveryHash 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) { $user = array_pop($users);
self :: log_debug('recoverPasswd(): incorrect hash/username'); $rdn = $user -> getValue('rdn');
LSerror :: addErrorCode('LSsession_06'); $username = $rdn[0];
} self :: log_debug("recoverPasswd(): user found, username = '$username'");
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];
if (checkEmail($emailAddress)) {
self :: log_debug("recoverPasswd(): Email = '$emailAddress'");
self :: $dn = $user -> getDn();
// 1ère étape : envoie du recoveryHash self :: log_debug("recoverPasswd(): start recovering password");
if (empty($recoveryHash)) { $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']);
$hash=self :: recoverPasswdFirstStep($user); $emailAddress = $emailAddress[0];
if ($hash) {
if (self :: recoverPasswdSendMail($emailAddress,1,$hash)) { if (!checkEmail($emailAddress)) {
// Mail a bien été envoyé LSerror :: addErrorCode('LSsession_19');
$recoveryPasswordInfos['recoveryHashMail']=$emailAddress; return;
} }
} self :: log_debug("recoverPasswd(): Email = '$emailAddress'");
} self :: $dn = $user -> getDn();
// 2nd étape : génération du mot de passe + envoie par mail
else { //
$pwd=self :: recoverPasswdSecondStep($user); $recoveryPasswordInfos = array();
if ($pwd) {
if (self :: recoverPasswdSendMail($emailAddress,2,$pwd)){ // First step : send recoveryHash
// Mail a bien été envoyé if (empty($recoveryHash)) {
$recoveryPasswordInfos['newPasswordMail']=$emailAddress; $hash = self :: recoverPasswdFirstStep($user);
} if ($hash) {
} if (self :: recoverPasswdSendMail($emailAddress, 1, $hash)) {
} // Recovery hash sent
} $recoveryPasswordInfos['recoveryHashMail'] = $emailAddress;
else {
LSerror :: addErrorCode('LSsession_19');
}
}
} }
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 * @retval string|False The new password on success or False
**/ **/
private static function recoverPasswdSecondStep($user) { private static function recoverPasswdSecondStep($user) {
$attr = $user -> attrs[self :: $ldapServer['authObjectTypeAttrPwd']]; $pwd_attr_name = LSauth :: getUserPasswordAttribute($user);
if ($attr instanceof LSattribute) { if (array_key_exists($pwd_attr_name, $user -> attrs)) {
$mdp = generatePassword( $pwd_attr = $user -> attrs[$pwd_attr_name];
$attr -> config['html_options']['chars'], $pwd = generatePassword(
$attr -> config['html_options']['lenght'] $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 = $user -> getForm('lostPassword');
$lostPasswdForm -> setPostData( $lostPasswdForm -> setPostData(
array( array(
self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''), self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''),
self :: $ldapServer['authObjectTypeAttrPwd'] => array($mdp) $pwd_attr_name => array($pwd)
) )
,true ,true
); );
if($lostPasswdForm -> validate()) { if($lostPasswdForm -> validate()) {
if ($user -> updateData('lostPassword')) { if ($user -> updateData('lostPassword')) {
return $mdp; return $pwd;
} }
else { else {
// Erreur durant la mise à jour de l'objet // Erreur durant la mise à jour de l'objet
@ -964,7 +1015,7 @@ class LSsession {
} }
else { else {
// l'attribut password n'existe pas // 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); LSerror :: addErrorCode('LSsession_20',1);
} }
return; return;
@ -983,6 +1034,7 @@ class LSsession {
'topDn' => self :: $topDn, 'topDn' => self :: $topDn,
'dn' => self :: $dn, 'dn' => self :: $dn,
'rdn' => self :: $rdn, 'rdn' => self :: $rdn,
'LSuserObjectType' => self :: $LSuserObjectType,
'userLDAPcreds' => self :: $userLDAPcreds, 'userLDAPcreds' => self :: $userLDAPcreds,
'ldapServerId' => self :: $ldapServerId, 'ldapServerId' => self :: $ldapServerId,
'ldapServer' => self :: $ldapServer, '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 * @retval mixed L'objet de l'utilisateur connecté ou false si il n'a pas put
* être créé * être créé
*/ */
public static function getLSuserObject($dn=null) { public static function &getLSuserObject($dn=null) {
if ($dn) { if ($dn) {
self :: $dn = $dn; self :: $dn = $dn;
} }
if (!self :: $LSuserObject) { if (!self :: $LSuserObject) {
if (self :: loadLSobject(self :: $ldapServer['authObjectType'])) { if (self :: $LSuserObjectType && self :: loadLSobject(self :: $LSuserObjectType)) {
self :: $LSuserObject = new self :: $ldapServer['authObjectType'](); self :: $LSuserObject = new self :: $LSuserObjectType();
self :: $LSuserObject -> loadData(self :: $dn); if (!self :: $LSuserObject -> loadData(self :: $dn)) {
self :: $LSuserObject = null;
return;
}
} }
else { else {
return; return;
@ -1024,7 +1079,7 @@ class LSsession {
* @retval boolean True if user connected, false instead * @retval boolean True if user connected, false instead
*/ */
public static function isConnected() { public static function isConnected() {
if (self :: $LSuserObject) if (self :: getLSuserObject())
return true; return true;
return false; 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 * @param[in] $object LSldapObject The new connected user object
* le type doit correspondre à
* self :: $ldapServer['authObjectType']
* *
* @retval boolean True en cas de succès, false sinon * @retval boolean True on succes, false otherwise
*/ */
public static function changeAuthUser($object) { public static function changeAuthUser($object) {
if ($object instanceof self :: $ldapServer['authObjectType']) { if($object instanceof LSldapObject)
self :: $dn = $object -> getDn(); return;
$rdn = $object -> getValue('rdn'); if(!in_array($object -> getType(), LSauth :: getAuthObjectTypes()))
if(is_array($rdn)) { return;
$rdn = $rdn[0]; self :: $dn = $object -> getDn();
} $rdn = $object -> getValue('rdn');
self :: $rdn = $rdn; if(is_array($rdn)) {
self :: $LSuserObject = $object; $rdn = $rdn[0];
}
self :: $rdn = $rdn;
self :: $LSuserObject = $object;
self :: $LSuserObjectType = $object -> getType();
if(self :: loadLSprofiles()) { if(self :: loadLSprofiles()) {
self :: loadLSaccess(); self :: loadLSaccess();
self :: loadLSaddonsViewsAccess(); self :: loadLSaddonsViewsAccess();
$_SESSION['LSsession']=self :: getContextInfos(); $_SESSION['LSsession']=self :: getContextInfos();
return true; return true;
}
} }
return; return;
} }