configuration->isPasswordResetActive()) { throw $this->createNotFoundException(); } return $this->render('security/password-reset/request.html.twig'); } /** * Request reset user password: submit form and send email. */ #[Route(path: '/send-email', name: 'resetting_send_email', methods: ['POST'])] public function sendEmailAction(Request $request, TranslatorInterface $translator): Response { if (!$this->configuration->isPasswordResetActive()) { throw $this->createNotFoundException(); } $username = $request->request->get('username'); if (!\is_string($username) || trim($username) === '') { throw $this->createAccessDeniedException('Username cannot be empty'); } $user = $this->userService->findUserByUsernameOrEmail($username); if (!$user->isPasswordRequestNonExpired($this->configuration->getPasswordResetRetryLifetime())) { if (!$user->isInternalUser()) { throw $this->createAccessDeniedException( \sprintf('The user "%s" tried to reset the password, but it is registered as "%s" auth-type.', $user->getUserIdentifier(), $user->getAuth()) ); } if (null === $user->getConfirmationToken()) { $user->setConfirmationToken($this->userService->generateSecurityToken()); } $mail = $this->generateResettingEmailMessage($user, $translator); $event = new EmailPasswordResetEvent($user, $mail); $this->eventDispatcher->dispatch($event); // this will finally send the email $this->eventDispatcher->dispatch(new EmailEvent($event->getEmail())); $user->markPasswordRequested(); $this->userService->saveUser($user); } return $this->redirectToRoute('resetting_check_email', ['username' => $username]); } /** * Tell the user to check his email provider. */ #[Route(path: '/check-email', name: 'resetting_check_email', methods: ['GET'])] public function checkEmailAction(Request $request): Response { if (!$this->configuration->isPasswordResetActive()) { throw $this->createNotFoundException(); } $username = $request->query->get('username'); if (empty($username)) { // the user does not come from the sendEmail action return $this->redirectToRoute('resetting_request'); } return $this->render('security/password-reset/check_email.html.twig', [ 'tokenLifetime' => $this->configuration->getPasswordResetRetryLifetime(), ]); } /** * Reset user password. */ #[Route(path: '/reset/{token}', name: 'resetting_reset', methods: ['GET', 'POST'])] public function resetAction(Request $request, LoginManager $loginManager, ?string $token): Response { if (!$this->configuration->isPasswordResetActive()) { throw $this->createNotFoundException(); } $user = $this->userService->findUserByConfirmationToken($token); if (null === $user) { return $this->redirectToRoute('login'); } if (!$user->isPasswordRequestNonExpired($this->configuration->getPasswordResetTokenLifetime())) { $this->flashWarning('This link has already expired'); return $this->redirectToRoute('resetting_request'); } $form = $this->createResetForm(); $form->setData($user); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $user->markPasswordResetted(); $user->setEnabled(true); $this->userService->saveUser($user); $response = $this->redirectToRoute('my_profile'); $loginManager->logInUser($user, $response); return $response; } return $this->render('security/password-reset/reset.html.twig', [ 'token' => $token, 'form' => $form->createView(), ]); } private function createResetForm(): FormInterface { $options = ['validation_groups' => ['ResetPassword', 'Default']]; return $this->createFormBuilder()->create('resetting_form', PasswordResetForm::class, $options)->getForm(); } private function generateResettingEmailMessage(User $user, TranslatorInterface $translator): Email { $username = $user->getDisplayName(); $language = $user->getLanguage(); $url = $this->generateUrl('resetting_reset', ['token' => $user->getConfirmationToken()], UrlGeneratorInterface::ABSOLUTE_URL); return (new TemplatedEmail()) ->to(new Address($user->getEmail())) ->subject( $translator->trans('reset.subject', ['%username%' => $username], 'email', $language) ) ->htmlTemplate('emails/password-reset.html.twig') ->context([ 'user' => $user, 'username' => $username, 'confirmationUrl' => $url, ]) ; } }