Skip to content

Commit

Permalink
[SecurityBundle][Routing] Add LogoutRouteLoader
Browse files Browse the repository at this point in the history
  • Loading branch information
MatTheCat committed Sep 17, 2023
1 parent 517128f commit 65f4a67
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CHANGELOG
* Allow an array of `pattern` in firewall configuration
* Add `$badges` argument to `Security::login`
* Deprecate the `require_previous_session` config option. Setting it has no effect anymore
* Add `LogoutRouteLoader`

6.3
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
use Symfony\Component\PasswordHasher\Hasher\Pbkdf2PasswordHasher;
use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher;
use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher;
use Symfony\Component\Routing\Loader\ContainerLoader;
use Symfony\Component\Security\Core\Authorization\Strategy\AffirmativeStrategy;
use Symfony\Component\Security\Core\Authorization\Strategy\ConsensusStrategy;
use Symfony\Component\Security\Core\Authorization\Strategy\PriorityStrategy;
Expand Down Expand Up @@ -170,6 +171,13 @@ public function load(array $configs, ContainerBuilder $container)
}

$this->createFirewalls($config, $container);

if ($container::willBeAvailable('symfony/routing', ContainerLoader::class, ['symfony/security-bundle'])) {
$this->createLogoutPathsParameter($config['firewalls'] ?? [], $container);
} else {
$container->removeDefinition('security.route_loader.logout');
}

$this->createAuthorization($config, $container);
$this->createRoleHierarchy($config, $container);

Expand Down Expand Up @@ -1091,4 +1099,16 @@ private function getSortedFactories(): array

return $this->sortedFactories;
}

private function createLogoutPathsParameter(array $firewallsConfig, ContainerBuilder $container): void
{
$logoutPaths = [];
foreach ($firewallsConfig as $name => $config) {
if ($logoutPath = $config['logout']['path'] ?? null) {
$logoutPaths[$name] = $logoutPath;
}
}

$container->setParameter('security.logout_paths', $logoutPaths);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Bundle\SecurityBundle\CacheWarmer\ExpressionCacheWarmer;
use Symfony\Bundle\SecurityBundle\EventListener\FirewallListener;
use Symfony\Bundle\SecurityBundle\Routing\LogoutRouteLoader;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
use Symfony\Bundle\SecurityBundle\Security\FirewallContext;
Expand Down Expand Up @@ -229,6 +230,13 @@
service('security.token_storage')->nullOnInvalid(),
])

->set('security.route_loader.logout', LogoutRouteLoader::class)
->args([
'%security.logout_paths%',
'security.logout_paths',
])
->tag('routing.route_loader')

// Provisioning
->set('security.user.provider.missing', MissingUserProvider::class)
->abstract()
Expand Down
50 changes: 50 additions & 0 deletions src/Symfony/Bundle/SecurityBundle/Routing/LogoutRouteLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\SecurityBundle\Routing;

use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

class LogoutRouteLoader
{
/**
* @param iterable<string, string> $logoutPaths Logout paths indexed by the corresponding firewall name
* @param string $parameterName Name of the container parameter containing {@see $logoutPaths}' value
*/
public function __construct(

Check failure on line 24 in src/Symfony/Bundle/SecurityBundle/Routing/LogoutRouteLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

PossiblyUnusedMethod

src/Symfony/Bundle/SecurityBundle/Routing/LogoutRouteLoader.php:24:21: PossiblyUnusedMethod: Cannot find any calls to method Symfony\Bundle\SecurityBundle\Routing\LogoutRouteLoader::__construct (see https://psalm.dev/087)

Check failure on line 24 in src/Symfony/Bundle/SecurityBundle/Routing/LogoutRouteLoader.php

View workflow job for this annotation

GitHub Actions / Psalm

PossiblyUnusedMethod

src/Symfony/Bundle/SecurityBundle/Routing/LogoutRouteLoader.php:24:21: PossiblyUnusedMethod: Cannot find any calls to method Symfony\Bundle\SecurityBundle\Routing\LogoutRouteLoader::__construct (see https://psalm.dev/087)
private readonly iterable $logoutPaths,
private readonly string $parameterName,
) {
}

public function __invoke(): RouteCollection
{
$collection = new RouteCollection();
$collection->addResource(new ContainerParametersResource([$this->parameterName => $this->logoutPaths]));

$routeNames = [];
foreach ($this->logoutPaths as $firewallName => $logoutPath) {
$routeName = '_logout_'.$firewallName;

if (isset($routeNames[$logoutPath])) {
$collection->addAlias($routeNames[$logoutPath], $routeName);
} else {
$routeNames[$logoutPath] = $routeName;
}

$collection->add($routeName, new Route($logoutPath));
}

return $collection;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bundle\SecurityBundle\Tests\Routing;

use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Routing\LogoutRouteLoader;
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

class LogoutRouteLoaderTest extends TestCase
{
public function testLoad()
{
$logoutPaths = [
'main' => '/logout',
'admin' => '/logout',
];

$loader = new LogoutRouteLoader($logoutPaths, 'parameterName');
$collection = $loader();

self::assertInstanceOf(RouteCollection::class, $collection);
self::assertCount(1, $collection);
self::assertEquals(new Route('/logout'), $collection->get('_logout_main'));
self::assertCount(1, $collection->getAliases());
self::assertEquals('_logout_admin', $collection->getAlias('_logout_main')->getId());

$resources = $collection->getResources();
self::assertCount(1, $resources);

$resource = reset($resources);
self::assertInstanceOf(ContainerParametersResource::class, $resource);
self::assertSame(['parameterName' => $logoutPaths], $resource->getParameters());
}
}

0 comments on commit 65f4a67

Please sign in to comment.