Create the database user in a transaction

In OC\User\Manager::createUserFromBackend the newly created user is read
using getUserObject($uid, $backend) but that can cause causal read
issues (wrote in DB primary, not yet in secondary).

In OC\User\Database user backend the user cache is unset after the
insert, so it can't be used by getRealUID() (which is called by
getUserObject()).

To avoid that we make sure the user cache is repopulated in a
transaction.

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
pull/35561/head
Thomas Citharel 2022-12-02 17:46:37 +07:00 committed by Julius Härtl (Rebase PR Action)
parent 8568c11d24
commit f7e65b1751
1 changed files with 18 additions and 11 deletions

@ -45,6 +45,7 @@ declare(strict_types=1);
*/
namespace OC\User;
use OCP\AppFramework\Db\TTransactional;
use OCP\Cache\CappedMemoryCache;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
@ -85,6 +86,8 @@ class Database extends ABackend implements
/** @var string */
private $table;
use TTransactional;
/**
* \OC\User\Database constructor.
*
@ -122,20 +125,24 @@ class Database extends ABackend implements
if (!$this->userExists($uid)) {
$this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
$qb = $this->dbConn->getQueryBuilder();
$qb->insert($this->table)
->values([
'uid' => $qb->createNamedParameter($uid),
'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)),
'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)),
]);
return $this->atomic(function () use ($uid, $password) {
$qb = $this->dbConn->getQueryBuilder();
$qb->insert($this->table)
->values([
'uid' => $qb->createNamedParameter($uid),
'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)),
'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)),
]);
$result = $qb->execute();
$result = $qb->executeStatement();
// Clear cache
unset($this->cache[$uid]);
// Clear cache
unset($this->cache[$uid]);
// Repopulate the cache
$this->loadUser($uid);
return $result ? true : false;
return (bool) $result;
}, $this->dbConn);
}
return false;