refactoring password resetting request

This commit is contained in:
Simon Vieille 2021-03-23 22:27:46 +01:00
parent 8e5363c2a4
commit eb93d1369a
5 changed files with 44 additions and 59 deletions

View file

@ -123,10 +123,7 @@ class AccountAdminController extends AdminController
if (4 === $strength['score'] && $password1 === $password2) { if (4 === $strength['score'] && $password1 === $password2) {
$account $account
->setPassword($encoder->encodePassword( ->setPassword($encoder->encodePassword($account, $password1))
$account,
$password1
))
->setConfirmationToken($tokenGenerator->generateToken()) ->setConfirmationToken($tokenGenerator->generateToken())
; ;

View file

@ -4,7 +4,7 @@ namespace App\Core\Controller\Auth;
use App\Core\Event\Account\PasswordRequestEvent; use App\Core\Event\Account\PasswordRequestEvent;
use App\Core\Manager\EntityManager; use App\Core\Manager\EntityManager;
use App\Core\Repository\UserRepository; use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -38,51 +38,38 @@ class AuthController extends AbstractController
/** /**
* @Route("/resetting/request", name="auth_resetting_request") * @Route("/resetting/request", name="auth_resetting_request")
*/ */
public function requestResetting( public function requestResetting(Request $request, UserRepository $repository, EventDispatcherInterface $eventDispatcher): Response
Request $request, {
UserRepository $repository,
TokenGeneratorInterface $tokenGenerator,
EntityManager $entityManager,
EventDispatcherInterface $eventDispatcher
): Response {
if ($this->getUser()) { if ($this->getUser()) {
return $this->redirectToRoute('admin_dashboard_index'); return $this->redirectToRoute('admin_dashboard_index');
} }
$emailSent = false;
if ($request->isMethod('POST')) { if ($request->isMethod('POST')) {
$csrfToken = $request->request->get('_csrf_token'); $csrfToken = $request->request->get('_csrf_token');
if ($this->isCsrfTokenValid('resetting_request', $csrfToken)) { if (!$this->isCsrfTokenValid('resetting_request', $csrfToken)) {
$username = trim((string) $request->request->get('username')); throw $this->createAccessDeniedException();
}
if ($username) { $username = trim((string) $request->request->get('username'));
$account = $repository->findOneByEmail($username);
if ($account) { if (!$username) {
$passwordRequestedAt = $account->getPasswordRequestedAt(); throw $this->createAccessDeniedException();
}
if (null !== $passwordRequestedAt && $passwordRequestedAt->getTimestamp() > (time() - 3600 / 2)) { $account = $repository->findOneByEmail($username);
$emailSent = true;
}
if (!$emailSent) { if ($account) {
$account->setConfirmationToken($tokenGenerator->generateToken()); $requestedAt = $account->getPasswordRequestedAt();
$account->setPasswordRequestedAt(new \DateTime('now'));
$entityManager->update($account); if (null === $requestedAt || $requestedAt->getTimestamp() < (time() - 3600 / 2)) {
$eventDispatcher->dispatch(new PasswordRequestEvent($account), PasswordRequestEvent::EVENT); $eventDispatcher->dispatch(new PasswordRequestEvent($account), PasswordRequestEvent::EVENT);
$emailSent = true;
}
}
} }
} }
} }
return $this->render('@Core/auth/resetting_request.html.twig', [ return $this->render('@Core/auth/resetting_request.html.twig', [
'email_sent' => $emailSent, 'email_sent' => $request->isMethod('POST'),
]); ]);
} }
@ -103,16 +90,11 @@ class AuthController extends AbstractController
$account = $repository->findOneByConfirmationToken($token); $account = $repository->findOneByConfirmationToken($token);
$passwordUpdated = false; $passwordUpdated = false;
$expired = false; $expired = true;
if ($account) { if ($account) {
$passwordRequestedAt = $account->getPasswordRequestedAt(); $requestedAt = $account->getPasswordRequestedAt();
$expired = (null === $requestedAt || ($requestedAt->getTimestamp() < (time() - 3600 * 2)));
if (null !== $passwordRequestedAt && $passwordRequestedAt->getTimestamp() < (time() - 3600 * 2)) {
$expired = true;
}
} else {
$expired = true;
} }
if ($request->isMethod('POST') && !$expired) { if ($request->isMethod('POST') && !$expired) {

View file

@ -3,18 +3,17 @@
namespace App\Core\Controller\User; namespace App\Core\Controller\User;
use App\Core\Controller\Admin\AdminController; use App\Core\Controller\Admin\AdminController;
use App\Entity\User as Entity;
use App\Core\Event\Account\PasswordRequestEvent; use App\Core\Event\Account\PasswordRequestEvent;
use App\Core\Factory\UserFactory as EntityFactory; use App\Core\Factory\UserFactory as EntityFactory;
use App\Core\Form\UserType as EntityType; use App\Core\Form\UserType as EntityType;
use App\Core\Manager\EntityManager; use App\Core\Manager\EntityManager;
use App\Entity\User as Entity;
use App\Repository\UserRepositoryQuery as RepositoryQuery; use App\Repository\UserRepositoryQuery as RepositoryQuery;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
/** /**
* @Route("/admin/user") * @Route("/admin/user")
@ -105,18 +104,9 @@ class UserAdminController extends AdminController
/** /**
* @Route("/resetting_request/{entity}", name="admin_user_resetting_request", methods={"POST"}) * @Route("/resetting_request/{entity}", name="admin_user_resetting_request", methods={"POST"})
*/ */
public function requestResetting( public function requestResetting(Entity $entity, EventDispatcherInterface $eventDispatcher, Request $request): Response
Entity $entity, {
EntityManager $entityManager,
TokenGeneratorInterface $tokenGenerator,
EventDispatcherInterface $eventDispatcher,
Request $request
): Response {
if ($this->isCsrfTokenValid('resetting_request'.$entity->getId(), $request->request->get('_token'))) { if ($this->isCsrfTokenValid('resetting_request'.$entity->getId(), $request->request->get('_token'))) {
$entity->setConfirmationToken($tokenGenerator->generateToken());
$entity->setPasswordRequestedAt(new \DateTime('now'));
$entityManager->update($entity);
$eventDispatcher->dispatch(new PasswordRequestEvent($entity), PasswordRequestEvent::EVENT); $eventDispatcher->dispatch(new PasswordRequestEvent($entity), PasswordRequestEvent::EVENT);
$this->addFlash('success', 'Demande envoyée.'); $this->addFlash('success', 'Demande envoyée.');

View file

@ -3,9 +3,11 @@
namespace App\Core\EventSuscriber\Account; namespace App\Core\EventSuscriber\Account;
use App\Core\Event\Account\PasswordRequestEvent; use App\Core\Event\Account\PasswordRequestEvent;
use App\Core\Manager\EntityManager;
use App\Core\Notification\MailNotifier; use App\Core\Notification\MailNotifier;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
/** /**
* class EventListener. * class EventListener.
@ -16,11 +18,19 @@ class PasswordRequestEventSubscriber implements EventSubscriberInterface
{ {
protected MailNotifier $notifier; protected MailNotifier $notifier;
protected UrlGeneratorInterface $urlGenerator; protected UrlGeneratorInterface $urlGenerator;
protected EntityManager $entityManager;
protected TokenGeneratorInterface $tokenGenerator;
public function __construct(MailNotifier $notifier, UrlGeneratorInterface $urlGenerator) public function __construct(
{ MailNotifier $notifier,
UrlGeneratorInterface $urlGenerator,
EntityManager $entityManager,
TokenGeneratorInterface $tokenGenerator
) {
$this->notifier = $notifier; $this->notifier = $notifier;
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
$this->entityManager = $entityManager;
$this->tokenGenerator = $tokenGenerator;
} }
public static function getSubscribedEvents() public static function getSubscribedEvents()
@ -32,15 +42,21 @@ class PasswordRequestEventSubscriber implements EventSubscriberInterface
public function onRequest(PasswordRequestEvent $event) public function onRequest(PasswordRequestEvent $event)
{ {
$user = $event->getUser();
$user->setConfirmationToken($this->tokenGenerator->generateToken());
$user->setPasswordRequestedAt(new \DateTime('now'));
$this->entityManager->update($user);
$this->notifier $this->notifier
->setFrom('system@tinternet.net') ->setFrom('system@tinternet.net')
->setSubject('[Tinternet & cie] Mot de passe perdu') ->setSubject('[Tinternet & cie] Mot de passe perdu')
->addRecipient($event->getUser()->getEmail()) ->addRecipient($user->getEmail())
->notify('resetting_request', [ ->notify('@Core/mail/account/resetting_request.html.twig', [
'reseting_update_link' => $this->urlGenerator->generate( 'reseting_update_link' => $this->urlGenerator->generate(
'auth_resetting_update', 'auth_resetting_update',
[ [
'token' => $event->getUser()->getConfirmationToken(), 'token' => $user->getConfirmationToken(),
], ],
UrlGeneratorInterface::ABSOLUTE_URL UrlGeneratorInterface::ABSOLUTE_URL
), ),