vendor/boldr/users-bundle/src/Controller/SecurityController.php line 163

Open in your IDE?
  1. <?php
  2. namespace Boldr\Cms\UsersBundle\Controller;
  3. use Boldr\Cms\UsersBundle\Form\{ ForgotPasswordTypeResetPasswordType };
  4. use Boldr\Cms\UsersBundle\Entity\User;
  5. use Boldr\Cms\UsersBundle\EmailFactory;
  6. use Boldr\Cms\UsersBundle\Event\UserPasswordChangedEvent;
  7. use Symfony\Component\HttpFoundation\{ RequestResponse };
  8. use Symfony\Component\Routing\Annotation\Route;
  9. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  10. use Symfony\Component\Mailer\MailerInterface;
  11. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  12. use Symfony\Component\Form\FormError;
  13. use Symfony\Component\Form\Extension\Core\Type\{ FormTypeTextTypePasswordTypeCheckboxType };
  14. use Symfony\Contracts\Translation\TranslatorInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Psr\EventDispatcher\EventDispatcherInterface;
  17. use DateTimeImmutable;
  18. use DateInterval;
  19. class SecurityController extends AbstractController
  20. {
  21.     public static function getSubscribedServices(): array
  22.     {
  23.         return array_merge(parent::getSubscribedServices(), [
  24.             MailerInterface::class,
  25.             AuthenticationUtils::class,
  26.             UserPasswordHasherInterface::class,
  27.             EmailFactory::class,
  28.             TranslatorInterface::class,
  29.             EventDispatcherInterface::class
  30.         ]);
  31.     }
  32.     /**
  33.      * @Route({
  34.      *     "nl": "/inloggen",
  35.      *     "de": "/anmelden",
  36.      *     "en": "/login"
  37.      * }, name="boldr_users_login")
  38.      */
  39.     public function login(Request $request): Response
  40.     {
  41.         if ($this->getUser())
  42.         {
  43.             return $this->redirectToRoute('cms_home');
  44.         }
  45.         $form $this->get('form.factory')->createNamedBuilder(''FormType::class, null, [
  46.             'translation_domain' => 'BoldrUsersBundle',
  47.             'csrf_field_name' => '_csrf_token',
  48.             'csrf_token_id' => 'authenticate'
  49.         ])
  50.             ->add('_username'TextType::class, [
  51.                 'label' => 'username',
  52.                 'attr' => [
  53.                     'autofocus' => 'autofocus'
  54.                 ]
  55.             ])
  56.             ->add('_password'PasswordType::class, [
  57.                 'label' => 'password'
  58.             ])
  59.             ->add('_remember_me'CheckboxType::class, [
  60.                 'label' => 'remember_me',
  61.                 'required' => false
  62.             ])
  63.             ->getForm();
  64.         $authenticationUtils $this->get(AuthenticationUtils::class);
  65.         $error $authenticationUtils->getLastAuthenticationError();
  66.         $lastUsername $authenticationUtils->getLastUsername();
  67.         $form->get('_username')->setData($lastUsername);
  68.         if ($error)
  69.         {
  70.             $form->addError(new FormError($this->get(TranslatorInterface::class)->trans($error->getMessageKey(), $error->getMessageData(), 'security')));
  71.         }
  72.         return $this->render('@BoldrUsers/login.html.twig', [
  73.             'error' => $error,
  74.             'form' => $form->createView()
  75.         ]);
  76.     }
  77.     /**
  78.      * @Route({
  79.      *    "nl": "/uitloggen",
  80.      *    "de": "/abmelden",
  81.      *    "en": "/logout"
  82.      * }, name="boldr_users_logout")
  83.      */
  84.     public function logout()
  85.     {
  86.         throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
  87.     }
  88.     /**
  89.      * @Route({
  90.      *     "en": "/forgot-password",
  91.      *     "nl": "/wachtwoord-vergeten",
  92.      *     "de": "/passwort-vergessen"
  93.      * }, name="boldr_users_forgot_password")
  94.      * @Route("/boldr-api/boldr-users/forgot-password", name="boldr_users_api_forgot_password")
  95.      */
  96.     public function forgotPassword(Request $request)
  97.     {
  98.         if ($this->getUser() !== null)
  99.         {
  100.             return $this->redirectToRoute('cms_home');
  101.         }
  102.         $form $this->createForm(ForgotPasswordType::class);
  103.         $form->handleRequest($request);
  104.         if ($form->isSubmitted() && $form->isValid())
  105.         {
  106.             $userRepository $this->getDoctrine()->getRepository(User::class);
  107.             $user $userRepository->createQueryBuilder('u')
  108.                 ->andWhere('u.username = ?1 OR u.emailAddress = ?1')
  109.                 ->setMaxResults(1)
  110.                 ->setParameter(1$form['usernameOrEmailAddress']->getData())
  111.                 ->getQuery()
  112.                 ->getOneOrNullResult();
  113.             if ($user !== null)
  114.             {
  115.                 if ($user->getForgotPasswordToken() === null || $user->getTimeForgotPasswordTokenExpires() < new DateTimeImmutable)
  116.                 {
  117.                     $forgotPasswordToken bin2hex(random_bytes(32));
  118.                     $timeForgotPasswordTokenExpires = (new DateTimeImmutable)->add(new DateInterval('PT24H'));
  119.                     $user->setForgotPasswordToken($forgotPasswordToken);
  120.                     $user->setTimeForgotPasswordTokenExpires($timeForgotPasswordTokenExpires);
  121.                     $this->getDoctrine()->getManager()->flush();
  122.                 }
  123.                 $email $this->get(EmailFactory::class)->createForgotPasswordEmail($user);
  124.                 try
  125.                 {
  126.                     $this->get(MailerInterface::class)->send($email);
  127.                 }
  128.                 catch (\Exception $ex)
  129.                 {
  130.                     // could not send
  131.                 }
  132.             }
  133.             if (in_array('application/json'$request->getAcceptableContentTypes()))
  134.             {
  135.                 return $this->json(['success' => true]);
  136.             }
  137.             return $this->render('@BoldrUsers/password-link-sent.html.twig');
  138.         }
  139.         return $this->render('@BoldrUsers/forgot-password.html.twig', [
  140.             'form' => $form->createView()
  141.         ]);
  142.     }
  143.     /**
  144.      * @Route({
  145.      *     "en": "/reset-password/{token}",
  146.      *     "nl": "/wachtwoord-opnieuw-instellen/{token}",
  147.      *     "de": "/passwort-zurucksetzen/{token}"
  148.      * }, name="boldr_users_reset_password")
  149.      * @Route("/boldr-api/boldr-users/reset-password", name="boldr_users_api_reset_password", methods={"POST"})
  150.      */
  151.     public function resetPassword(Request $request, ?string $token null)
  152.     {
  153.         $isJsonRequest in_array('application/json'$request->getAcceptableContentTypes());
  154.         if ($token === null)
  155.         {
  156.             if (!$request->request->has('token'))
  157.             {
  158.                 return $this->json(['success' => false'error' => 'missing_token_parameter']);
  159.             }
  160.             $token $request->request->get('token');
  161.         }
  162.         $userRepository $this->getDoctrine()->getRepository(User::class);
  163.         $user $userRepository->createQueryBuilder('u')
  164.             ->andWhere('u.forgotPasswordToken = :token AND u.timeForgotPasswordTokenExpires >= :now')
  165.             ->setParameter('token'$token)
  166.             ->setParameter('now', new DateTimeImmutable)
  167.             ->setMaxResults(1)
  168.             ->getQuery()
  169.             ->getOneOrNullResult();
  170.         if ($user === null)
  171.         {
  172.             if ($isJsonRequest)
  173.             {
  174.                 return $this->json(['success' => false'error' => 'invalid_or_expired_token']);
  175.             }
  176.             return $this->render('@BoldrUsers/reset-link-expired.html.twig');
  177.         }
  178.         $form $this->createForm(ResetPasswordType::class, null, ['allow_extra_fields' => true]);
  179.         $form->handleRequest($request);
  180.         $newPassword null;
  181.         if ($form->isSubmitted() && $form->isValid())
  182.         {
  183.             $newPassword $form['newPassword']->getData();
  184.         }
  185.         if ($request->request->has('new_password'))
  186.         {
  187.             $newPassword $request->request->get('new_password');
  188.         }
  189.         if ($newPassword !== null)
  190.         {
  191.             $passwordHash $this->get(UserPasswordHasherInterface::class)->hashPassword($user$newPassword);
  192.             $user->setPasswordHash($passwordHash);
  193.             $user->setForgotPasswordToken(null);
  194.             $user->setTimeForgotPasswordTokenExpires(null);
  195.             $this->getDoctrine()->getManager()->flush();
  196.             $event = new UserPasswordChangedEvent($user$newPasswordtrue);
  197.             $this->get(EventDispatcherInterface::class)->dispatch($event);
  198.             $email $this->get(EmailFactory::class)->createPasswordResetEmail($user);
  199.             try
  200.             {
  201.                 $this->get(MailerInterface::class)->send($email);
  202.             }
  203.             catch (\Exception $ex)
  204.             {
  205.                 // could not send email
  206.             }
  207.             if ($isJsonRequest)
  208.             {
  209.                 return $this->json(['success' => true]);
  210.             }
  211.             return $this->render('@BoldrUsers/password-reset.html.twig');
  212.         }
  213.         if ($isJsonRequest)
  214.         {
  215.             return $this->json(['success' => false'error' => 'missing_fields']);
  216.         }
  217.         return $this->render('@BoldrUsers/reset-password.html.twig', [
  218.             'form' => $form->createView()
  219.         ]);
  220.     }
  221.     /**
  222.      * @Route({
  223.      *     "en": "/confirm-email-address/{token}",
  224.      *     "nl": "/bevestig-email-adres/{token}",
  225.      *     "de": "/bestatige-email-adresse/{token}"
  226.      * }, name="boldr_users_confirm_email_address")
  227.      */
  228.     public function confirmEmailAddress(Request $requeststring $token): Response
  229.     {
  230.         $userRepository $this->getDoctrine()->getRepository(User::class);
  231.         $user $userRepository->findOneBy([
  232.             'emailAddressIsConfirmed' => false,
  233.             'confirmEmailAddressToken' => $token
  234.         ]);
  235.         if ($user === null)
  236.         {
  237.             return $this->render('@BoldrUsers/invalid-confirm-token.html.twig');
  238.         }
  239.         $user->setEmailAddressIsConfirmed(true);
  240.         $user->setConfirmEmailAddressToken(null);
  241.         $this->getDoctrine()->getManager()->flush();
  242.         if (in_array('application/json'$request->getAcceptableContentTypes()))
  243.         {
  244.             return $this->json(['success' => true]);
  245.         }
  246.         /** @FIXME Make sure it does not redirect to outside URL */
  247.         if ($request->query->has('redirect'))
  248.         {
  249.             return $this->redirect($request->query->get('redirect'));
  250.         }
  251.         return $this->render('@BoldrUsers/confirmed.html.twig', [
  252.             'user' => $user
  253.         ]);
  254.     }
  255.     /**
  256.      * @Route({
  257.      *     "en": "/resend-confirmation-email",
  258.      *     "nl": "/verstuur-bevestigingsemail-opnieuw",
  259.      *     "de": "/bestatigungsmail-erneut-senden"
  260.      * }, name="boldr_users_resend_confirmation_email")
  261.      * @Route("/boldr-api/boldr-users/resend-confirmation-email", name="boldr_users_api_resend_confirmation_email")
  262.      */
  263.     public function resendConfirmationEmail(Request $request): Response
  264.     {
  265.         $this->denyAccessUnlessGranted('ROLE_USER');
  266.         $isJsonRequest in_array('application/json'$request->getAcceptableContentTypes());
  267.         /** @var User */
  268.         $user $this->getUser();
  269.         if ($user->getEmailAddressIsConfirmed())
  270.         {
  271.             if ($isJsonRequest)
  272.             {
  273.                 return $this->json(['success' => false'error' => 'already_confirmed']);
  274.             }
  275.             return $this->render('@BoldrUsers/already-confirmed.html.twig');
  276.         }
  277.         // Generate a confirmation token if it does not exist yet
  278.         if ($user->getConfirmEmailAddressToken() === null)
  279.         {
  280.             $confirmEmailAddressToken bin2hex(random_bytes(32));
  281.             $user->setConfirmEmailAddressToken($confirmEmailAddressToken);
  282.             $this->getDoctrine()->getManager()->flush();
  283.         }
  284.         $email $this->get(EmailFactory::class)->createResendConfirmationEmail($user);
  285.         try
  286.         {
  287.             $this->get(MailerInterface::class)->send($email);
  288.         }
  289.         catch (\Exception $ex)
  290.         {
  291.             // could not send email
  292.         }
  293.         if ($isJsonRequest)
  294.         {
  295.             return $this->json(['success' => true]);
  296.         }
  297.         /** @FIXME Make sure it does not redirect to outside URL */
  298.         if ($request->query->has('redirect'))
  299.         {
  300.             return $this->redirect($request->query->get('redirect'));
  301.         }
  302.         return $this->render('@BoldrUsers/confirmation-email-resent.html.twig');
  303.     }
  304. }