* @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());
// 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) {
return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams));
}
+ if ($remember_login) {
+ $this->userSession->createRememberMeToken($loginResult);
+ }
+
return $this->generateRedirect($redirect_url);
}
<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>
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;
}
$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();
* @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()
*/
*/
protected $type;
+ /**
+ * @var int
+ */
+ protected $remember;
+
/**
* @var int
*/
* @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();
}
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)
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);
* @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);
$dbToken->setName($name);
$dbToken->setToken($this->hashToken($token));
$dbToken->setType($type);
+ $dbToken->setRemember($remember);
$dbToken->setLastActivity($this->time->getTime());
$this->mapper->insert($dbToken);
}
}
+ /**
+ * @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
*/
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);
}
/**
interface IProvider {
+
/**
* Create and persist a new token
*
* @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
*/
public function getToken($tokenId) ;
+ /**
+ * @param string $oldSessionId
+ * @param string $sessionId
+ */
+ public function renewSessionToken($oldSessionId, $sessionId);
+
/**
* Invalidate (delete) the given session token
*
const TEMPORARY_TOKEN = 0;
const PERMANENT_TOKEN = 1;
+ const DO_NOT_REMEMBER = 0;
+ const REMEMBER = 1;
/**
* Get the token ID
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;
* @param AppManager $appManager
* @param ISession $session
* @param IConfig $config
+ * @param Session $userSession
*/
public function __construct(AppManager $appManager, ISession $session, IConfig $config) {
$this->appManager = $appManager;
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;
}
/**
}
/**
- * 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);
}
}
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());
});
* @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;
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
*
* @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);
}
// 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
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
*/
*/
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
+ }
}
/**
//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);
}
/**
}
}
+
}
* @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);
}
/**
* 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);
$this->userSession->expects($this->never())
->method('createSessionToken');
+ $this->userSession->expects($this->never())
+ ->method('createRememberMeToken');
$this->config->expects($this->never())
->method('deleteUserValue');
->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)
$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();
->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));
->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));
->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()
->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)
$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));
->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)
$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));
->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));
$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);
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;
$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())
->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);
}
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();
}
->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));
}
->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);
}
}
$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() {
->method('updateTokenActivity')
->with($token);
- $manager->expects($this->any())
+ $manager->expects($this->once())
->method('get')
->with($expectedUser->getUID())
->will($this->returnValue($expectedUser));
}, '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();
->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();
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();
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() {
// 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';