Skip to content

Commit d300919

Browse files
ruudknicolas-grekas
authored andcommitted
[Security] Allow multiple OIDC discovery endpoints
1 parent d3f86d0 commit d300919

File tree

4 files changed

+106
-17
lines changed

4 files changed

+106
-17
lines changed

DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,18 @@ public function create(ContainerBuilder $container, string $id, array|string $co
4848

4949
// disable JWKSet argument
5050
$tokenHandlerDefinition->replaceArgument(1, null);
51-
$tokenHandlerDefinition->addMethodCall(
52-
'enableDiscovery',
53-
[
54-
new Reference($config['discovery']['cache']['id']),
55-
(new ChildDefinition('security.access_token_handler.oidc_discovery.http_client'))
56-
->replaceArgument(0, ['base_uri' => $config['discovery']['base_uri']]),
57-
"$id.oidc_configuration",
58-
"$id.oidc_jwk_set",
59-
]
60-
);
51+
52+
$clients = [];
53+
foreach ($config['discovery']['base_uri'] as $uri) {
54+
$clients[] = (new ChildDefinition('security.access_token_handler.oidc_discovery.http_client'))
55+
->replaceArgument(0, ['base_uri' => $uri]);
56+
}
57+
58+
$tokenHandlerDefinition->addMethodCall('enableDiscovery', [
59+
new Reference($config['discovery']['cache']['id']),
60+
$clients,
61+
"$id.oidc_configuration",
62+
]);
6163

6264
return;
6365
}
@@ -93,7 +95,7 @@ public function create(ContainerBuilder $container, string $id, array|string $co
9395
;
9496
}
9597

96-
$firewall = substr($id, strlen('security.access_token_handler.'));
98+
$firewall = substr($id, \strlen('security.access_token_handler.'));
9799
$container->getDefinition('security.access_token_handler.oidc.command.generate')
98100
->addMethodCall('addGenerator', [
99101
$firewall,
@@ -157,10 +159,11 @@ public function addConfiguration(NodeBuilder $node): void
157159
->arrayNode('discovery')
158160
->info('Enable the OIDC discovery.')
159161
->children()
160-
->scalarNode('base_uri')
162+
->arrayNode('base_uri')
163+
->acceptAndWrap(['string'])
161164
->info('Base URI of the OIDC server.')
162165
->isRequired()
163-
->cannotBeEmpty()
166+
->scalarPrototype()->end()
164167
->end()
165168
->arrayNode('cache')
166169
->children()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
$container->loadFromExtension('security', [
4+
'providers' => [
5+
'default' => [
6+
'memory' => null,
7+
],
8+
],
9+
'firewalls' => [
10+
'firewall1' => [
11+
'provider' => 'default',
12+
'access_token' => [
13+
'token_handler' => [
14+
'oidc_user_info' => [
15+
'base_uri' => [
16+
'https://www.example.com/realms/demo/protocol/openid-connect/userinfo',
17+
'https://www.github.com/realms/demo/protocol/openid-connect/userinfo',
18+
],
19+
'discovery' => [
20+
'cache' => [
21+
'id' => 'oidc_cache',
22+
],
23+
],
24+
],
25+
],
26+
],
27+
],
28+
],
29+
]);

Tests/DependencyInjection/Security/Factory/AccessTokenFactoryTest.php

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,6 @@ public function testInvalidOidcTokenHandlerConfigurationMissingAlgorithm()
346346
public function testOidcTokenHandlerConfigurationWithDiscovery()
347347
{
348348
$container = new ContainerBuilder();
349-
$jwkset = '{"keys":[{"kty":"EC","crv":"P-256","x":"FtgMtrsKDboRO-Zo0XC7tDJTATHVmwuf9GK409kkars","y":"rWDE0ERU2SfwGYCo1DWWdgFEbZ0MiAXLRBBOzBgs_jY","d":"4G7bRIiKih0qrFxc0dtvkHUll19tTyctoCR3eIbOrO0"},{"kty":"EC","crv":"P-256","x":"0QEAsI1wGI-dmYatdUZoWSRWggLEpyzopuhwk-YUnA4","y":"KYl-qyZ26HobuYwlQh-r0iHX61thfP82qqEku7i0woo","d":"iA_TV2zvftni_9aFAQwFO_9aypfJFCSpcCyevDvz220"}]}';
350349
$config = [
351350
'token_handler' => [
352351
'oidc' => [
@@ -384,10 +383,68 @@ public function testOidcTokenHandlerConfigurationWithDiscovery()
384383
'enableDiscovery',
385384
[
386385
new Reference('oidc_cache'),
387-
(new ChildDefinition('security.access_token_handler.oidc_discovery.http_client'))
386+
[
387+
(new ChildDefinition('security.access_token_handler.oidc_discovery.http_client'))
388388
->replaceArgument(0, ['base_uri' => 'https://www.example.com/realms/demo/']),
389+
],
390+
'security.access_token_handler.firewall1.oidc_configuration',
391+
],
392+
],
393+
];
394+
$this->assertEquals($expectedArgs, $container->getDefinition('security.access_token_handler.firewall1')->getArguments());
395+
$this->assertEquals($expectedCalls, $container->getDefinition('security.access_token_handler.firewall1')->getMethodCalls());
396+
}
397+
398+
public function testOidcTokenHandlerConfigurationWithMultipleDiscoveryBaseUri()
399+
{
400+
$container = new ContainerBuilder();
401+
$config = [
402+
'token_handler' => [
403+
'oidc' => [
404+
'discovery' => [
405+
'base_uri' => [
406+
'https://www.example.com/realms/demo/',
407+
'https://www.api.com/realms/api/',
408+
],
409+
'cache' => [
410+
'id' => 'oidc_cache',
411+
],
412+
],
413+
'algorithms' => ['RS256', 'ES256'],
414+
'issuers' => ['https://www.example.com'],
415+
'audience' => 'audience',
416+
],
417+
],
418+
];
419+
420+
$factory = new AccessTokenFactory($this->createTokenHandlerFactories());
421+
$finalizedConfig = $this->processConfig($config, $factory);
422+
423+
$factory->createAuthenticator($container, 'firewall1', $finalizedConfig, 'userprovider');
424+
425+
$this->assertTrue($container->hasDefinition('security.authenticator.access_token.firewall1'));
426+
$this->assertTrue($container->hasDefinition('security.access_token_handler.firewall1'));
427+
428+
$expectedArgs = [
429+
'index_0' => (new ChildDefinition('security.access_token_handler.oidc.signature'))
430+
->replaceArgument(0, ['RS256', 'ES256']),
431+
'index_1' => null,
432+
'index_2' => 'audience',
433+
'index_3' => ['https://www.example.com'],
434+
'index_4' => 'sub',
435+
];
436+
$expectedCalls = [
437+
[
438+
'enableDiscovery',
439+
[
440+
new Reference('oidc_cache'),
441+
[
442+
(new ChildDefinition('security.access_token_handler.oidc_discovery.http_client'))
443+
->replaceArgument(0, ['base_uri' => 'https://www.example.com/realms/demo/']),
444+
(new ChildDefinition('security.access_token_handler.oidc_discovery.http_client'))
445+
->replaceArgument(0, ['base_uri' => 'https://www.api.com/realms/api/']),
446+
],
389447
'security.access_token_handler.firewall1.oidc_configuration',
390-
'security.access_token_handler.firewall1.oidc_jwk_set',
391448
],
392449
],
393450
];

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"symfony/password-hasher": "^6.4|^7.0|^8.0",
3030
"symfony/security-core": "^7.4|^8.0",
3131
"symfony/security-csrf": "^6.4|^7.0|^8.0",
32-
"symfony/security-http": "^7.3|^8.0",
32+
"symfony/security-http": "^7.4|^8.0",
3333
"symfony/service-contracts": "^2.5|^3"
3434
},
3535
"require-dev": {

0 commit comments

Comments
 (0)