From 4f2027834110c14c1dfd3fe63a05f70e6bf8a39e Mon Sep 17 00:00:00 2001 From: Etienne Pallier Date: Wed, 13 Feb 2019 18:37:55 +0100 Subject: [PATCH] bugfix ldap (again) --- README.md | 2 +- src/Controller/MaterielsController.php | 26 ++++++++++++++++++++++++-- src/Controller/UsersController.php | 4 ++++ src/Model/Table/LdapConnectionsTable.php | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------- src/Template/Materiels/add.ctp | 19 ++++++++++++++++--- src/Template/Users/add.ctp | 2 ++ 6 files changed, 208 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 31a8024..0874c5a 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Logiciel testé et validé sur les configurations suivantes : VERSION ACTUELLE Date: 13/02/2019 -Version: 2.10.9 +Version: 2.10.9.bugfix1 Author: EP Bugfix LDAP anonyme et refactorisation diff --git a/src/Controller/MaterielsController.php b/src/Controller/MaterielsController.php index d4e8d08..1d3d888 100755 --- a/src/Controller/MaterielsController.php +++ b/src/Controller/MaterielsController.php @@ -804,14 +804,24 @@ class MaterielsController extends AppController if ($domaineresp == null) $domaineresp = false; $utilisateurconnect = TableRegistry::get('Users')->find('all')->toArray(); + $users = TableRegistry::get('LdapConnections')->getListUsers(); + //sort($users); + //$users = TableRegistry::get('LdapConnections')->getUsersWithNameAndEmail(); + //$user_names = array_keys($users); + //sort($user_names); // tri des utilisateurs par nom - sort($users); + //sort($users); + //debug($users); + $utilisateurs = $users; + /* $utilisateurs = []; for ($i = 0; $i < sizeof($users); $i ++) { + // $utilisateurs["Etienne Pallier"] = "Etienne Pallier" $utilisateurs[$users[$i]] = $users[$i]; } + */ // Ne pas commenter la ligne suivante, on en a besoin dans add.cpt $mail_responsable = TableRegistry::get('Users')->find() @@ -827,7 +837,19 @@ class MaterielsController extends AppController $this->set('cpMateriel', $cpMateriel); } - $this->set(compact('designation', 'utilisateurconnect', 'users', 'materiel', 'surCategories', 'categories', 'sousCategories', 'groupesThematiques', 'groupesMetiers', 'organismes', 'sites', 'utilisateurs', 'mail_responsable', 'domaineresp', 'lieu_detail', 'fournisseurs')); + //$this->set(compact('designation', 'utilisateurconnect', 'users', 'materiel', 'surCategories', 'categories', 'sousCategories', 'groupesThematiques', 'groupesMetiers', 'organismes', 'sites', 'utilisateurs', 'mail_responsable', 'domaineresp', 'lieu_detail', 'fournisseurs')); + $this->set(compact( + 'materiel', + 'utilisateurconnect', + 'designation', + 'surCategories', 'categories', 'sousCategories', + 'groupesThematiques', 'groupesMetiers', + 'organismes', 'sites', + 'mail_responsable', 'domaineresp', 'lieu_detail', 'fournisseurs', + //'users', + //'user_names', + 'utilisateurs' + )); $this->set('_serialize', [ 'materiel' ]); diff --git a/src/Controller/UsersController.php b/src/Controller/UsersController.php index 98cf5e6..99fcde9 100755 --- a/src/Controller/UsersController.php +++ b/src/Controller/UsersController.php @@ -214,6 +214,8 @@ class UsersController extends AppController 'keyField' => 'id', 'valueField' => 'nom' ]); + // TODO: remplacer getListUsers() par getUsersWithNameAndEmail() + // TODO: idem pour add() et edit() // On recup tous les users du LDAP (ou fakeLDAP si on n'est pas en mode LDAP) $users = TableRegistry::get('LdapConnections')->getListUsers(); // Tri des utilisateurs par nom @@ -308,6 +310,7 @@ class UsersController extends AppController ]); } + /* (EP) Il ne sert à rien de rechercher le login !!! // called from Javascript (Ajax) public function getLdapLogin($userName) { @@ -319,6 +322,7 @@ class UsersController extends AppController $this->viewBuilder()->layout = 'ajax'; } + */ // called from Javascript (Ajax) public function getLdapEmail($userName) diff --git a/src/Model/Table/LdapConnectionsTable.php b/src/Model/Table/LdapConnectionsTable.php index df63fc3..a551d79 100755 --- a/src/Model/Table/LdapConnectionsTable.php +++ b/src/Model/Table/LdapConnectionsTable.php @@ -173,6 +173,42 @@ class LdapConnectionsTable extends AppTable '); } + + + // 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() { @@ -181,7 +217,16 @@ class LdapConnectionsTable extends AppTable // REAL LDAP if ($this->LDAP_USED) { - $res = $this->searchLdap($this->filter, []); + + // 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); + } /* $ldapConnection = ldap_connect($this->host, $this->port); ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); @@ -198,15 +243,43 @@ class LdapConnectionsTable extends AppTable // FAKE LDAP else { - $res = $this->fakeLDAPUsers; + $users_fetched = $this->fakeLDAPUsers; } - return $res; + + // Noter que $user_fetched peut etre egal a FALSE (si rien trouvé) + return $users_fetched; } } catch (Exception $e) {} - return false; + + // Pb, rien trouvé + return FALSE; } + + // $userName = login + public function getUserAttributes($userName) + { + try { + + if ($this->checkConfiguration()) { + if ($this->USE_LDAP) { + $ldapConnection = ldap_connect($this->host, $this->port); + ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); + $results = ldap_search($ldapConnection, $this->baseDn, '(' . $this->authenticationType . '=' . $userName . ')'); + return ldap_get_entries($ldapConnection, $results); + } else + return array( + $this->getFakeLdapUser($userName) + ); + } + } catch (Exception $e) {} + + return false; + } + + + // REAL LDAP only /* * @param string $ldapConnection @@ -281,19 +354,43 @@ class LdapConnectionsTable extends AppTable return FALSE; } + // TODO: à implémenter + public function getUsersWithNameAndEmail() { + $usersWithNameAndEmail = []; + // 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; + for ($i = 0; $i < $nb_users; $i ++) + // $utilisateurs["Pallier Etienne"] = ["email"] + $usersWithNameAndEmail[ $u[$i]['sn'][0].' '.$u[$i]['givenname'][0] ] = $u[$i]['mail'][0]; + //debug($usersWithNameAndEmail); + // Sort users (without modifying the keys, don't use sort() but asort() !!!!!!!!!!!!!) + asort($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); - $utilisateurs = []; // (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; for ($i = 0; $i < $nb_users; $i ++) - // $utilisateurs["Pallier Etienne"] = "Pallier Etienne" + // $utilisateurs["Pallier Etienne"] = "Pallier Etienne" $utilisateurs[ $u[$i]['sn'][0].' '.$u[$i]['givenname'][0] ] = $u[$i]['sn'][0].' '.$u[$i]['givenname'][0]; /* if ($this->LDAP_USED) { @@ -307,6 +404,9 @@ class LdapConnectionsTable extends AppTable } */ //debug($utilisateurs); + // Sort users (without modifying the keys, don't use sort() but asort() !!!!!!!!!!!!!) + asort($utilisateurs); + //debug($utilisateurs); return $utilisateurs; } @@ -386,6 +486,8 @@ class LdapConnectionsTable extends AppTable // TODO: implement // REAL LDAP only private function checkAndFetchUserFromDB($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 // By default, user is not in DB return FALSE; } @@ -394,44 +496,44 @@ class LdapConnectionsTable extends AppTable // REAL LDAP only private function searchLdap($filter, $just_these, $user_login=NULL, $user_password=NULL) { - // CONNEXION - $ldapConnection = ldap_connect($this->host, $this->port) - or die("Could not connect to $this->host (port $this->port)"); - - if ($ldapConnection) { + // CONNEXION + $ldapConnection = ldap_connect($this->host, $this->port) + or die("Could not connect to $this->host (port $this->port)"); + + if ($ldapConnection) { + + // OPTIONS + ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); - // OPTIONS - ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); - - // BINDING - - // - Authentified - if ($this->ldap_authentified) - $ldapbind = ldap_bind($ldapConnection, $this->bindDn, $this->bindPass); // or die("Could not bind to LDAP server.". ldap_error($ldapConnection) ); - - // - Anonymous - // En cas de LDAP anonyme, binding quand même pour vérifier le mot de passe de l'utilisateur. - // Sans cette ligne, on passe avec n'importe quel password !!! - else { - $ldapbind = TRUE; - debug("log, pass= " . $user_login . ' ' . $user_password); - if ($user_login && $user_password) $ldapbind = ldap_bind($ldapConnection, $this->authenticationType.'='.$user_login, $user_password); - debug("ldapbind " . $ldapbind); - } - - // SEARCH - if ($ldapbind) { - //$search = $this->getLdapUserAttributes($ldapConnection, $filter, $just_these, $user_login); - $search = $this->getLdapUsersAttributes($ldapConnection, $filter, $just_these); - if ($search === false) die("Could not get user attributes from LDAP server, response was: " . ldap_error($ldapConnection) ); - //return $search[0]; - return $search; - } + // BINDING + // - Authentified + if ($this->ldap_authentified) + $ldapbind = ldap_bind($ldapConnection, $this->bindDn, $this->bindPass); // or die("Could not bind to LDAP server.". ldap_error($ldapConnection) ); + + // - Anonymous + // En cas de LDAP anonyme, binding quand même pour vérifier le mot de passe de l'utilisateur. + // Sans cette ligne, on passe avec n'importe quel password !!! + else { + $ldapbind = TRUE; + debug("log, pass= " . $user_login . ' ' . $user_password); + if ($user_login && $user_password) $ldapbind = ldap_bind($ldapConnection, $this->authenticationType.'='.$user_login, $user_password); + debug("ldapbind " . $ldapbind); } - // Il y a eu un pb, utilisateur non reconnu - return FALSE; + // SEARCH + if ($ldapbind) { + //$search = $this->getLdapUserAttributes($ldapConnection, $filter, $just_these, $user_login); + $search = $this->getLdapUsersAttributes($ldapConnection, $filter, $just_these); + 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; } @@ -518,23 +620,38 @@ class LdapConnectionsTable extends AppTable try { if ($this->checkConfiguration()) { - // We are using LDAP - if ($this->LDAP_USED) { + // REAL LDAP + if ($this->LDAP_USED) { + // No connexion allowed without password if (strlen(trim($user_password)) == 0) return FALSE; + + // VIEUX CODE QUI MARCHE !!! + $ldapConnection = ldap_connect($this->host, $this->port); + ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); + if (@ldap_bind($ldapConnection, $this->authenticationType . '=' . $user_login . ',' . $this->baseDn, $user_password)) { + return $this->getUserAttributes($login)[0]; + /* + * } else { + * return false; + */ + } + /* NEW CODE QUI MARCHE PAS + // TODO: optimisation possible // 1) Search user in CACHE (DB) $user_fetched = $this->checkAndFetchUserFromDB($user_login, $user_password); - if ($user_fetched === FALSE) { // 2) If not CACHED, search user in LDAP + if ($user_fetched === FALSE) { $user_fetched = $this->checkAndFetchUserFromLdap($user_login, $user_password); // CACHE the new user in DB for next time if ($user_fetched != FALSE) $this->saveNewUserInDB($user_fetched); } return $user_fetched; // Noter que $user_fetched peut etre egal a FALSE (si pas trouvé) + */ } - // We are not using LDAP (so, use FAKE LDAP instead) + // FAKE LDAP else { $user = $this->getFakeLdapUser($user_login); // debug($user); diff --git a/src/Template/Materiels/add.ctp b/src/Template/Materiels/add.ctp index 943413f..5fcea3e 100755 --- a/src/Template/Materiels/add.ctp +++ b/src/Template/Materiels/add.ctp @@ -1,4 +1,12 @@ designation; @@ -201,26 +209,31 @@ if (isset($cpMateriel)) { 'empty' => 'Choisir un utilisateur', 'default' => $username, 'options' => $utilisateurs + //'options' => $user_names ]); echo $this->Form->control('email_responsable', [ 'label' => 'Email de l\'utilisateur', 'readonly' => true, 'default' => $mail_responsable ]); + + /* $res = TableRegistry::get('Users')->find() ->where([ 'username' => $username, 'role' => 'Administration' ]) - ->first(); + ->first(); + */ $administrateurs = TableRegistry::get('Users')->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]) - ->where([ + ->where([ 'role =' => 'Administration' ]) - ->toArray(); + ->toArray(); + echo $this->Form->control('gestionnaire_id', [ 'label' => 'Nom du gestionnaire de référence du matériel', 'empty' => 'Choisir un gestionnaire', diff --git a/src/Template/Users/add.ctp b/src/Template/Users/add.ctp index 0302a76..a655635 100755 --- a/src/Template/Users/add.ctp +++ b/src/Template/Users/add.ctp @@ -103,12 +103,14 @@ $(document).ready(function () { }).done(function(data) { $("#email").val(data) }); + /* (EP) il ne sert à rien de rechercher le login !!! var loginUrl = url.replace("add", "getLdapLogin/"); $.ajax({ url: loginUrl + $("#nom").val() }).done(function(data) { $("#username").val(data) }); + */ }); }); -- libgit2 0.21.2