Thanks to visit codestin.com
Credit goes to github.com

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 <[email protected]>
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';

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
class JsonLoginFactory extends AbstractFactory implements AuthenticatorFactoryInterface
2626
{
27+
public const PRIORITY = -40;
28+
2729
public function __construct()
2830
{
2931
$this->addOption('username_path', 'username');
@@ -32,6 +34,11 @@ public function __construct()
3234
$this->defaultSuccessHandlerOptions = [];
3335
}
3436

37+
public function getPriority(): int
38+
{
39+
return self::PRIORITY;
40+
}
41+
3542
/**
3643
* {@inheritdoc}
3744
*/

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
*/
2828
class LoginLinkFactory extends AbstractFactory implements AuthenticatorFactoryInterface
2929
{
30+
public const PRIORITY = -20;
31+
3032
public function addConfiguration(NodeDefinition $node)
3133
{
3234
/** @var NodeBuilder $builder */
@@ -147,6 +149,11 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
147149
return $authenticatorId;
148150
}
149151

152+
public function getPriority(): int
153+
{
154+
return self::PRIORITY;
155+
}
156+
150157
public function getPosition()
151158
{
152159
return 'form';

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ public function create(ContainerBuilder $container, string $id, array $config, s
3434
throw new \LogicException('Login throttling is not supported when "security.enable_authenticator_manager" is not set to true.');
3535
}
3636

37+
public function getPriority(): int
38+
{
39+
// this factory doesn't register any authenticators, this priority doesn't matter
40+
return 0;
41+
}
42+
3743
public function getPosition(): string
3844
{
3945
// this factory doesn't register any authenticators, this position doesn't matter

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\DependencyInjection\ContainerBuilder;
2222
use Symfony\Component\DependencyInjection\ContainerInterface;
2323
use Symfony\Component\DependencyInjection\Definition;
24+
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
2425
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
2526
use Symfony\Component\DependencyInjection\Reference;
2627
use Symfony\Component\HttpFoundation\Cookie;
@@ -30,8 +31,10 @@
3031
/**
3132
* @internal
3233
*/
33-
class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
34+
class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface, PrependExtensionInterface
3435
{
36+
public const PRIORITY = -50;
37+
3538
protected $options = [
3639
'name' => 'REMEMBERME',
3740
'lifetime' => 31536000,
@@ -181,6 +184,14 @@ public function getPosition()
181184
return 'remember_me';
182185
}
183186

187+
/**
188+
* {@inheritDoc}
189+
*/
190+
public function getPriority(): int
191+
{
192+
return self::PRIORITY;
193+
}
194+
184195
public function getKey()
185196
{
186197
return 'remember-me';
@@ -331,4 +342,27 @@ private function createTokenVerifier(ContainerBuilder $container, string $firewa
331342

332343
return new Reference($tokenVerifierId, ContainerInterface::NULL_ON_INVALID_REFERENCE);
333344
}
345+
346+
/**
347+
* {@inheritdoc}
348+
*/
349+
public function prepend(ContainerBuilder $container)
350+
{
351+
$rememberMeSecureDefault = false;
352+
$rememberMeSameSiteDefault = null;
353+
354+
if (!isset($container->getExtensions()['framework'])) {
355+
return;
356+
}
357+
358+
foreach ($container->getExtensionConfig('framework') as $config) {
359+
if (isset($config['session']) && \is_array($config['session'])) {
360+
$rememberMeSecureDefault = $config['session']['cookie_secure'] ?? $rememberMeSecureDefault;
361+
$rememberMeSameSiteDefault = \array_key_exists('cookie_samesite', $config['session']) ? $config['session']['cookie_samesite'] : $rememberMeSameSiteDefault;
362+
}
363+
}
364+
365+
$this->options['secure'] = $rememberMeSecureDefault;
366+
$this->options['samesite'] = $rememberMeSameSiteDefault;
367+
}
334368
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
*/
2727
class RemoteUserFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2828
{
29+
public const PRIORITY = -10;
30+
2931
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint)
3032
{
3133
$providerId = 'security.authentication.provider.pre_authenticated.'.$id;
@@ -58,6 +60,11 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
5860
return $authenticatorId;
5961
}
6062

63+
public function getPriority(): int
64+
{
65+
return self::PRIORITY;
66+
}
67+
6168
public function getPosition()
6269
{
6370
return 'pre_auth';

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
* SecurityFactoryInterface is the interface for all security authentication listener.
1919
*
2020
* @author Fabien Potencier <[email protected]>
21+
*
22+
* @deprecated since Symfony 5.3, use AuthenticatorFactoryInterface instead.
2123
*/
2224
interface SecurityFactoryInterface
2325
{

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
class X509Factory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2727
{
28+
public const PRIORITY = -10;
29+
2830
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint)
2931
{
3032
$providerId = 'security.authentication.provider.pre_authenticated.'.$id;
@@ -60,6 +62,11 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
6062
return $authenticatorId;
6163
}
6264

65+
public function getPriority(): int
66+
{
67+
return self::PRIORITY;
68+
}
69+
6370
public function getPosition()
6471
{
6572
return 'pre_auth';

0 commit comments

Comments
 (0)