]> source.dussan.org Git - nextcloud-server.git/commitdiff
bring back remember-me
authorChristoph Wurst <christoph@winzerhof-wurst.at>
Tue, 6 Sep 2016 19:41:15 +0000 (21:41 +0200)
committerLukas Reschke <lukas@statuscode.ch>
Wed, 2 Nov 2016 12:39:16 +0000 (13:39 +0100)
* 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>
20 files changed:
core/Controller/LoginController.php
db_structure.xml
lib/base.php
lib/private/AppFramework/DependencyInjection/DIContainer.php
lib/private/Authentication/Token/DefaultToken.php
lib/private/Authentication/Token/DefaultTokenMapper.php
lib/private/Authentication/Token/DefaultTokenProvider.php
lib/private/Authentication/Token/IProvider.php
lib/private/Authentication/Token/IToken.php
lib/private/Authentication/TwoFactorAuth/Manager.php
lib/private/Server.php
lib/private/User/Session.php
lib/private/legacy/user.php
lib/public/IRequest.php
tests/Core/Controller/LoginControllerTest.php
tests/lib/Authentication/Token/DefaultTokenMapperTest.php
tests/lib/Authentication/Token/DefaultTokenProviderTest.php
tests/lib/Authentication/TwoFactorAuth/ManagerTest.php
tests/lib/User/SessionTest.php
version.php

index 884eea8869ef39ba8977b7d5e4c82f4b1039aa85..71478470ffe3ec3c12ba85635e693c4a68f526c5 100644 (file)
@@ -196,9 +196,10 @@ class LoginController extends Controller {
         * @param string $user
         * @param string $password
         * @param string $redirect_url
+        * @param boolean $remember_login
         * @return RedirectResponse
         */
-       public function tryLogin($user, $password, $redirect_url) {
+       public function tryLogin($user, $password, $redirect_url, $remember_login = false) {
                $currentDelay = $this->throttler->getDelay($this->request->getRemoteAddress());
                $this->throttler->sleepDelay($this->request->getRemoteAddress());
 
@@ -236,13 +237,13 @@ class LoginController extends Controller {
                // TODO: remove password checks from above and let the user session handle failures
                // requires https://github.com/owncloud/core/pull/24616
                $this->userSession->login($user, $password);
-               $this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password);
+               $this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, $remember_login);
 
                // User has successfully logged in, now remove the password reset link, when it is available
                $this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
 
                if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
-                       $this->twoFactorManager->prepareTwoFactorLogin($loginResult);
+                       $this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
 
                        $providers = $this->twoFactorManager->getProviders($loginResult);
                        if (count($providers) === 1) {
@@ -265,6 +266,10 @@ class LoginController extends Controller {
                        return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams));
                }
 
+               if ($remember_login) {
+                       $this->userSession->createRememberMeToken($loginResult);
+               }
+
                return $this->generateRedirect($redirect_url);
        }
 
index 77f6d7689863f4286a6bd822574a9fa4f0d07394..09dbde710d30fb507b78c74cb791249bd38932e9 100644 (file)
                                <length>2</length>
                        </field>
 
+                       <field>
+                               <name>remember</name>
+                               <type>integer</type>
+                               <default>0</default>
+                               <notnull>true</notnull>
+                               <unsigned>true</unsigned>
+                               <length>1</length>
+                       </field>
+
                        <field>
                                <name>last_activity</name>
                                <type>integer</type>
index e7bedb6959631c87cced39ba8ca7ddd91519a3c0..28fc57161c3a627ae578e294a319f14bb6629478 100644 (file)
@@ -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;
                }
index a1e845f132ecbd2b86e41397ae294e3e5e5d1b1e..e1516c47ed6bc2c23b17d4a9d6e80367a1d68e4a 100644 (file)
@@ -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();
index 904df9baa28da05cd4fcbcb10973373a4fce1cc1..faef2f73b33dfd84c93c04fe3dc6a63ab0b6879e 100644 (file)
@@ -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()
  */
@@ -70,6 +72,11 @@ class DefaultToken extends Entity implements IToken {
         */
        protected $type;
 
+       /**
+        * @var int
+        */
+       protected $remember;
+
        /**
         * @var int
         */
index 0ce26197ccfe59c23160b967a7445b313d8ecafc..752974ff24033af274418ff0f314dfd4b2227fba 100644 (file)
@@ -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);
index b0fbeb9b47ec6c13ab774ebda154aa8bb8956023..af1d600e4c3f5788a1134f73dfc391df6a541079 100644 (file)
@@ -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);
@@ -151,6 +153,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
@@ -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);
        }
 
        /**
index 65b515960ea4ed443f69de6ec356f7088ed0f216..b8c15571df197c9b136009364ba20a5874449c31 100644 (file)
@@ -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
@@ -50,6 +52,12 @@ interface IProvider {
         */
        public function getToken($tokenId) ;
 
+       /**
+        * @param string $oldSessionId
+        * @param string $sessionId
+        */
+       public function renewSessionToken($oldSessionId, $sessionId);
+
        /**
         * Invalidate (delete) the given session token
         *
index e1e78ca369a4961d3be44c2a0a8c4835ce4ec62d..14811dd3201a07e22ae5cadb58fe18ac6cbba6b6 100644 (file)
@@ -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
index 1bea7aa3478d0f1c582a0567dc05dff50e377ed6..5f47b2cfaa19ae0c41aa0c2b9572ea4d4f802770 100644 (file)
@@ -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);
        }
 
 }
index 21ec311401dac6926deec8d5f70ef60b71a57caa..7931e08074b351ab99e630b6c6e7f9bd612d0081 100644 (file)
@@ -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());
                });
 
index a213ee48c2ab62de689c9dd23bb751942272447a..68f17747a08b085190de2353f4f2e27b376a1f50 100644 (file)
@@ -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
@@ -709,6 +722,15 @@ class Session implements IUserSession, Emitter {
                return true;
        }
 
+       /**
+        * @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
         */
@@ -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 {
                }
        }
 
+
 }
index af2382dbb8648b5826e281869ce4d9b03babe699..ed0d14a1ab91b39928c2a073b7a361044c25fc6a 100644 (file)
@@ -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);
        }
 
        /**
index 11242c481f0ef7d298a46cdee313b893753379fd..b36a934b0c21be3ee3ca2b8f446daca152431f86 100644 (file)
@@ -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);
index ff50ac98fbd751969146a523edac5a7f3d6c8222..d16b9b114f35c4047fc1f9ea311f55b854bd5a8b 100644 (file)
@@ -322,6 +322,8 @@ class LoginControllerTest extends TestCase {
 
                $this->userSession->expects($this->never())
                        ->method('createSessionToken');
+               $this->userSession->expects($this->never())
+                       ->method('createRememberMeToken');
                $this->config->expects($this->never())
                        ->method('deleteUserValue');
 
@@ -363,7 +365,7 @@ class LoginControllerTest extends TestCase {
                        ->with($user, $password);
                $this->userSession->expects($this->once())
                        ->method('createSessionToken')
-                       ->with($this->request, $user->getUID(), $user, $password);
+                       ->with($this->request, $user->getUID(), $user, $password, false);
                $this->twoFactorManager->expects($this->once())
                        ->method('isTwoFactorAuthenticated')
                        ->with($user)
@@ -371,11 +373,63 @@ class LoginControllerTest extends TestCase {
                $this->config->expects($this->once())
                        ->method('deleteUserValue')
                        ->with('uid', 'core', 'lostpassword');
+               $this->userSession->expects($this->never())
+                       ->method('createRememberMeToken');
 
                $expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
                $this->assertEquals($expected, $this->loginController->tryLogin($user, $password, null));
        }
 
+       public function testLoginWithValidCredentialsAndRememberMe() {
+               /** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */
+               $user = $this->getMockBuilder('\OCP\IUser')->getMock();
+               $user->expects($this->any())
+                       ->method('getUID')
+                       ->will($this->returnValue('uid'));
+               $password = 'secret';
+               $indexPageUrl = \OC_Util::getDefaultPageUrl();
+
+               $this->request
+                       ->expects($this->exactly(2))
+                       ->method('getRemoteAddress')
+                       ->willReturn('192.168.0.1');
+               $this->request
+                       ->expects($this->once())
+                       ->method('passesCSRFCheck')
+                       ->willReturn(true);
+               $this->throttler
+                       ->expects($this->once())
+                       ->method('sleepDelay')
+                       ->with('192.168.0.1');
+               $this->throttler
+                       ->expects($this->once())
+                       ->method('getDelay')
+                       ->with('192.168.0.1')
+                       ->willReturn(200);
+               $this->userManager->expects($this->once())
+                       ->method('checkPassword')
+                       ->will($this->returnValue($user));
+               $this->userSession->expects($this->once())
+                       ->method('login')
+                       ->with($user, $password);
+               $this->userSession->expects($this->once())
+                       ->method('createSessionToken')
+                       ->with($this->request, $user->getUID(), $user, $password, true);
+               $this->twoFactorManager->expects($this->once())
+                       ->method('isTwoFactorAuthenticated')
+                       ->with($user)
+                       ->will($this->returnValue(false));
+               $this->config->expects($this->once())
+                       ->method('deleteUserValue')
+                       ->with('uid', 'core', 'lostpassword');
+               $this->userSession->expects($this->once())
+                       ->method('createRememberMeToken')
+                       ->with($user);
+
+               $expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
+               $this->assertEquals($expected, $this->loginController->tryLogin($user, $password, null, true));
+       }
+
        public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn() {
                /** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */
                $user = $this->getMockBuilder('\OCP\IUser')->getMock();
@@ -408,6 +462,8 @@ class LoginControllerTest extends TestCase {
                        ->will($this->returnValue(false));
                $this->config->expects($this->never())
                        ->method('deleteUserValue');
+               $this->userSession->expects($this->never())
+                       ->method('createRememberMeToken');
 
                $expected = new \OCP\AppFramework\Http\RedirectResponse(\OC_Util::getDefaultPageUrl());
                $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
@@ -450,6 +506,8 @@ class LoginControllerTest extends TestCase {
                        ->will($this->returnValue($redirectUrl));
                $this->config->expects($this->never())
                        ->method('deleteUserValue');
+               $this->userSession->expects($this->never())
+                       ->method('createRememberMeToken');
 
                $expected = new \OCP\AppFramework\Http\RedirectResponse($redirectUrl);
                $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
@@ -488,7 +546,7 @@ class LoginControllerTest extends TestCase {
                        ->will($this->returnValue($user));
                $this->userSession->expects($this->once())
                        ->method('createSessionToken')
-                       ->with($this->request, $user->getUID(), 'Jane', $password);
+                       ->with($this->request, $user->getUID(), 'Jane', $password, false);
                $this->userSession->expects($this->once())
                        ->method('isLoggedIn')
                        ->with()
@@ -540,7 +598,7 @@ class LoginControllerTest extends TestCase {
                        ->with('john@doe.com', $password);
                $this->userSession->expects($this->once())
                        ->method('createSessionToken')
-                       ->with($this->request, $user->getUID(), 'john@doe.com', $password);
+                       ->with($this->request, $user->getUID(), 'john@doe.com', $password, false);
                $this->twoFactorManager->expects($this->once())
                        ->method('isTwoFactorAuthenticated')
                        ->with($user)
@@ -564,6 +622,8 @@ class LoginControllerTest extends TestCase {
                $this->config->expects($this->once())
                        ->method('deleteUserValue')
                        ->with('john', 'core', 'lostpassword');
+               $this->userSession->expects($this->never())
+                       ->method('createRememberMeToken');
 
                $expected = new RedirectResponse($challengeUrl);
                $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
@@ -605,7 +665,7 @@ class LoginControllerTest extends TestCase {
                        ->with('john@doe.com', $password);
                $this->userSession->expects($this->once())
                        ->method('createSessionToken')
-                       ->with($this->request, $user->getUID(), 'john@doe.com', $password);
+                       ->with($this->request, $user->getUID(), 'john@doe.com', $password, false);
                $this->twoFactorManager->expects($this->once())
                        ->method('isTwoFactorAuthenticated')
                        ->with($user)
@@ -628,6 +688,8 @@ class LoginControllerTest extends TestCase {
                $this->config->expects($this->once())
                        ->method('deleteUserValue')
                        ->with('john', 'core', 'lostpassword');
+               $this->userSession->expects($this->never())
+                       ->method('createRememberMeToken');
 
                $expected = new RedirectResponse($challengeUrl);
                $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
@@ -680,6 +742,8 @@ class LoginControllerTest extends TestCase {
                        ->with('login', '192.168.0.1', ['user' => 'john@doe.com']);
                $this->config->expects($this->never())
                        ->method('deleteUserValue');
+               $this->userSession->expects($this->never())
+                       ->method('createRememberMeToken');
 
                $expected = new RedirectResponse('');
                $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', 'just wrong', null));
index d71d94684774cf4bc3df48180c4628db9678ea42..418a4d14f624f21ffafd7b460b7a0c327d5400b2 100644 (file)
@@ -130,6 +130,7 @@ class DefaultTokenMapperTest extends TestCase {
                $token->setName('Firefox on Android');
                $token->setToken('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b');
                $token->setType(IToken::TEMPORARY_TOKEN);
+               $token->setRemember(IToken::DO_NOT_REMEMBER);
                $token->setLastActivity($this->time - 60 * 60 * 24 * 3);
                $token->setLastCheck($this->time - 10);
 
index 7f90cf051f48f658334c98340c54484c7edca2a8..cd6bf7bad5788482777970d2e7fd9c90e6644411 100644 (file)
@@ -25,7 +25,6 @@ namespace Test\Authentication\Token;
 use OC\Authentication\Token\DefaultToken;
 use OC\Authentication\Token\DefaultTokenProvider;
 use OC\Authentication\Token\IToken;
-use OCP\AppFramework\Db\DoesNotExistException;
 use OCP\AppFramework\Utility\ITimeFactory;
 use OCP\IConfig;
 use OCP\ILogger;
@@ -81,6 +80,7 @@ class DefaultTokenProviderTest extends TestCase {
                $toInsert->setName($name);
                $toInsert->setToken(hash('sha512', $token . '1f4h9s'));
                $toInsert->setType($type);
+               $toInsert->setRemember(IToken::DO_NOT_REMEMBER);
                $toInsert->setLastActivity($this->time);
 
                $this->config->expects($this->any())
@@ -95,7 +95,7 @@ class DefaultTokenProviderTest extends TestCase {
                        ->method('insert')
                        ->with($this->equalTo($toInsert));
 
-               $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type);
+               $actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
 
                $this->assertEquals($toInsert, $actual);
        }
@@ -245,13 +245,19 @@ class DefaultTokenProviderTest extends TestCase {
 
        public function testInvalidateOldTokens() {
                $defaultSessionLifetime = 60 * 60 * 24;
-               $this->config->expects($this->once())
+               $defaultRememberMeLifetime = 60 * 60 * 24 * 15;
+               $this->config->expects($this->exactly(2))
                        ->method('getSystemValue')
-                       ->with('session_lifetime', $defaultSessionLifetime)
-                       ->will($this->returnValue(150));
-               $this->mapper->expects($this->once())
+                       ->will($this->returnValueMap([
+                               ['session_lifetime', $defaultSessionLifetime, 150],
+                               ['remember_login_cookie_lifetime', $defaultRememberMeLifetime, 300],
+                       ]));
+               $this->mapper->expects($this->at(0))
                        ->method('invalidateOld')
                        ->with($this->time - 150);
+               $this->mapper->expects($this->at(1))
+                       ->method('invalidateOld')
+                       ->with($this->time - 300);
 
                $this->tokenProvider->invalidateOldTokens();
        }
index 72b70d817d2c26a3bf3793d4bb16b5305d7adb5b..52f3ca285001c5be123955e4d960bd6d81206b56 100644 (file)
@@ -233,8 +233,15 @@ class ManagerTest extends TestCase {
                        ->with($this->user, $challenge)
                        ->will($this->returnValue(true));
                $this->session->expects($this->once())
+                       ->method('get')
+                       ->with('two_factor_remember_login')
+                       ->will($this->returnValue(false));
+               $this->session->expects($this->at(1))
                        ->method('remove')
                        ->with('two_factor_auth_uid');
+               $this->session->expects($this->at(2))
+                       ->method('remove')
+                       ->with('two_factor_remember_login');
 
                $this->assertTrue($this->manager->verifyChallenge('email', $this->user, $challenge));
        }
@@ -304,11 +311,29 @@ class ManagerTest extends TestCase {
                        ->method('getUID')
                        ->will($this->returnValue('ferdinand'));
 
-               $this->session->expects($this->once())
+               $this->session->expects($this->at(0))
+                       ->method('set')
+                       ->with('two_factor_auth_uid', 'ferdinand');
+               $this->session->expects($this->at(1))
+                       ->method('set')
+                       ->with('two_factor_remember_login', true);
+
+               $this->manager->prepareTwoFactorLogin($this->user, true);
+       }
+
+       public function testPrepareTwoFactorLoginDontRemember() {
+               $this->user->expects($this->once())
+                       ->method('getUID')
+                       ->will($this->returnValue('ferdinand'));
+
+               $this->session->expects($this->at(0))
                        ->method('set')
                        ->with('two_factor_auth_uid', 'ferdinand');
+               $this->session->expects($this->at(1))
+                       ->method('set')
+                       ->with('two_factor_remember_login', false);
 
-               $this->manager->prepareTwoFactorLogin($this->user);
+               $this->manager->prepareTwoFactorLogin($this->user, false);
        }
 
 }
index 268d8e10e5a8bd553d517f399c3065783a2f2ba5..c324870a60a6611b2dc0e02bce848760ff273d5e 100644 (file)
@@ -52,6 +52,8 @@ class SessionTest extends \Test\TestCase {
                $this->tokenProvider = $this->createMock(IProvider::class);
                $this->config = $this->createMock(IConfig::class);
                $this->throttler = $this->createMock(Throttler::class);
+
+               \OC_User::setIncognitoMode(false);
        }
 
        public function testGetUser() {
@@ -100,7 +102,7 @@ class SessionTest extends \Test\TestCase {
                        ->method('updateTokenActivity')
                        ->with($token);
 
-               $manager->expects($this->any())
+               $manager->expects($this->once())
                        ->method('get')
                        ->with($expectedUser->getUID())
                        ->will($this->returnValue($expectedUser));
@@ -181,16 +183,9 @@ class SessionTest extends \Test\TestCase {
                        }, 'foo'));
 
                $managerMethods = get_class_methods(Manager::class);
-               //keep following methods intact in order to ensure hooks are
-               //working
-               $doNotMock = array('__construct', 'emit', 'listen');
-               foreach ($doNotMock as $methodName) {
-                       $i = array_search($methodName, $managerMethods, true);
-                       if ($i !== false) {
-                               unset($managerMethods[$i]);
-                       }
-               }
-               $manager = $this->getMockBuilder(Manager::class)
+               //keep following methods intact in order to ensure hooks are working
+               $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+               $manager = $this->getMockBuilder(Manager::class)->setMethods($mockedManagerMethods)->getMock();
                        ->setMethods($managerMethods)
                        ->setConstructorArgs([$this->config])
                        ->getMock();
@@ -238,17 +233,10 @@ class SessionTest extends \Test\TestCase {
                        ->with('bar')
                        ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
 
-               $managerMethods = get_class_methods('\OC\User\Manager');
-               //keep following methods intact in order to ensure hooks are
-               //working
-               $doNotMock = array('__construct', 'emit', 'listen');
-               foreach ($doNotMock as $methodName) {
-                       $i = array_search($methodName, $managerMethods, true);
-                       if ($i !== false) {
-                               unset($managerMethods[$i]);
-                       }
-               }
-               $manager = $this->getMockBuilder(Manager::class)
+               $managerMethods = get_class_methods(\OC\User\Manager::class);
+               //keep following methods intact in order to ensure hooks are working
+               $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+               $manager = $this->getMockBuilder(Manager::class)->setMethods($mockedManagerMethods)->getMock();
                        ->setMethods($managerMethods)
                        ->setConstructorArgs([$this->config])
                        ->getMock();
@@ -273,17 +261,10 @@ class SessionTest extends \Test\TestCase {
 
        public function testLoginInvalidPassword() {
                $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-               $managerMethods = get_class_methods('\OC\User\Manager');
-               //keep following methods intact in order to ensure hooks are
-               //working
-               $doNotMock = array('__construct', 'emit', 'listen');
-               foreach ($doNotMock as $methodName) {
-                       $i = array_search($methodName, $managerMethods, true);
-                       if ($i !== false) {
-                               unset($managerMethods[$i]);
-                       }
-               }
-               $manager = $this->getMockBuilder(Manager::class)
+               $managerMethods = get_class_methods(\OC\User\Manager::class);
+               //keep following methods intact in order to ensure hooks are working
+               $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+               $manager = $this->getMockBuilder(Manager::class)->setMethods($mockedManagerMethods)->getMock();
                        ->setMethods($managerMethods)
                        ->setConstructorArgs([$this->config])
                        ->getMock();
@@ -513,156 +494,208 @@ class SessionTest extends \Test\TestCase {
 
        public function testRememberLoginValidToken() {
                $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-               $session->expects($this->exactly(1))
-                       ->method('set')
-                       ->with($this->callback(function ($key) {
-                               switch ($key) {
-                                       case 'user_id':
-                                               return true;
-                                       default:
-                                               return false;
-                               }
-                       }, 'foo'));
-               $session->expects($this->once())
-                       ->method('regenerateId');
+               $managerMethods = get_class_methods(\OC\User\Manager::class);
+               //keep following methods intact in order to ensure hooks are working
+               $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+               $manager = $this->getMockBuilder(Manager::class)->setMethods($mockedManagerMethods)->getMock();
+               $userSession = $this->getMockBuilder(Session::class)
+                       //override, otherwise tests will fail because of setcookie()
+                       ->setMethods(['setMagicInCookie'])
+                       ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+                       ->getMock();
 
-               $managerMethods = get_class_methods(Manager::class);
-               //keep following methods intact in order to ensure hooks are
-               //working
-               $doNotMock = array('__construct', 'emit', 'listen');
-               foreach ($doNotMock as $methodName) {
-                       $i = array_search($methodName, $managerMethods, true);
-                       if ($i !== false) {
-                               unset($managerMethods[$i]);
-                       }
-               }
-               $manager = $this->getMockBuilder(Manager::class)
+               $user = $this->createMock(IUser::class);
+               $token = 'goodToken';
+               $oldSessionId = 'sess321';
+               $sessionId = 'sess123';
                        ->setMethods($managerMethods)
                        ->setConstructorArgs([$this->config])
                        ->getMock();
 
-               $backend = $this->createMock(\Test\Util\User\Dummy::class);
+               $session->expects($this->once())
+                       ->method('regenerateId');
+               $manager->expects($this->once())
+                       ->method('get')
+                       ->with('foo')
+                       ->will($this->returnValue($user));
+               $this->config->expects($this->once())
+                       ->method('getUserKeys')
+                       ->with('foo', 'login_token')
+                       ->will($this->returnValue([$token]));
+               $this->config->expects($this->once())
+                       ->method('deleteUserValue')
+                       ->with('foo', 'login_token', $token);
+               $this->config->expects($this->once())
+                       ->method('setUserValue'); // TODO: mock new random value
 
-               $user = $this->getMockBuilder(User::class)->setConstructorArgs(['foo', $backend])->getMock();
+               $session->expects($this->once())
+                       ->method('getId')
+                       ->will($this->returnValue($sessionId));
+               $this->tokenProvider->expects($this->once())
+                       ->method('renewSessionToken')
+                       ->with($oldSessionId, $sessionId)
+                       ->will($this->returnValue(true));
 
                $user->expects($this->any())
                        ->method('getUID')
                        ->will($this->returnValue('foo'));
+               $userSession->expects($this->once())
+                       ->method('setMagicInCookie');
                $user->expects($this->once())
                        ->method('updateLastLoginTimestamp');
+               $session->expects($this->once())
+                       ->method('set')
+                       ->with('user_id', 'foo');
 
-               $manager->expects($this->once())
-                       ->method('get')
-                       ->with('foo')
-                       ->will($this->returnValue($user));
+               $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
 
-               //prepare login token
-               $token = 'goodToken';
-               \OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
+               $this->assertTrue($granted);
+       }
 
+       public function testRememberLoginInvalidSessionToken() {
+               $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
+               $managerMethods = get_class_methods(\OC\User\Manager::class);
+               //keep following methods intact in order to ensure hooks are working
+               $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+               $manager = $this->getMockBuilder(Manager::class)->setMethods($mockedManagerMethods)->getMock();
                $userSession = $this->getMockBuilder(Session::class)
                        //override, otherwise tests will fail because of setcookie()
                        ->setMethods(['setMagicInCookie'])
-                       //there  are passed as parameters to the constructor
                        ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
                        ->getMock();
 
-               $granted = $userSession->loginWithCookie('foo', $token);
-
-               $this->assertSame($granted, true);
-       }
+               $user = $this->createMock(IUser::class);
+               $token = 'goodToken';
+               $oldSessionId = 'sess321';
+               $sessionId = 'sess123';
 
-       public function testRememberLoginInvalidToken() {
-               $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-               $session->expects($this->never())
-                       ->method('set');
                $session->expects($this->once())
                        ->method('regenerateId');
+               $manager->expects($this->once())
+                       ->method('get')
+                       ->with('foo')
+                       ->will($this->returnValue($user));
+               $this->config->expects($this->once())
+                       ->method('getUserKeys')
+                       ->with('foo', 'login_token')
+                       ->will($this->returnValue([$token]));
+               $this->config->expects($this->once())
+                       ->method('deleteUserValue')
+                       ->with('foo', 'login_token', $token);
+               $this->config->expects($this->once())
+                       ->method('setUserValue'); // TODO: mock new random value
 
-               $managerMethods = get_class_methods('\OC\User\Manager');
-               //keep following methods intact in order to ensure hooks are
-               //working
-               $doNotMock = array('__construct', 'emit', 'listen');
-               foreach ($doNotMock as $methodName) {
-                       $i = array_search($methodName, $managerMethods, true);
-                       if ($i !== false) {
-                               unset($managerMethods[$i]);
-                       }
-               }
-               $manager = $this->getMockBuilder(Manager::class)
+               $session->expects($this->once())
+                       ->method('getId')
+                       ->will($this->returnValue($sessionId));
+               $this->tokenProvider->expects($this->once())
+                       ->method('renewSessionToken')
+                       ->with($oldSessionId, $sessionId)
+                       ->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
                        ->setMethods($managerMethods)
                        ->setConstructorArgs([$this->config])
                        ->getMock();
 
-               $backend = $this->createMock(\Test\Util\User\Dummy::class);
-
-               $user = $this->getMockBuilder(User::class)->setConstructorArgs(['foo', $backend])->getMock();
-
-               $user->expects($this->any())
+               $user->expects($this->never())
                        ->method('getUID')
                        ->will($this->returnValue('foo'));
+               $userSession->expects($this->never())
+                       ->method('setMagicInCookie');
                $user->expects($this->never())
                        ->method('updateLastLoginTimestamp');
+               $session->expects($this->never())
+                       ->method('set')
+                       ->with('user_id', 'foo');
+
+               $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
+
+               $this->assertFalse($granted);
+       }
+
+       public function testRememberLoginInvalidToken() {
+               $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
+               $managerMethods = get_class_methods(\OC\User\Manager::class);
+               //keep following methods intact in order to ensure hooks are working
+               $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+               $manager = $this->getMockBuilder(Manager::class)->setMethods($mockedManagerMethods)->getMock();
+               $userSession = $this->getMockBuilder(Session::class)
+                       //override, otherwise tests will fail because of setcookie()
+                       ->setMethods(['setMagicInCookie'])
+                       ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+                       ->getMock();
+
+               $user = $this->createMock(IUser::class);
+               $token = 'goodToken';
+               $oldSessionId = 'sess321';
 
+               $session->expects($this->once())
+                       ->method('regenerateId');
                $manager->expects($this->once())
                        ->method('get')
                        ->with('foo')
                        ->will($this->returnValue($user));
+               $this->config->expects($this->once())
+                       ->method('getUserKeys')
+                       ->with('foo', 'login_token')
+                       ->will($this->returnValue(['anothertoken']));
+               $this->config->expects($this->never())
+                       ->method('deleteUserValue')
+                       ->with('foo', 'login_token', $token);
+
+               $this->tokenProvider->expects($this->never())
+                       ->method('renewSessionToken');
+               $userSession->expects($this->never())
+                       ->method('setMagicInCookie');
+               $user->expects($this->never())
+                       ->method('updateLastLoginTimestamp');
+               $session->expects($this->never())
+                       ->method('set')
+                       ->with('user_id', 'foo');
 
-               //prepare login token
-               $token = 'goodToken';
-               \OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
-
-               $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
-               $granted = $userSession->loginWithCookie('foo', 'badToken');
+               $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
 
-               $this->assertSame($granted, false);
+               $this->assertFalse($granted);
        }
 
        public function testRememberLoginInvalidUser() {
                $session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-               $session->expects($this->never())
-                       ->method('set');
+               $managerMethods = get_class_methods(\OC\User\Manager::class);
+               //keep following methods intact in order to ensure hooks are working
+               $mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+               $manager = $this->getMockBuilder(Manager::class)->setMethods($mockedManagerMethods)->getMock();
+               $userSession = $this->getMockBuilder(Session::class)
+                       //override, otherwise tests will fail because of setcookie()
+                       ->setMethods(['setMagicInCookie'])
+                       ->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+                       ->getMock();
+               $token = 'goodToken';
+               $oldSessionId = 'sess321';
+
                $session->expects($this->once())
                        ->method('regenerateId');
-
-               $managerMethods = get_class_methods('\OC\User\Manager');
-               //keep following methods intact in order to ensure hooks are
-               //working
-               $doNotMock = array('__construct', 'emit', 'listen');
-               foreach ($doNotMock as $methodName) {
-                       $i = array_search($methodName, $managerMethods, true);
-                       if ($i !== false) {
-                               unset($managerMethods[$i]);
-                       }
-               }
-               $manager = $this->getMockBuilder(Manager::class)
                        ->setMethods($managerMethods)
                        ->setConstructorArgs([$this->config])
                        ->getMock();
-
-               $backend = $this->createMock(\Test\Util\User\Dummy::class);
-
-               $user = $this->getMockBuilder(User::class)->setConstructorArgs(['foo', $backend])->getMock();
-
-               $user->expects($this->never())
-                       ->method('getUID');
-               $user->expects($this->never())
-                       ->method('updateLastLoginTimestamp');
-
                $manager->expects($this->once())
                        ->method('get')
                        ->with('foo')
                        ->will($this->returnValue(null));
+               $this->config->expects($this->never())
+                       ->method('getUserKeys')
+                       ->with('foo', 'login_token')
+                       ->will($this->returnValue(['anothertoken']));
+
+               $this->tokenProvider->expects($this->never())
+                       ->method('renewSessionToken');
+               $userSession->expects($this->never())
+                       ->method('setMagicInCookie');
+               $session->expects($this->never())
+                       ->method('set')
+                       ->with('user_id', 'foo');
 
-               //prepare login token
-               $token = 'goodToken';
-               \OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
-
-               $userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
-               $granted = $userSession->loginWithCookie('foo', $token);
+               $granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
 
-               $this->assertSame($granted, false);
+               $this->assertFalse($granted);
        }
 
        public function testActiveUserAfterSetSession() {
index 96725a6bb4dda36b876011d9c4520865ce7cb4e2..e6de2e2bde0cc2257020cc59bcc18a22ecbae835 100644 (file)
@@ -25,7 +25,7 @@
 // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
 // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
 // when updating major/minor version number.
-$OC_Version = array(9, 2, 0, 4);
+$OC_Version = array(9, 2, 0, 5);
 
 // The human readable string
 $OC_VersionString = '11.0 alpha';