8000 feat(security): allow configuring a default authenticator per firewal… · symfony/symfony@ed18bb4 · GitHub
[go: up one dir, main page]

Skip to content

Commit ed18bb4

Browse files
committed
feat(security): allow configuring a default authenticator per firewall for programmatic login
1 parent c10a83f commit ed18bb4

File tree

12 files changed

+78
-2
lines changed

12 files changed

+78
-2
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ CHANGELOG
1111
* Add ability to fetch LDAP roles
1212
* Add `OAuth2TokenHandlerFactory` for `AccessTokenFactory`
1313
* Add discovery support to `OidcTokenHandler` and `OidcUserInfoTokenHandler`
14+
* Add the ability to configure a default authenticator per firewall, allowing `Security::login()` to work without explicitly providing an `AuthenticatorInterface` when multiple authenticators are registered
15+
1416

1517
7.2
1618
---

src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
178178
'access_denied_url' => $firewallConfig->getAccessDeniedUrl(),
179179
'user_checker' => $firewallConfig->getUserChecker(),
180180
'authenticators' => $firewallConfig->getAuthenticators(),
181+
'default_authenticator' => $firewallConfig->getDefaultAuthenticator(),
181182
];
182183

183184
// generate exit impersonation path from current request

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
233233
->booleanNode('stateless')->defaultFalse()->end()
234234
->booleanNode('lazy')->defaultFalse()->end()
235235
->scalarNode('context')->cannotBeEmpty()->end()
236+
->scalarNode('default_authenticator')->end()
236237
->arrayNode('logout')
237238
->treatTrueLike([])
238239
->canBeUnset()

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ private function createFirewalls(array $config, ContainerBuilder $container): vo
303303
$mapDef = $container->getDefinition('security.firewall.map');
304304
$map = $authenticationProviders = $contextRefs = $authenticators = [];
305305
foreach ($firewalls as $name => $firewall) {
306+
$defaultAuthenticators = [];
307+
if (isset($firewall['default_authenticator'])) {
308+
$defaultAuthenticators[$name] = $firewall['default_authenticator'];
309+
}
306310
if (isset($firewall['user_checker']) && 'security.user_checker' !== $firewall['user_checker']) {
307311
$customUserChecker = true;
308312
}
@@ -337,6 +341,7 @@ private function createFirewalls(array $config, ContainerBuilder $container): vo
337341
$container
338342
->getDefinition('security.helper')
339343
->replaceArgument(1, $authenticators)
344+
->replaceArgument(2, $defaultAuthenticators)
340345
;
341346

342347
$container->setAlias('security.firewall.context_locator', (string) ServiceLocatorTagPass::register($container, $contextRefs));

src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@
174174
<xsd:attribute name="stateless" type="xsd:boolean" />
175175
<xsd:attribute name="context" type="xsd:string" />
176176
<xsd:attribute name="lazy" type="xsd:boolean" />
177+
<xsd:attribute name="default-authenticator" type="xsd:string" />
177178
<!-- allow factories to use dynamic elements -->
178179
<xsd:anyAttribute processContents="lax" />
179180
</xsd:complexType>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
'security.csrf.token_manager' => service('security.csrf.token_manager')->ignoreOnInvalid(),
9898
]),
9999 10000
abstract_arg('authenticators'),
100+
abstract_arg('defaultAuthenticators'),
100101
])
101102
->alias(Security::class, 'security.helper')
102103

src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,10 @@
330330
<th>access_denied_url</th>
331331
<td>{{ collector.firewall.access_denied_url ?: '(none)' }}</td>
332332
</tr>
333+
<tr>
334+
<th>default_authenticator</th>
335+
<td>{{ collector.firewall.default_authenticator ?: '(none)' }}</td>
336+
</tr>
333337
<tr>
334338
<th>authenticators</th>
335339
<td>{{ collector.firewall.authenticators is empty ? '(none)' : profiler_dump(collector.firewall.authenticators, maxDepth=1) }}</td>

src/Symfony/Bundle/SecurityBundle/Security.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class Security implements AuthorizationCheckerInterface, UserAuthorizationChecke
4444
public function __construct(
4545
private readonly ContainerInterface $container,
4646
private readonly array $authenticators = [],
47+
private readonly array $defaultAuthenticators = [],
4748
) {
4849
}
4950

@@ -170,7 +171,7 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa
170171
/** @var ServiceProviderInterface $firewallAuthenticatorLocator */
171172
$firewallAuthenticatorLocator = $this->authenticators[$firewallName];
172173

173-
if (!$authenticatorName) {
174+
if (!$authenticatorName && !isset($this->defaultAuthenticators[$firewallName])) {
174175
$authenticatorIds = array_keys($firewallAuthenticatorLocator->getProvidedServices());
175176

176177
if (!$authenticatorIds) {
@@ -183,6 +184,7 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa
183184
retu 10000 rn $firewallAuthenticatorLocator->get($authenticatorIds[0]);
184185
}
185186

187+
$authenticatorName ??= $this->defaultAuthenticators[$firewallName];
186188
if ($firewallAuthenticatorLocator->has($authenticatorName)) {
187189
return $firewallAuthenticatorLocator->get($authenticatorName);
188190
}

src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function __construct(
3030
private readonly array $authenticators = [],
3131
private readonly ?array $switchUser = null,
3232
private readonly ?array $logout = null,
33+
private readonly ?string $defaultAuthenticator = null,
3334
) {
3435
}
3536

@@ -104,4 +105,9 @@ public function getLogout(): ?array
104105
{
105106
return $this->logout;
106107
}
108+
109+
public function getDefaultAuthenticator(): ?string
110+
{
111+
return $this->defaultAuthenticator;
112+
}
107113
}

src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ public function testGetFirewall()
150150
$this->assertSame($firewallConfig->getEntryPoint(), $collected['entry_point']);
151151
$this->assertSame($firewallConfig->getAccessDeniedHandler(), $collected['access_denied_handler']);
152152
$this->assertSame($firewallConfig->getAccessDeniedUrl(), $collected['access_denied_url']);
153+
$this->assertSame($firewallConfig->getAccessDeniedUrl(), $collected['default_authenticator']);
153154
$this->assertSame($firewallConfig->getUserChecker(), $collected['user_checker']);
154155
$this->assertSame($firewallConfig->getAuthenticators(), $collected['authenticators']->getValue());
155156
}

0 commit comments

Comments
 (0)
0