diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2016-09-06 21:41:15 +0200 |
---|---|---|
committer | Lukas Reschke <lukas@statuscode.ch> | 2016-11-02 13:39:16 +0100 |
commit | d907666232468503ab6ed2bdac44b6500be2beb6 (patch) | |
tree | 945f83d4ddeda3df811042b138e84a2cdf06d120 /lib/private/Authentication | |
parent | dada3ffb51ce9d941b15f1e3fdc1ce292acebb69 (diff) | |
download | nextcloud-server-d907666232468503ab6ed2bdac44b6500be2beb6.tar.gz nextcloud-server-d907666232468503ab6ed2bdac44b6500be2beb6.zip |
bring back remember-me
* try to reuse the old session token for remember me login
* decrypt/encrypt token password and set the session id accordingly
* create remember-me cookies only if checkbox is checked and 2fa solved
* adjust db token cleanup to store remembered tokens longer
* adjust unit tests
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib/private/Authentication')
6 files changed, 70 insertions, 17 deletions
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); } } |