diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php index adcd4de3f8..981ea74f56 100644 --- a/lib/private/Authentication/Token/Manager.php +++ b/lib/private/Authentication/Token/Manager.php @@ -121,8 +121,19 @@ class Manager implements IProvider { try { return $this->publicKeyTokenProvider->getToken($tokenId); } catch (InvalidTokenException $e) { - return $this->defaultTokenProvider->getToken($tokenId); + // No worries we try to convert it to a PublicKey Token } + + //Convert! + $token = $this->defaultTokenProvider->getToken($tokenId); + + try { + $password = $this->defaultTokenProvider->getPassword($token, $tokenId); + } catch (PasswordlessTokenException $e) { + $password = null; + } + + return $this->publicKeyTokenProvider->convertToken($token, $tokenId, $password); } /** @@ -149,7 +160,6 @@ class Manager implements IProvider { try { $this->publicKeyTokenProvider->renewSessionToken($oldSessionId, $sessionId); } catch (InvalidTokenException $e) { - //TODO: Move to new token $this->defaultTokenProvider->renewSessionToken($oldSessionId, $sessionId); } } @@ -163,7 +173,6 @@ class Manager implements IProvider { */ public function getPassword(IToken $savedToken, string $tokenId): string { if ($savedToken instanceof DefaultToken) { - //TODO convert to new token type return $this->defaultTokenProvider->getPassword($savedToken, $tokenId); } @@ -173,9 +182,7 @@ class Manager implements IProvider { } public function setPassword(IToken $token, string $tokenId, string $password) { - if ($token instanceof DefaultToken) { - //TODO conver to new token $this->defaultTokenProvider->setPassword($token, $tokenId, $password); } @@ -200,10 +207,14 @@ class Manager implements IProvider { } public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken { - if ($token instanceof DefaultToken) { - //TODO Migrate to new token - return $this->defaultTokenProvider->rotate($token, $oldTokenId, $newTokenId); + try { + $password = $this->defaultTokenProvider->getPassword($token, $oldTokenId); + } catch (PasswordlessTokenException $e) { + $password = null; + } + + return $this->publicKeyTokenProvider->convertToken($token, $newTokenId, $password); } if ($token instanceof PublicKeyToken) { diff --git a/lib/private/Authentication/Token/PublicKeyTokenMapper.php b/lib/private/Authentication/Token/PublicKeyTokenMapper.php index 6feb176fb6..30349fba31 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenMapper.php +++ b/lib/private/Authentication/Token/PublicKeyTokenMapper.php @@ -159,4 +159,12 @@ class PublicKeyTokenMapper extends QBMapper { $qb->execute(); } + public function deleteTempToken(PublicKeyToken $except) { + $qb = $this->db->getQueryBuilder(); + + $qb->delete('authtoken') + ->where($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN))) + ->andWhere($qb->expr()->neq('id', $qb->createNamedParameter($except->getId()))) + ->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(2, IQueryBuilder::PARAM_INT))); + } } diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 5c97877e73..e512133a96 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -67,36 +67,7 @@ class PublicKeyTokenProvider implements IProvider { string $name, int $type = IToken::TEMPORARY_TOKEN, int $remember = IToken::DO_NOT_REMEMBER): IToken { - $dbToken = new PublicKeyToken(); - $dbToken->setUid($uid); - $dbToken->setLoginName($loginName); - - $config = [ - 'digest_alg' => 'sha512', - 'private_key_bits' => 2048, - ]; - - // Generate new key - $res = openssl_pkey_new($config); - openssl_pkey_export($res, $privateKey); - - // Extract the public key from $res to $pubKey - $publicKey = openssl_pkey_get_details($res); - $publicKey = $publicKey['key']; - - $dbToken->setPublicKey($publicKey); - $dbToken->setPrivateKey($this->encrypt($privateKey, $token)); - - if (!is_null($password)) { - $dbToken->setPassword($this->encryptPassword($password, $publicKey)); - } - - $dbToken->setName($name); - $dbToken->setToken($this->hashToken($token)); - $dbToken->setType($type); - $dbToken->setRemember($remember); - $dbToken->setLastActivity($this->time->getTime()); - $dbToken->setLastCheck($this->time->getTime()); + $dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember); $this->mapper->insert($dbToken); @@ -219,6 +190,9 @@ class PublicKeyTokenProvider implements IProvider { throw new InvalidTokenException(); } + // When changeing passwords all temp tokens are deleted + $this->mapper->deleteTempToken($token); + // Update the password for all tokens $tokens = $this->mapper->getTokenByUser($token->getUID()); foreach ($tokens as $t) { @@ -226,8 +200,6 @@ class PublicKeyTokenProvider implements IProvider { $t->setPassword($this->encryptPassword($password, $publicKey)); $this->updateToken($t); } - - //TODO: should we also do this for temp tokens? } public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken { @@ -267,11 +239,13 @@ class PublicKeyTokenProvider implements IProvider { private function encryptPassword(string $password, string $publicKey): string { openssl_public_encrypt($password, $encryptedPassword, $publicKey, OPENSSL_PKCS1_OAEP_PADDING); + $encryptedPassword = base64_encode($encryptedPassword); return $encryptedPassword; } private function decryptPassword(string $encryptedPassword, string $privateKey): string { + $encryptedPassword = base64_decode($encryptedPassword); openssl_private_decrypt($encryptedPassword, $password, $privateKey, OPENSSL_PKCS1_OAEP_PADDING); return $password; @@ -281,4 +255,65 @@ class PublicKeyTokenProvider implements IProvider { $secret = $this->config->getSystemValue('secret'); return hash('sha512', $token . $secret); } + + /** + * Convert a DefaultToken to a publicKeyToken + * This will also be updated directly in the Database + */ + public function convertToken(DefaultToken $defaultToken, string $token, $password): PublicKeyToken { + $pkToken = $this->newToken( + $token, + $defaultToken->getUID(), + $defaultToken->getLoginName(), + $password, + $defaultToken->getName(), + $defaultToken->getType(), + $defaultToken->getRemember() + ); + + $pkToken->setId($defaultToken->getId()); + + return $this->mapper->update($pkToken); + } + + private function newToken(string $token, + string $uid, + string $loginName, + $password, + string $name, + int $type, + int $remember): PublicKeyToken { + $dbToken = new PublicKeyToken(); + $dbToken->setUid($uid); + $dbToken->setLoginName($loginName); + + $config = [ + 'digest_alg' => 'sha512', + 'private_key_bits' => 2048, + ]; + + // Generate new key + $res = openssl_pkey_new($config); + openssl_pkey_export($res, $privateKey); + + // Extract the public key from $res to $pubKey + $publicKey = openssl_pkey_get_details($res); + $publicKey = $publicKey['key']; + + $dbToken->setPublicKey($publicKey); + $dbToken->setPrivateKey($this->encrypt($privateKey, $token)); + + if (!is_null($password)) { + $dbToken->setPassword($this->encryptPassword($password, $publicKey)); + } + + $dbToken->setName($name); + $dbToken->setToken($this->hashToken($token)); + $dbToken->setType($type); + $dbToken->setRemember($remember); + $dbToken->setLastActivity($this->time->getTime()); + $dbToken->setLastCheck($this->time->getTime()); + + return $dbToken; + } }