Skip to content

Commit 25c197b

Browse files
[Security] add PasswordEncoderInterface::needsRehash()
1 parent 63d7309 commit 25c197b

13 files changed

+111
-0
lines changed

UPGRADE-4.4.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@ DependencyInjection
1919
my_service:
2020
factory: ['@factory_service', method]
2121
```
22+
23+
Security
24+
--------
25+
26+
* Implementations of `PasswordEncoderInterface` and `UserPasswordEncoderInterface` should add a new `needsRehash()` method

UPGRADE-5.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ Routing
304304
Security
305305
--------
306306

307+
* Implementations of `PasswordEncoderInterface` and `UserPasswordEncoderInterface` must have a new `needsRehash()` method
307308
* The `Role` and `SwitchUserRole` classes have been removed.
308309
* The `getReachableRoles()` method of the `RoleHierarchy` class has been removed. It has been replaced by the new
309310
`getReachableRoleNames()` method.

src/Symfony/Component/Security/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
4.4.0
5+
-----
6+
7+
* Added method `needsRehash()` to `PasswordEncoderInterface` and `UserPasswordEncoderInterface`
8+
49
4.3.0
510
-----
611

src/Symfony/Component/Security/Core/Encoder/BasePasswordEncoder.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
2020
{
2121
const MAX_PASSWORD_LENGTH = 4096;
2222

23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function needsRehash(string $encoded): bool
27+
{
28+
return false;
29+
}
30+
2331
/**
2432
* Demerges a merge password and salt string.
2533
*

src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,12 @@ public function isPasswordValid($encoded, $raw, $salt)
8787

8888
return \strlen($raw) <= self::MAX_PASSWORD_LENGTH && password_verify($raw, $encoded);
8989
}
90+
91+
/**
92+
* {@inheritdoc}
93+
*/
94+
public function needsRehash(string $encoded): bool
95+
{
96+
return password_needs_rehash($encoded, $this->algo, $this->options);
97+
}
9098
}

src/Symfony/Component/Security/Core/Encoder/PasswordEncoderInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* PasswordEncoderInterface is the interface for all encoders.
1818
*
1919
* @author Fabien Potencier <fabien@symfony.com>
20+
*
21+
* @method bool needsRehash(string $encoded)
2022
*/
2123
interface PasswordEncoderInterface
2224
{

src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,20 @@ public function isPasswordValid($encoded, $raw, $salt)
9494

9595
throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.');
9696
}
97+
98+
/**
99+
* {@inheritdoc}
100+
*/
101+
public function needsRehash(string $encoded): bool
102+
{
103+
if (\function_exists('sodium_crypto_pwhash_str_needs_rehash')) {
104+
return \sodium_crypto_pwhash_str_needs_rehash($encoded, $this->opsLimit, $this->memLimit);
105+
}
106+
107+
if (\extension_loaded('libsodium')) {
108+
return \Sodium\crypto_pwhash_str_needs_rehash($encoded, $this->opsLimit, $this->memLimit);
109+
}
110+
111+
throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.');
112+
}
97113
}

src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,14 @@ public function isPasswordValid(UserInterface $user, $raw)
4646

4747
return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt());
4848
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
public function needsRehash(UserInterface $user, string $encoded): bool
54+
{
55+
$encoder = $this->encoderFactory->getEncoder($user);
56+
57+
return method_exists($encoder, 'needsRehash') && $encoder->needsRehash($encoded);
58+
}
4959
}

src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoderInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
* UserPasswordEncoderInterface is the interface for the password encoder service.
1818
*
1919
* @author Ariel Ferrandini <arielferrandini@gmail.com>
20+
*
21+
* @method bool needsRehash(UserInterface $user, string $encoded)
2022
*/
2123
interface UserPasswordEncoderInterface
2224
{

src/Symfony/Component/Security/Core/Tests/Encoder/BasePasswordEncoderTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ public function testIsPasswordTooLong()
6060
$this->assertFalse($this->invokeIsPasswordTooLong(str_repeat('a', 10)));
6161
}
6262

63+
public function testNeedsRehash()
64+
{
65+
$encoder = new PasswordEncoder();
66+
$this->assertFalse($encoder->needsRehash('foo'));
67+
}
68+
6369
protected function invokeDemergePasswordAndSalt($password)
6470
{
6571
$encoder = new PasswordEncoder();

0 commit comments

Comments
 (0)