summaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
authorLukas Reschke <lukas@statuscode.ch>2016-06-26 14:51:00 +0200
committerGitHub <noreply@github.com>2016-06-26 14:51:00 +0200
commitdb6361ef0314868edc9d58a81c0806c8c758af0a (patch)
treea2c168943d0e15a2d28febf82e31e74b15504117 /lib/private
parent03449dcb9a56e642ff4eee31145498bbaeb83319 (diff)
parent7a9d60d87eb8e4414e5fe05830b088d426ff810d (diff)
downloadnextcloud-server-db6361ef0314868edc9d58a81c0806c8c758af0a.tar.gz
nextcloud-server-db6361ef0314868edc9d58a81c0806c8c758af0a.zip
Merge pull request #226 from nextcloud/master-upstream-sync
[Master] upstream sync
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/Authentication/Token/DefaultToken.php23
-rw-r--r--lib/private/Authentication/Token/DefaultTokenMapper.php4
-rw-r--r--lib/private/Authentication/Token/DefaultTokenProvider.php55
-rw-r--r--lib/private/Authentication/Token/IProvider.php26
-rw-r--r--lib/private/Authentication/Token/IToken.php14
-rw-r--r--lib/private/Console/Application.php3
-rw-r--r--lib/private/Files/View.php23
-rw-r--r--lib/private/User/Session.php192
-rw-r--r--lib/private/legacy/util.php11
9 files changed, 248 insertions, 103 deletions
diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php
index 299291e34af..79b03eed27f 100644
--- a/lib/private/Authentication/Token/DefaultToken.php
+++ b/lib/private/Authentication/Token/DefaultToken.php
@@ -74,6 +74,11 @@ class DefaultToken extends Entity implements IToken {
*/
protected $lastActivity;
+ /**
+ * @var int
+ */
+ protected $lastCheck;
+
public function getId() {
return $this->id;
}
@@ -109,4 +114,22 @@ class DefaultToken extends Entity implements IToken {
];
}
+ /**
+ * Get the timestamp of the last password check
+ *
+ * @return int
+ */
+ public function getLastCheck() {
+ return parent::getLastCheck();
+ }
+
+ /**
+ * Get the timestamp of the last password check
+ *
+ * @param int $time
+ */
+ public function setLastCheck($time) {
+ return parent::setLastCheck($time);
+ }
+
}
diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php
index 9450ed6b9f3..2e105dd4a5d 100644
--- a/lib/private/Authentication/Token/DefaultTokenMapper.php
+++ b/lib/private/Authentication/Token/DefaultTokenMapper.php
@@ -70,7 +70,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')
+ $result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check')
->from('authtoken')
->where($qb->expr()->eq('token', $qb->createParameter('token')))
->setParameter('token', $token)
@@ -96,7 +96,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')
+ $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check')
->from('authtoken')
->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
->setMaxResults(1000);
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index 84effc5f875..b9d06829572 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -92,19 +92,34 @@ class DefaultTokenProvider implements IProvider {
}
/**
+ * Save the updated token
+ *
+ * @param IToken $token
+ */
+ public function updateToken(IToken $token) {
+ if (!($token instanceof DefaultToken)) {
+ throw new InvalidTokenException();
+ }
+ $this->mapper->update($token);
+ }
+
+ /**
* Update token activity timestamp
*
* @throws InvalidTokenException
* @param IToken $token
*/
- public function updateToken(IToken $token) {
+ public function updateTokenActivity(IToken $token) {
if (!($token instanceof DefaultToken)) {
throw new InvalidTokenException();
}
/** @var DefaultToken $token */
- $token->setLastActivity($this->time->getTime());
-
- $this->mapper->update($token);
+ $now = $this->time->getTime();
+ if ($token->getLastActivity() < ($now - 60)) {
+ // Update token only once per minute
+ $token->setLastActivity($now);
+ $this->mapper->update($token);
+ }
}
/**
@@ -151,6 +166,23 @@ class DefaultTokenProvider implements IProvider {
}
/**
+ * Encrypt and set the password of the given token
+ *
+ * @param IToken $token
+ * @param string $tokenId
+ * @param string $password
+ * @throws InvalidTokenException
+ */
+ public function setPassword(IToken $token, $tokenId, $password) {
+ if (!($token instanceof DefaultToken)) {
+ throw new InvalidTokenException();
+ }
+ /** @var DefaultToken $token */
+ $token->setPassword($this->encryptPassword($password, $tokenId));
+ $this->mapper->update($token);
+ }
+
+ /**
* Invalidate (delete) the given session token
*
* @param string $token
@@ -180,21 +212,6 @@ class DefaultTokenProvider implements IProvider {
/**
* @param string $token
- * @throws InvalidTokenException
- * @return DefaultToken user UID
- */
- public function validateToken($token) {
- try {
- $dbToken = $this->mapper->getToken($this->hashToken($token));
- $this->logger->debug('valid default token for ' . $dbToken->getUID());
- return $dbToken;
- } catch (DoesNotExistException $ex) {
- throw new InvalidTokenException();
- }
- }
-
- /**
- * @param string $token
* @return string
*/
private function hashToken($token) {
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index fece7dcb567..d4bbe158e0a 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -50,13 +50,6 @@ interface IProvider {
public function getToken($tokenId) ;
/**
- * @param string $token
- * @throws InvalidTokenException
- * @return IToken
- */
- public function validateToken($token);
-
- /**
* Invalidate (delete) the given session token
*
* @param string $token
@@ -72,13 +65,20 @@ interface IProvider {
public function invalidateTokenById(IUser $user, $id);
/**
- * Update token activity timestamp
+ * Save the updated token
*
* @param IToken $token
*/
public function updateToken(IToken $token);
/**
+ * Update token activity timestamp
+ *
+ * @param IToken $token
+ */
+ public function updateTokenActivity(IToken $token);
+
+ /**
* Get all token of a user
*
* The provider may limit the number of result rows in case of an abuse
@@ -99,4 +99,14 @@ interface IProvider {
* @return string
*/
public function getPassword(IToken $token, $tokenId);
+
+ /**
+ * Encrypt and set the password of the given token
+ *
+ * @param IToken $token
+ * @param string $tokenId
+ * @param string $password
+ * @throws InvalidTokenException
+ */
+ public function setPassword(IToken $token, $tokenId, $password);
}
diff --git a/lib/private/Authentication/Token/IToken.php b/lib/private/Authentication/Token/IToken.php
index a34bdc2c43d..096550fd091 100644
--- a/lib/private/Authentication/Token/IToken.php
+++ b/lib/private/Authentication/Token/IToken.php
@@ -55,4 +55,18 @@ interface IToken extends JsonSerializable {
* @return string
*/
public function getPassword();
+
+ /**
+ * Get the timestamp of the last password check
+ *
+ * @return int
+ */
+ public function getLastCheck();
+
+ /**
+ * Get the timestamp of the last password check
+ *
+ * @param int $time
+ */
+ public function setLastCheck($time);
}
diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php
index ec91064278e..8a9191a4c53 100644
--- a/lib/private/Console/Application.php
+++ b/lib/private/Console/Application.php
@@ -138,9 +138,10 @@ class Application {
* @throws \Exception
*/
public function run(InputInterface $input = null, OutputInterface $output = null) {
+ $args = isset($this->request->server['argv']) ? $this->request->server['argv'] : [];
$this->dispatcher->dispatch(ConsoleEvent::EVENT_RUN, new ConsoleEvent(
ConsoleEvent::EVENT_RUN,
- $this->request->server['argv']
+ $args
));
return $this->application->run($input, $output);
}
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index e9daa123470..31549c93cb2 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -998,7 +998,10 @@ class View {
// Create the directories if any
if (!$this->file_exists($filePath)) {
- $this->mkdir($filePath);
+ $result = $this->createParentDirectories($filePath);
+ if($result === false) {
+ return false;
+ }
}
$source = fopen($tmpFile, 'r');
@@ -2107,4 +2110,22 @@ class View {
}
return [$uid, $filename];
}
+
+ /**
+ * Creates parent non-existing folders
+ *
+ * @param string $filePath
+ * @return bool
+ */
+ private function createParentDirectories($filePath) {
+ $parentDirectory = dirname($filePath);
+ while(!$this->file_exists($parentDirectory)) {
+ $result = $this->createParentDirectories($parentDirectory);
+ if($result === false) {
+ return false;
+ }
+ }
+ $this->mkdir($filePath);
+ return true;
+ }
}
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index 4e9c827448d..2b65f31af28 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -193,53 +193,35 @@ class Session implements IUserSession, Emitter {
if (is_null($this->activeUser)) {
return null;
}
- $this->validateSession($this->activeUser);
+ $this->validateSession();
}
return $this->activeUser;
}
- protected function validateSession(IUser $user) {
- try {
- $sessionId = $this->session->getId();
- } catch (SessionNotAvailableException $ex) {
- return;
- }
- try {
- $token = $this->tokenProvider->getToken($sessionId);
- } catch (InvalidTokenException $ex) {
- // Session was invalidated
- $this->logout();
- return;
- }
+ /**
+ * Validate whether the current session is valid
+ *
+ * - For token-authenticated clients, the token validity is checked
+ * - For browsers, the session token validity is checked
+ */
+ protected function validateSession() {
+ $token = null;
+ $appPassword = $this->session->get('app_password');
- // Check whether login credentials are still valid and the user was not disabled
- // This check is performed each 5 minutes
- $lastCheck = $this->session->get('last_login_check') ? : 0;
- $now = $this->timeFacory->getTime();
- if ($lastCheck < ($now - 60 * 5)) {
+ if (is_null($appPassword)) {
try {
- $pwd = $this->tokenProvider->getPassword($token, $sessionId);
- } catch (InvalidTokenException $ex) {
- // An invalid token password was used -> log user out
- $this->logout();
- return;
- } catch (PasswordlessTokenException $ex) {
- // Token has no password, nothing to check
- $this->session->set('last_login_check', $now);
- return;
- }
-
- if ($this->manager->checkPassword($token->getLoginName(), $pwd) === false
- || !$user->isEnabled()) {
- // Password has changed or user was disabled -> log user out
- $this->logout();
+ $token = $this->session->getId();
+ } catch (SessionNotAvailableException $ex) {
return;
}
- $this->session->set('last_login_check', $now);
+ } else {
+ $token = $appPassword;
}
- // Session is valid, so the token can be refreshed
- $this->updateToken($token);
+ if (!$this->validateToken($token)) {
+ // Session was invalidated
+ $this->logout();
+ }
}
/**
@@ -299,20 +281,21 @@ class Session implements IUserSession, Emitter {
public function login($uid, $password) {
$this->session->regenerateId();
if ($this->validateToken($password)) {
- $user = $this->getUser();
-
// When logging in with token, the password must be decrypted first before passing to login hook
try {
$token = $this->tokenProvider->getToken($password);
try {
- $password = $this->tokenProvider->getPassword($token, $password);
- $this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
+ $loginPassword = $this->tokenProvider->getPassword($token, $password);
+ $this->manager->emit('\OC\User', 'preLogin', array($uid, $loginPassword));
} catch (PasswordlessTokenException $ex) {
$this->manager->emit('\OC\User', 'preLogin', array($uid, ''));
}
} catch (InvalidTokenException $ex) {
// Invalid token, nothing to do
}
+
+ $this->loginWithToken($password);
+ $user = $this->getUser();
} else {
$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
$user = $this->manager->checkPassword($uid, $password);
@@ -370,7 +353,10 @@ class Session implements IUserSession, Emitter {
return false;
}
- if ($this->supportsCookies($request)) {
+ if ($isTokenPassword) {
+ $this->session->set('app_password', $password);
+ } else if($this->supportsCookies($request)) {
+ // Password login, but cookies supported -> create (browser) session token
$this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
}
@@ -463,8 +449,22 @@ class Session implements IUserSession, Emitter {
return false;
}
- private function loginWithToken($uid) {
- // TODO: $this->manager->emit('\OC\User', 'preTokenLogin', array($uid));
+ private function loginWithToken($token) {
+ try {
+ $dbToken = $this->tokenProvider->getToken($token);
+ } catch (InvalidTokenException $ex) {
+ return false;
+ }
+ $uid = $dbToken->getUID();
+
+ $password = '';
+ try {
+ $password = $this->tokenProvider->getPassword($dbToken, $token);
+ } catch (PasswordlessTokenException $ex) {
+ // Ignore and use empty string instead
+ }
+ $this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
+
$user = $this->manager->get($uid);
if (is_null($user)) {
// user does not exist
@@ -477,7 +477,8 @@ class Session implements IUserSession, Emitter {
//login
$this->setUser($user);
- // TODO: $this->manager->emit('\OC\User', 'postTokenLogin', array($user));
+
+ $this->manager->emit('\OC\User', 'postLogin', array($user, $password));
return true;
}
@@ -534,37 +535,71 @@ class Session implements IUserSession, Emitter {
}
/**
+ * @param IToken $dbToken
* @param string $token
* @return boolean
*/
- private function validateToken($token) {
+ private function checkTokenCredentials(IToken $dbToken, $token) {
+ // Check whether login credentials are still valid and the user was not disabled
+ // This check is performed each 5 minutes
+ $lastCheck = $dbToken->getLastCheck() ? : 0;
+ $now = $this->timeFacory->getTime();
+ if ($lastCheck > ($now - 60 * 5)) {
+ // Checked performed recently, nothing to do now
+ return true;
+ }
+
try {
- $token = $this->tokenProvider->validateToken($token);
- if (!is_null($token)) {
- $result = $this->loginWithToken($token->getUID());
- if ($result) {
- // Login success
- $this->updateToken($token);
- return true;
- }
- }
+ $pwd = $this->tokenProvider->getPassword($dbToken, $token);
} catch (InvalidTokenException $ex) {
+ // An invalid token password was used -> log user out
+ return false;
+ } catch (PasswordlessTokenException $ex) {
+ // Token has no password
+
+ if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
+ $this->tokenProvider->invalidateToken($token);
+ return false;
+ }
+ $dbToken->setLastCheck($now);
+ $this->tokenProvider->updateToken($dbToken);
+ return true;
}
- return false;
+
+ if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false
+ || (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) {
+ $this->tokenProvider->invalidateToken($token);
+ // Password has changed or user was disabled -> log user out
+ return false;
+ }
+ $dbToken->setLastCheck($now);
+ $this->tokenProvider->updateToken($dbToken);
+ return true;
}
/**
- * @param IToken $token
+ * Check if the given token exists and performs password/user-enabled checks
+ *
+ * Invalidates the token if checks fail
+ *
+ * @param string $token
+ * @return boolean
*/
- private function updateToken(IToken $token) {
- // To save unnecessary DB queries, this is only done once a minute
- $lastTokenUpdate = $this->session->get('last_token_update') ? : 0;
- $now = $this->timeFacory->getTime();
- if ($lastTokenUpdate < ($now - 60)) {
- $this->tokenProvider->updateToken($token);
- $this->session->set('last_token_update', $now);
+ private function validateToken($token) {
+ try {
+ $dbToken = $this->tokenProvider->getToken($token);
+ } catch (InvalidTokenException $ex) {
+ return false;
+ }
+
+ if (!$this->checkTokenCredentials($dbToken, $token)) {
+ return false;
}
+
+ $this->tokenProvider->updateTokenActivity($dbToken);
+
+ return true;
}
/**
@@ -578,15 +613,21 @@ class Session implements IUserSession, Emitter {
if (strpos($authHeader, 'token ') === false) {
// No auth header, let's try session id
try {
- $sessionId = $this->session->getId();
- return $this->validateToken($sessionId);
+ $token = $this->session->getId();
} catch (SessionNotAvailableException $ex) {
return false;
}
} else {
$token = substr($authHeader, 6);
- return $this->validateToken($token);
}
+
+ if (!$this->loginWithToken($token)) {
+ return false;
+ }
+ if(!$this->validateToken($token)) {
+ return false;
+ }
+ return true;
}
/**
@@ -676,4 +717,21 @@ class Session implements IUserSession, Emitter {
setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
}
+ /**
+ * Update password of the browser session token if there is one
+ *
+ * @param string $password
+ */
+ public function updateSessionTokenPassword($password) {
+ try {
+ $sessionId = $this->session->getId();
+ $token = $this->tokenProvider->getToken($sessionId);
+ $this->tokenProvider->setPassword($token, $sessionId, $password);
+ } catch (SessionNotAvailableException $ex) {
+ // Nothing to do
+ } catch (InvalidTokenException $ex) {
+ // Nothing to do
+ }
+ }
+
}
diff --git a/lib/private/legacy/util.php b/lib/private/legacy/util.php
index 4c9419d6eda..3c56008a48b 100644
--- a/lib/private/legacy/util.php
+++ b/lib/private/legacy/util.php
@@ -958,11 +958,12 @@ class OC_Util {
public static function checkLoggedIn() {
// Check if we are a user
if (!OC_User::isLoggedIn()) {
- header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php',
- [
- 'redirect_url' => \OC::$server->getRequest()->getRequestUri()
- ]
- )
+ header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
+ 'core.login.showLoginForm',
+ [
+ 'redirect_url' => urlencode(\OC::$server->getRequest()->getRequestUri()),
+ ]
+ )
);
exit();
}