From 8393c0d52559f51ec56a373c2e4c90ebbf920528 Mon Sep 17 00:00:00 2001 From: Peter Potrowl Date: Thu, 29 Jul 2021 16:09:35 +0200 Subject: [PATCH] [PasswordHasher] Fix usage of PasswordHasherAdapter in PasswordHasherFactory --- Hasher/PasswordHasherFactory.php | 25 +++++++++++++--------- Tests/Hasher/PasswordHasherFactoryTest.php | 23 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/Hasher/PasswordHasherFactory.php b/Hasher/PasswordHasherFactory.php index a2f2422..dd7e015 100644 --- a/Hasher/PasswordHasherFactory.php +++ b/Hasher/PasswordHasherFactory.php @@ -61,14 +61,7 @@ public function getPasswordHasher($user): PasswordHasherInterface throw new \RuntimeException(sprintf('No password hasher has been configured for account "%s".', \is_object($user) ? get_debug_type($user) : $user)); } - if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) { - $this->passwordHashers[$hasherKey] = $this->passwordHashers[$hasherKey] instanceof PasswordEncoderInterface - ? new PasswordHasherAdapter($this->passwordHashers[$hasherKey]) - : $this->createHasher($this->passwordHashers[$hasherKey]) - ; - } - - return $this->passwordHashers[$hasherKey]; + return $this->createHasherUsingAdapter($hasherKey); } /** @@ -111,6 +104,18 @@ private function createHasher(array $config, bool $isExtra = false): PasswordHas return new MigratingPasswordHasher($hasher, ...$extrapasswordHashers); } + private function createHasherUsingAdapter(string $hasherKey): PasswordHasherInterface + { + if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) { + $this->passwordHashers[$hasherKey] = $this->passwordHashers[$hasherKey] instanceof PasswordEncoderInterface + ? new PasswordHasherAdapter($this->passwordHashers[$hasherKey]) + : $this->createHasher($this->passwordHashers[$hasherKey]) + ; + } + + return $this->passwordHashers[$hasherKey]; + } + private function getHasherConfigFromAlgorithm(array $config): array { if ('auto' === $config['algorithm']) { @@ -142,8 +147,8 @@ private function getHasherConfigFromAlgorithm(array $config): array $hasherChain = [$this->createHasher($config, true)]; foreach ($frompasswordHashers as $name) { - if ($hasher = $this->passwordHashers[$name] ?? false) { - $hasher = $hasher instanceof PasswordHasherInterface ? $hasher : $this->createHasher($hasher, true); + if (isset($this->passwordHashers[$name])) { + $hasher = $this->createHasherUsingAdapter($name); } else { $hasher = $this->createHasher(['algorithm' => $name], true); } diff --git a/Tests/Hasher/PasswordHasherFactoryTest.php b/Tests/Hasher/PasswordHasherFactoryTest.php index 1f8fcb3..1f24a0d 100644 --- a/Tests/Hasher/PasswordHasherFactoryTest.php +++ b/Tests/Hasher/PasswordHasherFactoryTest.php @@ -163,6 +163,29 @@ public function testMigrateFrom() $this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null)); } + /** + * @group legacy + */ + public function testMigrateFromLegacy() + { + if (!SodiumPasswordHasher::isSupported()) { + $this->markTestSkipped('Sodium is not available'); + } + + $factory = new PasswordHasherFactory([ + 'plaintext_encoder' => $plaintext = new PlaintextPasswordEncoder(), + SomeUser::class => ['algorithm' => 'sodium', 'migrate_from' => ['bcrypt', 'plaintext_encoder']], + ]); + + $hasher = $factory->getPasswordHasher(SomeUser::class); + $this->assertInstanceOf(MigratingPasswordHasher::class, $hasher); + + $this->assertTrue($hasher->verify((new SodiumPasswordHasher())->hash('foo', null), 'foo', null)); + $this->assertTrue($hasher->verify((new NativePasswordHasher(null, null, null, \PASSWORD_BCRYPT))->hash('foo', null), 'foo', null)); + $this->assertTrue($hasher->verify($plaintext->encodePassword('foo', null), 'foo', null)); + $this->assertStringStartsWith(\SODIUM_CRYPTO_PWHASH_STRPREFIX, $hasher->hash('foo', null)); + } + public function testDefaultMigratingHashers() { $this->assertInstanceOf(