Skip to content

Commit e79f533

Browse files
committed
[SecurityBundle][Routing] Add LogoutRouteLoader
1 parent c005258 commit e79f533

File tree

5 files changed

+125
-0
lines changed

5 files changed

+125
-0
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Deprecate `Security::ACCESS_DENIED_ERROR`, `AUTHENTICATION_ERROR` and `LAST_USERNAME` constants, use the ones on `SecurityRequestAttributes` instead
88
* Allow an array of `pattern` in firewall configuration
99
* Add `$badges` argument to `Security::login`
10+
* Add `LogoutRouteLoader`
1011

1112
6.3
1213
---

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
use Symfony\Component\PasswordHasher\Hasher\Pbkdf2PasswordHasher;
5050
use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher;
5151
use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher;
52+
use Symfony\Component\Routing\Loader\ContainerLoader;
5253
use Symfony\Component\Security\Core\Authorization\Strategy\AffirmativeStrategy;
5354
use Symfony\Component\Security\Core\Authorization\Strategy\ConsensusStrategy;
5455
use Symfony\Component\Security\Core\Authorization\Strategy\PriorityStrategy;
@@ -170,6 +171,13 @@ public function load(array $configs, ContainerBuilder $container)
170171
}
171172

172173
$this->createFirewalls($config, $container);
174+
175+
if ($container::willBeAvailable('symfony/routing', ContainerLoader::class, ['symfony/security/bundle'])) {
176+
$this->createLogoutPathsParameter($config['firewalls'] ?? [], $container);
177+
} else {
178+
$container->removeDefinition('security.route_loader.logout');
179+
}
180+
173181
$this->createAuthorization($config, $container);
174182
$this->createRoleHierarchy($config, $container);
175183

@@ -1093,4 +1101,16 @@ private function getSortedFactories(): array
10931101

10941102
return $this->sortedFactories;
10951103
}
1104+
1105+
private function createLogoutPathsParameter(array $firewallsConfig, ContainerBuilder $container): void
1106+
{
1107+
$logoutPaths = [];
1108+
foreach ($firewallsConfig as $name => $config) {
1109+
if ($logoutPath = $config['logout']['path'] ?? null) {
1110+
$logoutPaths[$name] = $logoutPath;
1111+
}
1112+
}
1113+
1114+
$container->setParameter('security.logout_paths', $logoutPaths);
1115+
}
10961116
}

src/Symfony/Bundle/SecurityBundle/Resources/config/security.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Bundle\SecurityBundle\CacheWarmer\ExpressionCacheWarmer;
1515
use Symfony\Bundle\SecurityBundle\EventListener\FirewallListener;
16+
use Symfony\Bundle\SecurityBundle\Routing\LogoutRouteLoader;
1617
use Symfony\Bundle\SecurityBundle\Security;
1718
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
1819
use Symfony\Bundle\SecurityBundle\Security\FirewallContext;
@@ -229,6 +230,13 @@
229230
service('security.token_storage')->nullOnInvalid(),
230231
])
231232

233+
->set('security.route_loader.logout', LogoutRouteLoader::class)
234+
->args([
235+
'%security.logout_paths%',
236+
'security.logout_paths',
237+
])
238+
->tag('routing.route_loader')
239+
232240
// Provisioning
233241
->set('security.user.provider.missing', MissingUserProvider::class)
234242
->abstract()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\Routing;
13+
14+
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
15+
use Symfony\Component\Routing\Route;
16+
use Symfony\Component\Routing\RouteCollection;
17+
18+
class LogoutRouteLoader
19+
{
20+
/**
21+
* @param iterable<string, string> $logoutPaths Logout paths indexed by the corresponding firewall name
22+
* @param string $parameterName Name of the container parameter containing {@see $logoutPaths}' value
23+
*/
24+
public function __construct(
25+
private readonly iterable $logoutPaths,
26+
private readonly string $parameterName,
27+
) {
28+
}
29+
30+
public function __invoke(): RouteCollection
31+
{
32+
$collection = new RouteCollection();
33+
$collection->addResource(new ContainerParametersResource([$this->parameterName => $this->logoutPaths]));
34+
35+
$routeNames = [];
36+
foreach ($this->logoutPaths as $firewallName => $logoutPath) {
37+
$routeName = '_logout_'.$firewallName;
38+
39+
if (isset($routeNames[$logoutPath])) {
40+
$collection->addAlias($routeNames[$logoutPath], $routeName);
41+
} else {
42+
$routeNames[$logoutPath] = $routeName;
43+
}
44+
45+
$collection->add($routeName, new Route($logoutPath));
46+
}
47+
48+
return $collection;
49+
}
50+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\Tests\Routing;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\SecurityBundle\Routing\LogoutRouteLoader;
16+
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
17+
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
18+
use Symfony\Component\Routing\Route;
19+
use Symfony\Component\Routing\RouteCollection;
20+
21+
class LogoutRouteLoaderTest extends TestCase
22+
{
23+
public function testLoad()
24+
{
25+
$logoutPaths = [
26+
'main' => '/logout',
27+
'admin' => '/logout',
28+
];
29+
30+
$loader = new LogoutRouteLoader($logoutPaths, 'parameterName');
31+
$collection = $loader();
32+
33+
self::assertInstanceOf(RouteCollection::class, $collection);
34+
self::assertCount(1, $collection);
35+
self::assertEquals(new Route('/logout'), $collection->get('_logout_main'));
36+
self::assertCount(1, $collection->getAliases());
37+
self::assertEquals('_logout_admin', $collection->getAlias('_logout_main')->getId());
38+
39+
$resources = $collection->getResources();
40+
self::assertCount(1, $resources);
41+
42+
$resource = reset($resources);
43+
self::assertInstanceOf(ContainerParametersResource::class, $resource);
44+
self::assertSame(['parameterName' => $logoutPaths], $resource->getParameters());
45+
}
46+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy