summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@owncloud.com>2016-04-25 16:40:41 +0200
committerThomas Müller <thomas.mueller@tmit.eu>2016-05-11 13:36:46 +0200
commit2fa5e0a24e34b109fcd4adb98932e9537884bc9a (patch)
treeac0822860e46ffeb0fee03c5f593dfd49bbc62c5
parentd8cde414bd13c327ec2edaf1ae38380073c93e3e (diff)
downloadnextcloud-server-2fa5e0a24e34b109fcd4adb98932e9537884bc9a.tar.gz
nextcloud-server-2fa5e0a24e34b109fcd4adb98932e9537884bc9a.zip
invalidate (delete) session token on logout
add 'last_activity' column to session tokens and delete old ones via a background job
-rw-r--r--db_structure.xml9
-rw-r--r--lib/private/Authentication/Token/DefaultToken.php7
-rw-r--r--lib/private/Authentication/Token/DefaultTokenCleanupJob.php36
-rw-r--r--lib/private/Authentication/Token/DefaultTokenMapper.php32
-rw-r--r--lib/private/Authentication/Token/DefaultTokenProvider.php37
-rw-r--r--lib/private/Server.php8
-rw-r--r--lib/private/Setup.php6
-rw-r--r--lib/private/Updater.php1
-rw-r--r--lib/private/User/Session.php11
9 files changed, 139 insertions, 8 deletions
diff --git a/db_structure.xml b/db_structure.xml
index cde8f52dc67..68a812a6b8f 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -1079,6 +1079,15 @@
<length>100</length>
</field>
+ <field>
+ <name>last_activity</name>
+ <type>integer</type>
+ <default>0</default>
+ <notnull>true</notnull>
+ <unsigned>true</unsigned>
+ <length>4</length>
+ </field>
+
<index>
<name>authtoken_token_index</name>
<unique>true</unique>
diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php
index 28aee555601..9bdae789afd 100644
--- a/lib/private/Authentication/Token/DefaultToken.php
+++ b/lib/private/Authentication/Token/DefaultToken.php
@@ -47,12 +47,17 @@ class DefaultToken extends Entity implements IToken {
protected $token;
/**
+ * @var int
+ */
+ protected $lastActivity;
+
+ /**
* Get the token ID
*
* @return string
*/
public function getId() {
- return $token;
+ return $this->token;
}
}
diff --git a/lib/private/Authentication/Token/DefaultTokenCleanupJob.php b/lib/private/Authentication/Token/DefaultTokenCleanupJob.php
new file mode 100644
index 00000000000..4d1290eb623
--- /dev/null
+++ b/lib/private/Authentication/Token/DefaultTokenCleanupJob.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @author Christoph Wurst <christoph@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @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;
+use OC\BackgroundJob\Job;
+
+class DefaultTokenCleanupJob extends Job {
+
+ protected function run($argument) {
+ /* @var $provider DefaultTokenProvider */
+ $provider = OC::$server->query('OC\Authentication\Token\DefaultTokenProvider');
+ $provider->invalidateOldTokens();
+ }
+
+}
diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php
index 35989d0d350..9a73192c0d8 100644
--- a/lib/private/Authentication/Token/DefaultTokenMapper.php
+++ b/lib/private/Authentication/Token/DefaultTokenMapper.php
@@ -22,6 +22,7 @@
namespace OC\Authentication\Token;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\Mapper;
use OCP\IDBConnection;
@@ -31,6 +32,37 @@ class DefaultTokenMapper extends Mapper {
parent::__construct($db, 'authtoken');
}
+ /**
+ * Invalidate (delete) a given token
+ *
+ * @param string $token
+ */
+ public function invalidate($token) {
+ $sql = 'DELETE FROM `' . $this->getTableName() . '` '
+ . 'WHERE `token` = ?';
+ return $this->execute($sql, [
+ $token
+ ]);
+ }
+
+ /**
+ * @param int $olderThan
+ */
+ public function invalidateOld($olderThan) {
+ $sql = 'DELETE FROM `' . $this->getTableName() . '` '
+ . 'WHERE `last_activity` < ?';
+ $this->execute($sql, [
+ $olderThan
+ ]);
+ }
+
+ /**
+ * Get the user UID for the given token
+ *
+ * @param string $token
+ * @throws DoesNotExistException
+ * @return string
+ */
public function getTokenUser($token) {
$sql = 'SELECT `uid` '
. 'FROM `' . $this->getTableName() . '` '
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index c8aa396526b..71f798da370 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -42,6 +42,12 @@ class DefaultTokenProvider implements IProvider {
/** @var ILogger $logger */
private $logger;
+ /**
+ * @param DefaultTokenMapper $mapper
+ * @param ICrypto $crypto
+ * @param IConfig $config
+ * @param ILogger $logger
+ */
public function __construct(DefaultTokenMapper $mapper, ICrypto $crypto,
IConfig $config, ILogger $logger) {
$this->mapper = $mapper;
@@ -64,7 +70,8 @@ class DefaultTokenProvider implements IProvider {
$secret = $this->config->getSystemValue('secret');
$dbToken->setPassword($this->crypto->encrypt($password . $secret));
$dbToken->setName($name);
- $dbToken->setToken(hash('sha512', $token));
+ $dbToken->setToken($this->hashToken($token));
+ $dbToken->setLastActivity(time());
$this->mapper->insert($dbToken);
@@ -72,6 +79,24 @@ class DefaultTokenProvider implements IProvider {
}
/**
+ * Invalidate (delete) the given session token
+ *
+ * @param string $token
+ */
+ public function invalidateToken($token) {
+ $this->mapper->invalidate($this->hashToken($token));
+ }
+
+ /**
+ * Invalidate (delete) old session tokens
+ */
+ public function invalidateOldTokens() {
+ $olderThan = time() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
+ $this->logger->info('Invalidating tokens older than ' . date('c', $olderThan));
+ $this->mapper->invalidateOld($olderThan);
+ }
+
+ /**
* @param string $token
* @throws InvalidTokenException
* @return string user UID
@@ -79,7 +104,7 @@ class DefaultTokenProvider implements IProvider {
public function validateToken($token) {
$this->logger->debug('validating default token <' . $token . '>');
try {
- $dbToken = $this->mapper->getTokenUser(hash('sha512', $token));
+ $dbToken = $this->mapper->getTokenUser($this->hashToken($token));
$this->logger->debug('valid token for ' . $dbToken->getUid());
return $dbToken->getUid();
} catch (DoesNotExistException $ex) {
@@ -88,4 +113,12 @@ class DefaultTokenProvider implements IProvider {
}
}
+ /**
+ * @param string $token
+ * @return string
+ */
+ private function hashToken($token) {
+ return hash('sha512', $token);
+ }
+
}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index a438523dbcd..8af2f02479c 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -209,12 +209,12 @@ class Server extends ServerContainer implements IServerContainer {
});
return $groupManager;
});
- $this->registerService('DefaultTokenMapper', function (Server $c) {
+ $this->registerService('OC\Authentication\Token\DefaultTokenMapper', function (Server $c) {
$dbConnection = $c->getDatabaseConnection();
return new Authentication\Token\DefaultTokenMapper($dbConnection);
});
- $this->registerService('DefaultTokenProvider', function (Server $c) {
- $mapper = $c->query('DefaultTokenMapper');
+ $this->registerService('OC\Authentication\Token\DefaultTokenProvider', function (Server $c) {
+ $mapper = $c->query('OC\Authentication\Token\DefaultTokenMapper');
$crypto = $c->getCrypto();
$config = $c->getConfig();
$logger = $c->getLogger();
@@ -223,7 +223,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('UserSession', function (Server $c) {
$manager = $c->getUserManager();
$session = new \OC\Session\Memory('');
- $defaultTokenProvider = $c->query('DefaultTokenProvider');
+ $defaultTokenProvider = $c->query('OC\Authentication\Token\DefaultTokenProvider');
$tokenProviders = [
$defaultTokenProvider,
];
diff --git a/lib/private/Setup.php b/lib/private/Setup.php
index 23c66f98b7c..94197f7f27f 100644
--- a/lib/private/Setup.php
+++ b/lib/private/Setup.php
@@ -382,6 +382,8 @@ class Setup {
$config->setSystemValue('logtimezone', date_default_timezone_get());
}
+ self::installBackgroundJobs();
+
//and we are done
$config->setSystemValue('installed', true);
}
@@ -389,6 +391,10 @@ class Setup {
return $error;
}
+ public static function installBackgroundJobs() {
+ \OC::$server->getJobList()->add('\OC\Authentication\Token\DefaultTokenCleanupJob');
+ }
+
/**
* @return string Absolute path to htaccess
*/
diff --git a/lib/private/Updater.php b/lib/private/Updater.php
index 7ca3cd09362..fd082c837e0 100644
--- a/lib/private/Updater.php
+++ b/lib/private/Updater.php
@@ -216,6 +216,7 @@ class Updater extends BasicEmitter {
try {
Setup::updateHtaccess();
Setup::protectDataDirectory();
+ Setup::installBackgroundJobs();
} catch (\Exception $e) {
throw new \Exception($e->getMessage());
}
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index 2afe340353b..9db503e6add 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -316,16 +316,20 @@ class Session implements IUserSession, Emitter {
* @return boolean
*/
public function createSessionToken($uid, $password) {
+ $this->session->regenerateId();
if (is_null($this->manager->get($uid))) {
// User does not exist
return false;
}
$name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown device';
- $token = $this->tokenProvider->generateToken($token, $uid, $password, $name);
+ // TODO: use ISession::getId(), https://github.com/owncloud/core/pull/24229
+ $sessionId = session_id();
+ $token = $this->tokenProvider->generateToken($sessionId, $uid, $password, $name);
return $this->loginWithToken($uid);
}
/**
+ * @param IRequest $request
* @param string $token
* @return boolean
*/
@@ -407,6 +411,11 @@ class Session implements IUserSession, Emitter {
*/
public function logout() {
$this->manager->emit('\OC\User', 'logout');
+ $user = $this->getUser();
+ if (!is_null($user)) {
+ // TODO: use ISession::getId(), https://github.com/owncloud/core/pull/24229
+ $this->tokenProvider->invalidateToken(session_id());
+ }
$this->setUser(null);
$this->setLoginName(null);
$this->unsetMagicInCookie();