Skip to content

Commit 8e984fa

Browse files
committed
feature #41754 [SecurityBundle] Create a smooth upgrade path for security factories (wouterj)
This PR was merged into the 5.4 branch. Discussion ---------- [SecurityBundle] Create a smooth upgrade path for security factories | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | yes | Deprecations? | yes | Tickets | Ref #41613 (comment) | License | MIT | Doc PR | - This change allows removing `SecurityFactoryInterface` in Symfony 6. I've also changed the discrete ordering using "listener positions" to the much more common continuous ordering using priorities. I feel like priorities are much more self-explanatory. Commits ------- 7385fd5 [SecurityBundle] Create a smooth upgrade path for security factories
2 parents 65e1463 + 7385fd5 commit 8e984fa

20 files changed

+290
-93
lines changed

UPGRADE-5.4.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ Messenger
3737
SecurityBundle
3838
--------------
3939

40+
* Deprecate `SecurityFactoryInterface` and `SecurityExtension::addSecurityListenerFactory()` in favor of
41+
`AuthenticatorFactoryInterface` and `SecurityExtension::addAuthenticatorFactory()`
42+
* Add `AuthenticatorFactoryInterface::getPriority()` which replaces `SecurityFactoryInterface::getPosition()`.
43+
Previous positions are mapped to the following priorities:
44+
45+
| Position | Constant | Priority |
46+
| ----------- | ----------------------------------------------------- | -------- |
47+
| pre_auth | `RemoteUserFactory::PRIORITY`/`X509Factory::PRIORITY` | -10 |
48+
| form | `FormLoginFactory::PRIORITY` | -30 |
49+
| http | `HttpBasicFactory::PRIORITY` | -50 |
50+
| remember_me | `RememberMeFactory::PRIORITY` | -60 |
51+
| anonymous | n/a | -70 |
52+
53+
* Deprecate passing an array of arrays as 1st argument to `MainConfiguration`, pass a sorted flat array of
54+
factories instead.
4055
* Deprecate the `always_authenticate_before_granting` option
4156

4257
Security

UPGRADE-6.0.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,21 @@ Security
355355
SecurityBundle
356356
--------------
357357

358+
* Remove `SecurityFactoryInterface` and `SecurityExtension::addSecurityListenerFactory()` in favor of
359+
`AuthenticatorFactoryInterface` and `SecurityExtension::addAuthenticatorFactory()`
360+
* Add `AuthenticatorFactoryInterface::getPriority()` which replaces `SecurityFactoryInterface::getPosition()`.
361+
Previous positions are mapped to the following priorities:
362+
363+
| Position | Constant | Priority |
364+
| ----------- | ----------------------------------------------------- | -------- |
365+
| pre_auth | `RemoteUserFactory::PRIORITY`/`X509Factory::PRIORITY` | -10 |
366+
| form | `FormLoginFactory::PRIORITY` | -30 |
367+
| http | `HttpBasicFactory::PRIORITY` | -50 |
368+
| remember_me | `RememberMeFactory::PRIORITY` | -60 |
369+
| anonymous | n/a | -70 |
370+
371+
* Remove passing an array of arrays as 1st argument to `MainConfiguration`, pass a sorted flat array of
372+
factories instead.
358373
* Remove the `always_authenticate_before_granting` option
359374
* Remove the `UserPasswordEncoderCommand` class and the corresponding `user:encode-password` command,
360375
use `UserPasswordHashCommand` and `user:hash-password` instead

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ CHANGELOG
44
5.4
55
---
66

7+
* Deprecate `SecurityFactoryInterface` and `SecurityExtension::addSecurityListenerFactory()` in favor of
8+
`AuthenticatorFactoryInterface` and `SecurityExtension::addAuthenticatorFactory()`
9+
* Add `AuthenticatorFactoryInterface::getPriority()` which replaces `SecurityFactoryInterface::getPosition()`
10+
* Deprecate passing an array of arrays as 1st argument to `MainConfiguration`, pass a sorted flat array of
11+
factories instead.
712
* Deprecate the `always_authenticate_before_granting` option
813

914
5.3

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

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Bundle\SecurityBundle\DependencyInjection;
1313

1414
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory;
15+
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
16+
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
1517
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
1618
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
1719
use Symfony\Component\Config\Definition\ConfigurationInterface;
@@ -31,8 +33,17 @@ class MainConfiguration implements ConfigurationInterface
3133
private $factories;
3234
private $userProviderFactories;
3335

36+
/**
37+
* @param (SecurityFactoryInterface|AuthenticatorFactoryInterface)[] $factories
38+
*/
3439
public function __construct(array $factories, array $userProviderFactories)
3540
{
41+
if (\is_array(current($factories))) {
42+
trigger_deprecation('symfony/security-bundle', '5.4', 'Passing an array of arrays as 1st argument to "%s" is deprecated, pass a sorted array of factories instead.', __METHOD__);
43+
44+
$factories = array_merge(...array_values($factories));
45+
}
46+
3647
$this->factories = $factories;
3748
$this->userProviderFactories = $userProviderFactories;
3849
}
@@ -297,19 +308,17 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
297308
;
298309

299310
$abstractFactoryKeys = [];
300-
foreach ($factories as $factoriesAtPosition) {
301-
foreach ($factoriesAtPosition as $factory) {
302-
$name = str_replace('-', '_', $factory->getKey());
303-
$factoryNode = $firewallNodeBuilder->arrayNode($name)
304-
->canBeUnset()
305-
;
306-
307-
if ($factory instanceof AbstractFactory) {
308-
$abstractFactoryKeys[] = $name;
309-
}
310-
311-
$factory->addConfiguration($factoryNode);
311+
foreach ($factories as $factory) {
312+
$name = str_replace('-', '_', $factory->getKey());
313+
$factoryNode = $firewallNodeBuilder->arrayNode($name)
314+
->canBeUnset()
315+
;
316+
317+
if ($factory instanceof AbstractFactory) {
318+
$abstractFactoryKeys[] = $name;
312319
}
320+
321+
$factory->addConfiguration($factoryNode);
313322
}
314323

315324
// check for unreachable check paths

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AnonymousFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
5252
throw new InvalidConfigurationException(sprintf('The authenticator manager no longer has "anonymous" security. Please remove this option under the "%s" firewall'.($config['lazy'] ? ' and add "lazy: true"' : '').'.', $firewallName));
5353
}
5454

55+
public function getPriority()
56+
{
57+
return -60;
58+
}
59+
5560
public function getPosition()
5661
{
5762
return 'anonymous';

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AuthenticatorFactoryInterface.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111

1212
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
1313

14+
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
1415
use Symfony\Component\DependencyInjection\ContainerBuilder;
1516

1617
/**
18+
* @method int getPriority() defines the position at which the authenticator is called
19+
*
1720
* @author Wouter de Jong <wouter@wouterj.nl>
1821
*/
1922
interface AuthenticatorFactoryInterface
@@ -24,4 +27,14 @@ interface AuthenticatorFactoryInterface
2427
* @return string|string[] The authenticator service ID(s) to be used by the firewall
2528
*/
2629
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId);
30+
31+
/**
32+
* Defines the configuration key used to reference the authenticator
33+
* in the firewall configuration.
34+
*
35+
* @return string
36+
*/
37+
public function getKey();
38+
39+
public function addConfiguration(NodeDefinition $builder);
2740
}

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ public function create(ContainerBuilder $container, string $id, array $config, s
2727
throw new \LogicException('Custom authenticators are not supported when "security.enable_authenticator_manager" is not set to true.');
2828
}
2929

30+
public function getPriority(): int
31+
{
32+
return 0;
33+
}
34+
3035
public function getPosition(): string
3136
{
3237
return 'pre_auth';

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
*/
2828
class FormLoginFactory extends AbstractFactory implements AuthenticatorFactoryInterface
2929
{
30+
public const PRIORITY = -30;
31+
3032
public function __construct()
3133
{
3234
$this->addOption('username_parameter', '_username');
@@ -37,6 +39,11 @@ public function __construct()
3739
$this->addOption('post_only', true);
3840
}
3941

42+
public function getPriority(): int
43+
{
44+
return self::PRIORITY;
45+
}
46+
4047
public function getPosition()
4148
{
4249
return 'form';

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public function getPosition()
3434
return 'pre_auth';
3535
}
3636

37+
public function getPriority(): int
38+
{
39+
return 0;
40+
}
41+
3742
public function getKey()
3843
{
3944
return 'guard';

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
class HttpBasicFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2727
{
28+
public const PRIORITY = -50;
29+
2830
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint)
2931
{
3032
$provider = 'security.authentication.provider.dao.'.$id;
@@ -66,6 +68,11 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
6668
return $authenticatorId;
6769
}
6870

71+
public function getPriority(): int
72+
{
73+
return self::PRIORITY;
74+
}
75+
6976
public function getPosition()
7077
{
7178
return 'http';

0 commit comments

Comments
 (0)