From f38a2052e188de00204eaf495b7eadd70a9ab894 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 2 Jun 2025 16:08:14 +0200 Subject: [PATCH 1/4] Allow Symfony ^8.0 --- composer.json | 56 +++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/composer.json b/composer.json index 7459b017..66bc512f 100644 --- a/composer.json +++ b/composer.json @@ -19,37 +19,37 @@ "php": ">=8.2", "composer-runtime-api": ">=2.1", "ext-xml": "*", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^7.3", - "symfony/dependency-injection": "^6.4.11|^7.1.4", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/password-hasher": "^6.4|^7.0", - "symfony/security-core": "^7.3", - "symfony/security-csrf": "^6.4|^7.0", - "symfony/security-http": "^7.3", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^7.3|^8.0", + "symfony/dependency-injection": "^6.4.11|^7.1.4|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/password-hasher": "^6.4|^7.0|^8.0", + "symfony/security-core": "^7.3|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/security-http": "^7.3|^8.0", "symfony/service-contracts": "^2.5|^3" }, "require-dev": { - "symfony/asset": "^6.4|^7.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/form": "^6.4|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/ldap": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", - "symfony/twig-bundle": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0", + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/ldap": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0", "twig/twig": "^3.12", "web-token/jwt-library": "^3.3.2|^4.0" }, From 8faa44fd0ad168209a1df401376afa6f17d9a2a2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 2 Jun 2025 17:50:55 +0200 Subject: [PATCH 2/4] Bump Symfony 8 to PHP >= 8.4 --- composer.json | 68 ++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/composer.json b/composer.json index 66bc512f..614769d2 100644 --- a/composer.json +++ b/composer.json @@ -16,53 +16,43 @@ } ], "require": { - "php": ">=8.2", + "php": ">=8.4", "composer-runtime-api": ">=2.1", "ext-xml": "*", - "symfony/clock": "^6.4|^7.0|^8.0", - "symfony/config": "^7.3|^8.0", - "symfony/dependency-injection": "^6.4.11|^7.1.4|^8.0", - "symfony/event-dispatcher": "^6.4|^7.0|^8.0", - "symfony/http-kernel": "^6.4|^7.0|^8.0", - "symfony/http-foundation": "^6.4|^7.0|^8.0", - "symfony/password-hasher": "^6.4|^7.0|^8.0", - "symfony/security-core": "^7.3|^8.0", - "symfony/security-csrf": "^6.4|^7.0|^8.0", - "symfony/security-http": "^7.3|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/password-hasher": "^7.4|^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^7.4|^8.0", + "symfony/security-http": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "require-dev": { - "symfony/asset": "^6.4|^7.0|^8.0", - "symfony/browser-kit": "^6.4|^7.0|^8.0", - "symfony/console": "^6.4|^7.0|^8.0", - "symfony/css-selector": "^6.4|^7.0|^8.0", - "symfony/dom-crawler": "^6.4|^7.0|^8.0", - "symfony/expression-language": "^6.4|^7.0|^8.0", - "symfony/form": "^6.4|^7.0|^8.0", - "symfony/framework-bundle": "^6.4|^7.0|^8.0", - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/ldap": "^6.4|^7.0|^8.0", - "symfony/process": "^6.4|^7.0|^8.0", - "symfony/rate-limiter": "^6.4|^7.0|^8.0", - "symfony/serializer": "^6.4|^7.0|^8.0", - "symfony/translation": "^6.4|^7.0|^8.0", - "symfony/twig-bundle": "^6.4|^7.0|^8.0", - "symfony/twig-bridge": "^6.4|^7.0|^8.0", - "symfony/validator": "^6.4|^7.0|^8.0", - "symfony/yaml": "^6.4|^7.0|^8.0", + "symfony/asset": "^7.4|^8.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/dom-crawler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/ldap": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/twig-bundle": "^7.4|^8.0", + "symfony/twig-bridge": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0", "twig/twig": "^3.12", "web-token/jwt-library": "^3.3.2|^4.0" }, - "conflict": { - "symfony/browser-kit": "<6.4", - "symfony/console": "<6.4", - "symfony/framework-bundle": "<6.4", - "symfony/http-client": "<6.4", - "symfony/ldap": "<6.4", - "symfony/serializer": "<6.4", - "symfony/twig-bundle": "<6.4", - "symfony/validator": "<6.4" - }, "autoload": { "psr-4": { "Symfony\\Bundle\\SecurityBundle\\": "" }, "exclude-from-classmap": [ From a0f1ef99c038e560f4c96d9f1b81398153930bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 7 May 2025 12:05:16 +0200 Subject: [PATCH 3/4] [SecurityBundle] register alias for argument for password hasher --- CHANGELOG.md | 21 +++++++++++++++++++ DependencyInjection/SecurityExtension.php | 12 +++++++++++ .../SecurityExtensionTest.php | 15 ++++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77aa9573..5d28b7dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,27 @@ CHANGELOG ========= +7.4 +--- + + * Register alias for argument for password hasher when its key is not a class name: + + With the following configuration: + ```yaml + security: + password_hashers: + recovery_code: auto + ``` + + It is possible to inject the `recovery_code` password hasher in a service: + + ```php + public function __construct( + #[Target('recovery_code')] + private readonly PasswordHasherInterface $passwordHasher, + ) { + } + ``` 7.3 --- diff --git a/DependencyInjection/SecurityExtension.php b/DependencyInjection/SecurityExtension.php index 1711964b..0d41e3db 100644 --- a/DependencyInjection/SecurityExtension.php +++ b/DependencyInjection/SecurityExtension.php @@ -49,6 +49,7 @@ use Symfony\Component\PasswordHasher\Hasher\Pbkdf2PasswordHasher; use Symfony\Component\PasswordHasher\Hasher\PlaintextPasswordHasher; use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher; +use Symfony\Component\PasswordHasher\PasswordHasherInterface; use Symfony\Component\Routing\Loader\ContainerLoader; use Symfony\Component\Security\Core\Authorization\Strategy\AffirmativeStrategy; use Symfony\Component\Security\Core\Authorization\Strategy\ConsensusStrategy; @@ -706,6 +707,17 @@ private function createHashers(array $hashers, ContainerBuilder $container): voi $hasherMap = []; foreach ($hashers as $class => $hasher) { $hasherMap[$class] = $this->createHasher($hasher); + // The key is not a class, so we register an alias for argument to + // ease getting the hasher + if (!class_exists($class) && !interface_exists($class)) { + $id = 'security.password_hasher.'.$class; + $container + ->register($id, PasswordHasherInterface::class) + ->setFactory([new Reference('security.password_hasher_factory'), 'getPasswordHasher']) + ->setArgument(0, $class) + ; + $container->registerAliasForArgument($id, PasswordHasherInterface::class, $class); + } } $container diff --git a/Tests/DependencyInjection/SecurityExtensionTest.php b/Tests/DependencyInjection/SecurityExtensionTest.php index d0f3549a..4999fff7 100644 --- a/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/Tests/DependencyInjection/SecurityExtensionTest.php @@ -29,6 +29,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcher\PathRequestMatcher; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\PasswordHasher\PasswordHasherInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\InMemoryUserChecker; @@ -883,7 +884,7 @@ public function testCustomHasherWithMigrateFrom() $container->loadFromExtension('security', [ 'password_hashers' => [ 'legacy' => 'md5', - 'App\User' => [ + TestUserChecker::class => [ 'id' => 'App\Security\CustomHasher', 'migrate_from' => 'legacy', ], @@ -895,11 +896,19 @@ public function testCustomHasherWithMigrateFrom() $hashersMap = $container->getDefinition('security.password_hasher_factory')->getArgument(0); - $this->assertArrayHasKey('App\User', $hashersMap); - $this->assertEquals($hashersMap['App\User'], [ + $this->assertArrayHasKey(TestUserChecker::class, $hashersMap); + $this->assertEquals($hashersMap[TestUserChecker::class], [ 'instance' => new Reference('App\Security\CustomHasher'), 'migrate_from' => ['legacy'], ]); + + $legacyAlias = \sprintf('%s $%s', PasswordHasherInterface::class, 'legacy'); + $this->assertTrue($container->hasAlias($legacyAlias)); + $definition = $container->getDefinition((string) $container->getAlias($legacyAlias)); + $this->assertSame(PasswordHasherInterface::class, $definition->getClass()); + + $this->assertFalse($container->hasAlias(\sprintf('%s $%s', PasswordHasherInterface::class, 'symfonyBundleSecurityBundleTestsDependencyInjectionTestUserChecker'))); + $this->assertFalse($container->hasAlias(\sprintf('.%s $%s', PasswordHasherInterface::class, TestUserChecker::class))); } public function testAuthenticatorsDecoration() From 3bd98a4d7b01ea68bd5e388879e0f7204324db74 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 11 Jun 2025 18:53:52 +0200 Subject: [PATCH 4/4] fix missing newline --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d28b7dc..1d69d188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ CHANGELOG ) { } ``` + 7.3 ---