From 35f8127dca6e3c61d4e7c0ba487b4925f246729b Mon Sep 17 00:00:00 2001
From: Bertrand Gauthier <bertrand.gauthier@unicaen.fr>
Date: Wed, 23 May 2018 13:46:14 +0200
Subject: [PATCH] Action usurperIdentite manquante!

---
 .../Controller/UtilisateurController.php      | 135 +++++++++++++++++-
 1 file changed, 133 insertions(+), 2 deletions(-)

diff --git a/src/UnicaenAuth/Controller/UtilisateurController.php b/src/UnicaenAuth/Controller/UtilisateurController.php
index fbb9fc5..18bccc4 100644
--- a/src/UnicaenAuth/Controller/UtilisateurController.php
+++ b/src/UnicaenAuth/Controller/UtilisateurController.php
@@ -2,14 +2,30 @@
 
 namespace UnicaenAuth\Controller;
 
+use UnicaenApp\Exception\RuntimeException;
+use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper;
+use UnicaenAuth\Entity\Db\AbstractUser;
+use UnicaenAuth\Entity\Ldap\People;
+use UnicaenAuth\Entity\Shibboleth\ShibUser;
+use UnicaenAuth\Options\ModuleOptions;
+use UnicaenAuth\Service\ShibService;
+use UnicaenAuth\Service\UserContext;
+use Zend\Authentication\AuthenticationService;
 use Zend\Http\Request;
+use Zend\Http\Response;
 use Zend\Mvc\Controller\AbstractActionController;
+use ZfcUser\Mapper\User as UserMapper;
 
 /**
  * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr>
  */
 class UtilisateurController extends AbstractActionController
 {
+    /**
+     * @var LdapPeopleMapper
+     */
+    protected $ldapPeopleMapper;
+
     /**
      * Traite les requêtes AJAX POST de sélection d'un profil utilisateur.
      * La sélection est mémorisé en session par le service AuthUserContext.
@@ -43,12 +59,127 @@ class UtilisateurController extends AbstractActionController
 
         return false;
     }
-    
+
     /**
-     * @return \UnicaenAuth\Service\UserContext
+     * Usurpe l'identité d'un autre utilisateur.
+     *
+     * @return Response
+     */
+    public function usurperIdentiteAction()
+    {
+        $request = $this->getRequest();
+        if (! $request instanceof Request) {
+            exit(1);
+        }
+
+        $newIdentity = $request->getQuery('identity', $request->getPost('identity'));
+        if (! $newIdentity) {
+            return $this->redirect()->toRoute('home');
+        }
+
+        /** @var AuthenticationService $authenticationService */
+        $authenticationService = $this->getServiceLocator()->get(AuthenticationService::class);
+
+        $currentIdentity = $authenticationService->getIdentity();
+        if (! $currentIdentity || ! is_array($currentIdentity)) {
+            return $this->redirect()->toRoute('home');
+        }
+
+        if (isset($currentIdentity['ldap'])) {
+            // si l'identifiant demandé contient un @, on estime qu'il s'agit d'un eppn shibboleth : on autorise pas le mélange des genres!
+            // todo: faire mieux
+            if (strpos($newIdentity, '@') !== false) {
+                throw new RuntimeException("Usurpation Shibboleth interdite depuis une authentification LDAP");
+            }
+            /** @var People $currentIdentity */
+            $currentIdentity = $currentIdentity['ldap'];
+
+            // vérif existence de l'individu dans l'annuaire LDAP
+            $ldapPeople = $this->getLdapPeopleMapper()->findOneByUsername($newIdentity);
+            if (!$ldapPeople) {
+                throw new RuntimeException("Identifiant LDAP inconnu");
+            }
+        } elseif (isset($currentIdentity['shib'])) {
+            // si l'identifiant demandé ne contient pas @, on estime qu'il s'agit d'un identifiant LDAP : on autorise pas le mélange des genres!
+            // todo: faire mieux
+            if (strpos($newIdentity, '@') === false) {
+                throw new RuntimeException("Usurpation LDAP interdite depuis une authentification Shibboleth");
+            }
+            /** @var ShibUser $currentIdentity */
+            $currentIdentity = $currentIdentity['shib'];
+        }
+        else {
+            return $this->redirect()->toRoute('home');
+        }
+
+        // seuls les logins spécifiés dans la config sont habilités à usurper des identités
+        /** @var ModuleOptions $options */
+        $options = $this->getServiceLocator()->get('unicaen-auth_module_options');
+        if (! in_array($currentIdentity->getUsername(), $options->getUsurpationAllowedUsernames())) {
+            throw new RuntimeException("Usurpation non explicitement autorisée");
+        }
+
+        // cuisine spéciale pour Shibboleth
+        if ($currentIdentity instanceof ShibUser) {
+            $fromShibUser = $currentIdentity;
+            $toShibUser = $this->createShibUserFromUtilisateurUsername($newIdentity);
+            /** @var ShibService $shibService */
+            $shibService = $this->getServiceLocator()->get(ShibService::class);
+            $shibService->activateUsurpation($fromShibUser, $toShibUser);
+        }
+
+        $authenticationService->getStorage()->write($newIdentity);
+
+        return $this->redirect()->toRoute('home');
+    }
+
+    /**
+     * Recherche l'utilisateur dont le login est spécifié puis instancie un ShibUser à partir
+     * des attributs de cet utilisateur.
+     *
+     * @param string $username Ex tartempion@unicaen.fr
+     * @return ShibUser
+     */
+    protected function createShibUserFromUtilisateurUsername($username)
+    {
+        /** @var AbstractUser $utilisateur */
+        $utilisateur = $this->getUserMapper()->findByUsername($username);
+        if ($utilisateur === null) {
+            throw new RuntimeException("L'utilisateur '$username' n'existe pas dans la table des utilisateurs");
+        }
+
+        $shibUser = new ShibUser();
+        $shibUser->setEppn($utilisateur->getUsername());
+        $shibUser->setId(uniqid()); // peut pas mieux faire pour l'instant
+        $shibUser->setDisplayName($utilisateur->getDisplayName());
+        $shibUser->setEmail($utilisateur->getEmail());
+        $shibUser->setNom('?');     // peut pas mieux faire pour l'instant
+        $shibUser->setPrenom('?');  // peut pas mieux faire pour l'instant
+
+        return $shibUser;
+    }
+
+    /**
+     * @return UserMapper
+     */
+    public function getUserMapper()
+    {
+        return $this->getServiceLocator()->get('zfcuser_user_mapper');
+    }
+
+    /**
+     * @return UserContext
      */
     protected function getAuthUserContextService()
     {
         return $this->getServiceLocator()->get('AuthUserContext');
     }
+
+    /**
+     * @return LdapPeopleMapper
+     */
+    public function getLdapPeopleMapper()
+    {
+        return $this->serviceLocator->get('ldap_people_mapper');
+    }
 }
\ No newline at end of file
-- 
GitLab