<?php
namespace Mm\Escmid\EaaBundle\EventListener;
use Mm\Escmid\EaaBundle\Controller\ApiControllerInterface;
use Mm\Escmid\EaaBundle\Controller\AuthenticatedControllerInterface;
use Mm\Escmid\EaaBundle\Controller\LegacyController;
use Mm\Escmid\EaaBundle\Platform\Security\AccessDeniedHttpException;
use Mm\Escmid\EaaBundle\Platform\Security\AuthenticationException;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
use Symfony\Bundle\WebProfilerBundle\Controller\ExceptionPanelController;
use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController;
use Symfony\Bundle\WebProfilerBundle\Controller\RouterController;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
class AuthListener implements EventSubscriberInterface
{
private $controllersWhitelist = [];
/**
* AuthListener constructor.
*/
public function __construct()
{
}
public function onKernelController(ControllerEvent $event): void
{
/** @var Controller[] */
$controllers = $event->getController();
/*
* $controller passed can be either a class or a Closure. This is not usual in Symfony but it may happen.
* If it is a class, it comes in array format.
*/
if (!is_array($controllers)) {
return;
}
if ($controllers[0] instanceof AuthenticatedControllerInterface) {
$controllers[0]->setRequest($event->getRequest());
$this->checkController($controllers[0]);
} elseif (($controllers[0] instanceof ProfilerController)
|| ($controllers[0] instanceof RouterController)
) {
/*
* allow access for Symfony WebProfilerBundle controllers
*/
} elseif ($controllers[0] instanceof ApiControllerInterface) {
// allow access to API
} elseif ($controllers[0] instanceof RedirectController) {
// allow redirects
} elseif ($controllers[0] instanceof ExceptionPanelController) {
// allow handling exceptions
} else {
$unknown = true;
foreach ($this->controllersWhitelist as $className) {
if ($controllers[0] instanceof $className) {
$unknown = false;
break;
}
}
if ($unknown) {
throw new \Exception("Invalid controller '".$controllers[0]::class."', must be instance of either one of these:
\n* Mm\\Escmid\\EaaBundle\\Controller\\AuthenticatedControllerInterface\n
* Symfony\\Bundle\\WebProfilerBundle\\Controller\\ProfilerController\n
* Symfony\\Bundle\\WebProfilerBundle\\Controller\\RouterController\n
* Mm\\Escmid\\EaaBundle\\Controller\\ApiControllerInterface\n
* Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController\n
* Symfony\\Bundle\\WebProfilerBundle\\Controller\\ExceptionPanelController\n".'* '.implode("\n* ", $this->controllersWhitelist));
}
}
}
public function checkController(AuthenticatedControllerInterface $controller): void
{
$principal = $controller->getPrincipal();
$controller->refreshLastSessionActivity();
if ($controller->requiresLogin() || LegacyController::class === $controller::class) {
if (null == $principal || !$principal->isLoggedIn()) {
throw new AuthenticationException('Not logged in.');
}
}
if (!$controller->checkAreaPermissions()) {
$path = $controller->getCurrentPath();
throw new AccessDeniedHttpException(sprintf('Area Access denied for path %s.', $path));
}
if (!$controller->checkPermissions()) {
throw new AccessDeniedHttpException('Access denied.');
}
}
/**
* @return array<string, mixed>
*/
public static function getSubscribedEvents(): array
{
return [\Symfony\Component\HttpKernel\KernelEvents::CONTROLLER => 'onKernelController'];
}
}