<?php
declare(strict_types=1);
namespace App\Component\Firewall;
use App\Entity\User;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Event\LogoutEvent;
#[AsEventListener(priority: 4096)]
readonly class FirewallListener
{
private const WHITELIST = [
// Concawe offices (Skynet)
'91.183.59.41',
// Concawe offices (Unix Solutions)
'195.189.202.50',
// Peter Discart home
'81.82.232.137',
// Kristof Torfs home
'81.82.197.76',
// Chris Davidson home
'81.133.240.129',
];
public function __construct(
private Security $security,
private TokenStorageInterface $tokenStorage,
private EventDispatcherInterface $eventDispatcher,
private string $environment
) {
}
public function __invoke(ControllerEvent $event): void
{
if ('dev' === $this->environment) {
// Firewall only applies to online environments
return;
}
$user = $this->security->getUser();
if (!$user instanceof User) {
// Firewall only applies to authenticated users
return;
}
if (!$user->isStaff()) {
// Firewall only applies to staff members
return;
}
$ip = $event->getRequest()->getClientIp();
if (in_array($ip, self::WHITELIST, true)) {
// Firewall only applies to IP addresses that are not in the whitelist
return;
}
// Clear authentication
$this->logout($event->getRequest());
// Redirect
$event->setController(fn (): RedirectResponse => new RedirectResponse('/not-secure'));
// Stop event propagation
$event->stopPropagation();
}
private function logout(Request $request): void
{
// FIXME: Use the new Security bundle when upgrading to Symfony 6
$event = new LogoutEvent($request, $this->tokenStorage->getToken());
$this->eventDispatcher->dispatch($event);
$this->tokenStorage->setToken(null);
}
}