From 3dd5f3d5f659c391df3d5641b22cf28dc09f2ac8 Mon Sep 17 00:00:00 2001
From: Roeland Jago Douma <roeland@famdouma.nl>
Date: Tue, 15 May 2018 20:03:35 +0200
Subject: [PATCH] Abstract the Provider via a manager

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
---
 lib/composer/composer/autoload_classmap.php  |   1 +
 lib/composer/composer/autoload_static.php    |   1 +
 lib/private/Authentication/Token/Manager.php | 210 +++++++++++++++++++
 lib/private/Server.php                       |  10 +-
 4 files changed, 213 insertions(+), 9 deletions(-)
 create mode 100644 lib/private/Authentication/Token/Manager.php

diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 1d319026175..9b51d5fc3e3 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -421,6 +421,7 @@ return array(
     'OC\\Authentication\\Token\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php',
     'OC\\Authentication\\Token\\IProvider' => $baseDir . '/lib/private/Authentication/Token/IProvider.php',
     'OC\\Authentication\\Token\\IToken' => $baseDir . '/lib/private/Authentication/Token/IToken.php',
+    'OC\\Authentication\\Token\\Manager' => $baseDir . '/lib/private/Authentication/Token/Manager.php',
     'OC\\Authentication\\TwoFactorAuth\\Manager' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Manager.php',
     'OC\\Avatar' => $baseDir . '/lib/private/Avatar.php',
     'OC\\AvatarManager' => $baseDir . '/lib/private/AvatarManager.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index b66a7b18192..546a69b13eb 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -451,6 +451,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
         'OC\\Authentication\\Token\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php',
         'OC\\Authentication\\Token\\IProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IProvider.php',
         'OC\\Authentication\\Token\\IToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IToken.php',
+        'OC\\Authentication\\Token\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/Manager.php',
         'OC\\Authentication\\TwoFactorAuth\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Manager.php',
         'OC\\Avatar' => __DIR__ . '/../../..' . '/lib/private/Avatar.php',
         'OC\\AvatarManager' => __DIR__ . '/../../..' . '/lib/private/AvatarManager.php',
diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php
new file mode 100644
index 00000000000..4465c288c8c
--- /dev/null
+++ b/lib/private/Authentication/Token/Manager.php
@@ -0,0 +1,210 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Authentication\Token;
+
+use OC\Authentication\Exceptions\InvalidTokenException;
+use OC\Authentication\Exceptions\PasswordlessTokenException;
+use OCP\IUser;
+
+class Manager implements IProvider {
+
+	/** @var DefaultTokenProvider */
+	private $defaultTokenProvider;
+
+	public function __construct(DefaultTokenProvider $defaultTokenProvider) {
+		$this->defaultTokenProvider = $defaultTokenProvider;
+	}
+
+	/**
+	 * Create and persist a new token
+	 *
+	 * @param string $token
+	 * @param string $uid
+	 * @param string $loginName
+	 * @param string|null $password
+	 * @param string $name
+	 * @param int $type token type
+	 * @param int $remember whether the session token should be used for remember-me
+	 * @return IToken
+	 */
+	public function generateToken(string $token,
+								  string $uid,
+								  string $loginName,
+								  $password,
+								  string $name,
+								  int $type = IToken::TEMPORARY_TOKEN,
+								  int $remember = IToken::DO_NOT_REMEMBER): IToken {
+		//TODO switch to new token by default once it is there
+		return $this->defaultTokenProvider->generateToken(
+			$token,
+			$uid,
+			$loginName,
+			$password,
+			$name,
+			$type,
+			$remember
+		);
+	}
+
+	/**
+	 * Save the updated token
+	 *
+	 * @param IToken $token
+	 * @throws InvalidTokenException
+	 */
+	public function updateToken(IToken $token) {
+		if ($token instanceof DefaultToken) {
+			$this->defaultTokenProvider->updateToken($token);
+		}
+
+		throw new InvalidTokenException();
+	}
+
+	/**
+	 * Update token activity timestamp
+	 *
+	 * @throws InvalidTokenException
+	 * @param IToken $token
+	 */
+	public function updateTokenActivity(IToken $token) {
+		if ($token instanceof DefaultToken) {
+			$this->defaultTokenProvider->updateTokenActivity($token);
+		}
+
+		throw new InvalidTokenException();
+	}
+
+	/**
+	 * Get all tokens of a user
+	 *
+	 * The provider may limit the number of result rows in case of an abuse
+	 * where a high number of (session) tokens is generated
+	 *
+	 * @param IUser $user
+	 * @return IToken[]
+	 */
+	public function getTokenByUser(IUser $user): array {
+		return $this->defaultTokenProvider->getTokenByUser($user);
+	}
+
+	/**
+	 * Get a token by token
+	 *
+	 * @param string $tokenId
+	 * @throws InvalidTokenException
+	 * @return IToken
+	 */
+	public function getToken(string $tokenId): IToken {
+		// TODO: first try new token then old token
+		return $this->defaultTokenProvider->getToken($tokenId);
+	}
+
+	/**
+	 * Get a token by token id
+	 *
+	 * @param int $tokenId
+	 * @throws InvalidTokenException
+	 * @return IToken
+	 */
+	public function getTokenById(int $tokenId): IToken {
+		// TODO: Find a way to distinguis between tokens
+		return $this->defaultTokenProvider->getTokenById($tokenId);
+	}
+
+	/**
+	 * @param string $oldSessionId
+	 * @param string $sessionId
+	 * @throws InvalidTokenException
+	 */
+	public function renewSessionToken(string $oldSessionId, string $sessionId) {
+		// TODO: first try new then old
+		// TODO: if old move to new token type
+		$this->defaultTokenProvider->renewSessionToken($oldSessionId, $sessionId);
+	}
+
+	/**
+	 * @param IToken $savedToken
+	 * @param string $tokenId session token
+	 * @throws InvalidTokenException
+	 * @throws PasswordlessTokenException
+	 * @return string
+	 */
+	public function getPassword(IToken $savedToken, string $tokenId): string {
+		//TODO convert to new token type
+		if ($savedToken instanceof DefaultToken) {
+			return $this->defaultTokenProvider->getPassword($savedToken, $tokenId);
+		}
+	}
+
+	/**
+	 * Encrypt and set the password of the given token
+	 *
+	 * @param IToken $token
+	 * @param string $tokenId
+	 * @param string $password
+	 * @throws InvalidTokenException
+	 */
+	public function setPassword(IToken $token, string $tokenId, string $password) {
+		//TODO conver to new token
+		if ($token instanceof DefaultToken) {
+			$this->defaultTokenProvider->setPassword($token, $tokenId, $password);
+		}
+	}
+
+	/**
+	 * Invalidate (delete) the given session token
+	 *
+	 * @param string $token
+	 */
+	public function invalidateToken(string $token) {
+		// TODO: check both providers
+		$this->defaultTokenProvider->invalidateToken($token);
+	}
+
+	/**
+	 * Invalidate (delete) the given token
+	 *
+	 * @param IUser $user
+	 * @param int $id
+	 */
+	public function invalidateTokenById(IUser $user, int $id) {
+		//TODO find way to distinguis between tokens
+		$this->defaultTokenProvider->invalidateTokenById($user, $id);
+	}
+
+	/**
+	 * Invalidate (delete) old session tokens
+	 */
+	public function invalidateOldTokens() {
+		//Call on both
+		$this->defaultTokenProvider->invalidateOldTokens();
+	}
+
+	public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
+		// Migrate to new token
+		return $this->defaultTokenProvider->rotate($token, $oldTokenId, $newTokenId);
+	}
+
+
+}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index d1818c287e1..31f088ea718 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -339,15 +339,7 @@ class Server extends ServerContainer implements IServerContainer {
 			$dbConnection = $c->getDatabaseConnection();
 			return new Authentication\Token\DefaultTokenMapper($dbConnection);
 		});
-		$this->registerService(Authentication\Token\DefaultTokenProvider::class, function (Server $c) {
-			$mapper = $c->query(Authentication\Token\DefaultTokenMapper::class);
-			$crypto = $c->getCrypto();
-			$config = $c->getConfig();
-			$logger = $c->getLogger();
-			$timeFactory = new TimeFactory();
-			return new \OC\Authentication\Token\DefaultTokenProvider($mapper, $crypto, $config, $logger, $timeFactory);
-		});
-		$this->registerAlias(IProvider::class, Authentication\Token\DefaultTokenProvider::class);
+		$this->registerAlias(IProvider::class, Authentication\Token\Manager::class);
 
 		$this->registerService(\OCP\IUserSession::class, function (Server $c) {
 			$manager = $c->getUserManager();
-- 
GitLab