diff --git a/lib/UserBackend.php b/lib/UserBackend.php index d3114b4b..f8975814 100644 --- a/lib/UserBackend.php +++ b/lib/UserBackend.php @@ -310,7 +310,9 @@ public function checkPassword(string $loginName, string $password) { $newHash = ''; if ($this->hasher->verify($password, $storedHash, $newHash)) { if ($newHash !== '') { - $this->setPassword($loginName, $password); + // $loginName can be the email address, while setPassword() + // matches on the user id. + $this->setPassword((string)$row['uid'], $password); } return (string)$row['uid']; diff --git a/tests/unit/UserBackendTest.php b/tests/unit/UserBackendTest.php index 6f7a6f72..4cdaa540 100644 --- a/tests/unit/UserBackendTest.php +++ b/tests/unit/UserBackendTest.php @@ -102,4 +102,28 @@ public function testCustomLoginNameUid(): void { $this->assertEquals($uid, $this->backend->checkPassword($email, 'bar')); $this->assertEquals('Karl Doe', $this->backend->getDisplayName($uid)); } + + /** + * An outdated hash has to be upgraded no matter whether the guest logged + * in with the user id or with the email address. + */ + public function testOutdatedPasswordHashIsUpgradedOnEmailLogin(): void { + $email = 'foo@example.tld'; + $uid = hash('sha256', $email); + $this->backend->createUser($uid, 'bar'); + $this->backend->setInitialEmail($uid, $email); + + // An unprefixed bcrypt hash is a legacy hash, so verifying it always + // hands back a replacement hash. + $legacyHash = password_hash('bar', PASSWORD_BCRYPT); + $query = Server::get(IDBConnection::class)->getQueryBuilder(); + $query->update('guests_users') + ->set('password', $query->createNamedParameter($legacyHash)) + ->where($query->expr()->eq('uid_lower', $query->createNamedParameter($uid))); + $query->executeStatement(); + + $this->assertEquals($uid, $this->backend->checkPassword($email, 'bar')); + + $this->assertNotEquals($legacyHash, $this->backend->getPasswordHash($uid)); + } }