summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@owncloud.com>2016-04-26 11:32:35 +0200
committerThomas Müller <thomas.mueller@tmit.eu>2016-05-11 13:36:46 +0200
commit3ab922601a2e6b9b170007461b9e0718c70bddcd (patch)
tree77f04125c2d7c422f74f4583cf116da7a9ff56c9
parent2fa5e0a24e34b109fcd4adb98932e9537884bc9a (diff)
downloadnextcloud-server-3ab922601a2e6b9b170007461b9e0718c70bddcd.tar.gz
nextcloud-server-3ab922601a2e6b9b170007461b9e0718c70bddcd.zip
Check if session token is valid and log user out if the check fails
* Update last_activity timestamp of the session token * Check user backend credentials once in 5 minutes
-rw-r--r--core/Controller/LoginController.php1
-rw-r--r--db_structure.xml4
-rw-r--r--lib/private/Authentication/Token/DefaultToken.php7
-rw-r--r--lib/private/Authentication/Token/DefaultTokenMapper.php6
-rw-r--r--lib/private/Authentication/Token/DefaultTokenProvider.php67
-rw-r--r--lib/private/User/Session.php45
-rw-r--r--lib/private/legacy/user.php2
7 files changed, 107 insertions, 25 deletions
diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php
index fe1ad41aedb..e13d8ae10d2 100644
--- a/core/Controller/LoginController.php
+++ b/core/Controller/LoginController.php
@@ -26,7 +26,6 @@ namespace OC\Core\Controller;
use OC;
use OC\User\Session;
use OC_App;
-use OC_User;
use OC_Util;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\RedirectResponse;
diff --git a/db_structure.xml b/db_structure.xml
index 68a812a6b8f..dcbf426e5b8 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -1057,10 +1057,10 @@
<field>
<name>password</name>
- <type>text</type>
+ <type>clob</type>
<default></default>
<notnull>true</notnull>
- <length>100</length>
+ <length>4000</length>
</field>
<field>
diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php
index 9bdae789afd..6b859d7d063 100644
--- a/lib/private/Authentication/Token/DefaultToken.php
+++ b/lib/private/Authentication/Token/DefaultToken.php
@@ -51,13 +51,8 @@ class DefaultToken extends Entity implements IToken {
*/
protected $lastActivity;
- /**
- * Get the token ID
- *
- * @return string
- */
public function getId() {
- return $this->token;
+ return $this->id;
}
}
diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php
index 9a73192c0d8..d54d2489399 100644
--- a/lib/private/Authentication/Token/DefaultTokenMapper.php
+++ b/lib/private/Authentication/Token/DefaultTokenMapper.php
@@ -61,10 +61,10 @@ class DefaultTokenMapper extends Mapper {
*
* @param string $token
* @throws DoesNotExistException
- * @return string
+ * @return DefaultToken
*/
- public function getTokenUser($token) {
- $sql = 'SELECT `uid` '
+ public function getToken($token) {
+ $sql = 'SELECT `id`, `uid`, `password`, `name`, `token`, `last_activity` '
. 'FROM `' . $this->getTableName() . '` '
. 'WHERE `token` = ?';
return $this->findEntity($sql, [
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index 71f798da370..b3564e0e81b 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -48,8 +48,7 @@ class DefaultTokenProvider implements IProvider {
* @param IConfig $config
* @param ILogger $logger
*/
- public function __construct(DefaultTokenMapper $mapper, ICrypto $crypto,
- IConfig $config, ILogger $logger) {
+ public function __construct(DefaultTokenMapper $mapper, ICrypto $crypto, IConfig $config, ILogger $logger) {
$this->mapper = $mapper;
$this->crypto = $crypto;
$this->config = $config;
@@ -67,8 +66,7 @@ class DefaultTokenProvider implements IProvider {
public function generateToken($token, $uid, $password, $name) {
$dbToken = new DefaultToken();
$dbToken->setUid($uid);
- $secret = $this->config->getSystemValue('secret');
- $dbToken->setPassword($this->crypto->encrypt($password . $secret));
+ $dbToken->setPassword($this->encryptPassword($password, $token));
$dbToken->setName($name);
$dbToken->setToken($this->hashToken($token));
$dbToken->setLastActivity(time());
@@ -79,6 +77,37 @@ class DefaultTokenProvider implements IProvider {
}
/**
+ * Update token activity timestamp
+ *
+ * @param DefaultToken $token
+ */
+ public function updateToken(DefaultToken $token) {
+ $token->setLastActivity(time());
+
+ $this->mapper->update($token);
+ }
+
+ /**
+ * @param string $token
+ * @throws InvalidTokenException
+ */
+ public function getToken($token) {
+ try {
+ return $this->mapper->getToken($this->hashToken($token));
+ } catch (DoesNotExistException $ex) {
+ throw new InvalidTokenException();
+ }
+ }
+
+ /**
+ * @param DefaultToken $savedToken
+ * @param string $token session token
+ */
+ public function getPassword(DefaultToken $savedToken, $token) {
+ return $this->decryptPassword($savedToken->getPassword(), $token);
+ }
+
+ /**
* Invalidate (delete) the given session token
*
* @param string $token
@@ -104,7 +133,7 @@ class DefaultTokenProvider implements IProvider {
public function validateToken($token) {
$this->logger->debug('validating default token <' . $token . '>');
try {
- $dbToken = $this->mapper->getTokenUser($this->hashToken($token));
+ $dbToken = $this->mapper->getToken($this->hashToken($token));
$this->logger->debug('valid token for ' . $dbToken->getUid());
return $dbToken->getUid();
} catch (DoesNotExistException $ex) {
@@ -121,4 +150,32 @@ class DefaultTokenProvider implements IProvider {
return hash('sha512', $token);
}
+ /**
+ * Encrypt the given password
+ *
+ * The token is used as key
+ *
+ * @param string $password
+ * @param string $token
+ * @return string encrypted password
+ */
+ private function encryptPassword($password, $token) {
+ $secret = $this->config->getSystemValue('secret');
+ return $this->crypto->encrypt($password, $token . $secret);
+ }
+
+ /**
+ * Decrypt the given password
+ *
+ * The token is used as key
+ *
+ * @param string $password
+ * @param string $token
+ * @return string the decrypted key
+ */
+ private function decryptPassword($password, $token) {
+ $secret = $this->config->getSystemValue('secret');
+ return $this->crypto->decrypt($password, $token . $secret);
+ }
+
}
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index 9db503e6add..7d4594e7205 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -96,8 +96,7 @@ class Session implements IUserSession, Emitter {
* @param ISession $session
* @param IProvider[] $tokenProviders
*/
- public function __construct(IUserManager $manager, ISession $session,
- DefaultTokenProvider $tokenProvider, array $tokenProviders = []) {
+ public function __construct(IUserManager $manager, ISession $session, DefaultTokenProvider $tokenProvider, array $tokenProviders = []) {
$this->manager = $manager;
$this->session = $session;
$this->tokenProvider = $tokenProvider;
@@ -118,8 +117,7 @@ class Session implements IUserSession, Emitter {
* @param string $method optional
* @param callable $callback optional
*/
- public function removeListener($scope = null, $method = null,
- callable $callback = null) {
+ public function removeListener($scope = null, $method = null, callable $callback = null) {
$this->manager->removeListener($scope, $method, $callback);
}
@@ -183,8 +181,7 @@ class Session implements IUserSession, Emitter {
return $this->activeUser;
} else {
$uid = $this->session->get('user_id');
- if ($uid !== null) {
- $this->activeUser = $this->manager->get($uid);
+ if ($uid !== null && $this->isValidSession($uid)) {
return $this->activeUser;
} else {
return null;
@@ -192,6 +189,41 @@ class Session implements IUserSession, Emitter {
}
}
+ private function isValidSession($uid) {
+ $this->activeUser = $this->manager->get($uid);
+ if (is_null($this->activeUser)) {
+ // User does not exist
+ return false;
+ }
+ // TODO: use ISession::getId(), https://github.com/owncloud/core/pull/24229
+ $sessionId = session_id();
+ try {
+ $token = $this->tokenProvider->getToken($sessionId);
+ } catch (InvalidTokenException $ex) {
+ // Session was inalidated
+ $this->logout();
+ return false;
+ }
+
+ // Check whether login credentials are still valid
+ // This check is performed each 5 minutes
+ $lastCheck = $this->session->get('last_login_check') ? : 0;
+ if ($lastCheck < (time() - 60 * 5)) {
+ $pwd = $this->tokenProvider->getPassword($token, $sessionId);
+ if ($this->manager->checkPassword($uid, $pwd) === false) {
+ // Password has changed -> log user out
+ $this->logout();
+ return false;
+ }
+ $this->session->set('last_login_check', time());
+ }
+
+ // Session is valid, so the token can be refreshed
+ $this->tokenProvider->updateToken($token);
+
+ return true;
+ }
+
/**
* Checks whether the user is logged in
*
@@ -334,7 +366,6 @@ class Session implements IUserSession, Emitter {
* @return boolean
*/
private function validateToken(IRequest $request, $token) {
- // TODO: hash token
foreach ($this->tokenProviders as $provider) {
try {
$user = $provider->validateToken($token);
diff --git a/lib/private/legacy/user.php b/lib/private/legacy/user.php
index 575011d3985..ca408d347bd 100644
--- a/lib/private/legacy/user.php
+++ b/lib/private/legacy/user.php
@@ -68,7 +68,7 @@ class OC_User {
private static $_setupedBackends = array();
- // bool, stores if a user want to access a resource anonymously, e.g if he opens a public link
+ // bool, stores if a user want to access a resource anonymously, e.g if they open a public link
private static $incognitoMode = false;
/**