Splitting out part of #1845004: Replace custom password hashing library with PHP password_hash() based on discussion with catch

Suggested commit message:
git commit -m 'Issue #2503083 by claudiu.cristea, neclimdul, and pwolanin: Simplify PasswordInterface so it'\''s not coupled to UserInterface'

Problem

\Drupal\Core\Password\PasswordInterface is coupled to Drupal\user\UserInterface which is not needed and makes the code more complex

Proposed resolution

Simplify the interface (make it more like Drupal 7) so \Drupal\Core\Password\PasswordInterface only cares about string passwords and hashes, not user objects

Remaining tasks

change record

API changes

Method signatures changes:
\Drupal\Core\Password\PasswordInterface::check
\Drupal\Core\Password\PasswordInterface::hash

This should have no real impact outside core at this point.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task to improve the interface so we avoid breaking changes in 8.1 to switch hashing algorithms
Issue priority Normal, because it only lacks interoperability.
Disruption Disruptive for any existing contrib code calling core's password interface. This would be limited to modules providing additional authentication mechanisms.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pwolanin’s picture

Status: Active » Needs review
FileSize
19.67 KB

wow the existing checks in core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php don't make sense - a lot of the test variables are never set!

I think I got the relevant parts from the other patch, plus fixes to that test to make it actually test something.

neclimdul’s picture

Issue summary: View changes
FileSize
12.59 KB

patch

errr... crap... we both made patches

pwolanin’s picture

FileSize
19.67 KB
21.4 KB
2.3 KB

use the const PasswordInterface::PASSWORD_MAX_LENGTH instead of magic numbers.

pwolanin’s picture

FileSize
21.4 KB

Oops - that cross-post blew up. Here's my #2 patch again so it's tested.

pwolanin’s picture

FileSize
21.4 KB

reposting the same patch w/ new name since the bot isn't getting it.

neclimdul’s picture

  1. +++ b/core/lib/Drupal/Core/Password/PasswordInterface.php
    @@ -2,48 +2,47 @@
    +   * Maximum password length.
    +   */
    +  const PASSWORD_MAX_LENGTH = 512;
    +
    +  /**
    

    I didn't include this since it was out of scope from the IS. Are we sure we want to include that in this?

  2. +++ b/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php
    @@ -79,14 +88,13 @@ public function testWithinBounds() {
    +    // The weaker hash password should be flagged as needing an update.
    +    $this->assertTrue($this->passwordHasher->needsRehash($this->weakerHashedPassword), 'User with md5 password needs a new hash.');
    
    @@ -116,25 +123,22 @@ public function testPasswordHashing() {
    +    $password_hasher = new PhpassHashedPassword(PhpassHashedPassword::MIN_HASH_COUNT + 2);
    +    $this->assertTrue($password_hasher->needsRehash($this->hashedPassword), 'User needs a new hash after incrementing the log2 count.');
    

    These test the same thing. Also the first test is not testing md5 as implied by the comment. We should remove the first test.

pwolanin’s picture

If we are modifying the interface, I think add PASSWORD_MAX_LENGTH is reasonable.

Also - look in detail at my test fixes. The test is now testing a hash over an md5 hash and validating that it works.

neclimdul’s picture

No, and I don't appreciate you repeatedly implying I haven't read your patch. I read this about 5 times before you pinged me in IRC to make sure I understood it and additionally twice after talking on IRC to make sure I wasn't mistaken. It is not testing MD5 it testing a lower hash count which we have an explict test for later in test suite.

Let me see if I can explain this again more clearly.

  1. +++ b/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php
    @@ -58,10 +66,12 @@ class PasswordHashingTest extends UnitTestCase {
    +    $this->md5HashedPassword = 'U' . $this->passwordHasher->hash(md5($this->password));
    +    $this->weakerHashedPassword = $weak_hasher->hash($this->password);
    

    Here you set your hashes. The md5 hash was missing previously, that's a good catch.

  2. +++ b/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php
    @@ -79,14 +89,13 @@ public function testWithinBounds() {
    +    $this->assertTrue($this->passwordHasher->needsRehash($this->md5HashedPassword), 'User with md5 password needs a new hash.');
    +    // The weaker hash password should be flagged as needing an update.
    +    $this->assertTrue($this->passwordHasher->needsRehash($this->weakerHashedPassword), 'User with md5 password needs a new hash.');
    

    Here you test the MD5 hash, same as before, but a bit shorter then you also check the PhPass hashed password with the lower count but the comment mentions MD5 hash.

  3. +++ b/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php
    @@ -116,25 +124,22 @@ public function testPasswordHashing() {
       public function testPasswordRehashing() {
     
         // Increment the log2 iteration to MIN + 1.
    -    $this->passwordHasher = new PhpassHashedPassword(PhpassHashedPassword::MIN_HASH_COUNT + 1);
    -    $this->assertTrue($this->passwordHasher->userNeedsNewHash($this->user), 'User needs a new hash after incrementing the log2 count.');
    +    $password_hasher = new PhpassHashedPassword(PhpassHashedPassword::MIN_HASH_COUNT + 2);
    +    $this->assertTrue($password_hasher->needsRehash($this->hashedPassword), 'User needs a new hash after incrementing the log2 count.');
    

    Here we have an explicit test where we assert that we flag lower hash counts to be rehashed.

pwolanin’s picture

FileSize
20.43 KB
4.63 KB

@neclimdul - ok I see, yes - some of the changes are redundant. Sorry I misunderstood your comment.

The last submitted patch, 1: 2503083-1.patch, failed testing.

The last submitted patch, 3: 2503083-2.patch, failed testing.

The last submitted patch, 5: 2503083-5.patch, failed testing.

The last submitted patch, 2: simplify-2503083-1.patch, failed testing.

neclimdul’s picture

+++ b/core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php
@@ -161,19 +152,20 @@ public function testLongPassword($password, $allowed) {
+    $len = (PasswordInterface::PASSWORD_MAX_LENGTH - 2) / 3;

nit. (int) (PasswordInterface::PASSWORD_MAX_LENGTH / 3) will achieve the same thing and handle future changes better.

pwolanin’s picture

FileSize
20.58 KB
1022 bytes

Sure - this change uses floor() and % to make the math robust.

pwolanin’s picture

Issue summary: View changes
cilefen’s picture

Issue tags: +Needs change record

If it may be disruptive it needs a change record.

pwolanin’s picture

@cilifen - yes, I put it in the list of remaining tasks

neclimdul’s picture

Issue summary: View changes

Patch works for me.

claudiu.cristea’s picture

As you already touched the interface docs, why not cleaning up all the docs in that file? I already did that in #1845004-70: Replace custom password hashing library with PHP password_hash().

claudiu.cristea’s picture

Status: Needs review » Reviewed & tested by the community

Ah, sorry, my bad. The non-standard docs were not in interface but in PhpassHashedPassword. We'll clean that after #1845004: Replace custom password hashing library with PHP password_hash() will go in.

The patch looks good to me.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Still need a change record.

neclimdul’s picture

Status: Needs work » Needs review

Man its hard to find the link to create a change record... I think I've got it done.

cilefen’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC with the change record.

  • alexpott committed fd2bc62 on 8.0.x
    Issue #2503083 by pwolanin, neclimdul: Simplify PasswordInterface so it'...
alexpott’s picture

Status: Reviewed & tested by the community » Fixed

The lack of interoperability is a regression from D7 and disentangling PasswordInterace from UserInterface reduces fragility and makes it more useful. Committed fd2bc62 and pushed to 8.0.x. Thanks!

diff --git a/core/modules/migrate/src/MigratePassword.php b/core/modules/migrate/src/MigratePassword.php
index 6e69887..479aac8 100644
--- a/core/modules/migrate/src/MigratePassword.php
+++ b/core/modules/migrate/src/MigratePassword.php
@@ -8,7 +8,6 @@
 namespace Drupal\migrate;
 
 use Drupal\Core\Password\PasswordInterface;
-use Drupal\migrate\Entity\MigrationInterface;
 
 /**
  * Replaces the original 'password' service in order to prefix the MD5 re-hashed

Fixed unnecessary use added by the patch on commit.

JeroenT’s picture

Issue tags: -Needs change record

This issue already has a change record.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.