Skip to content
Snippets Groups Projects
Select Git revision
  • ecdf7d2bb1f964b3c44fbd761125c7c1a0970c6d
  • master default protected
  • ll-workflow
  • alc-scindage-donnees-pj
  • b24
  • FJ_LL_Tbl_Contrat
  • alc-docker-node
  • ll-apiplatform
  • php84
  • ll-rgpd
  • b23
  • alc-filtre-type-intervenant
  • ll-sans-mdb5
  • formules-ancienne-infra
  • ll-formules
  • alc-intervenant-dmep
  • ll-suppr-v_vol-s
  • b20
  • ll-postgresql
  • b23.0.1
  • b22
  • 24.8
  • 24.7
  • 24.6
  • 24.5
  • 24.4
  • 24.3
  • 24.2
  • 24.1
  • 24.0
  • 23.15
  • 24.0-beta19
  • 24.0-beta18
  • 24.0-beta17
  • 24.0-beta16
  • 24.0-beta15
  • 24.0-beta14
  • 24.0-beta13
  • 23.14
  • 24.0-beta12
  • 24.0-beta11
41 results

DataGen.php

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    AuthController.php 9.05 KiB
    <?php
    
    namespace UnicaenAuth\Controller;
    
    use DomainException;
    use UnicaenApp\Controller\Plugin\AppInfos;
    use UnicaenApp\Controller\Plugin\Mail;
    use UnicaenApp\Exception\RuntimeException;
    use UnicaenAuth\Service\Traits\ShibServiceAwareTrait;
    use UnicaenAuth\Service\Traits\UserServiceAwareTrait;
    use Zend\Authentication\AuthenticationService;
    use Zend\Authentication\Exception\ExceptionInterface;
    use Zend\Http\Request;
    use Zend\Http\Response;
    use Zend\Mvc\Controller\AbstractActionController;
    use Zend\View\Model\ViewModel;
    use ZfcUser\Controller\Plugin\ZfcUserAuthentication;
    
    /**
     * Classe ajoutée lors de l'implémentation de l'auth Shibboleth.
     *
     * @method ZfcUserAuthentication zfcUserAuthentication()
     * @method AppInfos appInfos()
     * @method Mail mail()
     *
     * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr>
     */
    class AuthController extends AbstractActionController
    {
        use ShibServiceAwareTrait;
        use UserServiceAwareTrait;
    
        /**
         * Cette action peut être appelée lorsque l'authentification Shibboleth est activée
         * (unicaen-auth.shibboleth.enable === true).
         *
         * > Si la config Apache de Shibboleth est correcte, une requête à l'adresse correspondant à cette action
         * (suite au clic sur le bouton "Authentification Shibboleth", typiquement)
         * est détournée par Apache pour réaliser l'authentification Shibboleth.
         * Ce n'est qu'une fois l'authentification réalisée avec succès que cette action est appelée.
         *
         * > Si la config Apache de Shibboleth est incorrecte ou absente (localhost par exemple), et que la simulation
         * Shibboleth est activée dans la config (unicaen-auth.shibboleth.simulate), cette action est appelée et
         * la simulation est enclenchée.
         *
         * @return Response|array
         */
        public function shibbolethAction()
        {
            $operation = $this->params()->fromRoute('operation');
    
            if ($operation === 'deconnexion') {
                return $this->shibbolethLogout();
            }
    
            $redirectUrl = $this->params()->fromQuery('redirect', '/');
    
            // enclenchement de la simulation shibboleth éventuellement activée dans la config
            if ($simulate = $this->shibService->getShibbolethSimulate()) {
                $this->setStoredAuthenticatedUsername($simulate['eppn']); // tout simplement!
    
                return $this->redirect()->toUrl($redirectUrl);
            }
    
            $shibUser = $this->shibService->getAuthenticatedUser();
            if ($shibUser === null) {
                return []; // une page d'aide s'affichera si les données issues de Shibboleth attendues sont absentes
            }
    
            // arrivé ici, l'authentification shibboleth a été faite en bonne et due forme et a réussie.
    
            $this->setStoredAuthenticatedUsername($shibUser->getUsername());
            $this->userService->userAuthenticated($shibUser);
    
            return $this->redirect()->toUrl($redirectUrl);
        }
    
        /**
         * Déconnexion Shibboleth.
         *
         * @return array|Response
         */
        private function shibbolethLogout()
        {
            // déconnexion applicative quoiqu'il arrive
            $this->zfcUserAuthentication()->getAuthAdapter()->resetAdapters();
            $this->zfcUserAuthentication()->getAuthAdapter()->logoutAdapters();
            $this->zfcUserAuthentication()->getAuthService()->clearIdentity();
    
            // déconnexion Shibboleth le cas échéant
            if ($this->shibService->isShibbolethEnabled()) {
                // désactivation de l'usurpation d'identité éventuelle
                $this->shibService->deactivateUsurpation();
    
                // URL par défaut vers laquelle on redirige après déconnexion : accueil
                $homeUrl = $this->url()->fromRoute('home', [], ['force_canonical' => true]);
                $returnAbsoluteUrl = $this->params()->fromQuery('return', $homeUrl);
    
                return $this->redirect()->toUrl($this->shibService->getLogoutUrl($returnAbsoluteUrl));
            } else {
                return []; // une page d'aide s'affichera
            }
        }
    
        /**
         * @param string $username
         */
        private function setStoredAuthenticatedUsername($username)
        {
            /** @var AuthenticationService $authService */
            $authService = $this->getServiceLocator()->get('zfcuser_auth_service');
            try {
                $authService->getStorage()->write($username);
            } catch (ExceptionInterface $e) {
                throw new RuntimeException("Impossible d'écrire dans le storage");
            }
        }
    
        /**
         * @return Response|ViewModel
         */
        public function requestPasswordResetAction()
        {
            $form = $this->userService->createResetPasswordEmailForm();
    
            $view = new ViewModel();
            $view->setVariable('form', $form);
            $view->setTemplate('unicaen-auth/auth/request-password-reset-form');
    
            /** @var Request $request */
            $request = $this->getRequest();
    
            if ($request->isPost()) {
                $data = $request->getPost();
                $form->setData($data);
                if ($form->isValid()) {
                    $email = $data['email'];
                    try {
                        $this->processPasswordResetRequest($email);
    
                        $view->setVariable('email', $email);
                        $view->setTemplate('unicaen-auth/auth/request-password-reset-success');
                    } catch (DomainException $de) {
                        // affichage de l'erreur comme une erreur de validation
                        $form->get('email')->setMessages([$de->getMessage()]);
                    }
                }
            }
    
            return $view;
        }
    
        /**
         * @param string $email
         */
        private function processPasswordResetRequest($email)
        {
            // Recherche de l'utilisateur ayant pour *username* (login) l'email spécifié
            $user = $this->userService->getUserMapper()->findOneByUsername($email);
    
            if ($user === null) {
                // Aucun utilisateur trouvé ayant l'email spécifié :
                // on ne fait rien mais on ne le signale pas sinon le formulaire permettrait
                // de tester si des emails potentiellement valides existent dans la base.
                return;
            }
            if (! $user->isLocal()) {
                // L'email spécifié appartient à un utilisateur non local : on signale l'impossibilité de changer le mdp.
                throw new DomainException("Le changement de mot de passe n'est pas possible pour cet utilisateur.");
            }
    
            // génération/enregistrement d'un token
            $token = $this->userService->updateUserPasswordResetToken($user);
    
            // envoi du mail contenant le lien de changement de mdp
            $app = $this->appInfos()->getNom();
            $subject = "[$app] Demande de changement de mot de passe";
            $changePasswordUrl = $this->url()->fromRoute('auth/changePassword', ['token' => $token], ['force_canonical' => true]);
            $body = <<<EOS
    <p>Une demande de changement de mot de passe a été faite sur l'application $app.</p>
    <p>Si vous n'en êtes pas l'auteur, vous pouvez ignorer ce message.</p>
    <p>Cliquez sur le lien suivant pour accéder au formulaire de changement de votre mot de passe :<br><a href='$changePasswordUrl'>$changePasswordUrl</a></p>
    EOS;
            $message = $this->mail()->createNewMessage($body, $subject);
            $message->setTo($email);
            $this->mail()->send($message);
        }
    
        /**
         * @return array|ViewModel
         */
        public function changePasswordAction()
        {
            $token = $this->params()->fromRoute('token');
            $view = new ViewModel();
    
            // recherche du token spécifié dans table utilisateur
            $user = $this->userService->getUserMapper()->findOneByPasswordResetToken($token);
            if ($user === null) {
                // token inexistant
                $view->setVariable('result', 'unknown_token');
                $view->setTemplate('unicaen-auth/auth/change-password-result');
    
                return $view;
            }
    
            $form = $this->userService->createPasswordChangeForm();
    
            /** @var Request $request */
            $request = $this->getRequest();
    
            if ($request->isPost()) {
                $data = $request->getPost();
                $form->setData($data);
                if ($form->isValid()) {
                    // màj password
                    $password = $this->params()->fromPost('password');
                    $this->userService->updateUserPassword($user, $password);
    
                    $view->setVariable('result', 'success');
                    $view->setTemplate('unicaen-auth/auth/change-password-result');
    
                    // todo: faut-il déconnecter l'utilisateur (attention au logout shib différent) ?
    
                    return $view;
                }
            }
    
            // test durée de vie du token
            $date = $this->userService->extractDateFromResetPasswordToken($token);
            if ($date < date_create()) {
                // token expiré, on le raz
                $this->userService->clearUserPasswordResetToken($user);
    
                $view->setVariable('result', 'dead_token');
                $view->setTemplate('unicaen-auth/auth/change-password-result');
    
                return $view;
            }
    
            $view->setVariable('form', $form);
            $view->setTemplate('unicaen-auth/auth/change-password-form');
    
            return $view;
        }
    }