<?php
namespace AppBundle\EventListener;
use AppBundle\Entity\User;
use CodersLab\Lms\SharedKernel\Application\Command\UpdateUserLanguage;
use CodersLab\Lms\SharedKernel\Application\Listener\IAuthenticationListener;
use CodersLab\Lms\SharedKernel\Common\Exception\UserMismatchException;
use CodersLab\Lms\SharedKernel\Domain\Bus\CommandBus;
use CodersLab\Lms\SharedKernel\Domain\IdentityAccess\UserLanguage;
use DateInterval;
use DateTime;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
final class AuthenticationSuccessListener implements IAuthenticationListener
{
private const JWT_ATTRIBUTE_NAME = 'jwt';
private JWTTokenManagerInterface $jwtManager;
private JWTEncoderInterface $JWTEncoder;
private TokenStorageInterface $tokenStorage;
private SessionInterface $session;
private CommandBus $commandBus;
public function __construct(
JWTTokenManagerInterface $jwtManager,
JWTEncoderInterface $JWTEncoder,
TokenStorageInterface $tokenStorage,
SessionInterface $session,
CommandBus $commandBus
) {
$this->jwtManager = $jwtManager;
$this->JWTEncoder = $JWTEncoder;
$this->tokenStorage = $tokenStorage;
$this->session = $session;
$this->commandBus = $commandBus;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event): void
{
$request = $event->getRequest();
$jwt = $request->cookies->get(IAuthenticationListener::COOKIE_NAME, '');
$sessionUser = $this->tokenStorage->getToken()->getUser();
try {
$token = $this->JWTEncoder->decode($jwt);
if ($sessionUser->getUsername() !== $token['username']) {
throw new UserMismatchException();
}
} catch (JWTDecodeFailureException | UserMismatchException $exception) {
/** @var User $user */
$user = $event->getAuthenticationToken()->getUser();
$jwt = $this->jwtManager->create($user);
if ($this->session->get('_locale') !== null) {
$this->commandBus->dispatch(
new UpdateUserLanguage(
$user->getId(),
new UserLanguage($this->session->get('_locale'))
)
);
}
}
$request->attributes->set(self::JWT_ATTRIBUTE_NAME, $jwt);
}
public function onKernelResponse(ResponseEvent $event): void
{
$attributes = $event->getRequest()->attributes;
if (!$attributes->has(self::JWT_ATTRIBUTE_NAME)) {
return;
}
$cookie = new Cookie(
IAuthenticationListener::COOKIE_NAME,
$attributes->get(self::JWT_ATTRIBUTE_NAME),
(new DateTime())->add(new DateInterval('P365D')),
'/',
null,
false,
false
);
$headers = $event->getResponse()->headers;
$headers->setCookie($cookie);
}
}