<?php
namespace App\EventListener;
use App\Entity\Commons\OAuth2\AccessToken;
use App\Exception\Security as SecurityException;
use App\Service\CdpService;
use App\Service\UserManager;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
use Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2Token;
class SecurityEventListener implements EventSubscriberInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
/**
* @var CdpService
*/
protected $cdp;
/**
* @var UserManager
*/
protected $userManager;
public function __construct(CdpService $cdp, UserManager $userManager, RequestStack $requestStack)
{
$this->cdp = $cdp;
$this->userManager = $userManager;
}
public static function getSubscribedEvents()
{
return [
AuthenticationEvents::AUTHENTICATION_SUCCESS => [['onOAuth2Authentication', 20]],
KernelEvents::EXCEPTION => [['onSecurityException']],
];
}
public function onOAuth2Authentication(AuthenticationEvent $event)
{
$token = $event->getAuthenticationToken();
if (!$token instanceof OAuth2Token) {
return;
}
$accessTokenId = $token->getAttribute('server_request')->getAttribute('oauth_access_token_id');
$clientId = $token->getAttribute('server_request')->getAttribute('oauth_client_id');
$accessTokenEntity = $this->cdp->getCommonsEntityManager()->createQueryBuilder()
->from(AccessToken::class, 'access_token')
->select('access_token')
->innerJoin('access_token.account', 'account')
->innerJoin('account.fond', 'fond')
->addSelect('account')
->addSelect('fond')
->andWhere('access_token.identifier = :identifier')
->setParameter('identifier', $accessTokenId)
->getQuery()
->getOneOrNullResult()
;
if (!$accessTokenEntity) {
throw new SecurityException("Token entity not found", SecurityException::CODE_GENERAL);
}
$account = $accessTokenEntity->getAccount();
$user = $token->getUser(); // Ou bien $accessTokenEntity.account.user
if (!$user) {
throw new SecurityException("Token without user", SecurityException::CODE_GENERAL);
}
$this->userManager->updateConnectedAt($user);
$this->cdp
->setCurrentUser($user)
->setCurrentAccount($account)
->setCurrentFond($account->getFond())
;
}
public function onSecurityException(ExceptionEvent $event)
{
$exception = $event->getThrowable();
if (!$exception instanceof SecurityException\SecurityException) {
return;
}
$this->logger->error($exception->getMessage(), [
'code' => $exception->getCode(),
]);
$response = new JsonResponse([
'error' => $exception->getMessage(),
'code' => $exception->getCode(),
], Response::HTTP_FORBIDDEN);
$event->setResponse($response);
}
}