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

Skip to content

Commit dcde4e5

Browse files
committed
[PasswordHasher] Fixed compatibility with existing password encoders
1 parent b6966d9 commit dcde4e5

File tree

4 files changed

+80
-1
lines changed

4 files changed

+80
-1
lines changed

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Symfony\Component\PasswordHasher\Exception\LogicException;
1515
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
1616
use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface;
17+
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
18+
use Symfony\Component\Security\Core\Encoder\PasswordHasherAdapter;
1719

1820
/**
1921
* A generic hasher factory implementation.
@@ -25,6 +27,9 @@ class PasswordHasherFactory implements PasswordHasherFactoryInterface
2527
{
2628
private $passwordHashers;
2729

30+
/**
31+
* @param array<string, PasswordHasherInterface|array> $passwordHashers
32+
*/
2833
public function __construct(array $passwordHashers)
2934
{
3035
$this->passwordHashers = $passwordHashers;
@@ -57,7 +62,10 @@ public function getPasswordHasher($user): PasswordHasherInterface
5762
}
5863

5964
if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) {
60-
$this->passwordHashers[$hasherKey] = $this->createHasher($this->passwordHashers[$hasherKey]);
65+
$this->passwordHashers[$hasherKey] = $this->passwordHashers[$hasherKey] instanceof PasswordEncoderInterface
66+
? new PasswordHasherAdapter($this->passwordHashers[$hasherKey])
67+
: $this->createHasher($this->passwordHashers[$hasherKey])
68+
;
6169
}
6270

6371
return $this->passwordHashers[$hasherKey];
@@ -82,6 +90,9 @@ private function createHasher(array $config, bool $isExtra = false): PasswordHas
8290
}
8391

8492
$hasher = new $config['class'](...$config['arguments']);
93+
if (!$hasher instanceof PasswordHasherInterface && $hasher instanceof PasswordEncoderInterface) {
94+
$hasher = new PasswordHasherAdapter($hasher);
95+
}
8596

8697
if ($isExtra || !\in_array($config['class'], [NativePasswordHasher::class, SodiumPasswordHasher::class], true)) {
8798
return $hasher;

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface;
1919
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory;
2020
use Symfony\Component\PasswordHasher\Hasher\SodiumPasswordHasher;
21+
use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder;
2122
use Symfony\Component\Security\Core\User\InMemoryUser;
2223
use Symfony\Component\Security\Core\User\UserInterface;
2324

@@ -176,6 +177,24 @@ public function testDefaultMigratingHashers()
176177
(new PasswordHasherFactory([SomeUser::class => ['class' => SodiumPasswordHasher::class, 'arguments' => []]]))->getPasswordHasher(SomeUser::class)
177178
);
178179
}
180+
181+
/**
182+
* @group legacy
183+
*/
184+
public function testLegacyEncoderObject()
185+
{
186+
$factory = new PasswordHasherFactory([SomeUser::class => new PlaintextPasswordEncoder()]);
187+
self::assertSame('foo{bar}', $factory->getPasswordHasher(SomeUser::class)->hash('foo', 'bar'));
188+
}
189+
190+
/**
191+
* @group legacy
192+
*/
193+
public function testLegacyEncoderClass()
194+
{
195+
$factory = new PasswordHasherFactory([SomeUser::class => ['class' => PlaintextPasswordEncoder::class, 'arguments' => []]]);
196+
self::assertSame('foo{bar}', $factory->getPasswordHasher(SomeUser::class)->hash('foo', 'bar'));
197+
}
179198
}
180199

181200
class SomeUser implements UserInterface

src/Symfony/Component/PasswordHasher/composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
"symfony/security-core": "^5.3",
2424
"symfony/console": "^5"
2525
},
26+
"conflict": {
27+
"symfony/security-core": "<5.3"
28+
},
2629
"autoload": {
2730
"psr-4": { "Symfony\\Component\\PasswordHasher\\": "" },
2831
"exclude-from-classmap": [
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Core\Encoder;
13+
14+
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
15+
16+
/**
17+
* Forward compatibility for new new PasswordHasher component.
18+
*
19+
* @author Alexander M. Turek <[email protected]>
20+
*
21+
* @internal To be removed in Symfony 6
22+
*/
23+
final class PasswordHasherAdapter implements LegacyPasswordHasherInterface
24+
{
25+
private $passwordEncoder;
26+
27+
public function __construct(PasswordEncoderInterface $passwordEncoder)
28+
{
29+
$this->passwordEncoder = $passwordEncoder;
30+
}
31+
32+
public function hash(string $plainPassword, ?string $salt = null): string
33+
{
34+
return $this->passwordEncoder->encodePassword($plainPassword, $salt);
35+
}
36+
37+
public function verify(string $hashedPassword, string $plainPassword, ?string $salt = null): bool
38+
{
39+
return $this->passwordEncoder->isPasswordValid($hashedPassword, $plainPassword, $salt);
40+
}
41+
42+
public function needsRehash(string $hashedPassword): bool
43+
{
44+
return $this->passwordEncoder->needsRehash($hashedPassword);
45+
}
46+
}

0 commit comments

Comments
 (0)