name); //return strtolower($this->getName()); if ($alias_controller_name == 'ChefSciences') return 'responsables scientifiques (PI)'; if ($alias_controller_name == 'ChefProjets') return 'chefs de projet'; return 'utilisateurs'; } // "l'" utilisateur (et non pas "le utilisateur") // @deprecated // @override parent public function getArticle() { return "L'"; } public $paginate = [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ], 'limit' => 20, 'order' => [ 'Users.nom' => 'asc' ] ]; public function initialize() { parent::initialize(); $this->loadComponent('Paginator'); // déplacé dans beforeFilter() //$this->Auth->allow(['logout']); // Pour autoriser le SIGNUP des nouveaux utilisateurs //$this->Auth->allow(['logout', 'add']); } // 1) AVANT connexion public function beforeFilter(Event $event) { parent::beforeFilter($event); $this->LdapAuth->allow(['logout']); } /* * @Override * * Initialisation des autorisations pour les actions spécifiques à ce controleur * */ protected function setAuthorizations() { /* * a) Noms et verbes à utiliser (surtout dans les notifications) pour les actions * */ $this->setActionsNounAndPastVerb([ 'login' => ['Connexion','connecté'], 'logout' => ['Déconnexion','déconnecté'], ]); /* * b) Actions de ce controleur qui enverront des notifications (log et/ou email) * * 'log' = logger seulement * 'mail' => envoyer un mail seulement * 'both' = faire les 2 (logger ET envoyer un mail) * */ $this->setNotificationAllowedOnActions([ 'login' => 'log', // Ne marchera pas car pas d'utilisateur en session //'logout' => 'log', 'add' => 'log', 'edit' => 'log', 'delete' => 'log', // ... ]); /* * c) Règles d'accès (ACLs) * */ // Actions autorisées à tous foreach (['login', 'logout', 'getLdapLogin', 'getLdapEmail', 'indexRecap'] as $action) $this->setAuthorizationsForAction($action, 0); // Action autorisées seulement à superadmin // TODO: affiner dans le cas d'un LDAP : même superadmin ne doit pas pouvoir supprimer ou modifier (sauf certains attributs) un utilisateur foreach (['add', 'edit', 'delete'] as $action) $this->setAuthorizationsForAction($action, -1, ['super'=>0]); } // setAuthorizations // 2) APRES connexion /** * Give authorization for users * * @param * $user * @return boolean */ /* public function isAuthorized($user, $action=null, $id=null, $role=null, $userCname=null) { // $configuration = $this->confLabinvent; // $role = $this->Users->find()->where(['username' => $user[$configuration->authentificationType_ldap][0]])->first()['role']; // $action = $this->request->getAttribute('params')['action']; $action = $this->getActionPassed(); // Actions de CE controleur accessibles à tous les profils // if (in_array($action, ['index', 'view', 'getLdapLogin', 'getLdapEmail','indexRecap'])) return true; if (in_array($action, [ 'getLdapLogin', 'getLdapEmail', 'indexRecap' ])) return true; // Inutile car déjà dit dans parent::isAuthorized() // Super-Admin peut accéder à toutes les actions de CE controleur // if ($role == 'Super Administrateur') return true; // Par défaut refuser // return false; return parent::isAuthorized($user); } */ // ref: https://book.cakephp.org/4/fr/controllers/components/authentication.html#identifier-les-utilisateurs-et-les-connecter public function login() { ####$this->myDebug("step 2: UsersController.login()"); // Un utilisateur a essayé de se loguer if ($this->request->is('post')) { // Identification du user en utilisant les données POST // - sans LDAP //$user = $this->Auth->identify(); // - avec LDAP (ou fake ldap) // (calls /Controller/Component/LdapAuthComponent.php/connection()) $user = $this->LdapAuth->connection(); //var_dump($user); //debug($user); //if ($user) { if ($user === FALSE) // Utilisateur non reconnu $this->Flash->error(__('Login ou mot de passe invalide, réessayez')); else { // Le login a été accepté // Sauvegarde le user dans la session //$this->Auth->setUser($user); $this->LdapAuth->setUser($user); //DEBUG && debug($user); if (DEBUG) { $pass = $user['userpassword']; unset($user['userpassword']); //debug($user); $user['userpassword'] = $pass; //debug($user); } /* Voici ce que contient $user : - en mode fakeldap : [ 'sn' => [ (int) 0 => 'Pallier' ], 'mail' => [ (int) 0 => 'Etienne.Pallier@irap.omp.eu' ], 'givenname' => [ (int) 0 => 'Etienne' ], 'uid' => [ (int) 0 => 'epallier' ], 'userpassword' => [ (int) 0 => 'mot-de-passe-crypté' ] ] - en mode vrai ldap (IRAP) : [ 'cn' => [ 'count' => (int) 1, (int) 0 => 'Teddy Bai' ], (int) 0 => 'cn', 'mail' => [ 'count' => (int) 1, (int) 0 => 'no_mail' ], (int) 1 => 'mail', ... 'uid' => [ 'count' => (int) 1, (int) 0 => 'tbai' ], (int) 7 => 'uid', 'sn' => [ 'count' => (int) 1, (int) 0 => 'Bai' ], (int) 8 => 'sn', 'givenname' => [ 'count' => (int) 1, (int) 0 => 'Teddy' ], (int) 9 => 'givenname', 'arrivaldate' => [ 'count' => (int) 1, (int) 0 => '02/11/2020' ], (int) 13 => 'arrivaldate', 'birthday' => [ 'count' => (int) 1, (int) 0 => '29/05/1991' ], (int) 14 => 'birthday', 'title' => [ 'count' => (int) 1, (int) 0 => 'M' ], (int) 19 => 'title', 'site' => [ 'count' => (int) 1, (int) 0 => 'Roche' ], (int) 20 => 'site', ... 'dn' => 'uid=tbai,ou=users,dc=irap,dc=omp,dc=eu' ] */ ///if (SessionTimeoutON) $this->statsUpdateForCurrentUserWhen(null,'login'); //$this->statsUpdateForCurrentUserWhen($user,'sur login'); //$this->statsUpdateForCurrentUserOnLogin(); //exit; // On va maintenant à la page qui etait demandée //return $this->redirect($this->Auth->redirectUrl()); return $this->redirect($this->LdapAuth->redirectUrl()); } // login OK } // POST } // login() public function logout() { //debug($this->u); // L'action logout ne passe pas par afterFilter(), // et donc il faut la traiter explicitement... ////if (SessionTimeoutON) // Si user PAS déjà logout, on enregistre sa stat if ($this->LdapAuth->user()) $this->statsUpdateForCurrentUserWhen(null,'logout'); //$this->statsUpdateForCurrentUserOnLogout(); //$this->Flash->success('You are now logged out.'); return $this->redirect($this->LdapAuth->logout()); // Puis ça va sur /users/login } /* * Renvoie les infos de l'utilisateur qui sont dans la session * * Voici ce que contient $_SESSION['Auth']['User'] par exemple : [ 'sn' => [ (int) 0 => 'Pallier' ], 'mail' => [ (int) 0 => 'Etienne.Pallier@irap.omp.eu' ], 'givenname' => [ (int) 0 => 'Etienne' ], 'uid' => [ (int) 0 => 'epallier' ], 'userpassword' => [ (int) 0 => 'mot-de-passe-crypté' ] ] */ private function _getCurrentUserInfosFromSession() { // Current user infos return isset($_SESSION['Auth']['User']) ? $_SESSION['Auth']['User'] : []; } private function _getCurrentUserFullNameFromSession($user_infos = null) { if (!$user_infos) $user_infos = $this->_getCurrentUserInfosFromSession(); //debug($user_infos); // "Pallier Etienne" return $user_infos ? $user_infos['sn'][0].' '.$user_infos['givenname'][0] : 'Name Firstname'; } private function _getCurrentUserLoginFromSession($user_infos = null) { DEBUG && debug($user_infos); if (empty($user_infos)) $user_infos = $this->_getCurrentUserInfosFromSession(); //DEBUG && debug($user_infos); if (DEBUG) { $pass = $user_infos['userpassword']; unset($user_infos['userpassword']); debug($user_infos); debug($user_infos['uid']); $user_infos['userpassword'] = $pass; //debug($user_infos); } if (empty($user_infos)) throw new \ErrorException("Pas d'utilisateur défini dans la session (user_infos empty) !!!"); //if (!$user_infos) $user_infos = $this->_getCurrentUserInfosFromSession(); //if (!$user_infos) throw new \ErrorException("Pas d'utilisateur défini dans la session !!!"); /* debug($user_infos); => ce qui donne : [ 'sn' => [ (int) 0 => 'Utilisateur' ], 'mail' => [ (int) 0 => 'newuser@email.com' ], 'givenname' => [ (int) 0 => 'Newuser' ], 'uid' => [ (int) 0 => 'newuser' ], 'userpassword' => [ (int) 0 => '$2y$10$LZzpws3oDidBcqO/Fy1RTedLLk3ENTmplny5J7bZ6R1PqFoGOw3Ma' ] ] */ // "Pallier Etienne" //$user_login_field_name = $this->authenticationType; //$user_login_field_name = isset($user_infos['uid']) ? 'uid' : 'samaccountname'; $user_login_field_name = isset($user_infos[self::DEFAULT_AUTH_TYPE]) ? self::DEFAULT_AUTH_TYPE : 'samaccountname'; // 'uid' ou 'samaccountname'... if (! isset($user_infos[$user_login_field_name])) { debug($user_login_field_name); debug($user_infos); throw new \ErrorException("La variable $user_infos ne contient pas le user login (ni champ 'uid' ni champ 'samaccountname')"); } //return $user_infos ? $user_infos[$user_login_field_name][0] : 'user_login'; return $user_infos[$user_login_field_name][0]; } private function _getCurrentUserEntityFromSession_ORIG($session_user = null) { $user_fullname = $this->_getCurrentUserFullNameFromSession($session_user); //debug("user_fullname:"); debug($user_fullname); // "Pallier Etienne" return $this->Users->find()->where(['nom'=>$user_fullname])->first(); } private function _getCurrentUserEntityFromSession($session_user = null) { $user_login = $this->_getCurrentUserLoginFromSession($session_user); DEBUG && debug($user_login); // le login if (is_null($user_login)) throw new \ErrorException("Pas de user login trouvé dans la session (user_login is null)"); $user = $this->Users->find()->where(['username'=>$user_login])->first(); DEBUG && debug($user); //$user = null; if (is_null($user)) { debug("Liste des users de la table users :"); $all_users = $this->Users->find()->toArray(); //$all_users = $this->Users->find()->toList(); //debug($all_users); for ($i = 0; $i < 2; $i++) debug($all_users[$i]); throw new \ErrorException("Pas de user trouvé dans la table users pour 'username'=$user_login"); /* Voici ce qui est affiché pour $all_users : object(App\Model\Entity\User) { 'id' => (int) 1, 'created' => null, 'modified' => object(Cake\I18n\FrozenTime) { 'time' => '2019-06-06T14:48:42+02:00', 'timezone' => 'Europe/Paris', 'fixedNowTime' => false }, 'nom' => 'Hillembrand Cedric', 'username' => 'chillembrand', 'email' => 'Cedric.Hillembrand@...', 'role' => 'Super Administrateur', 'groupes_metier_id' => (int) 3, 'is_resp_groupes_metier' => false, 'password' => null, 'groupes_thematique_id' => null, 'is_resp_groupes_thematique' => false, 'sur_categorie_id' => null, '[new]' => false, '[accessible]' => [ '*' => true, 'id' => false ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[hasErrors]' => false, '[errors]' => [], '[invalid]' => [], '[repository]' => 'Users' } object(App\Model\Entity\User) { 'id' => (int) 5, 'created' => null, 'modified' => object(Cake\I18n\FrozenTime) { 'time' => '2019-06-06T14:48:43+02:00', 'timezone' => 'Europe/Paris', 'fixedNowTime' => false }, 'nom' => 'Pallier Etienne', 'username' => 'epallier', 'email' => 'Etienne.Pallier@...', 'role' => 'Super Administrateur', 'groupes_metier_id' => (int) 3, 'is_resp_groupes_metier' => false, 'password' => null, 'groupes_thematique_id' => null, 'is_resp_groupes_thematique' => false, 'sur_categorie_id' => null, '[new]' => false, '[accessible]' => [ '*' => true, 'id' => false ], '[dirty]' => [], '[original]' => [], '[virtual]' => [], '[hasErrors]' => false, '[errors]' => [], '[invalid]' => [], '[repository]' => 'Users' } */ } // $user is null return $user; } // _getCurrentUserEntityFromSession() /* * Mise à jour des stats pour le user courant ($user_infos) (et pour l'année courante) * au moment de l'événement $event_name */ public function statsUpdateForCurrentUserWhen($session_user=null, $event_name) { $user_id = ($event_name=='logout') ? $this->u->id : $this->_getCurrentUserEntityFromSession($session_user)->id; DEBUG && debug($user_id); // l'id du user dans table users if (is_null($user_id)) throw new \ErrorException("Pas de user trouvé dans la session (user_id is null)"); $this->Users->Stats->updateForUserWhen($user_id, $event_name); } /** * Index method * * @return \Cake\Http\Response|null */ public function index() { //debug($this->viewVars); //$priviledgedUsers = $this->Users->find()->where(['role !=' => 'Utilisateur']); // ALL users //$entities = $this->paginate(); // ce qui revient au même que : //$users = $this->paginate($this->Users); // Only priviledged users //$users = $this->paginate($priviledgedUsers); // Affichage informations disponible pour l'utilisateur connecté $this->myDebug($this->LdapAuth->user()); $filtre = $this->request->getQuery('filtre'); // Si on est sur l'instance de l'IRAP (InventIrap), // on affiche l'url vers la page de l'ANNUAIRE du site web du labo $lab_website_urls = $this->confLabinvent->labNameShort != 'IRAP' ? [] : [ "Annuaire IRAP" => 'https://www.irap.omp.eu/annuaire', "Annuaire IRAP (OMP)" => 'http://ezomp2.omp.obs-mip.fr/annuaire/annuaire-irap2', ]; $this->set(compact('lab_website_urls', 'filtre')); $conditions = $filtre ? ['role =' => 'Responsable'] : []; /* $entities = $this->paginate($this->Users->find('all', [ 'conditions' => $conditions ])); */ $contains = [ 'Sites', 'GroupesThematiques', 'GroupesMetiers', 'SurCategories' ]; $sortWhitelist = [ 'nom' => 'nom', 'email' => 'email', 'role' => 'role', 'site_id' => 'Sites.nom', 'groupes_thematique_id' => 'GroupesThematiques.nom', 'groupes_metier_id' => 'GroupesMetiers.nom', 'sur_categorie_id' => 'SurCategories.nom', ]; $orderby = 'nom'; $limit = 20; $this->index_generic( 'utilisateurs', [ 'nom' => [], 'email' => [], 'role' => [], 'site_id'=>[ //'nice_name'=>'Domaine', 'contained_entity_name'=>'site', 'controller_name'=>'Sites', ], 'groupes_thematique_id'=>[ //'nice_name'=>'Groupe Thématique', 'contained_entity_name'=>'groupes_thematique', 'controller_name'=>'GroupesThematiques', 'improved' => 'groupe_thematique_with_resp', ], 'groupes_metier_id'=>[ //'nice_name'=>'Groupe Métier', 'contained_entity_name'=>'groupes_metier', 'controller_name'=>'GroupesMetiers', 'improved' => 'groupe_metier_with_resp', ], 'sur_categorie_id'=>[ //'nice_name'=>'Domaine', 'contained_entity_name'=>'sur_category', 'controller_name'=>'SurCategories', ], ], $contains, false, true, $orderby, $conditions, $sortWhitelist, $limit ); /* $this->paginate = [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ], 'sortWhitelist' => [ 'nom', 'email', 'role', 'GroupesThematiques.nom', 'GroupesMetiers.nom', 'SurCategories.nom', ], 'limit' => 20, /S 'order' => [ 'Users.nom' => 'asc' ] S/ ]; */ /* Inutile si pas de JSON $this->set('_serialize', [ 'users' ]); */ } // index() /** * Index_recap method * * @return \Cake\Http\Response|null */ /* (EP202010 fusionnée avec index()) public function indexRecap() { $this->paginate = [ 'contain' => [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories' ], 'sortWhitelist' => [ 'nom', 'email', 'GroupesThematiques.nom', 'GroupesMetiers.nom', 'SurCategories.nom', ], ]; $entities = $this->paginate($this->Users->find('all', [ 'conditions' => [ 'role =' => 'Responsable' ] ])); // Affichage informations disponible pour l'utilisateur connecté $this->myDebug($this->LdapAuth->user()); /S $this->set('nbUsers', $this->Users->find('all', [ 'conditions' => [ 'role =' => 'Responsable' ] ]) ->count()); S/ $this->set(compact('entities')); /S Uniquement pour JSON $this->set('_serialize', [ 'users' ]); S/ } */ /** * View method * * @param string|null $id * User id. * @return \Cake\Http\Response|null * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ public function view($id = null) { /* $child_entity_types = [ 'GroupesMetiers', 'GroupesThematiques', 'SurCategories', ]; */ //return parent::view($id, $associated_entity_types); //return $this->view_generic($id, $associated_entity_types, 'SurCategories'); //return $this->view_generic($id, $child_entity_types, ['SurCategories']); //$this->view_generic($id, $child_entity_types); $improved = [ 'groupes_thematique_id' => 'groupe_thematique_with_resp', 'groupes_metier_id' => 'groupe_metier_with_resp', ]; $excluded = [ 'is_resp_groupes_metier', 'is_resp_groupes_thematique', 'modified', ]; $this->view_generic($id, [], null, null, null, $improved, $excluded ); return; $user = $this->Users->get($id, [ 'contain' => [ //'Sites', //'GroupesMetiers', //'GroupesThematiques', //'SurCategories' ] ]); $this->set('user', $user); /* (EP) inutile sauf json $this->set('_serialize', [ 'user' ]); */ } /** * Add method * * @return \Cake\Http\Response|void Redirects on successful add, renders view otherwise. */ public function add() { // Création d'un objet User VIDE avec tous les champs $user = $this->Users->newEntity(); // (POST) Un user vient d'être créé, on le sauve en BD, // puis on va sur la vue individuelle de ce nouveau user if ($this->request->is('post')) { $user = $this->Users->patchEntity($user, $this->request->getData()); if ($this->Users->save($user)) { $this->Flash->success(__('L\'utilisateur a bien été ajouté.')); // On va maintenant à la vue individuelle de ce nouvel utilisateur return $this->redirect([ 'action' => 'view', $user->id ]); } else { $this->Flash->error(__('L\'utilisateur n\'a pas pu être ajouté.')); } } // (pas POST) Ici, on vient sur la vue d'ajout (add.ctp) pour la première fois // On prépare donc quelques listes qui seront nécessaires à cette vue $groupesMetiers = $this->Users->GroupesMetiers->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); $groupesThematiques = $this->Users->GroupesThematiques->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); //->toArray(); /* Ajoute l'élément 0 => 'N/A' en tête de tableau * SANS changer les clés !!! // 1) on ajoute un élément vide à la clé "0", // et on trie le tableau sur les values (nom) (en conservant les clés) // => l'élément vide se retrouve donc en tête $groupesThematiques[0] = ''; asort($groupesThematiques); // 2) on remplace l'élément vide (en tête) par 'N/A', qui est donc toujours en tête ! $groupesThematiques[0] = 'N/A'; */ $sur_categorie = $this->Users->SurCategories->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); // TODO: Refactoriser: idem pour add() et edit() (ainsi que leurs pendants dans MaterielsController) $this->setUsersLists(); /* // On recup tous les users du LDAP (ou fakeLDAP si on n'est pas en mode LDAP) //$users = TableRegistry::get('LdapConnections')->getListUsers(); //sort($users); $users_login_and_email = TableRegistry::getTableLocator()->get('LdapConnections')->getUsersLoginAndEmail(); $users_name = array_keys($users_login_and_email); // Formatage en $users_option_list["Etienne Pallier"] = "Etienne Pallier" ... $users_option_list = []; for ($i = 0; $i < sizeof($users_name); $i ++) { $users_option_list[$users_name[$i]] = $users_name[$i]; } */ // On passe à la vue add.ctp toutes les variables créés ci-dessus // "user" est l'utilisateur $user créé au début, et qui est vide $this->set(compact( 'user', 'groupesMetiers', //'users_option_list', 'users_login_and_email', 'groupesThematiques', 'sur_categorie' )); $this->set('_serialize', [ 'user' ]); // Ici, la vue add.ctp (formulaire d'ajout d'un user) est maintenant automatiquement affichée } /** * Edit method * * @param string|null $id * User id. * @return \Cake\Http\Response|void Redirects on successful edit, renders view otherwise. * @throws \Cake\Http\Exception\NotFoundException When record not found. */ public function edit($id = null) { $user = $this->Users->get($id, [ 'contain' => [ //'Sites', ] ]); if ($this->request->is([ 'patch', 'post', 'put' ])) { //debug($this->request->getData()); //exit; /* 'username' => 'pdevoto', 'password' => '$2y$10$nBQMNstgN.sgad1ZANznY.pbJI.ZG/.Q5qX4gC8SXCFQnDIZC8rcW', (from DB = '$2y$10$nBQMNstgN.sgad1ZANznY.pbJI.ZG/.Q5qX4gC8SXCFQnDIZC8rcW') 'email' => 'Pierre.Devoto@irap.omp.eu', 'role' => 'Responsable', 'groupes_metier_id' => '2', 'groupes_thematique_id' => '1', 'sur_categorie_id' => '1' */ $user = $this->Users->patchEntity($user, $this->request->getData()); //debug($user); exit; if ($this->Users->save($user)) { $this->Flash->success(__("L'utilisateur a bien été modifié")); return $this->redirect([ 'action' => 'view', $id ]); } else { //debug($user->getErrors()); $this->Flash->error(__("L'utilisateur n'a pas pu être modifié")); } } $sites = $this->Users->Sites->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); $groupesMetiers = $this->Users->GroupesMetiers->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); $groupesThematiques = $this->Users->GroupesThematiques->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); /* Ajoute l'élément 0 => 'N/A' en tête de tableau ->toArray(); * SANS changer les clés !!! // 1) on ajoute un élément vide à la clé "0", // et on trie le tableau sur les values (nom) (en conservant les clés) // => l'élément vide se retrouve donc en tête $groupesThematiques[0] = ''; asort($groupesThematiques); // 2) on remplace l'élément vide (en tête) par 'N/A', qui est donc toujours en tête ! $groupesThematiques[0] = 'N/A'; */ $sur_categorie = $this->Users->SurCategories->find('list', [ 'keyField' => 'id', 'valueField' => 'nom' ]); $this->set(compact('user', 'sites', 'groupesMetiers', 'groupesThematiques', 'sur_categorie')); /* inutile si pas json $this->set('_serialize', [ 'user' ]); */ } // edit() /** * Delete method * * @param string|null $id * User id. * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ public function delete($id = null) { $this->delete_generic($id); /* $this->request->allowMethod([ 'post', 'delete' ]); $user = $this->Users->get($id); if ($this->Users->delete($user)) { $this->Flash->success(__('L\'utilisateur a bien été supprimé.')); } else { $this->Flash->error(__('L\'utilisateur n\'a pas pu être supprimé.')); } return $this->redirect([ 'action' => 'index' ]); */ } // called from Javascript (Ajax) public function getLdapLogin($userName) { $u = TableRegistry::get('LdapConnections')->getListLoginUsers(); if ($u[$userName] !== null) { $this->set('login', $u[$userName]); } $this->viewBuilder()->layout = 'ajax'; } // called from Javascript (Ajax) public function getLdapEmail($userName) { $u = TableRegistry::get('LdapConnections')->getListEmailUsers(); if ($u[$userName] !== null) { $this->set('email', $u[$userName]); } else { $this->set('email', ' '); } $this->viewBuilder()->layout = 'ajax'; } }