diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2019-05-03 15:09:19 +0200 |
---|---|---|
committer | Christoph Wurst <christoph@winzerhof-wurst.at> | 2019-05-07 18:04:36 +0200 |
commit | 170582d4f5eef1cc53c043d67c5d9d07d097155c (patch) | |
tree | 640d7a0c0fbfdf1d9a567c7fa5ddbb3cdb4f5316 /core | |
parent | 5893f218c247d4c0829fb74161e663f3903e15ad (diff) | |
download | nextcloud-server-170582d4f5eef1cc53c043d67c5d9d07d097155c.tar.gz nextcloud-server-170582d4f5eef1cc53c043d67c5d9d07d097155c.zip |
Add a login chain to reduce the complexity of LoginController::tryLogin
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'core')
-rw-r--r-- | core/Controller/LoginController.php | 163 |
1 files changed, 37 insertions, 126 deletions
diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php index 85d3b6b837f..9c11a37639a 100644 --- a/core/Controller/LoginController.php +++ b/core/Controller/LoginController.php @@ -33,7 +33,8 @@ namespace OC\Core\Controller; -use OC\Authentication\Token\IToken; +use OC\Authentication\Login\Chain; +use OC\Authentication\Login\LoginData; use OC\Authentication\TwoFactorAuth\Manager; use OC\Security\Bruteforce\Throttler; use OC\User\Session; @@ -44,17 +45,14 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; -use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Defaults; use OCP\IConfig; use OCP\ILogger; use OCP\IRequest; use OCP\ISession; use OCP\IURLGenerator; -use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; -use OC\Hooks\PublicEmitter; use OCP\Util; class LoginController extends Controller { @@ -74,27 +72,14 @@ class LoginController extends Controller { private $urlGenerator; /** @var ILogger */ private $logger; - /** @var Manager */ - private $twoFactorManager; /** @var Defaults */ private $defaults; /** @var Throttler */ private $throttler; + /** @var Chain */ + private $loginChain; - /** - * @param string $appName - * @param IRequest $request - * @param IUserManager $userManager - * @param IConfig $config - * @param ISession $session - * @param IUserSession $userSession - * @param IURLGenerator $urlGenerator - * @param ILogger $logger - * @param Manager $twoFactorManager - * @param Defaults $defaults - * @param Throttler $throttler - */ - public function __construct($appName, + public function __construct(?string $appName, IRequest $request, IUserManager $userManager, IConfig $config, @@ -102,9 +87,9 @@ class LoginController extends Controller { IUserSession $userSession, IURLGenerator $urlGenerator, ILogger $logger, - Manager $twoFactorManager, Defaults $defaults, - Throttler $throttler) { + Throttler $throttler, + Chain $loginChain) { parent::__construct($appName, $request); $this->userManager = $userManager; $this->config = $config; @@ -112,9 +97,9 @@ class LoginController extends Controller { $this->userSession = $userSession; $this->urlGenerator = $urlGenerator; $this->logger = $logger; - $this->twoFactorManager = $twoFactorManager; $this->defaults = $defaults; $this->throttler = $throttler; + $this->loginChain = $loginChain; } /** @@ -226,8 +211,8 @@ class LoginController extends Controller { * @param array $parameters * @return array */ - private function setPasswordResetParameters( - string $user = null, array $parameters): array { + private function setPasswordResetParameters(?string $user, + array $parameters): array { if ($user !== null && $user !== '') { $userObj = $this->userManager->get($user); } else { @@ -250,12 +235,8 @@ class LoginController extends Controller { return $parameters; } - /** - * @param string $redirectUrl - * @return RedirectResponse - */ - private function generateRedirect($redirectUrl) { - if (!is_null($redirectUrl) && $this->userSession->isLoggedIn()) { + private function generateRedirect(?string $redirectUrl): RedirectResponse { + if ($redirectUrl !== null && $this->userSession->isLoggedIn()) { $location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl)); // Deny the redirect if the URL contains a @ // This prevents unvalidated redirects like ?redirect_url=:user@domain.com @@ -275,16 +256,15 @@ class LoginController extends Controller { * @param string $user * @param string $password * @param string $redirect_url - * @param boolean $remember_login * @param string $timezone * @param string $timezone_offset * @return RedirectResponse */ - public function tryLogin($user, $password, $redirect_url, $remember_login = true, $timezone = '', $timezone_offset = '') { - if(!is_string($user)) { - throw new \InvalidArgumentException('Username must be string'); - } - + public function tryLogin(string $user, + string $password, + string $redirect_url = null, + string $timezone = '', + string $timezone_offset = ''): RedirectResponse { // If the user is already logged in and the CSRF check does not pass then // simply redirect the user to the correct page as required. This is the // case when an user has already logged-in, in another tab. @@ -292,96 +272,27 @@ class LoginController extends Controller { return $this->generateRedirect($redirect_url); } - if ($this->userManager instanceof PublicEmitter) { - $this->userManager->emit('\OC\User', 'preLogin', array($user, $password)); - } - - $originalUser = $user; - - $userObj = $this->userManager->get($user); - - if ($userObj !== null && $userObj->isEnabled() === false) { - $this->logger->warning('Login failed: \''. $user . '\' disabled' . - ' (Remote IP: \''. $this->request->getRemoteAddress(). '\')', - ['app' => 'core']); - return $this->createLoginFailedResponse($user, $originalUser, - $redirect_url, self::LOGIN_MSG_USERDISABLED); - } - - // TODO: Add all the insane error handling - /* @var $loginResult IUser */ - $loginResult = $this->userManager->checkPasswordNoLogging($user, $password); - if ($loginResult === false) { - $users = $this->userManager->getByEmail($user); - // we only allow login by email if unique - if (count($users) === 1) { - $previousUser = $user; - $user = $users[0]->getUID(); - if($user !== $previousUser) { - $loginResult = $this->userManager->checkPassword($user, $password); - } - } - } - - if ($loginResult === false) { - $this->logger->warning('Login failed: \''. $user . - '\' (Remote IP: \''. $this->request->getRemoteAddress(). '\')', - ['app' => 'core']); - return $this->createLoginFailedResponse($user, $originalUser, - $redirect_url, self::LOGIN_MSG_INVALIDPASSWORD); - } - - // TODO: remove password checks from above and let the user session handle failures - // requires https://github.com/owncloud/core/pull/24616 - $this->userSession->completeLogin($loginResult, ['loginName' => $user, 'password' => $password]); - - $tokenType = IToken::REMEMBER; - if ((int)$this->config->getSystemValue('remember_login_cookie_lifetime', 60*60*24*15) === 0) { - $remember_login = false; - $tokenType = IToken::DO_NOT_REMEMBER; - } - - $this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, $tokenType); - $this->userSession->updateTokens($loginResult->getUID(), $password); - - // User has successfully logged in, now remove the password reset link, when it is available - $this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword'); - - $this->session->set('last-password-confirm', $loginResult->getLastLogin()); - - if ($timezone_offset !== '') { - $this->config->setUserValue($loginResult->getUID(), 'core', 'timezone', $timezone); - $this->session->set('timezone', $timezone_offset); - } - - if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) { - $this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login); - - $providers = $this->twoFactorManager->getProviderSet($loginResult)->getPrimaryProviders(); - if (count($providers) === 1) { - // Single provider, hence we can redirect to that provider's challenge page directly - /* @var $provider IProvider */ - $provider = array_pop($providers); - $url = 'core.TwoFactorChallenge.showChallenge'; - $urlParams = [ - 'challengeProviderId' => $provider->getId(), - ]; - } else { - $url = 'core.TwoFactorChallenge.selectChallenge'; - $urlParams = []; - } - - if (!is_null($redirect_url)) { - $urlParams['redirect_url'] = $redirect_url; - } - - return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams)); + $data = new LoginData( + $this->request, + $user, + $password, + $redirect_url, + $timezone, + $timezone_offset + ); + $result = $this->loginChain->process($data); + if (!$result->isSuccess()) { + return $this->createLoginFailedResponse( + $data->getUsername(), + $user, + $redirect_url, + $result->getErrorMessage() + ); } - if ($remember_login) { - $this->userSession->createRememberMeToken($loginResult); + if ($result->getRedirectUrl() !== null) { + return new RedirectResponse($result->getRedirectUrl()); } - return $this->generateRedirect($redirect_url); } @@ -398,8 +309,8 @@ class LoginController extends Controller { $user, $originalUser, $redirect_url, string $loginMessage) { // Read current user and append if possible we need to // return the unmodified user otherwise we will leak the login name - $args = !is_null($user) ? ['user' => $originalUser] : []; - if (!is_null($redirect_url)) { + $args = $user !== null ? ['user' => $originalUser] : []; + if ($redirect_url !== null) { $args['redirect_url'] = $redirect_url; } $response = new RedirectResponse( |