DEBUG_MODE) {
//Configure::write('debug', true);
debug($arg);
if ($stop) exit();
}
}
public function __construct()
{
parent::__construct();
}
// EP
public function useFakeLdap()
{
return ! $this->useLdap();
}
public function useLdap()
{
$this->checkConfiguration();
return $this->LDAP_USED;
}
private function buildFakeLdapUsers()
{
return $this->buildFakeLdapUsersFromDB();
}
private function buildFakeLdapUsersFromDB()
{
$users = TableRegistry::getTableLocator()->get('Users')->find();
$ldapUsers = [];
foreach ($users as $user) {
$names = explode(" ", $user['nom']);
$givenName = isset($names[1]) ? $names[1] : " ";
$ldapUsers[] = [
// Nom
'sn' => [
$names[0]
],
// Email
'mail' => [
$user['email']
],
// Pnom
'givenname' => [
$givenName
],
// Login ("uid" for IRAP, "samaccountname" for CRAL)
$this->authenticationType => [
$user['username']
],
// Pass
'userpassword' => [
$user['password']
]
];
}
/* EP (aout 2017)
* ATTENTION : Utilisateur IMPORTANT.
* Avec cet utilisateur, on simule un utilisateur qui n'est PAS dans la table utilisateurs
* Il devrait donc se voir attribuer un role "Utilisateur" sans pour autant que ça soit écrit dans la table !!!
* login = '_NouvelUtilisateur_username'
* pass = '_NouvelUtilisateur_password'
* $prefix = "_NouvelUtilisateur_";
*/
$ldapUsers[] = [
'sn' => [
'UTILISATEUR'
],
'givenname' => [
'FAKE_LDAP'
],
// 'mail' => [$login.'email'],
'mail' => [
'fakeldapuser@domain.fr'
],
// $this->authenticationType => [$prefix.'username'],
$this->authenticationType => [
$this->getTheFakeLdapUser()['login']
],
// $this->authenticationType => ['usere'],
'userpassword' => [
$this->getTheFakeLdapUser()['pass']
]
// 'userpassword' => ['toto'],
];
return $ldapUsers;
}
private function checkConfiguration()
{
$config = TableRegistry::getTableLocator()->get('Configurations')
->find()
->where(['id =' => 1])
->first();
$this->DEBUG_MODE = $config->mode_debug;
$this->LDAP_USED = $config->ldap_used;
if (! $this->LDAP_USED) {
$this->authenticationType = $config->ldap_authenticationType;
if (empty($this->fakeLDAPUsers))
$this->fakeLDAPUsers = $this->buildFakeLdapUsers();
return true;
}
// debug($this->fakeLDAPUsers);
$ldapConfig = $config->toArray();
if (! empty($config->ldap_host) && ! empty($config->ldap_port) && ! empty($config->ldap_baseDn) && ! empty($config->ldap_authenticationType) && ! empty($config->ldap_filter)) {
$this->host = $config->ldap_host;
$this->port = $config->ldap_port;
$this->baseDn = $config->ldap_baseDn;
$this->filter = $config->ldap_filter;
$this->authenticationType = $config->ldap_authenticationType;
$this->ldap_authentified = $config->ldap_authentified;
$this->bindDn = $config->ldap_bindDn;
$this->bindPass = $config->ldap_bindPass;
return true;
}
throw new Exception('The ldap configuration is not valid :
- host = ' . @$ldapConfig['host'] . '
- port = ' . @$ldapConfig['port'] . '
- baseDn = ' . @$ldapConfig['baseDn'] . '
- filter = ' . @$ldapConfig['filter'] . '
- authenticationType = ' . @$ldapConfig['authenticationType'] . '
');
}
// REAL LDAP only
/**
* @return array or boolean : all users from DB (CACHE of the LDAP) or FALSE (if table emtpy or expired data)
*/
private function fetchAllUsersFromDB() {
// On remet à jour tous les 7 jours
$PEREMPTION_NB_DAYS = 7;
// Doit aussi retourner FALSE si la ligne FAKE de la table users
// (celle qui contient le user_name "FAKE_USER")
// a une date "updated" périmée (now - updated > $PEREMPTION_NB_DAYS)
// (update automatique de tous les users, chaque semaine, pour rester synced avec le LDAP)
// By default, no user in CACHE
return FALSE;
}
// REAL LDAP only
// Sauvegarde de tous les users du LDAP en BD (avec un rythme de mise à jour hebdo)
// Seulement les champs: nom, pnom, login, pass, email, create, updated, profile
private function saveAllUsersInDB($users_fetched) {
// START TRANSACTION
// 1) Update (ou création) de la ligne FAKE (contient le user_name "FAKE_USER") => avec une date "updated"
// 2) Update (ou création) de chaque user contenu dans $users_fetched
// Attention à ne pas perdre l'attribut "profile", surtout pour les users privilégiés!!! (les autres ont un profile = "Utilisateur")
// END TRANSACTION (COMMIT)
// SAVE s'est bien passé
return TRUE;
}
/**
* @return $users_fetched or FALSE
*/
// REAL or FAKE LDAP
public function getAllLdapUsers()
{
try {
if ($this->checkConfiguration()) {
// REAL LDAP
if ($this->LDAP_USED) {
// 1) Search users in CACHE (DB)
$users_fetched = $this->fetchAllUsersFromDB();
// 2) Not found in CACHE, so search users in LDAP
if ($users_fetched === FALSE) {
$users_fetched = $this->searchLdap($this->filter, []);
// CACHE the new user in DB for next time
if ($users_fetched !== FALSE) $this->saveAllUsersInDB($users_fetched);
}
}
// FAKE LDAP
else {
$users_fetched = $this->fakeLDAPUsers;
}
// Noter que $user_fetched peut etre egal a FALSE (si rien trouvé)
return $users_fetched;
}
}
catch (Exception $e) {}
// Pb, rien trouvé
return FALSE;
}
public function getAuthenticationType()
{
return $this->authenticationType;
}
// EP added
public function getFakeLdapUser($login)
{
foreach ($this->fakeLDAPUsers as $user) {
if ($login == $user[$this->authenticationType][0])
return $user;
}
return FALSE;
}
/**
* Return a list of Users with key = username & value = email
*/
public function getUsersLoginAndEmail() {
$usersWithNameAndEmail = [];
// Get all users (with ALL their attributes)
$u = $this->getAllLdapUsers();
// Sort users
//sort($u);
//debug($u);
$this->mydebugmsg("ldap users 0 and 1:");
$this->mydebugmsg($u[0]);
$this->mydebugmsg($u[1]);
// (EP) Refactorisation pour éviter code redondant du temps des stagiaires...
$nb_users = $this->LDAP_USED ? $u['count'] : sizeof($u)-1;
for ($i = 0; $i < $nb_users; $i ++)
// $utilisateurs["Pallier Etienne"] = ["email"]
////$usersWithNameAndEmail[ $u[$i]['sn'][0].' '.$u[$i]['givenname'][0] ] = $u[$i]['mail'][0];
$usersWithNameAndEmail[ $u[$i]['sn'][0].' '.$u[$i]['givenname'][0] ] = array(
//"login" => $u[$i]['uid'][0] // (IRAP)
//"login" => $u[$i]['samaccountname'][0] // CRAL
"login" => $u[$i][$this->authenticationType][0],
"email" => $u[$i]['mail'][0]
);
// Sort users (without modifying the keys, don't use sort() but asort() !!!!!!!!!!!!!)
ksort($usersWithNameAndEmail);
//debug($usersWithNameAndEmail);
return $usersWithNameAndEmail;
}
/**
* Return a list of Users with key = username & value = username
*/
public function getListUsers()
{
$utilisateurs = [];
// Get all users (with ALL their attributes)
$u = $this->getAllLdapUsers();
// Sort users
//sort($u);
//debug($u);
// (EP) Refactorisation pour éviter code redondant ci-dessous, c'était pourtant pas compliqué, poil dans la main...
$nb_users = $this->LDAP_USED ? $u['count'] : sizeof($u)-1;
// $utilisateurs["Pallier Etienne"] = "Pallier Etienne"
for ($i = 0; $i < $nb_users; $i ++)
$utilisateurs[ $u[$i]['sn'][0].' '.$u[$i]['givenname'][0] ] = $u[$i]['sn'][0].' '.$u[$i]['givenname'][0];
//debug($utilisateurs);
// Sort users (without modifying the keys, don't use sort() but asort() !!!!!!!!!!!!!)
ksort($utilisateurs);
//debug($utilisateurs);
return $utilisateurs;
}
/**
* Return a list of login ofUsers with key = username & value = login
*/
public function getListLoginUsers()
{
$u = $this->getAllLdapUsers();
$utilisateurs = [];
if ($this->LDAP_USED) {
for ($i = 0; $i < $u['count']; $i ++) {
$utilisateurs[$u[$i]['sn'][0] . ' ' . $u[$i]['givenname'][0]] = $u[$i][$this->authenticationType][0];
}
} else {
for ($i = 0; $i < sizeof($u) - 1; $i ++) {
$utilisateurs[$u[$i]['sn'][0] . ' ' . $u[$i]['givenname'][0]] = $u[$i][$this->authenticationType][0];
}
}
return $utilisateurs;
}
/**
* Return a list of mail of Users with key = username & value = mail
*/
public function getListEmailUsers()
{
$u = $this->getAllLdapUsers();
$utilisateurs = [];
if ($this->LDAP_USED) {
for ($i = 0; $i < $u['count']; $i ++) {
if (isset($u[$i]['mail'][0])) {
$utilisateurs[$u[$i]['sn'][0] . ' ' . $u[$i]['givenname'][0]] = $u[$i]['mail'][0];
} else {
$utilisateurs[$u[$i]['sn'][0] . ' ' . $u[$i]['givenname'][0]] = 'N/A';
}
}
} else {
for ($i = 0; $i < sizeof($u) - 1; $i ++) {
$utilisateurs[$u[$i]['sn'][0] . ' ' . $u[$i]['givenname'][0]] = $u[$i]['mail'][0];
}
}
return $utilisateurs;
}
/**
* Return size of list users
public function getNbUsers()
{
$u = $this->getAllLdapUsers();
if ($this->LDAP_USED) {
$nbUsers = $u['count'];
} else {
$nbUsers = sizeof($u) - 1;
}
return $nbUsers;
}
*/
// Utilisateur du ldap qui n'est pas dans la table utilisateurs
// => il a donc le role "Utilisateur" PAR DEFAUT
private function getTheFakeLdapUser()
{
return [
'login' => '_fake_ldap_user_',
'pass' => '_fake_ldap_user_pass'
];
}
// REAL LDAP only
//TODO:
private function _formatUserFromDbAsLDAP($user) {
return $user;
}
// REAL LDAP only
private function checkAndFetchLDAPUserFromDB($user_login, $user_password) {
// Doit aussi return false si ce user_login est "périmé" (sa date "created" est > 2 mois par exemple),
// ce qui obligera à relire ses données dans le LDAP et donc se mettre à jour
if (! $this->LDAP_CACHED) return FALSE;
// Search user in DB
$user = TableRegistry::getTableLocator()->get('Users')->find()
->where([
'username' => $user_login
])
->first();
if (!is_null($user)) {
$user = $this->_formatUserFromDbAsLDAP($user);
}
// By default, user is not in DB
return FALSE;
}
// REAL LDAP only
// SEARCH en 4 étapes
private function searchLdap($filter, $just_these, $user_login=NULL, $user_password=NULL) {
// (1) CONNEXION
$ldapConnection = ldap_connect($this->host, $this->port)
or die("Could not connect to $this->host (port $this->port)");
if ($ldapConnection) {
// (2) SET OPTIONS
ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3);
// (3) BINDING OPTIONNEL (true by default if not done)
$ldapbind = TRUE;
// - Authentified LDAP
// (EP) ATTENTION: Ne pas faire die() ici car ça stopperait net la mauvaise connexion d'un utilisateur, avec ce message d'erreur !
// Il vaut mieux retourner FALSE et afficher un joli message de refus sur la page d'accueil
if ($this->ldap_authentified)
//$ldapbind = @ldap_bind($ldapConnection, $this->bindDn, $this->bindPass);
$ldapbind = ldap_bind($ldapConnection, $this->bindDn, $this->bindPass);
//or die("Could not bind to LDAP server.". ldap_error($ldapConnection) );
// - Anonymous LDAP
// (EP) En cas de LDAP anonyme, binding uniquement si login session (pour vérifier le mot de passe de l'utilisateur).
// Car sans cette ligne, on passe avec n'importe quel password !!!
// NB: pas de die() ici, voir remarque juste au-dessus
else if ($user_login && $user_password)
//$ldapbind = @ldap_bind($ldapConnection, $this->authenticationType . '=' . $user_login . ',' . $this->baseDn, $user_password);
$ldapbind = ldap_bind($ldapConnection, $this->authenticationType . '=' . $user_login . ',' . $this->baseDn, $user_password);
// or die("Could not bind to LDAP server: ". ldap_error($ldapConnection) );
// (4) SEARCH
if ($ldapbind) {
// $filter = "(&".$this->filter."(".$this->authenticationType . '=' . $user_login."))";
// ex: (&(compteinfo=Oui)(uid=epallier))
$results = ldap_search($ldapConnection, $this->baseDn, $filter, $just_these)
or die("Could not search to LDAP server response was: " . ldap_error($ldapConnection) );
$search = ldap_get_entries($ldapConnection, $results);
//echo $results["count"]." entries returned\n";
if ($search === FALSE) die("Could not get user attributes from LDAP server, response was: " . ldap_error($ldapConnection) );
//return $search[0];
return $search;
}
}
// Il y a eu un pb, utilisateur non reconnu
return FALSE;
} // searchLdap()
// TODO: implement
private function saveNewUserInDB($user_fetched) {
// SAVE new user in DB
return TRUE;
}
/*
* @param string $user_login
* @param string $user_password
* @return logged user LDAP attributes or FALSE if user not found in LDAP
*/
public function ldapAuthentication($user_login, $user_password) {
try {
if ($this->checkConfiguration()) {
// REAL LDAP
if ($this->LDAP_USED) {
// No connexion allowed without password
if (strlen(trim($user_password)) == 0) return FALSE;
// TODO: optimisation possible
// 1) Search user in CACHE (DB)
$user_fetched = $this->checkAndFetchLDAPUserFromDB($user_login, $user_password);
// 2) If not CACHED, search user in LDAP
if ($user_fetched === FALSE) {
//$user_fetched = $this->checkAndFetchUserFromLdap($user_login, $user_password);
$just_these = [];
// TODO: vérifier si cette ligne est bien utile ou pas... (avant on faisait ça)
//if (! $this->ldap_authentified) $just_these = array("cn");
// Construction du filtre avec le filtre de la base de données avec un & sur le login de l'utilisateur
// Si aucun filtre n'est défini dans la base de données on aura juste (& ($this->authenticationType=$user_login))
// ex: "(&(objectClass=person)(memberOf:1.2.840.113556.1.4.1941:=cn=ucbl.osu.cral,ou=groups,ou=27,ou=sim,ou=univ-lyon1,dc=univ-lyon1,dc=fr)(sAMAccountName=$user_login))";
$filter = "(&".$this->filter."(".$this->authenticationType . '=' . $user_login."))";
//TODO: optimisation, refactoriser si comportement général
//$binddn .= ','.$this->baseDn;
$user_fetched = $this->searchLdap($filter, $just_these, $user_login, $user_password);
// CACHE the new user in DB for next time
if ($user_fetched != FALSE) {
$this->saveNewUserInDB($user_fetched[0]);
return $user_fetched[0];
}
}
else {
debug("user found in DB");
debug($user_fetched);
}
//return $user_fetched; // Noter que $user_fetched peut etre egal a FALSE (si pas trouvé)
}
// FAKE LDAP
else {
//debug($this->USE_LDAP);
//debug($this->baseDn);
$user = $this->getFakeLdapUser($user_login);
// debug($user);
//if ($user === false) return FALSE;
if ($user !== false) {
// $this->authenticationType peut valoir "uid" ou "cn"... (par défaut "uid" pour le fake ldap, à confirmer...)
// if ($user['uid'][0] == "_NouvelUtilisateur_username" && $user['userpassword'][0] == "_NouvelUtilisateur_password") return $user;
// if ($user[$this->authenticationType][0] == "_NouvelUtilisateur_username" && $user['userpassword'][0] == "_NouvelUtilisateur_password") return $user;
if ($user[$this->authenticationType][0] == $this->getTheFakeLdapUser()['login'] && $user['userpassword'][0] == $this->getTheFakeLdapUser()['pass'])
return $user;
if ( (new DefaultPasswordHasher())->check($user_password,$user['userpassword'][0]) )
return $user;
// if ($user != false && $user['userpassword'][0] == $password) {
}
}
}
} catch (Exception $e) {
//echo 'Exception LDAP : ', $e->getMessage(), "\n";
}
// Il y a eu un problème, l'utilisateur n'est pas reconnu
return FALSE;
} // end ldapAuthentication()
}
?>