Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0d18620

Browse filesBrowse files
committed
[SecurityBundle][PasswordHasher] Fix password migration with custom hasher service with security bundle config
1 parent 7c4f174 commit 0d18620
Copy full SHA for 0d18620

File tree

4 files changed

+96
-19
lines changed
Filter options

4 files changed

+96
-19
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,10 @@ private function createHasher(array $config)
848848
{
849849
// a custom hasher service
850850
if (isset($config['id'])) {
851-
return new Reference($config['id']);
851+
return $config['migrate_from'] ?? false ? [
852+
'instance' => new Reference($config['id']),
853+
'migrate_from' => $config['migrate_from'],
854+
] : new Reference($config['id']);
852855
}
853856

854857
if ($config['migrate_from'] ?? false) {

‎src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,33 @@ public function testLegacyAuthorizationManagerSignature()
881881
$this->assertEquals('%security.access.always_authenticate_before_granting%', (string) $args[3]);
882882
}
883883

884+
public function testCustomHasherWithMigrateFrom()
885+
{
886+
$container = $this->getRawContainer();
887+
888+
$container->loadFromExtension('security', [
889+
'enable_authenticator_manager' => true,
890+
'password_hashers' => [
891+
'legacy' => 'md5',
892+
'App\User' => [
893+
'id' => 'App\Security\CustomHasher',
894+
'migrate_from' => 'legacy',
895+
],
896+
],
897+
'firewalls' => ['main' => ['http_basic' => true]],
898+
]);
899+
900+
$container->compile();
901+
902+
$hashersMap = $container->getDefinition('security.password_hasher_factory')->getArgument(0);
903+
904+
$this->assertArrayHasKey('App\User', $hashersMap);
905+
$this->assertEquals($hashersMap['App\User'], [
906+
'instance' => new Reference('App\Security\CustomHasher'),
907+
'migrate_from' => ['legacy'],
908+
]);
909+
}
910+
884911
protected function getRawContainer()
885912
{
886913
$container = new ContainerBuilder();

‎src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/PasswordHasher/Hasher/PasswordHasherFactory.php
+32-18Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ public function getPasswordHasher($user): PasswordHasherInterface
7171
*/
7272
private function createHasher(array $config, bool $isExtra = false): PasswordHasherInterface
7373
{
74+
if (isset($config['instance'])) {
75+
if (!isset($config['migrate_from'])) {
76+
return $config['instance'];
77+
}
78+
79+
$config = $this->getMigratingPasswordConfig($config);
80+
}
81+
7482
if (isset($config['algorithm'])) {
7583
$rawConfig = $config;
7684
$config = $this->getHasherConfigFromAlgorithm($config);
@@ -142,24 +150,8 @@ private function getHasherConfigFromAlgorithm(array $config): array
142150
];
143151
}
144152

145-
if ($frompasswordHashers = ($config['migrate_from'] ?? false)) {
146-
unset($config['migrate_from']);
147-
$hasherChain = [$this->createHasher($config, true)];
148-
149-
foreach ($frompasswordHashers as $name) {
150-
if (isset($this->passwordHashers[$name])) {
151-
$hasher = $this->createHasherUsingAdapter($name);
152-
} else {
153-
$hasher = $this->createHasher(['algorithm' => $name], true);
154-
}
155-
156-
$hasherChain[] = $hasher;
157-
}
158-
159-
return [
160-
'class' => MigratingPasswordHasher::class,
161-
'arguments' => $hasherChain,
162-
];
153+
if ($config['migrate_from'] ?? false) {
154+
return $this->getMigratingPasswordConfig($config);
163155
}
164156

165157
switch ($config['algorithm']) {
@@ -239,4 +231,26 @@ private function getHasherConfigFromAlgorithm(array $config): array
239231
],
240232
];
241233
}
234+
235+
private function getMigratingPasswordConfig(array &$config): array
236+
{
237+
$frompasswordHashers = $config['migrate_from'];
238+
unset($config['migrate_from']);
239+
$hasherChain = [$this->createHasher($config, true)];
240+
241+
foreach ($frompasswordHashers as $name) {
242+
if ($this->passwordHashers[$name] ?? false) {
243+
$hasher = $this->createHasherUsingAdapter($name);
244+
} else {
245+
$hasher = $this->createHasher(['algorithm' => $name], true);
246+
}
247+
248+
$hasherChain[] = $hasher;
249+
}
250+
251+
return [
252+
'class' => MigratingPasswordHasher::class,
253+
'arguments' => $hasherChain,
254+
];
255+
}
242256
}

‎src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/PasswordHasher/Tests/Hasher/PasswordHasherFactoryTest.php
+33Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ public function testGetHasherWithService()
4949
$this->assertEquals($expectedHasher->hash('foo', ''), $hasher->hash('foo', ''));
5050
}
5151

52+
public function testGetHasherWithInstance()
53+
{
54+
$factory = new PasswordHasherFactory([
55+
PasswordAuthenticatedUserInterface::class => ['instance' => new MessageDigestPasswordHasher('sha1')],
56+
]);
57+
58+
$hasher = $factory->getPasswordHasher($this->createMock(PasswordAuthenticatedUserInterface::class));
59+
$expectedHasher = new MessageDigestPasswordHasher('sha1');
60+
$this->assertEquals($expectedHasher->hash('foo', ''), $hasher->hash('foo', ''));
61+
}
62+
5263
public function testGetHasherWithClassName()
5364
{
5465
$factory = new PasswordHasherFactory([
@@ -163,6 +174,28 @@ public function testMigrateFrom()
163174
$this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null));
164175
}
165176

177+
public function testMigrateFromWithCustomInstance()
178+
{
179+
if (!SodiumPasswordHasher::isSupported()) {
180+
$this->markTestSkipped('Sodium is not available');
181+
}
182+
183+
$sodium = new SodiumPasswordHasher();
184+
185+
$factory = new PasswordHasherFactory([
186+
'digest_hasher' => $digest = new MessageDigestPasswordHasher('sha256'),
187+
SomeUser::class => ['instance' => $sodium, 'migrate_from' => ['bcrypt', 'digest_hasher']],
188+
]);
189+
190+
$hasher = $factory->getPasswordHasher(SomeUser::class);
191+
$this->assertInstanceOf(MigratingPasswordHasher::class, $hasher);
192+
193+
$this->assertTrue($hasher->verify((new SodiumPasswordHasher())->hash('foo', null), 'foo', null));
194+
$this->assertTrue($hasher->verify((new NativePasswordHasher(null, null, null, \PASSWORD_BCRYPT))->hash('foo', null), 'foo', null));
195+
$this->assertTrue($hasher->verify($digest->hash('foo', null), 'foo', null));
196+
$this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null));
197+
}
198+
166199
/**
167200
* @group legacy
168201
*/

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.