src/Controller/PasswordForgottenController.php line 63

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Domain\Account\AccountPasswordEmailForgottenService;
  4. use App\Domain\Account\AccountPasswordForgottenService;
  5. use App\Domain\EgeeDataExportation\DataExportationService;
  6. use App\Domain\EgeeDataExportation\EgeeRequest;
  7. use App\Domain\Encryption\EncryptionTrait;
  8. use App\Domain\Encryption\HashingService;
  9. use App\Domain\Notification\Pdf\PdfService;
  10. use App\Repository\AccountRepository;
  11. use Psr\Log\LoggerInterface;
  12. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  13. use Symfony\Component\DependencyInjection\ContainerInterface;
  14. use Symfony\Component\Filesystem\Filesystem;
  15. use Symfony\Component\HttpFoundation\Request;
  16. use Symfony\Component\HttpFoundation\Response;
  17. use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
  18. use Symfony\Component\Routing\Annotation\Route;
  19. class PasswordForgottenController extends AbstractController
  20. {
  21.     use EncryptionTrait;
  22.     private $hashingService;
  23.     private $servicesContainer;
  24.     private $filesystem;
  25.     private $accountPasswordForgottenService;
  26.     private $accountPasswordEmailForgottenService;
  27.     private $logger;
  28.     public function __construct(
  29.         ContainerInterface $servicesContainer,
  30.         Filesystem $filesystem,
  31.         AccountPasswordForgottenService $accountPasswordForgottenService,
  32.         AccountPasswordEmailForgottenService $accountPasswordEmailForgottenService,
  33.         LoggerInterface $logger,
  34.         HashingService $hashingService
  35.     ) {
  36.         $this->servicesContainer $servicesContainer;
  37.         $this->filesystem $filesystem;
  38.         $this->accountPasswordForgottenService $accountPasswordForgottenService;
  39.         $this->accountPasswordEmailForgottenService $accountPasswordEmailForgottenService;
  40.         $this->logger $logger;
  41.         $this->hashingService $hashingService;
  42.     }
  43.     /**
  44.      * @Route("/password-forgotten", name="password-forgotten", methods={"GET","POST"})
  45.      *
  46.      * Formulaire de perte de mot de passe.
  47.      * Différentes informations sont à renseigner pour s'assurer de l'identité
  48.      * de l'internaute.
  49.      *
  50.      * Nouvelle gestion de récupération de mot de passe :
  51.      * 1. saisie de l'adresse email + référence client ;
  52.      * 2. vérification de la correspondance email <=> reférence dans la base de données ;
  53.      * 3. envoi d'un message avec lien unique vers un formulaire permettant de réinitialiser le mot de passe (durée de vie 30 minutes) ;
  54.      * 4. enregistrement du nouveau mot de passe ;
  55.      * 5. flux EGEE.
  56.      */
  57.     public function showForm(Request $request): Response
  58.     {
  59.         if ($request->isMethod('POST')) {
  60.             $this->addFlash(
  61.                 'success',
  62.                 '<strong>Votre demande a bien été prise en compte.</strong>'
  63.             );
  64.             $this->addFlash(
  65.                 'success',
  66.                 'Un e-mail contenant les instructions à suivre pour réinitialiser votre mot de passe vient de vous être envoyé.'
  67.             );
  68.             return $this->redirectToRoute('password-forgotten');
  69.         }
  70.         return $this->render(
  71.             'password_forgotten/form.html.twig',
  72.             [
  73.                 'menu' => '',
  74.             ]
  75.         );
  76.     }
  77.     /**
  78.      * @Route("/password-forgotten-action", name="password-forgotten-action", methods={"GET","POST"})
  79.      *
  80.      **/
  81.     public function formProcess(Request $requestAccountRepository $accountRepository)
  82.     {
  83.         if (!$this->isCsrfTokenValid('password-forgotten'$request->request->get('_token'))) {
  84.             return $this->redirectToRoute('password-forgotten');
  85.         }
  86.         $pathPasswordForgotten $this->servicesContainer->getParameter('password.directory');
  87.         $this->filesystem->mkdir($pathPasswordForgotten);
  88.         $dataEmail $request->request->all();
  89.         if (!$dataEmail['reference'] || !$dataEmail['customer_email'] || !filter_var($dataEmail['customer_email'], FILTER_VALIDATE_EMAIL)) {
  90.             $this->addFlash(
  91.                 'danger',
  92.                 'Attention vous devez fournir une adresse mail valide'
  93.             );
  94.             return $this->redirectToRoute('password-forgotten');
  95.         }
  96.         // vérification correspondance ref/email
  97.         $account $accountRepository->findOneBy(['reference' => $dataEmail['reference']]);
  98.         if (!$account || !$account->getEmail()) {
  99.             $this->addFlash(
  100.                 'danger',
  101.                 "Attention l'adresse mail ou la référence est invalide"
  102.             );
  103.             $this->logger->error(
  104.                 'Traitement de perte de mot de passe : correspondance email/ref invalide, ref inexistante',
  105.                 [
  106.                     'reference' => $dataEmail['reference'],
  107.                     'email' => $dataEmail['customer_email'],
  108.                 ]
  109.             );
  110.             return $this->redirectToRoute('password-forgotten');
  111.         }
  112.         if ($account->getEmail() != $dataEmail['customer_email']) {
  113.             $this->addFlash(
  114.                 'danger',
  115.                 "Attention l'adresse mail ou la référence est invalide"
  116.             );
  117.             $this->logger->error(
  118.                 'Traitement de perte de mot de passe : correspondance email/ref invalide',
  119.                 [
  120.                     'reference' => $dataEmail['reference'],
  121.                     'email' => $dataEmail['customer_email'],
  122.                 ]
  123.             );
  124.             return $this->redirectToRoute('password-forgotten');
  125.         }
  126.         $dateRequest date('Y-m-d H:i:s');
  127.         $code urlencode($this->encrypt($dataEmail['customer_email'].$dataEmail['reference'].$dateRequest));
  128.         $ip $this->getUserIp();
  129.         $email $dataEmail['customer_email'];
  130.         $urlDomainSiteEau $this->servicesContainer->getParameter('url.site.eau');
  131.         $baseurl $request->getScheme().'://'.$request->getHttpHost().$request->getBasePath();
  132.         $url $baseurl.'/password-change?code='.$code.'&reference='.$dataEmail['reference'];
  133.         $dataEmail['url'] = $url;
  134.         $this->filesystem->dumpFile($pathPasswordForgotten.'/'.$dataEmail['reference'], $code."\n");
  135.         $this->filesystem->appendToFile($pathPasswordForgotten.'/'.$dataEmail['reference'], $dateRequest."\n");
  136.         $this->filesystem->appendToFile($pathPasswordForgotten.'/'.$dataEmail['reference'], $ip."\n");
  137.         $this->filesystem->appendToFile($pathPasswordForgotten.'/'.$dataEmail['reference'], $email."\n");
  138.         try {
  139.             $this->accountPasswordForgottenService->processUpdatePassword($dataEmail);
  140.             $this->addFlash(
  141.                 'success',
  142.                 'Un message de confirmation a été retourné à votre adresse e-mail. Si ce dernier n\'apparait pas veuillez vérifier vos courriers indésirables.'
  143.             );
  144.             $this->logger->info(
  145.                 'Traitement de perte de mot de passe : envoi email ok',
  146.                 [
  147.                     'reference' => $dataEmail['reference'],
  148.                     'email' => $dataEmail['customer_email'],
  149.                 ]
  150.             );
  151.         } catch (TransportExceptionInterface $e) {
  152.             $this->addFlash(
  153.                 'danger',
  154.                 'Une erreur est survenue lors de l’envoi du message.'
  155.             );
  156.             $this->logger->error(
  157.                 'Traitement de perte de mot de passe : envoi email en erreur',
  158.                 [
  159.                     'reference' => $dataEmail['reference'],
  160.                     'email' => $dataEmail['customer_email'],
  161.                 ]
  162.             );
  163.         }
  164.         return $this->redirectToRoute('password-forgotten');
  165.     }
  166.     /**
  167.      * @Route("/password-forgottent-email-action", name="password-forgotten-email-action", methods={"GET","POST"})
  168.      *
  169.      **/
  170.     public function passwordChangeEmailFormProcess(Request $requestAccountRepository $accountRepository)
  171.     {
  172.         if (!$this->isCsrfTokenValid('password-email-forgotten'$request->request->get('_token'))) {
  173.             return $this->redirectToRoute('password-forgotten');
  174.         }
  175.         $dataEmail $request->request->all();
  176.         $account $accountRepository->findOneBy(['reference' => $dataEmail['reference']]);
  177.         if (!$account) {
  178.             $this->addFlash(
  179.                 'danger',
  180.                 'Cette référence est inconnue'
  181.             );
  182.             $this->logger->error(
  183.                 'Traitement de perte de mot de passe email différent : erreur (référence inconnue)'
  184.             );
  185.             return $this->redirectToRoute('password-forgotten');
  186.         }
  187.         if (!filter_var($dataEmail['recup_email'], FILTER_VALIDATE_EMAIL)) {
  188.             $this->addFlash(
  189.                 'danger',
  190.                 'Cette adresse email n\'est pas valide'
  191.             );
  192.             $this->logger->error(
  193.                 'Traitement de perte de mot de passe email différent : erreur (adresse email incorrecte)'
  194.             );
  195.             return $this->redirectToRoute('password-forgotten');
  196.         }
  197.         if ($dataEmail['recup_nom']
  198.             && $dataEmail['recup_address']
  199.             && $dataEmail['recup_commune']
  200.             && $dataEmail['recup_tel']
  201.             && $dataEmail['recup_numero']
  202.         ) {
  203.             try {
  204.                 $pdf = new PdfService();
  205.                 $dataEmail['attachedFiles'] = null;
  206.                 $dataEmail['generatedDate'] = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Paris'));
  207.                 $template $this->renderView('email_notifications/password-email-change-reset-request.html.twig'$dataEmail);
  208.                 $pdf->setTitle('password-email-change-reset-request');
  209.                 $pdf->setCliReference($dataEmail['reference']);
  210.                 $fileName $pdf->generateFile($template);
  211.                 $attachments $request->files->all();
  212.                 $attachments['attachment'] = $fileName;
  213.                 $this->accountPasswordEmailForgottenService->process($dataEmail$attachments);
  214.                 unlink($fileName);
  215.                 $this->addFlash(
  216.                     'success',
  217.                     "Votre message a été envoyé avec succès.\nUn accusé de réception a été retourné à l’adresse e-mail indiquée."
  218.                 );
  219.                 $this->logger->info(
  220.                     'Mot de passe perdu et adresse mail différente - envoi mail réussi',
  221.                     [
  222.                         'email' => $dataEmail['recup_email'],
  223.                     ]
  224.                 );
  225.             } catch (TransportExceptionInterface $e) {
  226.                 $this->addFlash(
  227.                     'danger',
  228.                     'Une erreur est survenue lors de l’envoi du message.'
  229.                 );
  230.                 $this->logger->error(
  231.                     'Mot de passe perdu et adresse mail différente - envoi mail en échec',
  232.                     [
  233.                         'email' => $dataEmail['recup_email'],
  234.                     ]
  235.                 );
  236.             }
  237.         }
  238.         return $this->redirectToRoute('password-forgotten');
  239.     }
  240.     /**
  241.      * @Route("/password-change", name="password-change", methods={"GET","POST"})
  242.      *
  243.      **/
  244.     public function passwordChangeForm(Request $requestAccountRepository $accountRepository)
  245.     {
  246.         $pathPasswordForgotten $this->servicesContainer->getParameter('password.directory');
  247.         $dateLimit date('Y-m-d H:m:s', (time() - 1800));
  248.         // 1. Mauvais paramètres
  249.         if (empty($request->query->get('code')) || empty($request->query->get('reference'))) {
  250.             $this->addFlash(
  251.                 'danger',
  252.                 'Une erreur est survenue lors du changement de mot de passe.'
  253.             );
  254.             $this->logger->error(
  255.                 'Traitement de perte de mot de passe : changement en erreur (aucun code ou ref dans la requête)'
  256.             );
  257.             return $this->redirectToRoute('password-forgotten');
  258.         }
  259.         // 2. Demande introuvable.
  260.         $code $ip $dateRequest '';
  261.         if (file_exists($pathPasswordForgotten.'/'.$request->query->get('reference'))) {
  262.             $passwordRequest file($pathPasswordForgotten.'/'.$request->query->get('reference'));
  263.             if (isset($passwordRequest[0]) && isset($passwordRequest[1]) && isset($passwordRequest[2])) {
  264.                 $code str_replace(["\n""\r"], ''$passwordRequest[0]);
  265.                 $dateRequest str_replace(["\n""\r"], ''$passwordRequest[1]);
  266.                 $ip str_replace(["\n""\r"], ''$passwordRequest[2]);
  267.             }
  268.             //$this->filesystem->remove([$pathPasswordForgotten.'/'.$request->query->get('reference')]);
  269.         }
  270.         if (empty($code) || empty($ip) || empty($dateRequest)) {
  271.             $this->addFlash(
  272.                 'danger',
  273.                 'Une erreur est survenue lors du changement de mot de passe.'
  274.             );
  275.             $this->logger->error(
  276.                 'Traitement de perte de mot de passe : changement en erreur (demande non trouvée)'
  277.             );
  278.             return $this->redirectToRoute('password-forgotten');
  279.         }
  280.         if (urldecode($code) != $request->query->get('code')) {
  281.             $this->addFlash(
  282.                 'danger',
  283.                 'Une erreur est survenue lors du changement de mot de passe.'
  284.             );
  285.             $this->logger->error(
  286.                 'Traitement de perte de mot de passe : changement en erreur (le hash est incorrect)'
  287.             );
  288.             return $this->redirectToRoute('password-forgotten');
  289.         }
  290.         // 3. Référence inconnue
  291.         $account $accountRepository->findOneBy(['reference' => $request->query->get('reference')]);
  292.         if (!$account) {
  293.             $this->addFlash(
  294.                 'danger',
  295.                 'Une erreur est survenue lors du changement de mot de passe.'
  296.             );
  297.             $this->logger->error(
  298.                 'Traitement de perte de mot de passe : changement en erreur (référence inconnue)'
  299.             );
  300.             return $this->redirectToRoute('password-forgotten');
  301.         }
  302.         // 4. Délai d'expiration dépassé.
  303.         if ($dateRequest <= $dateLimit) {
  304.             $this->addFlash(
  305.                 'danger',
  306.                 'Une erreur est survenue lors du changement de mot de passe. La demande est expirée'
  307.             );
  308.             $this->logger->error(
  309.                 'Traitement de perte de mot de passe : changement en erreur (demande expirée)'
  310.             );
  311.             return $this->redirectToRoute('password-forgotten');
  312.         }
  313.         return $this->render(
  314.             'password_forgotten/form-change.html.twig',
  315.             [
  316.                 'menu' => '',
  317.                 'reference' => $request->query->get('reference'),
  318.             ]
  319.         );
  320.     }
  321.     /**
  322.      * @Route("/password-change-action", name="password-change-action", methods={"GET","POST"})
  323.      *
  324.      **/
  325.     public function passwordChangeFormProcess(Request $requestAccountRepository $accountRepositoryDataExportationService $dataExportationService)
  326.     {
  327.         $dataForm $request->request->all();
  328.         if ($this->isCsrfTokenValid('setup-password'.$dataForm['reference'], $request->request->get('_token'))) {
  329.             if ('' != $request->request->get('password')
  330.                 && ($request->request->get('password') === $request->request->get('password_confirmation'))) {
  331.                 $entityManager $this->getDoctrine()->getManager();
  332.                 $account $accountRepository->findOneBy(['reference' => $dataForm['reference']]);
  333.                 $account->setPassword(
  334.                     $this->hashingService->hashPassword($request->request->get('password'))
  335.                 );
  336.                 $entityManager->flush();
  337.                 $pathPasswordForgotten $this->servicesContainer->getParameter('password.directory');
  338.                 $email '';
  339.                 if (file_exists($pathPasswordForgotten.'/'.$dataForm['reference'])) {
  340.                     $passwordRequest file($pathPasswordForgotten.'/'.$dataForm['reference']);
  341.                     $email str_replace(["\n""\r"], ''$passwordRequest[3]);
  342.                     $this->filesystem->remove([$pathPasswordForgotten.'/'.$dataForm['reference']]);
  343.                 }
  344.                 // --------------------------------------------------
  345.                 // On modifie le temoin de changement de mot de passe
  346.                 $reference preg_replace('/\s+/'''$account->getReference());
  347.                 $dossierParent substr($reference03);
  348.                 $varPath getcwd().'/../var';
  349.                 $filename $varPath.'/accounts/'.$dossierParent.'/'.$reference;
  350.                 if (file_exists($filename)) {
  351.                     $timestamp time();
  352.                     $result file_put_contents($filename$timestamp);
  353.                     if (false !== $result) {
  354.                         $this->logger->info('Modification fichier timestamp', ['customer' => $account->getReference()]);
  355.                     } else {
  356.                         $this->logger->info('Impossible d\'écrire dans le fichier timestamp', ['customer' => $account->getReference()]);
  357.                     }
  358.                 }
  359.                 // --------------------------------------------------
  360.                 $egeeRequest = new EgeeRequest(
  361.                     'egee_flux/password-change.xml.twig',
  362.                     [
  363.                         'DATE_DEMANDE' => date('Ymd'),
  364.                         'CLI_REFERENCE' => $dataForm['reference'],
  365.                         'email' => $email,
  366.                         'phone' => '',
  367.                     ]
  368.                 );
  369.                 $dataExportationService->persist($egeeRequest);
  370.                 $this->addFlash(
  371.                     'success',
  372.                     'Votre mot de passe a été changé avec succès.'
  373.                 );
  374.                 $this->logger->info(
  375.                     'Usager - Changement de mot de passe',
  376.                     [
  377.                         'reference' => $dataForm['reference'],
  378.                     ]
  379.                 );
  380.             } else {
  381.                 $this->addFlash(
  382.                     'danger',
  383.                     'Attention les mots de passe ne correspondent pas.'
  384.                 );
  385.                 $this->logger->error(
  386.                     'Usager - Changement de mot de passe en erreur les mots de passe ne correspondent pas',
  387.                     [
  388.                         'reference' => $dataForm['reference'],
  389.                     ]
  390.                 );
  391.             }
  392.         }
  393.         return $this->redirectToRoute('login');
  394.     }
  395.     private function getUserIp()
  396.     {
  397.         $ip '';
  398.         if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
  399.             $ip $_SERVER['HTTP_CLIENT_IP'];
  400.         } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  401.             $ip $_SERVER['HTTP_X_FORWARDED_FOR'];
  402.         } elseif (!empty($_SERVER['REMOTE_ADDR'])) {
  403.             $ip $_SERVER['REMOTE_ADDR'];
  404.         }
  405.         return $ip;
  406.     }
  407. }