Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Security] Remove callable firewall listeners support #60879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions UPGRADE-8.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ Security
+}
```

* Remove callable firewall listeners support, extend `AbstractListener` or implement `FirewallListenerInterface` instead
* Remove `AbstractListener::__invoke`
* Remove `LazyFirewallContext::__invoke()`

Serializer
----------

Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

8.0
---

* Remove `LazyFirewallContext::__invoke()`

7.4
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
use Symfony\Bundle\SecurityBundle\Security\LazyFirewallContext;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener;
use Symfony\Component\Security\Http\Firewall\AbstractListener;
use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
use Symfony\Contracts\Service\ResetInterface;

/**
Expand All @@ -33,7 +31,7 @@ final class TraceableFirewallListener extends FirewallListener implements ResetI
public function getWrappedListeners(): array
{
return array_map(
static fn (WrappedListener|WrappedLazyListener $listener) => $listener->getInfo(),
static fn (WrappedLazyListener $listener) => $listener->getInfo(),
$this->wrappedListeners
);
}
Expand Down Expand Up @@ -62,10 +60,7 @@ protected function callListeners(RequestEvent $event, iterable $listeners): void
if ($listener instanceof TraceableAuthenticatorManagerListener) {
$contextAuthenticatorManagerListener ??= $listener;
}
$contextWrappedListeners[] = $listener instanceof FirewallListenerInterface
? new WrappedLazyListener($listener)
: new WrappedListener($listener)
;
$contextWrappedListeners[] = new WrappedLazyListener($listener);
}
$this->listeners = $contextWrappedListeners;
}, $listener, FirewallContext::class)();
Expand All @@ -78,23 +73,20 @@ protected function callListeners(RequestEvent $event, iterable $listeners): void
if ($listener instanceof TraceableAuthenticatorManagerListener) {
$this->authenticatorManagerListener ??= $listener;
}
$wrappedListener = $listener instanceof FirewallListenerInterface
? new WrappedLazyListener($listener)
: new WrappedListener($listener)
;
$wrappedListener = new WrappedLazyListener($listener);
$this->wrappedListeners[] = $wrappedListener;

$requestListeners[] = $wrappedListener;
}
}

foreach ($requestListeners as $listener) {
if (!$listener instanceof FirewallListenerInterface) {
$listener($event);
} elseif (false !== $listener->supports($event->getRequest())) {
$listener->authenticate($event);
if (false === $listener->supports($event->getRequest())) {
continue;
}

$listener->authenticate($event);

if ($event->hasResponse()) {
break;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@
namespace Symfony\Bundle\SecurityBundle\Debug;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Exception\LazyResponseException;
use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener;
use Symfony\Component\Security\Http\Firewall\AbstractListener;
use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
use Symfony\Component\VarDumper\Caster\ClassStub;

/**
* Wraps a lazy security listener.
Expand All @@ -26,7 +29,10 @@
*/
final class WrappedLazyListener extends AbstractListener
{
use TraceableListenerTrait;
private ?Response $response = null;
private FirewallListenerInterface $listener;
private ?float $time = null;
private ClassStub $stub;

public function __construct(FirewallListenerInterface $listener)
{
Expand Down Expand Up @@ -54,4 +60,21 @@ public function authenticate(RequestEvent $event): void

$this->response = $event->getResponse();
}

public function getInfo(): array
{
return [
'response' => $this->response,
'time' => $this->time,
'stub' => $this->stub ??= new ClassStub($this->listener instanceof TraceableAuthenticatorManagerListener ? $this->listener->getAuthenticatorManagerListener()::class : $this->listener::class),
];
}

/**
* Proxies all method calls to the original listener.
*/
public function __call(string $method, array $arguments): mixed
{
return $this->listener->{$method}(...$arguments);
}
}
42 changes: 0 additions & 42 deletions src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
class FirewallContext
{
/**
* @param iterable<mixed, callable> $listeners
* @param iterable<mixed, FirewallListenerInterface> $listeners
*/
public function __construct(
private iterable $listeners,
Expand All @@ -40,7 +40,7 @@ public function getConfig(): ?FirewallConfig
}

/**
* @return iterable<mixed, FirewallListenerInterface|callable>
* @return iterable<mixed, FirewallListenerInterface>
*/
public function getListeners(): iterable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Http\Event\LazyResponseEvent;
use Symfony\Component\Security\Http\Firewall\AbstractListener;
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
use Symfony\Component\Security\Http\Firewall\LogoutListener;
Expand Down Expand Up @@ -54,20 +53,15 @@ public function authenticate(RequestEvent $event): void
$lazy = $request->isMethodCacheable();

foreach (parent::getListeners() as $listener) {
if (!$listener instanceof FirewallListenerInterface) {
trigger_deprecation('symfony/security-http', '7.4', 'Using a callable as firewall listener is deprecated, extend "%s" or implement "%s" instead.', AbstractListener::class, FirewallListenerInterface::class);

if (false !== $supports = $listener->supports($request)) {
$listeners[] = $listener;
$lazy = false;
} elseif (false !== $supports = $listener->supports($request)) {
$listeners[] = [$listener, 'authenticate'];
$lazy = $lazy && null === $supports;
}
}

if (!$lazy) {
foreach ($listeners as $listener) {
$listener($event);
$listener->authenticate($event);

if ($event->hasResponse()) {
return;
Expand All @@ -80,7 +74,7 @@ public function authenticate(RequestEvent $event): void
$this->tokenStorage->setInitializer(function () use ($event, $listeners) {
$event = new LazyResponseEvent($event);
foreach ($listeners as $listener) {
$listener($event);
$listener->authenticate($event);
}
});
}
Expand All @@ -89,14 +83,4 @@ public static function getPriority(): int
{
return 0;
}

/**
* @deprecated since Symfony 7.4, to be removed in 8.0
*/
public function __invoke(RequestEvent $event): void
{
trigger_deprecation('symfony/security-bundle', '7.4', 'The "%s()" method is deprecated since Symfony 7.4 and will be removed in 8.0.', __METHOD__);

$this->authenticate($event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Symfony\Component\Security\Http\Firewall\AuthenticatorManagerListener;
use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
use Symfony\Component\VarDumper\Caster\ClassStub;

/**
* @group time-sensitive
Expand Down Expand Up @@ -75,7 +76,8 @@ public function authenticate(RequestEvent $event): void

$listeners = $firewall->getWrappedListeners();
$this->assertCount(1, $listeners);
$this->assertSame($listener, $listeners[0]['stub']);
$this->assertInstanceOf(ClassStub::class, $listeners[0]['stub']);
$this->assertSame((string) new ClassStub($listener::class), (string) $listeners[0]['stub']);
}

public function testOnKernelRequestRecordsAuthenticatorsInfo()
Expand Down
1 change: 0 additions & 1 deletion src/Symfony/Bundle/SecurityBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"symfony/clock": "^7.4|^8.0",
"symfony/config": "^7.4|^8.0",
"symfony/dependency-injection": "^7.4|^8.0",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/event-dispatcher": "^7.4|^8.0",
"symfony/http-kernel": "^7.4|^8.0",
"symfony/http-foundation": "^7.4|^8.0",
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Security/Http/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG
=========

8.0
---

* Remove callable firewall listeners support, extend `AbstractListener` or implement `FirewallListenerInterface` instead
* Remove `AbstractListener::__invoke`

7.4
---

Expand Down
23 changes: 6 additions & 17 deletions src/Symfony/Component/Security/Http/Firewall.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Http\Firewall\AbstractListener;
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
Expand Down Expand Up @@ -66,14 +64,12 @@ public function onKernelRequest(RequestEvent $event): void
// Authentication listeners are pre-sorted by SortFirewallListenersPass
$authenticationListeners = function () use ($authenticationListeners, $logoutListener) {
if (null !== $logoutListener) {
$logoutListenerPriority = $this->getListenerPriority($logoutListener);
$logoutListenerPriority = $logoutListener::getPriority();
}

foreach ($authenticationListeners as $listener) {
$listenerPriority = $this->getListenerPriority($listener);

// Yielding the LogoutListener at the correct position
if (null !== $logoutListener && $listenerPriority < $logoutListenerPriority) {
if (null !== $logoutListener && $listener::getPriority() < $logoutListenerPriority) {
yield $logoutListener;
$logoutListener = null;
}
Expand Down Expand Up @@ -111,22 +107,15 @@ public static function getSubscribedEvents(): array
protected function callListeners(RequestEvent $event, iterable $listeners): void
{
foreach ($listeners as $listener) {
if (!$listener instanceof FirewallListenerInterface) {
trigger_deprecation('symfony/security-http', '7.4', 'Using a callable as firewall listener is deprecated, extend "%s" or implement "%s" instead.', AbstractListener::class, FirewallListenerInterface::class);

$listener($event);
} elseif (false !== $listener->supports($event->getRequest())) {
$listener->authenticate($event);
if (false === $listener->supports($event->getRequest())) {
continue;
}

$listener->authenticate($event);

if ($event->hasResponse()) {
break;
}
}
}

private function getListenerPriority(object $listener): int
{
return $listener instanceof FirewallListenerInterface ? $listener->getPriority() : 0;
}
}
Loading
Loading