From d8cde414bd13c327ec2edaf1ae38380073c93e3e Mon Sep 17 00:00:00 2001 From: Christoph Wurst Date: Mon, 25 Apr 2016 14:10:55 +0200 Subject: [PATCH] token based auth * Add InvalidTokenException * add DefaultTokenMapper and use it to check if a auth token exists * create new token for the browser session if none exists hash stored token; save user agent * encrypt login password when creating the token --- core/Application.php | 13 +- core/Controller/LoginController.php | 75 +++++--- core/routes.php | 3 +- core/templates/login.php | 2 +- db_structure.xml | 60 ++++++ lib/base.php | 176 +---------------- .../Exceptions/InvalidTokenException.php | 29 +++ .../Authentication/Token/DefaultToken.php | 58 ++++++ .../Token/DefaultTokenMapper.php | 43 +++++ .../Token/DefaultTokenProvider.php | 91 +++++++++ .../Authentication/Token/IProvider.php | 35 ++++ lib/private/Authentication/Token/IToken.php | 36 ++++ lib/private/Server.php | 19 +- lib/private/User/Session.php | 178 +++++++++++++++--- lib/private/legacy/user.php | 25 +-- lib/private/legacy/util.php | 3 +- 16 files changed, 596 insertions(+), 250 deletions(-) create mode 100644 lib/private/Authentication/Exceptions/InvalidTokenException.php create mode 100644 lib/private/Authentication/Token/DefaultToken.php create mode 100644 lib/private/Authentication/Token/DefaultTokenMapper.php create mode 100644 lib/private/Authentication/Token/DefaultTokenProvider.php create mode 100644 lib/private/Authentication/Token/IProvider.php create mode 100644 lib/private/Authentication/Token/IToken.php diff --git a/core/Application.php b/core/Application.php index 0a54386a2c..faadad3298 100644 --- a/core/Application.php +++ b/core/Application.php @@ -1,6 +1,7 @@ + * @author Christoph Wurst * @author Lukas Reschke * @author Morris Jobke * @author Roeland Jago Douma @@ -28,12 +29,13 @@ namespace OC\Core; use OC\AppFramework\Utility\SimpleContainer; use OC\AppFramework\Utility\TimeFactory; +use OC\Core\Controller\AvatarController; use OC\Core\Controller\LoginController; -use \OCP\AppFramework\App; use OC\Core\Controller\LostController; use OC\Core\Controller\UserController; -use OC\Core\Controller\AvatarController; -use \OCP\Util; +use OC_Defaults; +use OCP\AppFramework\App; +use OCP\Util; /** * Class Application @@ -132,6 +134,9 @@ class Application extends App { $container->registerService('UserSession', function(SimpleContainer $c) { return $c->query('ServerContainer')->getUserSession(); }); + $container->registerService('Session', function(SimpleContainer $c) { + return $c->query('ServerContainer')->getSession(); + }); $container->registerService('Cache', function(SimpleContainer $c) { return $c->query('ServerContainer')->getCache(); }); @@ -139,7 +144,7 @@ class Application extends App { return $c->query('ServerContainer')->getUserFolder(); }); $container->registerService('Defaults', function() { - return new \OC_Defaults; + return new OC_Defaults; }); $container->registerService('Mailer', function(SimpleContainer $c) { return $c->query('ServerContainer')->getMailer(); diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php index 796706d364..fe1ad41aed 100644 --- a/core/Controller/LoginController.php +++ b/core/Controller/LoginController.php @@ -1,5 +1,7 @@ * @author Lukas Reschke * * @copyright Copyright (c) 2016, ownCloud, Inc. @@ -21,7 +23,11 @@ namespace OC\Core\Controller; -use OC\Setup; +use OC; +use OC\User\Session; +use OC_App; +use OC_User; +use OC_Util; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; @@ -31,17 +37,21 @@ use OCP\ISession; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; -use OCP\IUserSession; class LoginController extends Controller { + /** @var IUserManager */ private $userManager; + /** @var IConfig */ private $config; + /** @var ISession */ private $session; - /** @var IUserSession */ + + /** @var Session */ private $userSession; + /** @var IURLGenerator */ private $urlGenerator; @@ -51,16 +61,12 @@ class LoginController extends Controller { * @param IUserManager $userManager * @param IConfig $config * @param ISession $session - * @param IUserSession $userSession + * @param Session $userSession * @param IURLGenerator $urlGenerator */ - function __construct($appName, - IRequest $request, - IUserManager $userManager, - IConfig $config, - ISession $session, - IUserSession $userSession, - IURLGenerator $urlGenerator) { + function __construct($appName, IRequest $request, IUserManager $userManager, + IConfig $config, ISession $session, Session $userSession, + IURLGenerator $urlGenerator) { parent::__construct($appName, $request); $this->userManager = $userManager; $this->config = $config; @@ -96,18 +102,16 @@ class LoginController extends Controller { * * @return TemplateResponse */ - public function showLoginForm($user, - $redirect_url, - $remember_login) { - if($this->userSession->isLoggedIn()) { - return new RedirectResponse(\OC_Util::getDefaultPageUrl()); + public function showLoginForm($user, $redirect_url, $remember_login) { + if ($this->userSession->isLoggedIn()) { + return new RedirectResponse(OC_Util::getDefaultPageUrl()); } $parameters = array(); $loginMessages = $this->session->get('loginMessages'); $errors = []; $messages = []; - if(is_array($loginMessages)) { + if (is_array($loginMessages)) { list($errors, $messages) = $loginMessages; } $this->session->remove('loginMessages'); @@ -137,8 +141,8 @@ class LoginController extends Controller { } } - $parameters['alt_login'] = \OC_App::getAlternativeLogIns(); - $parameters['rememberLoginAllowed'] = \OC_Util::rememberLoginAllowed(); + $parameters['alt_login'] = OC_App::getAlternativeLogIns(); + $parameters['rememberLoginAllowed'] = OC_Util::rememberLoginAllowed(); $parameters['rememberLoginState'] = !empty($remember_login) ? $remember_login : 0; if (!is_null($user) && $user !== '') { @@ -150,11 +154,36 @@ class LoginController extends Controller { } return new TemplateResponse( - $this->appName, - 'login', - $parameters, - 'guest' + $this->appName, 'login', $parameters, 'guest' ); } + /** + * @NoCSRFRequired + * @PublicPage + * @UseSession + * + * @param string $user + * @param string $password + * @param string $redirect_url + * @return RedirectResponse + */ + public function tryLogin($user, $password, $redirect_url) { + // TODO: Add all the insane error handling + if ($this->userManager->checkPassword($user, $password) === false) { + return new RedirectResponse($this->urlGenerator->linkToRoute('login#showLoginForm')); + } + $this->userSession->createSessionToken($user, $password); + if (!is_null($redirect_url) && $this->userSession->isLoggedIn()) { + $location = OC::$server->getURLGenerator()->getAbsoluteURL(urldecode($redirect_url)); + // Deny the redirect if the URL contains a @ + // This prevents unvalidated redirects like ?redirect_url=:user@domain.com + if (strpos($location, '@') === false) { + return new RedirectResponse($location); + } + } + // TODO: Show invalid login warning + return new RedirectResponse($this->urlGenerator->linkTo('files', 'index')); + } + } diff --git a/core/routes.php b/core/routes.php index a9c800af4e..e86cd702b8 100644 --- a/core/routes.php +++ b/core/routes.php @@ -42,9 +42,10 @@ $application->registerRoutes($this, [ ['name' => 'avatar#postCroppedAvatar', 'url' => '/avatar/cropped', 'verb' => 'POST'], ['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'], ['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'], + ['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'], ['name' => 'login#showLoginForm', 'url' => '/login', 'verb' => 'GET'], ['name' => 'login#logout', 'url' => '/logout', 'verb' => 'GET'], - ] + ], ]); // Post installation check diff --git a/core/templates/login.php b/core/templates/login.php index 86c186928c..45814fc71d 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -9,7 +9,7 @@ script('core', [ ?> -
+
'); diff --git a/db_structure.xml b/db_structure.xml index 99541a4f90..cde8f52dc6 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -1031,6 +1031,66 @@ + + *dbprefix*authtoken + + + + + id + integer + 0 + true + 1 + true + 4 + + + + + uid + text + + true + 64 + + + + password + text + + true + 100 + + + + name + text + + true + 100 + + + + token + text + + true + 100 + + + + authtoken_token_index + true + + token + ascending + + + + +
+