diff --git a/core/lib/Drupal/Core/Password/LegacyPassword.php b/core/lib/Drupal/Core/Password/LegacyPassword.php index c44e164..0a2b281 100644 --- a/core/lib/Drupal/Core/Password/LegacyPassword.php +++ b/core/lib/Drupal/Core/Password/LegacyPassword.php @@ -13,7 +13,7 @@ * * @see http://www.openwall.com/phpass/ */ -class LegacyPassword implements PasswordInterface { +class LegacyPassword extends PasswordHashBase { /** * The minimum allowed log2 number of iterations for password stretching. @@ -158,7 +158,7 @@ protected function enforceLog2Boundaries($count_log2) { */ protected function crypt($algo, $password, $setting) { // Prevent DoS attacks by refusing to hash large passwords. - if (strlen($password) > PasswordInterface::PASSWORD_MAX_LENGTH) { + if (strlen($password) > PasswordHashInterface::PASSWORD_MAX_LENGTH) { return FALSE; } @@ -222,7 +222,7 @@ public function hash($password) { /** * {@inheritdoc} */ - public function check($password, $hash) { + public function verify($password, $hash) { if (substr($hash, 0, 2) == 'U$') { // This may be an updated password from user_update_7000(). Such hashes // have 'U' added as the first character and need an extra md5() (see the diff --git a/core/lib/Drupal/Core/Password/PasswordHashBase.php b/core/lib/Drupal/Core/Password/PasswordHashBase.php new file mode 100644 index 0000000..a967a10 --- /dev/null +++ b/core/lib/Drupal/Core/Password/PasswordHashBase.php @@ -0,0 +1,17 @@ +verify($password, $hash); + } + +} diff --git a/core/lib/Drupal/Core/Password/PasswordHashInterface.php b/core/lib/Drupal/Core/Password/PasswordHashInterface.php new file mode 100644 index 0000000..13c4a48 --- /dev/null +++ b/core/lib/Drupal/Core/Password/PasswordHashInterface.php @@ -0,0 +1,25 @@ +=5.5.0 password hashing function password_verify(). + * @deprecated Scheduled for removal in Drupal 9.0.x. Implement interface + * PasswordHashInterface instead of PasswordInterface and use + * \Drupal\Core\Password\PasswordHashInterface::verify(). * - * @see password_verify() + * @see \Drupal\Core\Password\PasswordHashInterface::verify() */ public function check($password, $hash); diff --git a/core/lib/Drupal/Core/Password/PhpPassword.php b/core/lib/Drupal/Core/Password/PhpPassword.php index 36a39af..ca43b7d 100644 --- a/core/lib/Drupal/Core/Password/PhpPassword.php +++ b/core/lib/Drupal/Core/Password/PhpPassword.php @@ -7,7 +7,7 @@ * * @see http://php.net/manual/en/book.password.php */ -class PhpPassword implements PasswordInterface { +class PhpPassword extends PasswordHashBase { /** * The algorithmic cost that should be used. @@ -27,7 +27,7 @@ class PhpPassword implements PasswordInterface { * * This password hashing service was used in Drupal 7 and Drupal < 8.3.0. * - * @var \Drupal\Core\Password\PasswordInterface + * @var \Drupal\Core\Password\PasswordHashInterface */ protected $legacyPassword; @@ -36,10 +36,10 @@ class PhpPassword implements PasswordInterface { * * @param int $cost * The algorithmic cost that should be used. - * @param \Drupal\Core\Password\PasswordInterface $legacy_password + * @param \Drupal\Core\Password\PasswordHashInterface $legacy_password * The legacy password hashing service. */ - function __construct($cost, PasswordInterface $legacy_password) { + function __construct($cost, PasswordHashInterface $legacy_password) { $this->cost = $cost; $this->legacyPassword = $legacy_password; } @@ -59,7 +59,7 @@ public function hash($password) { /** * {@inheritdoc} */ - public function check($password, $hash) { + public function verify($password, $hash) { // Drupal >= 8.3.x hashed password. if (substr($hash, 0, 4) === '$2y$') { $stored_hash = $hash; @@ -73,7 +73,7 @@ public function check($password, $hash) { // - Either a Drupal 7, < 8.3.0 hash, // - Or a Drupal 6 (or md5) hash migrated to Drupal < 8.3.0. else { - return $this->legacyPassword->check($password, $hash); + return $this->legacyPassword->verify($password, $hash); } return password_verify($password, $stored_hash); diff --git a/core/lib/Drupal/Core/ProxyClass/Password/LegacyPassword.php b/core/lib/Drupal/Core/ProxyClass/Password/LegacyPassword.php index 995c5c0..4b534fd 100644 --- a/core/lib/Drupal/Core/ProxyClass/Password/LegacyPassword.php +++ b/core/lib/Drupal/Core/ProxyClass/Password/LegacyPassword.php @@ -12,7 +12,7 @@ * * @see \Drupal\Component\ProxyBuilder */ - class LegacyPassword implements \Drupal\Core\Password\PasswordInterface + class LegacyPassword implements \Drupal\Core\Password\PasswordHashInterface { use \Drupal\Core\DependencyInjection\DependencySerializationTrait; @@ -86,9 +86,9 @@ public function hash($password) /** * {@inheritdoc} */ - public function check($password, $hash) + public function verify($password, $hash) { - return $this->lazyLoadItself()->check($password, $hash); + return $this->lazyLoadItself()->verify($password, $hash); } /** @@ -99,6 +99,14 @@ public function needsRehash($hash) return $this->lazyLoadItself()->needsRehash($hash); } + /** + * {@inheritdoc} + */ + public function check($password, $hash) + { + return $this->lazyLoadItself()->check($password, $hash); + } + } } diff --git a/core/lib/Drupal/Core/ProxyClass/Password/PhpPassword.php b/core/lib/Drupal/Core/ProxyClass/Password/PhpPassword.php index 6cc2ad1..af4c0c4 100644 --- a/core/lib/Drupal/Core/ProxyClass/Password/PhpPassword.php +++ b/core/lib/Drupal/Core/ProxyClass/Password/PhpPassword.php @@ -12,7 +12,7 @@ * * @see \Drupal\Component\ProxyBuilder */ - class PhpPassword implements \Drupal\Core\Password\PasswordInterface + class PhpPassword implements \Drupal\Core\Password\PasswordHashInterface { use \Drupal\Core\DependencyInjection\DependencySerializationTrait; @@ -78,9 +78,9 @@ public function hash($password) /** * {@inheritdoc} */ - public function check($password, $hash) + public function verify($password, $hash) { - return $this->lazyLoadItself()->check($password, $hash); + return $this->lazyLoadItself()->verify($password, $hash); } /** @@ -91,6 +91,14 @@ public function needsRehash($hash) return $this->lazyLoadItself()->needsRehash($hash); } + /** + * {@inheritdoc} + */ + public function check($password, $hash) + { + return $this->lazyLoadItself()->check($password, $hash); + } + } } diff --git a/core/modules/user/src/Plugin/migrate/destination/EntityUser.php b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php index b11d867..1050a7a 100644 --- a/core/modules/user/src/Plugin/migrate/destination/EntityUser.php +++ b/core/modules/user/src/Plugin/migrate/destination/EntityUser.php @@ -8,7 +8,7 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Field\Plugin\Field\FieldType\EmailItem; -use Drupal\Core\Password\PasswordInterface; +use Drupal\Core\Password\PasswordHashInterface; use Drupal\migrate\Plugin\MigrationInterface; use Drupal\migrate\Plugin\migrate\destination\EntityContentBase; use Drupal\migrate\Row; @@ -24,7 +24,7 @@ class EntityUser extends EntityContentBase { /** * The password service class. * - * @var \Drupal\Core\Password\PasswordInterface + * @var \Drupal\Core\Password\PasswordHashInterface */ protected $password; @@ -47,10 +47,10 @@ class EntityUser extends EntityContentBase { * The entity manager service. * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager * The field type plugin manager service. - * @param \Drupal\Core\Password\PasswordInterface $password + * @param \Drupal\Core\Password\PasswordHashInterface $password * The password service. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, PasswordInterface $password) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, PasswordHashInterface $password) { parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_manager, $field_type_manager); $this->password = $password; } diff --git a/core/modules/user/src/Tests/UserLoginTest.php b/core/modules/user/src/Tests/UserLoginTest.php index 7d5bcbe..8941bdb 100644 --- a/core/modules/user/src/Tests/UserLoginTest.php +++ b/core/modules/user/src/Tests/UserLoginTest.php @@ -109,7 +109,7 @@ function testPerUserLoginFloodControl() { * Tests that user password is re-hashed upon login, after changing the cost. */ function testPasswordRehashOnLoginAfterChangingCost() { - /** @var \Drupal\Core\Password\PasswordInterface $hashing_service */ + /** @var \Drupal\Core\Password\PasswordHashInterface $hashing_service */ $hashing_service = $this->container->get('password'); // Create a new user and authenticate. @@ -137,7 +137,7 @@ function testPasswordRehashOnLoginAfterChangingCost() { // Check that after login the password has been rehashed and is valid. $new_hash = User::load($account->id())->getPassword(); $this->assertNotEqual($new_hash, $old_hash); - $this->assertTrue($hashing_service->check($plain_password, $new_hash)); + $this->assertTrue($hashing_service->verify($plain_password, $new_hash)); $this->assertFalse($hashing_service->needsRehash($new_hash)); } @@ -145,14 +145,14 @@ function testPasswordRehashOnLoginAfterChangingCost() { * Tests rehashing of Drupal 6 (md5) passwords migrated to Drupal 8. */ public function testDrupal6MigratedPasswordRehashing() { - /** @var \Drupal\Core\Password\PasswordInterface $main_hashing_service */ + /** @var \Drupal\Core\Password\PasswordHashInterface $main_hashing_service */ $main_hashing_service = $this->container->get('password'); $account = $this->drupalCreateUser(); $plain_password = $account->pass_raw; $md5_pass = md5($plain_password); - /** @var \Drupal\Core\Password\PasswordInterface[] $migration_cases */ + /** @var \Drupal\Core\Password\PasswordHashInterface[] $migration_cases */ $migration_cases = [ // Drupal 6 (md5) passwords migrated to Drupal < 8.3.0 used the legacy // password hashing engine, inherited from Drupal 7. @@ -182,7 +182,7 @@ public function testDrupal6MigratedPasswordRehashing() { // Check that after login the password has been rehashed and is valid. $new_hash = User::load($account->id())->getPassword(); $this->assertNotEqual($new_hash, $old_hash); - $this->assertTrue($main_hashing_service->check($plain_password, $new_hash)); + $this->assertTrue($main_hashing_service->verify($plain_password, $new_hash)); $this->assertFalse($main_hashing_service->needsRehash($new_hash)); } } @@ -191,9 +191,9 @@ public function testDrupal6MigratedPasswordRehashing() { * Tests rehashing of Drupal 7 and < 8.3.0 passwords. */ public function testPasswordRehashing() { - /** @var \Drupal\Core\Password\PasswordInterface $hashing_service */ + /** @var \Drupal\Core\Password\PasswordHashInterface $hashing_service */ $hashing_service = $this->container->get('password'); - /** @var \Drupal\Core\Password\PasswordInterface $legacy_hashing_service */ + /** @var \Drupal\Core\Password\PasswordHashInterface $legacy_hashing_service */ $legacy_hashing_service = $this->container->get('legacy_password'); $account = $this->drupalCreateUser(); @@ -216,7 +216,7 @@ public function testPasswordRehashing() { // Check that after login the password has been rehashed and is valid. $new_hash = User::load($account->id())->getPassword(); $this->assertNotEqual($new_hash, $old_hash); - $this->assertTrue($hashing_service->check($plain, $new_hash)); + $this->assertTrue($hashing_service->verify($plain, $new_hash)); $this->assertFalse($hashing_service->needsRehash($new_hash)); } diff --git a/core/modules/user/src/UserAuth.php b/core/modules/user/src/UserAuth.php index 9fbcf09..d18eed3 100644 --- a/core/modules/user/src/UserAuth.php +++ b/core/modules/user/src/UserAuth.php @@ -3,7 +3,7 @@ namespace Drupal\user; use Drupal\Core\Entity\EntityManagerInterface; -use Drupal\Core\Password\PasswordInterface; +use Drupal\Core\Password\PasswordHashInterface; /** * Validates user authentication credentials. @@ -20,7 +20,7 @@ class UserAuth implements UserAuthInterface { /** * The password hashing service. * - * @var \Drupal\Core\Password\PasswordInterface + * @var \Drupal\Core\Password\PasswordHashInterface */ protected $passwordChecker; @@ -29,10 +29,10 @@ class UserAuth implements UserAuthInterface { * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. - * @param \Drupal\Core\Password\PasswordInterface $password_checker + * @param \Drupal\Core\Password\PasswordHashInterface $password_checker * The password service. */ - public function __construct(EntityManagerInterface $entity_manager, PasswordInterface $password_checker) { + public function __construct(EntityManagerInterface $entity_manager, PasswordHashInterface $password_checker) { $this->entityManager = $entity_manager; $this->passwordChecker = $password_checker; } @@ -47,7 +47,7 @@ public function authenticate($username, $password) { $account_search = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $username)); if ($account = reset($account_search)) { - if ($this->passwordChecker->check($password, $account->getPassword())) { + if ($this->passwordChecker->verify($password, $account->getPassword())) { // Successful authentication. $uid = $account->id(); diff --git a/core/modules/user/tests/src/Unit/UserAuthTest.php b/core/modules/user/tests/src/Unit/UserAuthTest.php index 1b96d8f..23e2885 100644 --- a/core/modules/user/tests/src/Unit/UserAuthTest.php +++ b/core/modules/user/tests/src/Unit/UserAuthTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\user\Unit; +use Drupal\Core\Password\PasswordHashInterface; use Drupal\Tests\UnitTestCase; use Drupal\user\UserAuth; @@ -21,7 +22,7 @@ class UserAuthTest extends UnitTestCase { /** * The mocked password service. * - * @var \Drupal\Core\Password\PasswordInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Password\PasswordHashInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $passwordService; @@ -65,7 +66,7 @@ protected function setUp() { ->with('user') ->will($this->returnValue($this->userStorage)); - $this->passwordService = $this->getMock('Drupal\Core\Password\PasswordInterface'); + $this->passwordService = $this->getMock(PasswordHashInterface::class); $this->testUser = $this->getMockBuilder('Drupal\user\Entity\User') ->disableOriginalConstructor() diff --git a/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php b/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php index 74b3042..8ce4430 100644 --- a/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php +++ b/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php @@ -8,7 +8,7 @@ namespace Drupal\Tests\Core\Password; use Drupal\Core\Password\LegacyPassword; -use Drupal\Core\Password\PasswordInterface; +use Drupal\Core\Password\PasswordHashInterface; use Drupal\Core\Password\PhpPassword; use Drupal\Tests\UnitTestCase; @@ -23,7 +23,7 @@ class PasswordHashingTest extends UnitTestCase { /** * The current password hashing service. * - * @var \Drupal\Core\Password\PasswordInterface + * @var \Drupal\Core\Password\PasswordHashInterface */ protected $hashingService; @@ -32,7 +32,7 @@ class PasswordHashingTest extends UnitTestCase { * * This service was used in Drupal 7 and Drupal < 8.3.0. * - * @var \Drupal\Core\Password\PasswordInterface + * @var \Drupal\Core\Password\PasswordHashInterface */ protected $legacyHashingService; @@ -123,8 +123,8 @@ public function testPasswordNeedsRehashing() { /** * Tests that plain-text password is verifying against all its hashes. * - * @covers \Drupal\Core\Password\PhpPassword::check - * @covers \Drupal\Core\Password\LegacyPassword::check + * @covers \Drupal\Core\Password\PhpPassword::verify + * @covers \Drupal\Core\Password\LegacyPassword::verify */ public function testPasswordHashing() { // Check that text hashed with current service is different than teh others. @@ -135,16 +135,16 @@ public function testPasswordHashing() { // Check that the plain-text password is verifying against all its hashes. // This is important because migrated and legacy hashes should be checked // with the user plain-text entered password on first login. - $this->assertTrue($this->hashingService->check($this->plainPassword, $this->md5ToLegacyHashedPassword)); - $this->assertTrue($this->hashingService->check($this->plainPassword, $this->md5HashedPassword)); - $this->assertTrue($this->hashingService->check($this->plainPassword, $this->legacyHashedPassword)); + $this->assertTrue($this->hashingService->verify($this->plainPassword, $this->md5ToLegacyHashedPassword)); + $this->assertTrue($this->hashingService->verify($this->plainPassword, $this->md5HashedPassword)); + $this->assertTrue($this->hashingService->verify($this->plainPassword, $this->legacyHashedPassword)); } /** * Tests that password needs rehashing when the cost changes. * * @covers \Drupal\Core\Password\PhpPassword::hash - * @covers \Drupal\Core\Password\PhpPassword::check + * @covers \Drupal\Core\Password\PhpPassword::verify * @covers \Drupal\Core\Password\PhpPassword::needsRehash */ public function testPasswordNeedsRehashingOnCostChange() { @@ -187,14 +187,14 @@ public function testLongPassword($password, $allowed) { */ public function providerLongPasswords() { // '512 byte long password is allowed.' - $passwords['allowed'] = [str_repeat('x', PasswordInterface::PASSWORD_MAX_LENGTH), TRUE]; + $passwords['allowed'] = [str_repeat('x', PasswordHashInterface::PASSWORD_MAX_LENGTH), TRUE]; // 513 byte long password is not allowed. - $passwords['too_long'] = [str_repeat('x', PasswordInterface::PASSWORD_MAX_LENGTH + 1), FALSE]; + $passwords['too_long'] = [str_repeat('x', PasswordHashInterface::PASSWORD_MAX_LENGTH + 1), FALSE]; // Check a string of 3-byte UTF-8 characters, 510 byte long password is // allowed. - $len = floor(PasswordInterface::PASSWORD_MAX_LENGTH / 3); - $diff = PasswordInterface::PASSWORD_MAX_LENGTH % 3; + $len = floor(PasswordHashInterface::PASSWORD_MAX_LENGTH / 3); + $diff = PasswordHashInterface::PASSWORD_MAX_LENGTH % 3; $passwords['utf8'] = [str_repeat('€', $len), TRUE]; // 512 byte long password is allowed. $passwords['ut8_extended'] = [$passwords['utf8'][0] . str_repeat('x', $diff), TRUE];