fix(authtoken): Store only one hash for authtokens with the current password per user

Signed-off-by: Julius Härtl <jus@bitgrid.net>
pull/36562/head
Julius Härtl 3 years ago
parent dd891e7e81
commit 580feecdbf
No known key found for this signature in database
GPG Key ID: 4C614C6ED2CDE6DF
  1. 27
      lib/private/Authentication/Token/PublicKeyTokenMapper.php
  2. 24
      lib/private/Authentication/Token/PublicKeyTokenProvider.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);
}
}

@ -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() {

Loading…
Cancel
Save