diff --git a/DataCollector/SecurityDataCollector.php b/DataCollector/SecurityDataCollector.php
index aa6e8d9a..cd0e41ac 100644
--- a/DataCollector/SecurityDataCollector.php
+++ b/DataCollector/SecurityDataCollector.php
@@ -101,10 +101,12 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
}
$logoutUrl = null;
- try {
- $logoutUrl = $this->logoutUrlGenerator?->getLogoutPath();
- } catch (\Exception) {
- // fail silently when the logout URL cannot be generated
+ if ($this->logoutUrlGenerator && method_exists($token, 'getFirewallName')) {
+ try {
+ $logoutUrl = $this->logoutUrlGenerator->getLogoutPath($token->getFirewallName());
+ } catch (\Exception) {
+ // fail silently when the logout URL cannot be generated
+ }
}
$this->data = [
diff --git a/DependencyInjection/Security/AccessToken/CasTokenHandlerFactory.php b/DependencyInjection/Security/AccessToken/CasTokenHandlerFactory.php
index a0c2ca04..63ff5db1 100644
--- a/DependencyInjection/Security/AccessToken/CasTokenHandlerFactory.php
+++ b/DependencyInjection/Security/AccessToken/CasTokenHandlerFactory.php
@@ -42,7 +42,6 @@ public function addConfiguration(NodeBuilder $node): void
{
$node
->arrayNode($this->getKey())
- ->fixXmlConfig($this->getKey())
->children()
->scalarNode('validation_url')
->info('CAS server validation URL')
diff --git a/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php b/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php
index de53d5e8..0bfd4793 100644
--- a/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php
+++ b/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php
@@ -90,7 +90,8 @@ public function addConfiguration(NodeBuilder $node): void
{
$node
->arrayNode($this->getKey())
- ->fixXmlConfig($this->getKey())
+ ->fixXmlConfig('issuer')
+ ->fixXmlConfig('algorithm')
->validate()
->ifTrue(static fn ($v) => !isset($v['algorithm']) && !isset($v['algorithms']))
->thenInvalid('You must set either "algorithm" or "algorithms".')
@@ -172,6 +173,7 @@ public function addConfiguration(NodeBuilder $node): void
->info('JSON-encoded JWKSet used to sign the token (must contain a list of valid public keys).')
->end()
->arrayNode('encryption')
+ ->fixXmlConfig('algorithm')
->canBeEnabled()
->children()
->booleanNode('enforce')
diff --git a/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php b/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php
index c6308ff3..0b69d4e7 100644
--- a/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php
+++ b/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php
@@ -63,7 +63,6 @@ public function addConfiguration(NodeBuilder $node): void
{
$node
->arrayNode($this->getKey())
- ->fixXmlConfig($this->getKey())
->beforeNormalization()
->ifString()
->then(fn ($v) => ['claim' => 'sub', 'base_uri' => $v])
diff --git a/DependencyInjection/Security/Factory/AccessTokenFactory.php b/DependencyInjection/Security/Factory/AccessTokenFactory.php
index 371049c8..f5aa4711 100644
--- a/DependencyInjection/Security/Factory/AccessTokenFactory.php
+++ b/DependencyInjection/Security/Factory/AccessTokenFactory.php
@@ -43,11 +43,10 @@ public function addConfiguration(NodeDefinition $node): void
{
parent::addConfiguration($node);
- $builder = $node->children();
+ $builder = $node->fixXmlConfig('token_extractor')->children();
$builder
->scalarNode('realm')->defaultNull()->end()
->arrayNode('token_extractors')
- ->fixXmlConfig('token_extractors')
->beforeNormalization()
->ifString()
->then(fn ($v) => [$v])
diff --git a/DependencyInjection/Security/Factory/RememberMeFactory.php b/DependencyInjection/Security/Factory/RememberMeFactory.php
index c62c01d4..57308068 100644
--- a/DependencyInjection/Security/Factory/RememberMeFactory.php
+++ b/DependencyInjection/Security/Factory/RememberMeFactory.php
@@ -126,6 +126,7 @@ public function getKey(): string
public function addConfiguration(NodeDefinition $node): void
{
$builder = $node
+ ->fixXmlConfig('signature_property', 'signature_properties')
->fixXmlConfig('user_provider')
->children()
;
diff --git a/Resources/config/schema/security-1.0.xsd b/Resources/config/schema/security-1.0.xsd
index 692321a4..537119d8 100644
--- a/Resources/config/schema/security-1.0.xsd
+++ b/Resources/config/schema/security-1.0.xsd
@@ -9,11 +9,8 @@
-
-
-
+
-
@@ -21,28 +18,10 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -55,7 +34,6 @@
-
@@ -196,12 +174,16 @@
+
+
+
+
@@ -304,6 +286,7 @@
+
@@ -321,59 +304,66 @@
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -442,7 +432,7 @@
-
+
@@ -452,6 +442,7 @@
+
diff --git a/Tests/Command/DebugFirewallCommandTest.php b/Tests/Command/DebugFirewallCommandTest.php
new file mode 100644
index 00000000..673f0c43
--- /dev/null
+++ b/Tests/Command/DebugFirewallCommandTest.php
@@ -0,0 +1,197 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\SecurityBundle\Tests\Command;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Bundle\SecurityBundle\Command\DebugFirewallCommand;
+use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
+use Symfony\Bundle\SecurityBundle\Security\FirewallContext;
+use Symfony\Bundle\SecurityBundle\Tests\Fixtures\DummyAuthenticator;
+use Symfony\Component\Console\Tester\CommandTester;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
+
+class DebugFirewallCommandTest extends TestCase
+{
+ public function testFirewallListOutputMatchesFixture()
+ {
+ $firewallNames = ['main', 'api'];
+ $contexts = $this->createMock(ContainerInterface::class);
+ $eventDispatchers = $this->createMock(ContainerInterface::class);
+
+ $command = new DebugFirewallCommand($firewallNames, $contexts, $eventDispatchers, []);
+ $tester = new CommandTester($command);
+
+ $this->assertSame(0, $tester->execute([]));
+ $this->assertStringContainsString('Firewalls', $tester->getDisplay());
+ $this->assertStringContainsString('The following firewalls are defined:', $tester->getDisplay());
+ $this->assertStringContainsString('* main', $tester->getDisplay());
+ $this->assertStringContainsString('* api', $tester->getDisplay());
+ $this->assertStringContainsString('To view details of a specific firewall', $tester->getDisplay());
+ }
+
+ public function testFirewallNotFoundDisplaysError()
+ {
+ $firewallNames = ['main', 'api'];
+
+ $contexts = $this->createMock(ContainerInterface::class);
+ $contexts->method('has')->willReturn(false);
+
+ $eventDispatchers = $this->createMock(ContainerInterface::class);
+ $authenticators = [];
+
+ $command = new DebugFirewallCommand(
+ $firewallNames,
+ $contexts,
+ $eventDispatchers,
+ $authenticators
+ );
+
+ $tester = new CommandTester($command);
+
+ $this->assertSame(1, $tester->execute(['name' => 'admin']));
+ $this->assertStringContainsString('Firewall admin was not found.', $tester->getDisplay());
+ $this->assertStringContainsString('Available firewalls are: main, api', $tester->getDisplay());
+ }
+
+ public function testFirewallMainOutputMatchesFixture()
+ {
+ $firewallNames = ['main'];
+
+ $config = new FirewallConfig(
+ name: 'main',
+ userChecker: 'user_checker_service',
+ requestMatcher: null,
+ securityEnabled: true,
+ stateless: false,
+ provider: 'user_provider_service',
+ context: 'main',
+ entryPoint: 'entry_point_service',
+ accessDeniedHandler: 'access_denied_handler_service',
+ accessDeniedUrl: '/access-denied',
+ authenticators: [],
+ switchUser: null
+ );
+
+ $context = new FirewallContext([], config: $config);
+
+ $contexts = $this->createMock(ContainerInterface::class);
+ $contexts->method('has')->willReturn(true);
+ $contexts->method('get')->willReturn($context);
+
+ $eventDispatchers = $this->createMock(ContainerInterface::class);
+ $authenticator = new DummyAuthenticator();
+ $authenticators = ['main' => [$authenticator]];
+
+ $command = new DebugFirewallCommand($firewallNames, $contexts, $eventDispatchers, $authenticators);
+ $tester = new CommandTester($command);
+
+ $this->assertSame(0, $tester->execute(['name' => 'main', '--events' => true]));
+ $this->assertEquals($this->getFixtureOutput('firewall_main_output.txt'), trim(str_replace(\PHP_EOL, "\n", $tester->getDisplay())));
+ }
+
+ public function testFirewallWithEventsOutputMatchesFixture()
+ {
+ $firewallNames = ['main'];
+
+ $config = new FirewallConfig(
+ name: 'main',
+ userChecker: 'user_checker_service',
+ context: 'main',
+ stateless: false,
+ provider: 'user_provider_service',
+ entryPoint: 'entry_point_service',
+ accessDeniedHandler: 'access_denied_handler_service',
+ accessDeniedUrl: '/access-denied',
+ );
+
+ $context = new FirewallContext([], config: $config);
+
+ $contexts = $this->createMock(ContainerInterface::class);
+ $contexts->method('has')->willReturn(true);
+ $contexts->method('get')->willReturn($context);
+
+ $dispatcher = $this->createMock(EventDispatcherInterface::class);
+ $listener = fn () => null;
+ $listenerTwo = fn (int $number) => $number * 2;
+ $dispatcher->method('getListeners')->willReturn([
+ 'security.event' => [$listener, $listenerTwo],
+ ]);
+ $dispatcher->method('getListenerPriority')->willReturn(42);
+
+ $eventDispatchers = $this->createMock(ContainerInterface::class);
+ $eventDispatchers->method('has')->willReturn(true);
+ $eventDispatchers->method('get')->willReturn($dispatcher);
+
+ $authenticator = new DummyAuthenticator();
+ $authenticatorTwo = new DummyAuthenticator();
+ $authenticatorThree = new DummyAuthenticator();
+ $authenticators = ['main' => [$authenticator, $authenticatorTwo], 'api' => [$authenticatorThree]];
+
+ $command = new DebugFirewallCommand($firewallNames, $contexts, $eventDispatchers, $authenticators);
+ $tester = new CommandTester($command);
+
+ $this->assertSame(0, $tester->execute(['name' => 'main', '--events' => true]));
+ $this->assertEquals($this->getFixtureOutput('firewall_main_with_events_output.txt'), trim(str_replace(\PHP_EOL, "\n", $tester->getDisplay())));
+ }
+
+ public function testFirewallWithSwitchUserDisplaysSection()
+ {
+ $firewallNames = ['main'];
+
+ $switchUserConfig = [
+ 'parameter' => '_switch_user_test',
+ 'provider' => 'custom_provider_test',
+ 'role' => 'ROLE_ALLOWED_TO_SWITCH',
+ ];
+
+ $config = new FirewallConfig(
+ name: 'main',
+ userChecker: 'user_checker_service_test',
+ context: 'main',
+ stateless: false,
+ provider: 'user_provider_service_test',
+ entryPoint: 'entry_point_service_test',
+ accessDeniedHandler: 'access_denied_handler_service_test',
+ accessDeniedUrl: '/access-denied-test',
+ switchUser: $switchUserConfig,
+ );
+
+ $context = new FirewallContext([], config: $config);
+
+ $contexts = $this->createMock(ContainerInterface::class);
+ $contexts->method('has')->willReturn(true);
+ $contexts->method('get')->willReturn($context);
+
+ $eventDispatchers = $this->createMock(ContainerInterface::class);
+ $authenticator = new DummyAuthenticator();
+ $authenticatorTwo = $this->createMock(AuthenticatorInterface::class);
+ $authenticators = ['main' => [$authenticator], 'api' => [$authenticatorTwo]];
+
+ $command = new DebugFirewallCommand(
+ $firewallNames,
+ $contexts,
+ $eventDispatchers,
+ $authenticators
+ );
+ $tester = new CommandTester($command);
+
+ $this->assertSame(0, $tester->execute(['name' => 'main']));
+ $this->assertEquals($this->getFixtureOutput('firewall_main_with_switch_user.txt'), trim(str_replace(\PHP_EOL, "\n", $tester->getDisplay())));
+ }
+
+ private function getFixtureOutput(string $file): string
+ {
+ return trim(file_get_contents(__DIR__.'/../Fixtures/Descriptor/'.$file));
+ }
+}
diff --git a/Tests/DataCollector/SecurityDataCollectorTest.php b/Tests/DataCollector/SecurityDataCollectorTest.php
index 5528c9b7..df6bcd0c 100644
--- a/Tests/DataCollector/SecurityDataCollectorTest.php
+++ b/Tests/DataCollector/SecurityDataCollectorTest.php
@@ -41,7 +41,7 @@ class SecurityDataCollectorTest extends TestCase
{
public function testCollectWhenSecurityIsDisabled()
{
- $collector = new SecurityDataCollector(null, null, null, null, null, null, true);
+ $collector = new SecurityDataCollector(null, null, null, null, null, null);
$collector->collect(new Request(), new Response());
$this->assertSame('security', $collector->getName());
@@ -61,7 +61,7 @@ public function testCollectWhenSecurityIsDisabled()
public function testCollectWhenAuthenticationTokenIsNull()
{
$tokenStorage = new TokenStorage();
- $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null, true);
+ $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null);
$collector->collect(new Request(), new Response());
$this->assertTrue($collector->isEnabled());
@@ -83,7 +83,7 @@ public function testCollectAuthenticationTokenAndRoles(array $roles, array $norm
$tokenStorage = new TokenStorage();
$tokenStorage->setToken(new UsernamePasswordToken(new InMemoryUser('hhamon', 'P4$$w0rD', $roles), 'provider', $roles));
- $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null, true);
+ $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null);
$collector->collect(new Request(), new Response());
$collector->lateCollect();
@@ -106,7 +106,7 @@ public function testCollectSwitchUserToken()
$tokenStorage = new TokenStorage();
$tokenStorage->setToken(new SwitchUserToken(new InMemoryUser('hhamon', 'P4$$w0rD', ['ROLE_USER']), 'provider', ['ROLE_USER'], $adminToken));
- $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null, true);
+ $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy(), null, null, null, null);
$collector->collect(new Request(), new Response());
$collector->lateCollect();
@@ -136,7 +136,7 @@ public function testGetFirewall()
->with($request)
->willReturn($firewallConfig);
- $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator()), true);
+ $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator()));
$collector->collect($request, new Response());
$collector->lateCollect();
$collected = $collector->getFirewall();
@@ -160,7 +160,7 @@ public function testGetFirewallReturnsNull()
$response = new Response();
// Don't inject any firewall map
- $collector = new SecurityDataCollector(null, null, null, null, null, null, true);
+ $collector = new SecurityDataCollector(null, null, null, null, null, null);
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
@@ -170,7 +170,7 @@ public function testGetFirewallReturnsNull()
->disableOriginalConstructor()
->getMock();
- $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator()), true);
+ $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator()));
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
@@ -180,7 +180,7 @@ public function testGetFirewallReturnsNull()
->disableOriginalConstructor()
->getMock();
- $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator()), true);
+ $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator()));
$collector->collect($request, $response);
$this->assertNull($collector->getFirewall());
}
@@ -214,7 +214,7 @@ public function testGetListeners()
$firewall = new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator());
$firewall->onKernelRequest($event);
- $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, $firewall, true);
+ $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, $firewall);
$collector->collect($request, $response);
$this->assertNotEmpty($collected = $collector->getListeners()[0]);
@@ -261,7 +261,7 @@ public function dispatch(object $event, ?string $eventName = null): object
],
]]);
- $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null, true);
+ $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null);
$dataCollector->collect(new Request(), new Response());
@@ -349,7 +349,7 @@ public function dispatch(object $event, ?string $eventName = null): object
],
]);
- $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null, true);
+ $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null);
$dataCollector->collect(new Request(), new Response());
@@ -421,7 +421,7 @@ public function testGetVotersIfAccessDecisionManagerHasNoVoters()
'voterDetails' => [],
]]);
- $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null, true);
+ $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager, null, null);
$dataCollector->collect(new Request(), new Response());
diff --git a/Tests/DependencyInjection/CompleteConfigurationTestCase.php b/Tests/DependencyInjection/CompleteConfigurationTestCase.php
index 04fba9fe..dcb67011 100644
--- a/Tests/DependencyInjection/CompleteConfigurationTestCase.php
+++ b/Tests/DependencyInjection/CompleteConfigurationTestCase.php
@@ -726,6 +726,41 @@ public function testFirewallPatterns()
$this->assertSame('(?:^/register$|^/documentation$)', $container->getDefinition($requestMatcherId)->getArgument(0));
}
+ public function testAccessTokenOidc()
+ {
+ $container = $this->getContainer('access_token_oidc');
+
+ $this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1'));
+ $this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1'));
+
+ $def = $container->getDefinition('security.access_token_handler.firewall1');
+ $this->assertSame('audience', $def->getArgument(2));
+ $this->assertSame(['https://www.example.com'], $def->getArgument(3));
+ $this->assertSame('sub', $def->getArgument(4));
+ }
+
+ public function testAccessTokenOidcWithEncryption()
+ {
+ $container = $this->getContainer('access_token_oidc_encryption');
+
+ $this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1'));
+ $this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1'));
+
+ $def = $container->getDefinition('security.access_token_handler.firewall1');
+ $this->assertSame(['RS256'], $def->getArgument(0)->getArgument(0));
+ }
+
+ public function testAccessTokenOidcUserInfoWithDiscovery()
+ {
+ if ('xml' === $this->getFileExtension()) {
+ $this->markTestSkipped('OIDC user info discovery is not supported by the XML schema.');
+ }
+ $container = $this->getContainer('access_token_oidc_user_info_discovery');
+
+ $this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1'));
+ $this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1'));
+ }
+
protected function getContainer($file)
{
$file .= '.'.$this->getFileExtension();
diff --git a/Tests/DependencyInjection/Fixtures/php/access_token_oidc.php b/Tests/DependencyInjection/Fixtures/php/access_token_oidc.php
new file mode 100644
index 00000000..b4631c4b
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/php/access_token_oidc.php
@@ -0,0 +1,25 @@
+loadFromExtension('security', [
+ 'providers' => [
+ 'default' => [
+ 'memory' => null,
+ ],
+ ],
+ 'firewalls' => [
+ 'firewall1' => [
+ 'provider' => 'default',
+ 'access_token' => [
+ 'token_handler' => [
+ 'oidc' => [
+ 'algorithms' => ['RS256'],
+ 'issuers' => ['https://www.example.com'],
+ 'audience' => 'audience',
+ 'keyset' => '{"keys":[{"kty":"RSA","n":"abc","e":"AQAB"}]}',
+ ],
+ ],
+ ],
+ ],
+ ],
+]);
+
diff --git a/Tests/DependencyInjection/Fixtures/php/access_token_oidc_encryption.php b/Tests/DependencyInjection/Fixtures/php/access_token_oidc_encryption.php
new file mode 100644
index 00000000..65bb9479
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/php/access_token_oidc_encryption.php
@@ -0,0 +1,30 @@
+loadFromExtension('security', [
+ 'providers' => [
+ 'default' => [
+ 'memory' => null,
+ ],
+ ],
+ 'firewalls' => [
+ 'firewall1' => [
+ 'provider' => 'default',
+ 'access_token' => [
+ 'token_handler' => [
+ 'oidc' => [
+ 'algorithms' => ['RS256'],
+ 'issuers' => ['https://www.example.com'],
+ 'audience' => 'audience',
+ 'keyset' => '{"keys":[{"kty":"RSA","n":"abc","e":"AQAB"}]}',
+ 'encryption' => [
+ 'enabled' => true,
+ 'keyset' => '{"keys":[{"kty":"RSA","n":"abc","e":"AQAB","d":"def"}]}',
+ 'algorithms' => ['RSA-OAEP'],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+]);
+
diff --git a/Tests/DependencyInjection/Fixtures/php/access_token_oidc_user_info_discovery.php b/Tests/DependencyInjection/Fixtures/php/access_token_oidc_user_info_discovery.php
new file mode 100644
index 00000000..f01b7263
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/php/access_token_oidc_user_info_discovery.php
@@ -0,0 +1,27 @@
+loadFromExtension('security', [
+ 'providers' => [
+ 'default' => [
+ 'memory' => null,
+ ],
+ ],
+ 'firewalls' => [
+ 'firewall1' => [
+ 'provider' => 'default',
+ 'access_token' => [
+ 'token_handler' => [
+ 'oidc_user_info' => [
+ 'base_uri' => 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo',
+ 'discovery' => [
+ 'cache' => [
+ 'id' => 'oidc_cache',
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+]);
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/access_token_oidc.xml b/Tests/DependencyInjection/Fixtures/xml/access_token_oidc.xml
new file mode 100644
index 00000000..2b197ae4
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/xml/access_token_oidc.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ https://www.example.com
+ RS256
+
+
+
+
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/access_token_oidc_encryption.xml b/Tests/DependencyInjection/Fixtures/xml/access_token_oidc_encryption.xml
new file mode 100644
index 00000000..d21da9ca
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/xml/access_token_oidc_encryption.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ https://www.example.com
+ RS256
+
+ RSA-OAEP
+
+
+
+
+
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/access_token_oidc_user_info_discovery.xml b/Tests/DependencyInjection/Fixtures/xml/access_token_oidc_user_info_discovery.xml
new file mode 100644
index 00000000..91874379
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/xml/access_token_oidc_user_info_discovery.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/argon2i_hasher.xml b/Tests/DependencyInjection/Fixtures/xml/argon2i_hasher.xml
index 3dc2c685..133de4f8 100644
--- a/Tests/DependencyInjection/Fixtures/xml/argon2i_hasher.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/argon2i_hasher.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/bcrypt_hasher.xml b/Tests/DependencyInjection/Fixtures/xml/bcrypt_hasher.xml
index d4c5d3de..0e790e25 100644
--- a/Tests/DependencyInjection/Fixtures/xml/bcrypt_hasher.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/bcrypt_hasher.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/container1.xml b/Tests/DependencyInjection/Fixtures/xml/container1.xml
index f54c5064..fb5080de 100644
--- a/Tests/DependencyInjection/Fixtures/xml/container1.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/container1.xml
@@ -9,19 +9,19 @@
https://symfony.com/schema/dic/security/security-1.0.xsd">
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml b/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml
index e2f0e986..37e0b8af 100644
--- a/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml
@@ -9,15 +9,11 @@
https://symfony.com/schema/dic/security/security-1.0.xsd">
-
-
-
+
-
-
-
-
-
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml b/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml
index e7f3e687..c1b51373 100644
--- a/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml
@@ -9,15 +9,11 @@
https://symfony.com/schema/dic/security/security-1.0.xsd">
-
-
-
+
-
-
-
-
-
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml b/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml
index 462136c6..6d5e7149 100644
--- a/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml
@@ -9,15 +9,11 @@
https://symfony.com/schema/dic/security/security-1.0.xsd">
-
-
-
+
-
-
-
-
-
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml b/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml
index cb82f2cc..0cd1ab6d 100644
--- a/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml
@@ -9,15 +9,11 @@
https://symfony.com/schema/dic/security/security-1.0.xsd">
-
-
-
+
-
-
-
-
-
+
+
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/migrating_hasher.xml b/Tests/DependencyInjection/Fixtures/xml/migrating_hasher.xml
index a4a9d201..110868de 100644
--- a/Tests/DependencyInjection/Fixtures/xml/migrating_hasher.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/migrating_hasher.xml
@@ -13,9 +13,9 @@
-
+
bcrypt
-
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/remember_me_options.xml b/Tests/DependencyInjection/Fixtures/xml/remember_me_options.xml
index 767397ad..e051ce22 100644
--- a/Tests/DependencyInjection/Fixtures/xml/remember_me_options.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/remember_me_options.xml
@@ -9,9 +9,7 @@
https://symfony.com/schema/dic/security/security-1.0.xsd">
-
-
-
+
diff --git a/Tests/DependencyInjection/Fixtures/xml/sodium_hasher.xml b/Tests/DependencyInjection/Fixtures/xml/sodium_hasher.xml
index fd5cacef..eb26969a 100644
--- a/Tests/DependencyInjection/Fixtures/xml/sodium_hasher.xml
+++ b/Tests/DependencyInjection/Fixtures/xml/sodium_hasher.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/Tests/DependencyInjection/Fixtures/yml/access_token_oidc.yml b/Tests/DependencyInjection/Fixtures/yml/access_token_oidc.yml
new file mode 100644
index 00000000..7da369de
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/yml/access_token_oidc.yml
@@ -0,0 +1,16 @@
+security:
+ providers:
+ default:
+ memory: ~
+
+ firewalls:
+ firewall1:
+ provider: default
+ access_token:
+ token_handler:
+ oidc:
+ algorithms: ['RS256']
+ issuers: ['https://www.example.com']
+ audience: 'audience'
+ keyset: '{"keys":[{"kty":"RSA","n":"abc","e":"AQAB"}]}'
+
diff --git a/Tests/DependencyInjection/Fixtures/yml/access_token_oidc_encryption.yml b/Tests/DependencyInjection/Fixtures/yml/access_token_oidc_encryption.yml
new file mode 100644
index 00000000..956b33f4
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/yml/access_token_oidc_encryption.yml
@@ -0,0 +1,20 @@
+security:
+ providers:
+ default:
+ memory: ~
+
+ firewalls:
+ firewall1:
+ provider: default
+ access_token:
+ token_handler:
+ oidc:
+ algorithms: ['RS256']
+ issuers: ['https://www.example.com']
+ audience: 'audience'
+ keyset: '{"keys":[{"kty":"RSA","n":"abc","e":"AQAB"}]}'
+ encryption:
+ enabled: true
+ keyset: '{"keys":[{"kty":"RSA","n":"abc","e":"AQAB","d":"def"}]}'
+ algorithms: ['RSA-OAEP']
+
diff --git a/Tests/DependencyInjection/Fixtures/yml/access_token_oidc_user_info_discovery.yml b/Tests/DependencyInjection/Fixtures/yml/access_token_oidc_user_info_discovery.yml
new file mode 100644
index 00000000..62e80d8d
--- /dev/null
+++ b/Tests/DependencyInjection/Fixtures/yml/access_token_oidc_user_info_discovery.yml
@@ -0,0 +1,16 @@
+security:
+ providers:
+ default:
+ memory: ~
+
+ firewalls:
+ firewall1:
+ provider: default
+ access_token:
+ token_handler:
+ oidc_user_info:
+ base_uri: 'https://www.example.com/realms/demo/protocol/openid-connect/userinfo'
+ discovery:
+ cache:
+ id: 'oidc_cache'
+
diff --git a/Tests/Fixtures/Descriptor/firewall_main_output.txt b/Tests/Fixtures/Descriptor/firewall_main_output.txt
new file mode 100644
index 00000000..d2241625
--- /dev/null
+++ b/Tests/Fixtures/Descriptor/firewall_main_output.txt
@@ -0,0 +1,30 @@
+Firewall "main"
+===============
+
+ ----------------------- -------------------------------
+ Option Value
+ ----------------------- -------------------------------
+ Name main
+ Context main
+ Lazy No
+ Stateless No
+ User Checker user_checker_service
+ Provider user_provider_service
+ Entry Point entry_point_service
+ Access Denied URL /access-denied
+ Access Denied Handler access_denied_handler_service
+ ----------------------- -------------------------------
+
+Event listeners for firewall "main"
+===================================
+
+ No event dispatcher has been registered for this firewall.
+
+Authenticators for firewall "main"
+==================================
+
+ -----------------------------------------------------------------
+ Classname
+ -----------------------------------------------------------------
+ Symfony\Bundle\SecurityBundle\Tests\Fixtures\DummyAuthenticator
+ -----------------------------------------------------------------
diff --git a/Tests/Fixtures/Descriptor/firewall_main_with_events_output.txt b/Tests/Fixtures/Descriptor/firewall_main_with_events_output.txt
new file mode 100644
index 00000000..2d02f34b
--- /dev/null
+++ b/Tests/Fixtures/Descriptor/firewall_main_with_events_output.txt
@@ -0,0 +1,39 @@
+Firewall "main"
+===============
+
+ ----------------------- -------------------------------
+ Option Value
+ ----------------------- -------------------------------
+ Name main
+ Context main
+ Lazy No
+ Stateless No
+ User Checker user_checker_service
+ Provider user_provider_service
+ Entry Point entry_point_service
+ Access Denied URL /access-denied
+ Access Denied Handler access_denied_handler_service
+ ----------------------- -------------------------------
+
+Event listeners for firewall "main"
+===================================
+
+"security.event" event
+----------------------
+
+ ------- ----------- ----------
+ Order Callable Priority
+ ------- ----------- ----------
+ #1 Closure() 42
+ #2 Closure() 42
+ ------- ----------- ----------
+
+Authenticators for firewall "main"
+==================================
+
+ -----------------------------------------------------------------
+ Classname
+ -----------------------------------------------------------------
+ Symfony\Bundle\SecurityBundle\Tests\Fixtures\DummyAuthenticator
+ Symfony\Bundle\SecurityBundle\Tests\Fixtures\DummyAuthenticator
+ -----------------------------------------------------------------
diff --git a/Tests/Fixtures/Descriptor/firewall_main_with_switch_user.txt b/Tests/Fixtures/Descriptor/firewall_main_with_switch_user.txt
new file mode 100644
index 00000000..4843b86f
--- /dev/null
+++ b/Tests/Fixtures/Descriptor/firewall_main_with_switch_user.txt
@@ -0,0 +1,36 @@
+Firewall "main"
+===============
+
+ ----------------------- ------------------------------------
+ Option Value
+ ----------------------- ------------------------------------
+ Name main
+ Context main
+ Lazy No
+ Stateless No
+ User Checker user_checker_service_test
+ Provider user_provider_service_test
+ Entry Point entry_point_service_test
+ Access Denied URL /access-denied-test
+ Access Denied Handler access_denied_handler_service_test
+ ----------------------- ------------------------------------
+
+User switching
+--------------
+
+ ----------- ------------------------
+ Option Value
+ ----------- ------------------------
+ Parameter _switch_user_test
+ Provider custom_provider_test
+ User Role ROLE_ALLOWED_TO_SWITCH
+ ----------- ------------------------
+
+Authenticators for firewall "main"
+==================================
+
+ -----------------------------------------------------------------
+ Classname
+ -----------------------------------------------------------------
+ Symfony\Bundle\SecurityBundle\Tests\Fixtures\DummyAuthenticator
+ -----------------------------------------------------------------
diff --git a/Tests/Fixtures/DummyAuthenticator.php b/Tests/Fixtures/DummyAuthenticator.php
new file mode 100644
index 00000000..8ac51a1e
--- /dev/null
+++ b/Tests/Fixtures/DummyAuthenticator.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\SecurityBundle\Tests\Fixtures;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
+use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
+use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
+use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
+
+class DummyAuthenticator implements AuthenticatorInterface
+{
+ public function supports(Request $request): ?bool
+ {
+ return null;
+ }
+
+ public function authenticate(Request $request): Passport
+ {
+ }
+
+ public function createToken(Passport $passport, string $firewallName): TokenInterface
+ {
+ }
+
+ public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
+ {
+ return null;
+ }
+
+ public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
+ {
+ return null;
+ }
+
+ public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
+ {
+ }
+}