parent
7c97a68088
commit
e197147327
@ -0,0 +1,184 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
namespace App\Controller; |
||||||
|
|
||||||
|
use App\Entity\User; |
||||||
|
use App\Form\ChangePasswordFormType; |
||||||
|
use App\Form\ResetPasswordRequestFormType; |
||||||
|
use Doctrine\ORM\EntityManagerInterface; |
||||||
|
use Symfony\Bridge\Twig\Mime\TemplatedEmail; |
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; |
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse; |
||||||
|
use Symfony\Component\HttpFoundation\Request; |
||||||
|
use Symfony\Component\HttpFoundation\Response; |
||||||
|
use Symfony\Component\Mailer\MailerInterface; |
||||||
|
use Symfony\Component\Mime\Address; |
||||||
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; |
||||||
|
use Symfony\Component\Routing\Annotation\Route; |
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface; |
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait; |
||||||
|
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface; |
||||||
|
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface; |
||||||
|
|
||||||
|
/** |
||||||
|
* @Route("/reset-password") |
||||||
|
*/ |
||||||
|
class ResetPasswordController extends AbstractController |
||||||
|
{ |
||||||
|
use ResetPasswordControllerTrait; |
||||||
|
|
||||||
|
private ResetPasswordHelperInterface $resetPasswordHelper; |
||||||
|
private EntityManagerInterface $entityManager; |
||||||
|
|
||||||
|
public function __construct(ResetPasswordHelperInterface $resetPasswordHelper, EntityManagerInterface $entityManager) |
||||||
|
{ |
||||||
|
$this->resetPasswordHelper = $resetPasswordHelper; |
||||||
|
$this->entityManager = $entityManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Display & process form to request a password reset. |
||||||
|
* |
||||||
|
* @Route("", name="app_forgot_password_request") |
||||||
|
*/ |
||||||
|
public function request(Request $request, MailerInterface $mailer, TranslatorInterface $translator): Response |
||||||
|
{ |
||||||
|
$form = $this->createForm(ResetPasswordRequestFormType::class); |
||||||
|
$form->handleRequest($request); |
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) { |
||||||
|
return $this->processSendingPasswordResetEmail( |
||||||
|
$form->get('email')->getData(), |
||||||
|
$mailer, |
||||||
|
$translator |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
return $this->render('reset_password/request.html.twig', [ |
||||||
|
'requestForm' => $form->createView(), |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Confirmation page after a user has requested a password reset. |
||||||
|
* |
||||||
|
* @Route("/check-email", name="app_check_email") |
||||||
|
*/ |
||||||
|
public function checkEmail(): Response |
||||||
|
{ |
||||||
|
// Generate a fake token if the user does not exist or someone hit this page directly. |
||||||
|
// This prevents exposing whether or not a user was found with the given email address or not |
||||||
|
if (null === ($resetToken = $this->getTokenObjectFromSession())) { |
||||||
|
$resetToken = $this->resetPasswordHelper->generateFakeResetToken(); |
||||||
|
} |
||||||
|
|
||||||
|
return $this->render('reset_password/check_email.html.twig', [ |
||||||
|
'resetToken' => $resetToken, |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Validates and process the reset URL that the user clicked in their email. |
||||||
|
* |
||||||
|
* @Route("/reset/{token}", name="app_reset_password") |
||||||
|
*/ |
||||||
|
public function reset(Request $request, UserPasswordHasherInterface $userPasswordHasher, TranslatorInterface $translator, string $token = null): Response |
||||||
|
{ |
||||||
|
if ($token) { |
||||||
|
// We store the token in session and remove it from the URL, to avoid the URL being |
||||||
|
// loaded in a browser and potentially leaking the token to 3rd party JavaScript. |
||||||
|
$this->storeTokenInSession($token); |
||||||
|
|
||||||
|
return $this->redirectToRoute('app_reset_password'); |
||||||
|
} |
||||||
|
|
||||||
|
$token = $this->getTokenFromSession(); |
||||||
|
if (null === $token) { |
||||||
|
throw $this->createNotFoundException('No reset password token found in the URL or in the session.'); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
$user = $this->resetPasswordHelper->validateTokenAndFetchUser($token); |
||||||
|
} catch (ResetPasswordExceptionInterface $e) { |
||||||
|
$this->addFlash('reset_password_error', sprintf( |
||||||
|
'%s - %s', |
||||||
|
$translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_VALIDATE, [], 'ResetPasswordBundle'), |
||||||
|
$translator->trans($e->getReason(), [], 'ResetPasswordBundle') |
||||||
|
)); |
||||||
|
|
||||||
|
return $this->redirectToRoute('app_forgot_password_request'); |
||||||
|
} |
||||||
|
|
||||||
|
// The token is valid; allow the user to change their password. |
||||||
|
$form = $this->createForm(ChangePasswordFormType::class); |
||||||
|
$form->handleRequest($request); |
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) { |
||||||
|
// A password reset token should be used only once, remove it. |
||||||
|
$this->resetPasswordHelper->removeResetRequest($token); |
||||||
|
|
||||||
|
// Encode(hash) the plain password, and set it. |
||||||
|
$encodedPassword = $userPasswordHasher->hashPassword( |
||||||
|
$user, |
||||||
|
$form->get('plainPassword')->getData() |
||||||
|
); |
||||||
|
|
||||||
|
$user->setPassword($encodedPassword); |
||||||
|
$this->entityManager->flush(); |
||||||
|
|
||||||
|
// The session is cleaned up after the password has been changed. |
||||||
|
$this->cleanSessionAfterReset(); |
||||||
|
|
||||||
|
return $this->redirectToRoute('app_home'); |
||||||
|
} |
||||||
|
|
||||||
|
return $this->render('reset_password/reset.html.twig', [ |
||||||
|
'resetForm' => $form->createView(), |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer, TranslatorInterface $translator): RedirectResponse |
||||||
|
{ |
||||||
|
$user = $this->entityManager->getRepository(User::class)->findOneBy([ |
||||||
|
'email' => $emailFormData, |
||||||
|
]); |
||||||
|
|
||||||
|
// Do not reveal whether a user account was found or not. |
||||||
|
if (!$user) { |
||||||
|
return $this->redirectToRoute('app_check_email'); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
$resetToken = $this->resetPasswordHelper->generateResetToken($user); |
||||||
|
} catch (ResetPasswordExceptionInterface $e) { |
||||||
|
// If you want to tell the user why a reset email was not sent, uncomment |
||||||
|
// the lines below and change the redirect to 'app_forgot_password_request'. |
||||||
|
// Caution: This may reveal if a user is registered or not. |
||||||
|
// |
||||||
|
// $this->addFlash('reset_password_error', sprintf( |
||||||
|
// '%s - %s', |
||||||
|
// $translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_HANDLE, [], 'ResetPasswordBundle'), |
||||||
|
// $translator->trans($e->getReason(), [], 'ResetPasswordBundle') |
||||||
|
// )); |
||||||
|
|
||||||
|
return $this->redirectToRoute('app_check_email'); |
||||||
|
} |
||||||
|
|
||||||
|
$email = (new TemplatedEmail()) |
||||||
|
->from(new Address('mailer@sfycas.local', '"Sfycas mail bot"')) |
||||||
|
->to($user->getEmail()) |
||||||
|
->subject('Your password reset request') |
||||||
|
->htmlTemplate('reset_password/email.html.twig') |
||||||
|
->context([ |
||||||
|
'resetToken' => $resetToken, |
||||||
|
]) |
||||||
|
; |
||||||
|
|
||||||
|
$mailer->send($email); |
||||||
|
|
||||||
|
// Store the token object in session for retrieval in check-email route. |
||||||
|
$this->setTokenObjectInSession($resetToken); |
||||||
|
|
||||||
|
return $this->redirectToRoute('app_check_email'); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas"> |
||||||
|
<cas:authenticationFailure code="INVALID_TICKET"> |
||||||
|
{{ message}} |
||||||
|
</cas:authenticationFailure> |
||||||
|
</cas:serviceResponse> |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'> |
||||||
|
<cas:authenticationSuccess> |
||||||
|
<cas:user>{{ login }}</cas:user> |
||||||
|
</cas:authenticationSuccess> |
||||||
|
</cas:serviceResponse> |
||||||
Loading…
Reference in new issue