mirror of
https://github.com/nextcloud/server.git
synced 2024-07-29 20:15:55 +02:00
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
This commit is contained in:
parent
2fa5e0a24e
commit
3ab922601a
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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, [
|
||||
|
@ -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());
|
||||
@ -78,6 +76,37 @@ class DefaultTokenProvider implements IProvider {
|
||||
return $dbToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user