Merge pull request #46123 from nextcloud/feat/user-password-hash

feat: Allow getting/setting the password hash of a user
This commit is contained in:
Pytal 2024-07-09 08:00:01 -07:00 committed by GitHub
commit 3a97dbf248
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 110 additions and 1 deletions

View file

@ -799,6 +799,7 @@ return array(
'OCP\\User\\Backend\\IGetHomeBackend' => $baseDir . '/lib/public/User/Backend/IGetHomeBackend.php',
'OCP\\User\\Backend\\IGetRealUIDBackend' => $baseDir . '/lib/public/User/Backend/IGetRealUIDBackend.php',
'OCP\\User\\Backend\\IPasswordConfirmationBackend' => $baseDir . '/lib/public/User/Backend/IPasswordConfirmationBackend.php',
'OCP\\User\\Backend\\IPasswordHashBackend' => $baseDir . '/lib/public/User/Backend/IPasswordHashBackend.php',
'OCP\\User\\Backend\\IProvideAvatarBackend' => $baseDir . '/lib/public/User/Backend/IProvideAvatarBackend.php',
'OCP\\User\\Backend\\IProvideEnabledStateBackend' => $baseDir . '/lib/public/User/Backend/IProvideEnabledStateBackend.php',
'OCP\\User\\Backend\\ISearchKnownUsersBackend' => $baseDir . '/lib/public/User/Backend/ISearchKnownUsersBackend.php',

View file

@ -832,6 +832,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\User\\Backend\\IGetHomeBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IGetHomeBackend.php',
'OCP\\User\\Backend\\IGetRealUIDBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IGetRealUIDBackend.php',
'OCP\\User\\Backend\\IPasswordConfirmationBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IPasswordConfirmationBackend.php',
'OCP\\User\\Backend\\IPasswordHashBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IPasswordHashBackend.php',
'OCP\\User\\Backend\\IProvideAvatarBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IProvideAvatarBackend.php',
'OCP\\User\\Backend\\IProvideEnabledStateBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/IProvideEnabledStateBackend.php',
'OCP\\User\\Backend\\ISearchKnownUsersBackend' => __DIR__ . '/../../..' . '/lib/public/User/Backend/ISearchKnownUsersBackend.php',

View file

@ -8,6 +8,7 @@ declare(strict_types=1);
*/
namespace OC\User;
use InvalidArgumentException;
use OCP\AppFramework\Db\TTransactional;
use OCP\Cache\CappedMemoryCache;
use OCP\EventDispatcher\IEventDispatcher;
@ -21,6 +22,7 @@ use OCP\User\Backend\ICreateUserBackend;
use OCP\User\Backend\IGetDisplayNameBackend;
use OCP\User\Backend\IGetHomeBackend;
use OCP\User\Backend\IGetRealUIDBackend;
use OCP\User\Backend\IPasswordHashBackend;
use OCP\User\Backend\ISearchKnownUsersBackend;
use OCP\User\Backend\ISetDisplayNameBackend;
use OCP\User\Backend\ISetPasswordBackend;
@ -37,7 +39,8 @@ class Database extends ABackend implements
IGetHomeBackend,
ICountUsersBackend,
ISearchKnownUsersBackend,
IGetRealUIDBackend {
IGetRealUIDBackend,
IPasswordHashBackend {
/** @var CappedMemoryCache */
private $cache;
@ -176,6 +179,40 @@ class Database extends ABackend implements
return false;
}
public function getPasswordHash(string $userId): ?string {
$this->fixDI();
if (!$this->userExists($userId)) {
return null;
}
if (!empty($this->cache[$userId]['password'])) {
return $this->cache[$userId]['password'];
}
$qb = $this->dbConn->getQueryBuilder();
$qb->select('password')
->from($this->table)
->where($qb->expr()->eq('uid_lower', $qb->createNamedParameter(mb_strtolower($userId))));
/** @var false|string $hash */
$hash = $qb->executeQuery()->fetchOne();
if ($hash === false) {
return null;
}
$this->cache[$userId]['password'] = $hash;
return $hash;
}
public function setPasswordHash(string $userId, string $passwordHash): bool {
if (!\OCP\Server::get(IHasher::class)->validate($passwordHash)) {
throw new InvalidArgumentException();
}
$this->fixDI();
$result = $this->updatePassword($userId, $passwordHash);
if (!$result) {
return false;
}
$this->cache[$userId]['password'] = $passwordHash;
return true;
}
/**
* Set display name
*

View file

@ -73,6 +73,14 @@ class LazyUser implements IUser {
return $this->getUser()->setPassword($password, $recoveryPassword);
}
public function getPasswordHash(): ?string {
return $this->getUser()->getPasswordHash();
}
public function setPasswordHash(string $passwordHash): bool {
return $this->getUser()->setPasswordHash($passwordHash);
}
public function getHome() {
return $this->getUser()->getHome();
}

View file

@ -25,6 +25,7 @@ use OCP\IUser;
use OCP\IUserBackend;
use OCP\Notification\IManager as INotificationManager;
use OCP\User\Backend\IGetHomeBackend;
use OCP\User\Backend\IPasswordHashBackend;
use OCP\User\Backend\IProvideAvatarBackend;
use OCP\User\Backend\IProvideEnabledStateBackend;
use OCP\User\Backend\ISetDisplayNameBackend;
@ -319,6 +320,20 @@ class User implements IUser {
}
}
public function getPasswordHash(): ?string {
if (!($this->backend instanceof IPasswordHashBackend)) {
return null;
}
return $this->backend->getPasswordHash($this->uid);
}
public function setPasswordHash(string $passwordHash): bool {
if (!($this->backend instanceof IPasswordHashBackend)) {
return false;
}
return $this->backend->setPasswordHash($this->uid, $passwordHash);
}
/**
* get the users home folder to mount
*

View file

@ -76,6 +76,23 @@ interface IUser {
*/
public function setPassword($password, $recoveryPassword = null);
/**
* Get the password hash of the user
*
* @return ?string the password hash hashed by `\OCP\Security\IHasher::hash()`
* @since 30.0.0
*/
public function getPasswordHash(): ?string;
/**
* Set the password hash of the user
*
* @param string $passwordHash the password hash hashed by `\OCP\Security\IHasher::hash()`
* @throws InvalidArgumentException when `$passwordHash` is not a valid hash
* @since 30.0.0
*/
public function setPasswordHash(string $passwordHash): bool;
/**
* get the users home folder to mount
*

View file

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCP\User\Backend;
use InvalidArgumentException;
/**
* @since 30.0.0
*/
interface IPasswordHashBackend {
/**
* @return ?string the password hash hashed by `\OCP\Security\IHasher::hash()`
* @since 30.0.0
*/
public function getPasswordHash(string $userId): ?string;
/**
* @param string $passwordHash the password hash hashed by `\OCP\Security\IHasher::hash()`
* @throws InvalidArgumentException when `$passwordHash` is not a valid hash
* @since 30.0.0
*/
public function setPasswordHash(string $userId, string $passwordHash): bool;
}