<?php
namespace Eckinox\SecurityBundle\EventSubscriber;
use App\Entity\Security\AppUser;
use App\Entity\Security\User;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
class PasswordChangeSubscriber implements EventSubscriberInterface
{
private Security $security;
private UrlGeneratorInterface $urlGenerator;
public function __construct(Security $security, UrlGeneratorInterface $urlGenerator)
{
$this->security = $security;
$this->urlGenerator = $urlGenerator;
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['forcePasswordChange', 0]],
];
}
public function forcePasswordChange(RequestEvent $event): void
{
$route = $event->getRequest()->get('_route');
if (!$event->isMainRequest()) {
return;
}
$user = $this->security->getUser();
// if you do not have a valid user, it means it's not an authenticated request, so it's not our concern
if ($user instanceof AppUser) {
$route = "eckinox_security_app_user_create_password";
$twoFARoute = 'eckinox_app_2fa_login';
} elseif ($user instanceof User) {
$route = "eckinox_security_user_create_password";
$twoFARoute = 'eckinox_2fa_login';
} else {
return;
}
if($event->getRequest()->get('_route') === $twoFARoute) {
return;
}
// if we are visiting the password change route, no need to redirect
// otherwise we'd create an infinite redirection loop
if ($event->getRequest()->get('_route') === $route) {
return;
}
// if it's not their first login, and they do not need to change their password, move on
if (!$user->isPasswordChangeRequired()) {
return;
}
// if we get here, it means we need to redirect them to the password change view.
$event->setResponse(new RedirectResponse($this->urlGenerator->generate($route)));
}
}
?>