summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/base.php6
-rw-r--r--lib/private/AppFramework/DependencyInjection/DIContainer.php1
-rw-r--r--lib/private/Authentication/Token/DefaultToken.php7
-rw-r--r--lib/private/Authentication/Token/DefaultTokenMapper.php17
-rw-r--r--lib/private/Authentication/Token/DefaultTokenProvider.php32
-rw-r--r--lib/private/Authentication/Token/IProvider.php10
-rw-r--r--lib/private/Authentication/Token/IToken.php2
-rw-r--r--lib/private/Authentication/TwoFactorAuth/Manager.php19
-rw-r--r--lib/private/Server.php2
-rw-r--r--lib/private/User/Session.php70
-rw-r--r--lib/private/legacy/user.php5
-rw-r--r--lib/public/IRequest.php2
12 files changed, 133 insertions, 40 deletions
diff --git a/lib/base.php b/lib/base.php
index e7bedb69596..28fc57161c3 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -1035,6 +1035,12 @@ class OC {
if ($userSession->tryTokenLogin($request)) {
return true;
}
+ if (isset($_COOKIE['nc_username'])
+ && isset($_COOKIE['nc_token'])
+ && isset($_COOKIE['nc_session_id'])
+ && $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
+ return true;
+ }
if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
return true;
}
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index a1e845f132e..e1516c47ed6 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -290,6 +290,7 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$this->registerService('OCP\\IUserSession', function($c) {
return $this->getServer()->getUserSession();
});
+ $this->registerAlias(\OC\User\Session::class, \OCP\IUserSession::class);
$this->registerService('OCP\\ISession', function($c) {
return $this->getServer()->getSession();
diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php
index 904df9baa28..faef2f73b33 100644
--- a/lib/private/Authentication/Token/DefaultToken.php
+++ b/lib/private/Authentication/Token/DefaultToken.php
@@ -35,6 +35,8 @@ use OCP\AppFramework\Db\Entity;
* @method string getToken()
* @method void setType(string $type)
* @method int getType()
+ * @method void setRemember(int $remember)
+ * @method int getRemember()
* @method void setLastActivity(int $lastActivity)
* @method int getLastActivity()
*/
@@ -73,6 +75,11 @@ class DefaultToken extends Entity implements IToken {
/**
* @var int
*/
+ protected $remember;
+
+ /**
+ * @var int
+ */
protected $lastActivity;
/**
diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php
index 0ce26197ccf..752974ff240 100644
--- a/lib/private/Authentication/Token/DefaultTokenMapper.php
+++ b/lib/private/Authentication/Token/DefaultTokenMapper.php
@@ -40,24 +40,25 @@ class DefaultTokenMapper extends Mapper {
* @param string $token
*/
public function invalidate($token) {
+ /* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$qb->delete('authtoken')
- ->andWhere($qb->expr()->eq('token', $qb->createParameter('token')))
+ ->where($qb->expr()->eq('token', $qb->createParameter('token')))
->setParameter('token', $token)
->execute();
}
/**
* @param int $olderThan
+ * @param int $remember
*/
- public function invalidateOld($olderThan) {
+ public function invalidateOld($olderThan, $remember = IToken::DO_NOT_REMEMBER) {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$qb->delete('authtoken')
- ->where($qb->expr()->lt('last_activity', $qb->createParameter('last_activity')))
- ->andWhere($qb->expr()->eq('type', $qb->createParameter('type')))
- ->setParameter('last_activity', $olderThan, IQueryBuilder::PARAM_INT)
- ->setParameter('type', IToken::TEMPORARY_TOKEN, IQueryBuilder::PARAM_INT)
+ ->where($qb->expr()->lt('last_activity', $qb->createNamedParameter($olderThan, IQueryBuilder::PARAM_INT)))
+ ->andWhere($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN, IQueryBuilder::PARAM_INT)))
+ ->andWhere($qb->expr()->eq('remember', $qb->createNamedParameter($remember, IQueryBuilder::PARAM_INT)))
->execute();
}
@@ -71,7 +72,7 @@ class DefaultTokenMapper extends Mapper {
public function getToken($token) {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
- $result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check')
+ $result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check')
->from('authtoken')
->where($qb->expr()->eq('token', $qb->createParameter('token')))
->setParameter('token', $token)
@@ -97,7 +98,7 @@ class DefaultTokenMapper extends Mapper {
public function getTokenByUser(IUser $user) {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
- $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check')
+ $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check')
->from('authtoken')
->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
->setMaxResults(1000);
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index b0fbeb9b47e..af1d600e4c3 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -73,9 +73,10 @@ class DefaultTokenProvider implements IProvider {
* @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($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN) {
+ public function generateToken($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN, $remember = IToken::DO_NOT_REMEMBER) {
$dbToken = new DefaultToken();
$dbToken->setUid($uid);
$dbToken->setLoginName($loginName);
@@ -85,6 +86,7 @@ class DefaultTokenProvider implements IProvider {
$dbToken->setName($name);
$dbToken->setToken($this->hashToken($token));
$dbToken->setType($type);
+ $dbToken->setRemember($remember);
$dbToken->setLastActivity($this->time->getTime());
$this->mapper->insert($dbToken);
@@ -152,6 +154,27 @@ class DefaultTokenProvider implements IProvider {
}
/**
+ * @param string $oldSessionId
+ * @param string $sessionId
+ */
+ public function renewSessionToken($oldSessionId, $sessionId) {
+ $token = $this->getToken($oldSessionId);
+
+ $newToken = new DefaultToken();
+ $newToken->setUid($token->getUID());
+ $newToken->setLoginName($token->getLoginName());
+ if (!is_null($token->getPassword())) {
+ $password = $this->decryptPassword($token->getPassword(), $oldSessionId);
+ $newToken->setPassword($this->encryptPassword($password, $sessionId));
+ }
+ $newToken->setName($token->getName());
+ $newToken->setToken($this->hashToken($sessionId));
+ $newToken->setType(IToken::TEMPORARY_TOKEN);
+ $newToken->setLastActivity($this->time->getTime());
+ $this->mapper->insert($newToken);
+ }
+
+ /**
* @param IToken $savedToken
* @param string $tokenId session token
* @throws InvalidTokenException
@@ -207,8 +230,11 @@ class DefaultTokenProvider implements IProvider {
*/
public function invalidateOldTokens() {
$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
- $this->logger->info('Invalidating tokens older than ' . date('c', $olderThan));
- $this->mapper->invalidateOld($olderThan);
+ $this->logger->info('Invalidating session tokens older than ' . date('c', $olderThan));
+ $this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
+ $rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
+ $this->logger->info('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold));
+ $this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
}
/**
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index 65b515960ea..b8c15571df1 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -28,6 +28,7 @@ use OCP\IUser;
interface IProvider {
+
/**
* Create and persist a new token
*
@@ -37,9 +38,10 @@ interface IProvider {
* @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($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN);
+ public function generateToken($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN, $remember = IToken::DO_NOT_REMEMBER);
/**
* Get a token by token id
@@ -51,6 +53,12 @@ interface IProvider {
public function getToken($tokenId) ;
/**
+ * @param string $oldSessionId
+ * @param string $sessionId
+ */
+ public function renewSessionToken($oldSessionId, $sessionId);
+
+ /**
* Invalidate (delete) the given session token
*
* @param string $token
diff --git a/lib/private/Authentication/Token/IToken.php b/lib/private/Authentication/Token/IToken.php
index e1e78ca369a..14811dd3201 100644
--- a/lib/private/Authentication/Token/IToken.php
+++ b/lib/private/Authentication/Token/IToken.php
@@ -28,6 +28,8 @@ interface IToken extends JsonSerializable {
const TEMPORARY_TOKEN = 0;
const PERMANENT_TOKEN = 1;
+ const DO_NOT_REMEMBER = 0;
+ const REMEMBER = 1;
/**
* Get the token ID
diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php
index 1bea7aa3478..5f47b2cfaa1 100644
--- a/lib/private/Authentication/TwoFactorAuth/Manager.php
+++ b/lib/private/Authentication/TwoFactorAuth/Manager.php
@@ -37,6 +37,7 @@ class Manager {
const SESSION_UID_KEY = 'two_factor_auth_uid';
const BACKUP_CODES_APP_ID = 'twofactor_backupcodes';
const BACKUP_CODES_PROVIDER_ID = 'backup_codes';
+ const REMEBER_LOGIN = 'two_factor_remember_login';
/** @var AppManager */
private $appManager;
@@ -51,6 +52,7 @@ class Manager {
* @param AppManager $appManager
* @param ISession $session
* @param IConfig $config
+ * @param Session $userSession
*/
public function __construct(AppManager $appManager, ISession $session, IConfig $config) {
$this->appManager = $appManager;
@@ -171,11 +173,16 @@ class Manager {
return false;
}
- $result = $provider->verifyChallenge($user, $challenge);
- if ($result) {
+ $passed = $provider->verifyChallenge($user, $challenge);
+ if ($passed) {
+ if ($this->session->get(self::REMEBER_LOGIN) === true) {
+ // TODO: resolve cyclic dependency and use DI
+ \OC::$server->getUserSession()->createRememberMeToken($user);
+ }
$this->session->remove(self::SESSION_UID_KEY);
+ $this->session->remove(self::REMEBER_LOGIN);
}
- return $result;
+ return $passed;
}
/**
@@ -202,12 +209,14 @@ class Manager {
}
/**
- * Prepare the 2FA login (set session value)
+ * Prepare the 2FA login
*
* @param IUser $user
+ * @param boolean $rememberMe
*/
- public function prepareTwoFactorLogin(IUser $user) {
+ public function prepareTwoFactorLogin(IUser $user, $rememberMe) {
$this->session->set(self::SESSION_UID_KEY, $user->getUID());
+ $this->session->set(self::REMEBER_LOGIN, $rememberMe);
}
}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 21ec311401d..7931e08074b 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -283,7 +283,7 @@ class Server extends ServerContainer implements IServerContainer {
return $userSession;
});
- $this->registerService('\OC\Authentication\TwoFactorAuth\Manager', function (Server $c) {
+ $this->registerService(\OC\Authentication\TwoFactorAuth\Manager::class, function (Server $c) {
return new \OC\Authentication\TwoFactorAuth\Manager($c->getAppManager(), $c->getSession(), $c->getConfig());
});
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index a213ee48c2a..68f17747a08 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -526,9 +526,10 @@ class Session implements IUserSession, Emitter {
* @param string $uid user UID
* @param string $loginName login name
* @param string $password
+ * @param int $remember
* @return boolean
*/
- public function createSessionToken(IRequest $request, $uid, $loginName, $password = null) {
+ public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
if (is_null($this->manager->get($uid))) {
// User does not exist
return false;
@@ -537,7 +538,7 @@ class Session implements IUserSession, Emitter {
try {
$sessionId = $this->session->getId();
$pwd = $this->getPassword($password);
- $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name);
+ $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, IToken::REMEMBER);
return true;
} catch (SessionNotAvailableException $ex) {
// This can happen with OCC, where a memory session is used
@@ -680,9 +681,10 @@ class Session implements IUserSession, Emitter {
*
* @param string $uid the username
* @param string $currentToken
+ * @param string $oldSessionId
* @return bool
*/
- public function loginWithCookie($uid, $currentToken) {
+ public function loginWithCookie($uid, $currentToken, $oldSessionId) {
$this->session->regenerateId();
$this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
$user = $this->manager->get($uid);
@@ -692,15 +694,26 @@ class Session implements IUserSession, Emitter {
}
// get stored tokens
- $tokens = OC::$server->getConfig()->getUserKeys($uid, 'login_token');
+ $tokens = $this->config->getUserKeys($uid, 'login_token');
// test cookies token against stored tokens
if (!in_array($currentToken, $tokens, true)) {
return false;
}
// replace successfully used token with a new one
- OC::$server->getConfig()->deleteUserValue($uid, 'login_token', $currentToken);
+ $this->config->deleteUserValue($uid, 'login_token', $currentToken);
$newToken = OC::$server->getSecureRandom()->generate(32);
- OC::$server->getConfig()->setUserValue($uid, 'login_token', $newToken, time());
+ $this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFacory->getTime());
+
+ try {
+ $sessionId = $this->session->getId();
+ $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
+ } catch (SessionNotAvailableException $ex) {
+ return false;
+ } catch (InvalidTokenException $ex) {
+ \OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
+ return false;
+ }
+
$this->setMagicInCookie($user->getUID(), $newToken);
//login
@@ -710,6 +723,15 @@ class Session implements IUserSession, Emitter {
}
/**
+ * @param IUser $user
+ */
+ public function createRememberMeToken(IUser $user) {
+ $token = OC::$server->getSecureRandom()->generate(32);
+ $this->config->setUserValue($user->getUID(), 'login_token', $token, time());
+ $this->setMagicInCookie($user->getUID(), $token);
+ }
+
+ /**
* logout the user from the session
*/
public function logout() {
@@ -736,10 +758,19 @@ class Session implements IUserSession, Emitter {
*/
public function setMagicInCookie($username, $token) {
$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
- $expires = time() + OC::$server->getConfig()->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
- setcookie('oc_username', $username, $expires, OC::$WEBROOT, '', $secureCookie, true);
- setcookie('oc_token', $token, $expires, OC::$WEBROOT, '', $secureCookie, true);
- setcookie('oc_remember_login', '1', $expires, OC::$WEBROOT, '', $secureCookie, true);
+ $webRoot = \OC::$WEBROOT;
+ if ($webRoot === '') {
+ $webRoot = '/';
+ }
+
+ $expires = $this->timeFacory->getTime() + OC::$server->getConfig()->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
+ setcookie('nc_username', $username, $expires, $webRoot, '', $secureCookie, true);
+ setcookie('nc_token', $token, $expires, $webRoot, '', $secureCookie, true);
+ try {
+ setcookie('nc_session_id', $this->session->getId(), $expires, $webRoot, '', $secureCookie, true);
+ } catch (SessionNotAvailableException $ex) {
+ // ignore
+ }
}
/**
@@ -749,17 +780,17 @@ class Session implements IUserSession, Emitter {
//TODO: DI for cookies and IRequest
$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
- unset($_COOKIE['oc_username']); //TODO: DI
- unset($_COOKIE['oc_token']);
- unset($_COOKIE['oc_remember_login']);
- setcookie('oc_username', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
- setcookie('oc_token', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
- setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
+ unset($_COOKIE['nc_username']); //TODO: DI
+ unset($_COOKIE['nc_token']);
+ unset($_COOKIE['nc_session_id']);
+ setcookie('nc_username', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
+ setcookie('nc_token', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
+ setcookie('nc_session_id', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
// old cookies might be stored under /webroot/ instead of /webroot
// and Firefox doesn't like it!
- setcookie('oc_username', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
- setcookie('oc_token', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
- setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
+ setcookie('nc_username', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
+ setcookie('nc_token', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
+ setcookie('nc_session_id', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
}
/**
@@ -779,4 +810,5 @@ class Session implements IUserSession, Emitter {
}
}
+
}
diff --git a/lib/private/legacy/user.php b/lib/private/legacy/user.php
index af2382dbb86..ed0d14a1ab9 100644
--- a/lib/private/legacy/user.php
+++ b/lib/private/legacy/user.php
@@ -155,10 +155,11 @@ class OC_User {
* @deprecated use \OCP\IUserSession::loginWithCookie()
* @param string $uid The username of the user to log in
* @param string $token
+ * @param string $oldSessionId
* @return bool
*/
- public static function loginWithCookie($uid, $token) {
- return self::getUserSession()->loginWithCookie($uid, $token);
+ public static function loginWithCookie($uid, $token, $oldSessionId) {
+ return self::getUserSession()->loginWithCookie($uid, $token, $oldSessionId);
}
/**
diff --git a/lib/public/IRequest.php b/lib/public/IRequest.php
index 11242c481f0..b36a934b0c2 100644
--- a/lib/public/IRequest.php
+++ b/lib/public/IRequest.php
@@ -145,7 +145,7 @@ interface IRequest {
* Shortcut for getting cookie variables
*
* @param string $key the key that will be taken from the $_COOKIE array
- * @return string the value in the $_COOKIE element
+ * @return string|null the value in the $_COOKIE element
* @since 6.0.0
*/
public function getCookie($key);