diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2022-10-02 14:11:41 +0200 |
---|---|---|
committer | Christoph Wurst <christoph@winzerhof-wurst.at> | 2022-10-18 08:28:22 +0200 |
commit | c5922e67d37f3bcf7748a36b4c7ab10d1d10f2b8 (patch) | |
tree | bf00de8c823c15886571e8fe7b2066e03be8dddd /lib/private/Authentication/Token | |
parent | 495d49a1324d5047ab122a20d1900e0239d4de59 (diff) | |
download | nextcloud-server-c5922e67d37f3bcf7748a36b4c7ab10d1d10f2b8.tar.gz nextcloud-server-c5922e67d37f3bcf7748a36b4c7ab10d1d10f2b8.zip |
Run session token renewals in a database transaction
The session token renewal does
1) Read the old token
2) Write a new token
3) Delete the old token
If two processes succeed to read the old token there can be two new tokens because
the queries were not run in a transaction. This is particularly problematic on
clustered DBs where 1) would go to a read node and 2) and 3) go to a write node.
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib/private/Authentication/Token')
-rw-r--r-- | lib/private/Authentication/Token/PublicKeyTokenProvider.php | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 511aad76211..c7e29568383 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -34,14 +34,18 @@ use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\TokenPasswordExpiredException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Exceptions\WipeTokenException; +use OCP\AppFramework\Db\TTransactional; use OCP\Cache\CappedMemoryCache; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; +use OCP\IDBConnection; use OCP\Security\ICrypto; use Psr\Log\LoggerInterface; class PublicKeyTokenProvider implements IProvider { + use TTransactional; + /** @var PublicKeyTokenMapper */ private $mapper; @@ -51,6 +55,8 @@ class PublicKeyTokenProvider implements IProvider { /** @var IConfig */ private $config; + private IDBConnection $db; + /** @var LoggerInterface */ private $logger; @@ -63,11 +69,13 @@ class PublicKeyTokenProvider implements IProvider { public function __construct(PublicKeyTokenMapper $mapper, ICrypto $crypto, IConfig $config, + IDBConnection $db, LoggerInterface $logger, ITimeFactory $time) { $this->mapper = $mapper; $this->crypto = $crypto; $this->config = $config; + $this->db = $db; $this->logger = $logger; $this->time = $time; @@ -164,31 +172,32 @@ class PublicKeyTokenProvider implements IProvider { public function renewSessionToken(string $oldSessionId, string $sessionId): IToken { $this->cache->clear(); - $token = $this->getToken($oldSessionId); - - if (!($token instanceof PublicKeyToken)) { - throw new InvalidTokenException("Invalid token type"); - } + return $this->atomic(function () use ($oldSessionId, $sessionId) { + $token = $this->getToken($oldSessionId); - $password = null; - if (!is_null($token->getPassword())) { - $privateKey = $this->decrypt($token->getPrivateKey(), $oldSessionId); - $password = $this->decryptPassword($token->getPassword(), $privateKey); - } - - $newToken = $this->generateToken( - $sessionId, - $token->getUID(), - $token->getLoginName(), - $password, - $token->getName(), - IToken::TEMPORARY_TOKEN, - $token->getRemember() - ); - - $this->mapper->delete($token); + if (!($token instanceof PublicKeyToken)) { + throw new InvalidTokenException("Invalid token type"); + } - return $newToken; + $password = null; + if (!is_null($token->getPassword())) { + $privateKey = $this->decrypt($token->getPrivateKey(), $oldSessionId); + $password = $this->decryptPassword($token->getPassword(), $privateKey); + } + $newToken = $this->generateToken( + $sessionId, + $token->getUID(), + $token->getLoginName(), + $password, + $token->getName(), + IToken::TEMPORARY_TOKEN, + $token->getRemember() + ); + + $this->mapper->delete($token); + + return $newToken; + }, $this->db); } public function invalidateToken(string $token) { |