summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulius Härtl <jus@bitgrid.net>2023-02-04 22:35:35 +0100
committerJulius Härtl <jus@bitgrid.net>2023-02-09 13:44:00 +0100
commit580feecdbfa0dac342d133fa1482f7a4bd4539fb (patch)
tree4613481f3a24c58fde0b833fa54c27614f886fdc
parentdd891e7e8128bfd888a9451514db3c1b82b1a9cc (diff)
downloadnextcloud-server-580feecdbfa0dac342d133fa1482f7a4bd4539fb.tar.gz
nextcloud-server-580feecdbfa0dac342d133fa1482f7a4bd4539fb.zip
fix(authtoken): Store only one hash for authtokens with the current password per user
Signed-off-by: Julius Härtl <jus@bitgrid.net>
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenMapper.php27
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenProvider.php24
2 files changed, 50 insertions, 1 deletions
diff --git a/lib/private/Authentication/Token/PublicKeyTokenMapper.php b/lib/private/Authentication/Token/PublicKeyTokenMapper.php
index 7b11ef8adf3..8feb275b3b7 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenMapper.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenMapper.php
@@ -229,4 +229,31 @@ class PublicKeyTokenMapper extends QBMapper {
);
$update->executeStatement();
}
+
+ public function updateHashesForUser(string $userId, string $passwordHash): void {
+ $qb = $this->db->getQueryBuilder();
+ $update = $qb->update($this->getTableName())
+ ->set('password_hash', $qb->createNamedParameter($passwordHash))
+ ->where(
+ $qb->expr()->eq('uid', $qb->createNamedParameter($userId))
+ );
+ $update->executeStatement();
+ }
+
+ public function getFirstTokenForUser(string $userId): ?PublicKeyToken {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('uid', $qb->createNamedParameter($userId)))
+ ->setMaxResults(1)
+ ->orderBy('id');
+ $result = $qb->executeQuery();
+
+ $data = $result->fetch();
+ $result->closeCursor();
+ if ($data === false) {
+ return null;
+ }
+ return PublicKeyToken::fromRow($data);
+ }
}
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
index c8adec24b31..e64abcd231f 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
@@ -102,9 +102,23 @@ class PublicKeyTokenProvider implements IProvider {
$name = mb_substr($name, 0, 120) . '…';
}
+ // We need to check against one old token to see if there is a password
+ // hash that we can reuse for detecting outdated passwords
+ $randomOldToken = $this->mapper->getFirstTokenForUser($uid);
+ $oldTokenMatches = $randomOldToken && $this->hasher->verify(sha1($password) . $password, $randomOldToken->getPasswordHash());
+
$dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember);
+
+ if ($oldTokenMatches) {
+ $dbToken->setPasswordHash($randomOldToken->getPasswordHash());
+ }
+
$this->mapper->insert($dbToken);
+ if (!$oldTokenMatches && $password !== null) {
+ $this->updatePasswords($uid, $password);
+ }
+
// Add the token to the cache
$this->cache[$dbToken->getToken()] = $dbToken;
@@ -289,10 +303,11 @@ class PublicKeyTokenProvider implements IProvider {
// Update the password for all tokens
$tokens = $this->mapper->getTokenByUser($token->getUID());
+ $hashedPassword = $this->hashPassword($password);
foreach ($tokens as $t) {
$publicKey = $t->getPublicKey();
$t->setPassword($this->encryptPassword($password, $publicKey));
- $t->setPasswordHash($this->hashPassword($password));
+ $t->setPasswordHash($hashedPassword);
$this->updateToken($t);
}
}
@@ -481,6 +496,13 @@ class PublicKeyTokenProvider implements IProvider {
$this->updateToken($t);
}
}
+
+ // If password hashes are different we update them all to be equal so
+ // that the next execution only needs to verify once
+ if (count($hashNeedsUpdate) > 1) {
+ $newPasswordHash = $this->hashPassword($password);
+ $this->mapper->updateHashesForUser($uid, $newPasswordHash);
+ }
}
private function logOpensslError() {