<?php
namespace App\EventListener;
use App\Service\App\ApiResponseService;
use InvalidArgumentException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Yaml\Yaml;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
class KernelListener
{
/** @var Security */
private Security $security;
/** @var ApiResponseService */
private ApiResponseService $apiResponseService;
/** @var ContainerInterface */
private ContainerInterface $container;
/** @var array */
private array $userRoles;
/** @var string */
private string $configFile;
/** @var string */
private string $securityFile;
/**
* @param Security $security
* @param ApiResponseService $apiResponseService
* @param ContainerInterface $container
* @param string $configFile
* @param string $securityFile
* @throws ClientExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
*/
public function __construct(
Security $security,
ApiResponseService $apiResponseService,
ContainerInterface $container,
string $configFile,
string $securityFile
)
{
$this->security = $security;
$this->apiResponseService = $apiResponseService;
$this->container = $container;
$this->configFile = $configFile;
$this->securityFile = $securityFile;
}
/**
* @param RequestEvent $event
* @throws ClientExceptionInterface
* @throws DecodingExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface
* @throws TransportExceptionInterface
*/
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
$route = $request->attributes->get('_route');
if ($this->security->getUser()) {
$this->userRoles = $this->security->getUser()->getRoles();
$configArray = $this->loadYamlConfigurations($this->configFile);
$securityArray = $this->loadYamlConfigurations($this->securityFile);
$adminRolesToSecure = $securityArray['security']['role_hierarchy']['ADMIN_ROLES_TO_SECURE'];
$clientRolesToSecure = $securityArray['security']['role_hierarchy']['CLIENT_ROLES_TO_SECURE'];
// secure all admin route
if (array_intersect($adminRolesToSecure, $this->userRoles)) {
if (!$this->accessAuthorisation($route, $configArray)) {
$event->setResponse($this->apiResponseService->getAccessDeniedResponse());
}
}
// secure client route
if (array_intersect($clientRolesToSecure, $this->userRoles)) {
if (!$this->accessAuthorisation($route, $configArray)) {
$event->setResponse($this->apiResponseService->getAccessDeniedResponse());
}
}
}
}
/**
* @param string $route
* @param array $configArray
* @return bool|null
*/
private function accessAuthorisation(string $route, array $configArray): ?bool
{
if (array_key_exists($route, $configArray)) {
if ($routeConfig = $configArray[$route]) {
return array_intersect($this->userRoles, $routeConfig['requested_roles']) &&
$this->container->get('security.authorization_checker')->isGranted($routeConfig['attribute'], $routeConfig['subject']);
}
}
return null;
}
/**
* @return array|mixed
*/
private function loadYamlConfigurations(string $path)
{
$array = Yaml::parse(file_get_contents($path));
if (!is_array($array)) {
throw new InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path));
}
return $array;
}
}