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;
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 {
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,
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;
$this->userSession = $userSession;
$this->urlGenerator = $urlGenerator;
$this->logger = $logger;
- $this->twoFactorManager = $twoFactorManager;
$this->defaults = $defaults;
$this->throttler = $throttler;
+ $this->loginChain = $loginChain;
}
/**
* @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 {
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
* @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.
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);
}
$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(
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => $baseDir . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
'OC\\Authentication\\LoginCredentials\\Credentials' => $baseDir . '/lib/private/Authentication/LoginCredentials/Credentials.php',
'OC\\Authentication\\LoginCredentials\\Store' => $baseDir . '/lib/private/Authentication/LoginCredentials/Store.php',
+ 'OC\\Authentication\\Login\\ALoginCommand' => $baseDir . '/lib/private/Authentication/Login/ALoginCommand.php',
+ 'OC\\Authentication\\Login\\Chain' => $baseDir . '/lib/private/Authentication/Login/Chain.php',
+ 'OC\\Authentication\\Login\\ClearLostPasswordTokensCommand' => $baseDir . '/lib/private/Authentication/Login/ClearLostPasswordTokensCommand.php',
+ 'OC\\Authentication\\Login\\CompleteLoginCommand' => $baseDir . '/lib/private/Authentication/Login/CompleteLoginCommand.php',
+ 'OC\\Authentication\\Login\\CreateSessionTokenCommand' => $baseDir . '/lib/private/Authentication/Login/CreateSessionTokenCommand.php',
+ 'OC\\Authentication\\Login\\EmailLoginCommand' => $baseDir . '/lib/private/Authentication/Login/EmailLoginCommand.php',
+ 'OC\\Authentication\\Login\\FinishRememberedLoginCommand' => $baseDir . '/lib/private/Authentication/Login/FinishRememberedLoginCommand.php',
+ 'OC\\Authentication\\Login\\LoggedInCheckCommand' => $baseDir . '/lib/private/Authentication/Login/LoggedInCheckCommand.php',
+ 'OC\\Authentication\\Login\\LoginData' => $baseDir . '/lib/private/Authentication/Login/LoginData.php',
+ 'OC\\Authentication\\Login\\LoginResult' => $baseDir . '/lib/private/Authentication/Login/LoginResult.php',
+ 'OC\\Authentication\\Login\\PreLoginHookCommand' => $baseDir . '/lib/private/Authentication/Login/PreLoginHookCommand.php',
+ 'OC\\Authentication\\Login\\SetUserTimezoneCommand' => $baseDir . '/lib/private/Authentication/Login/SetUserTimezoneCommand.php',
+ 'OC\\Authentication\\Login\\TwoFactorCommand' => $baseDir . '/lib/private/Authentication/Login/TwoFactorCommand.php',
+ 'OC\\Authentication\\Login\\UidLoginCommand' => $baseDir . '/lib/private/Authentication/Login/UidLoginCommand.php',
+ 'OC\\Authentication\\Login\\UpdateLastPasswordConfirmCommand' => $baseDir . '/lib/private/Authentication/Login/UpdateLastPasswordConfirmCommand.php',
+ 'OC\\Authentication\\Login\\UserDisabledCheckCommand' => $baseDir . '/lib/private/Authentication/Login/UserDisabledCheckCommand.php',
'OC\\Authentication\\Token\\DefaultToken' => $baseDir . '/lib/private/Authentication/Token/DefaultToken.php',
'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php',
'OC\\Authentication\\Token\\DefaultTokenMapper' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenMapper.php',
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
'OC\\Authentication\\LoginCredentials\\Credentials' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Credentials.php',
'OC\\Authentication\\LoginCredentials\\Store' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Store.php',
+ 'OC\\Authentication\\Login\\ALoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/ALoginCommand.php',
+ 'OC\\Authentication\\Login\\Chain' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/Chain.php',
+ 'OC\\Authentication\\Login\\ClearLostPasswordTokensCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/ClearLostPasswordTokensCommand.php',
+ 'OC\\Authentication\\Login\\CompleteLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/CompleteLoginCommand.php',
+ 'OC\\Authentication\\Login\\CreateSessionTokenCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/CreateSessionTokenCommand.php',
+ 'OC\\Authentication\\Login\\EmailLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/EmailLoginCommand.php',
+ 'OC\\Authentication\\Login\\FinishRememberedLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/FinishRememberedLoginCommand.php',
+ 'OC\\Authentication\\Login\\LoggedInCheckCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoggedInCheckCommand.php',
+ 'OC\\Authentication\\Login\\LoginData' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoginData.php',
+ 'OC\\Authentication\\Login\\LoginResult' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/LoginResult.php',
+ 'OC\\Authentication\\Login\\PreLoginHookCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/PreLoginHookCommand.php',
+ 'OC\\Authentication\\Login\\SetUserTimezoneCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/SetUserTimezoneCommand.php',
+ 'OC\\Authentication\\Login\\TwoFactorCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/TwoFactorCommand.php',
+ 'OC\\Authentication\\Login\\UidLoginCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/UidLoginCommand.php',
+ 'OC\\Authentication\\Login\\UpdateLastPasswordConfirmCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/UpdateLastPasswordConfirmCommand.php',
+ 'OC\\Authentication\\Login\\UserDisabledCheckCommand' => __DIR__ . '/../../..' . '/lib/private/Authentication/Login/UserDisabledCheckCommand.php',
'OC\\Authentication\\Token\\DefaultToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultToken.php',
'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php',
'OC\\Authentication\\Token\\DefaultTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenMapper.php',
--- /dev/null
+<?php
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+abstract class ALoginCommand {
+
+ /** @var ALoginCommand */
+ protected $next;
+
+ public function setNext(ALoginCommand $next): ALoginCommand {
+ $this->next = $next;
+ return $next;
+ }
+
+ protected function processNextOrFinishSuccessfully(LoginData $loginData): LoginResult {
+ if ($this->next !== null) {
+ return $this->next->process($loginData);
+ } else {
+ return LoginResult::success($loginData);
+ }
+ }
+
+ public abstract function process(LoginData $loginData): LoginResult;
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+class Chain {
+
+ /** @var PreLoginHookCommand */
+ private $preLoginHookCommand;
+
+ /** @var UserDisabledCheckCommand */
+ private $userDisabledCheckCommand;
+
+ /** @var UidLoginCommand */
+ private $uidLoginCommand;
+
+ /** @var EmailLoginCommand */
+ private $emailLoginCommand;
+
+ /** @var LoggedInCheckCommand */
+ private $loggedInCheckCommand;
+
+ /** @var CompleteLoginCommand */
+ private $completeLoginCommand;
+
+ /** @var CreateSessionTokenCommand */
+ private $createSessionTokenCommand;
+
+ /** @var ClearLostPasswordTokensCommand */
+ private $clearLostPasswordTokensCommand;
+
+ /** @var UpdateLastPasswordConfirmCommand */
+ private $updateLastPasswordConfirmCommand;
+
+ /** @var SetUserTimezoneCommand */
+ private $setUserTimezoneCommand;
+
+ /** @var TwoFactorCommand */
+ private $twoFactorCommand;
+
+ /** @var FinishRememberedLoginCommand */
+ private $finishRememberedLoginCommand;
+
+ public function __construct(PreLoginHookCommand $preLoginHookCommand,
+ UserDisabledCheckCommand $userDisabledCheckCommand,
+ UidLoginCommand $uidLoginCommand,
+ EmailLoginCommand $emailLoginCommand,
+ LoggedInCheckCommand $loggedInCheckCommand,
+ CompleteLoginCommand $completeLoginCommand,
+ CreateSessionTokenCommand $createSessionTokenCommand,
+ ClearLostPasswordTokensCommand $clearLostPasswordTokensCommand,
+ UpdateLastPasswordConfirmCommand $updateLastPasswordConfirmCommand,
+ SetUserTimezoneCommand $setUserTimezoneCommand,
+ TwoFactorCommand $twoFactorCommand,
+ FinishRememberedLoginCommand $finishRememberedLoginCommand
+ ) {
+ $this->preLoginHookCommand = $preLoginHookCommand;
+ $this->userDisabledCheckCommand = $userDisabledCheckCommand;
+ $this->uidLoginCommand = $uidLoginCommand;
+ $this->emailLoginCommand = $emailLoginCommand;
+ $this->loggedInCheckCommand = $loggedInCheckCommand;
+ $this->completeLoginCommand = $completeLoginCommand;
+ $this->createSessionTokenCommand = $createSessionTokenCommand;
+ $this->clearLostPasswordTokensCommand = $clearLostPasswordTokensCommand;
+ $this->updateLastPasswordConfirmCommand = $updateLastPasswordConfirmCommand;
+ $this->setUserTimezoneCommand = $setUserTimezoneCommand;
+ $this->twoFactorCommand = $twoFactorCommand;
+ $this->finishRememberedLoginCommand = $finishRememberedLoginCommand;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ $chain = $this->preLoginHookCommand;
+ $chain
+ ->setNext($this->userDisabledCheckCommand)
+ ->setNext($this->uidLoginCommand)
+ ->setNext($this->emailLoginCommand)
+ ->setNext($this->loggedInCheckCommand)
+ ->setNext($this->completeLoginCommand)
+ ->setNext($this->createSessionTokenCommand)
+ ->setNext($this->clearLostPasswordTokensCommand)
+ ->setNext($this->updateLastPasswordConfirmCommand)
+ ->setNext($this->setUserTimezoneCommand)
+ ->setNext($this->twoFactorCommand)
+ ->setNext($this->finishRememberedLoginCommand);
+
+ return $chain->process($loginData);
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OCP\IConfig;
+
+class ClearLostPasswordTokensCommand extends ALoginCommand {
+
+ /** @var IConfig */
+ private $config;
+
+ public function __construct(IConfig $config) {
+ $this->config = $config;
+ }
+
+ /**
+ * User has successfully logged in, now remove the password reset link, when it is available
+ */
+ public function process(LoginData $loginData): LoginResult {
+ $this->config->deleteUserValue(
+ $loginData->getUser()->getUID(),
+ 'core',
+ 'lostpassword'
+ );
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OC\User\Session;
+
+class CompleteLoginCommand extends ALoginCommand {
+
+ /** @var Session */
+ private $userSession;
+
+ public function __construct(Session $userSession) {
+ $this->userSession = $userSession;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ $this->userSession->completeLogin(
+ $loginData->getUser(),
+ [
+ 'loginName' => $loginData->getUsername(),
+ 'password' => $loginData->getPassword(),
+ ]
+ );
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OC\Authentication\Token\IToken;
+use OC\User\Session;
+use OCP\IConfig;
+
+class CreateSessionTokenCommand extends ALoginCommand {
+
+ /** @var IConfig */
+ private $config;
+
+ /** @var Session */
+ private $userSession;
+
+ public function __construct(IConfig $config,
+ Session $userSession) {
+ $this->config = $config;
+ $this->userSession = $userSession;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ $tokenType = IToken::REMEMBER;
+ if ((int)$this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15) === 0) {
+ $loginData->setRememberLogin(false);
+ $tokenType = IToken::DO_NOT_REMEMBER;
+ }
+
+ $this->userSession->createSessionToken(
+ $loginData->getRequest(),
+ $loginData->getUser()->getUID(),
+ $loginData->getUsername(),
+ $loginData->getPassword(),
+ $tokenType
+ );
+ $this->userSession->updateTokens(
+ $loginData->getUser()->getUID(),
+ $loginData->getUsername()
+ );
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OCP\IUserManager;
+
+class EmailLoginCommand extends ALoginCommand {
+
+ /** @var IUserManager */
+ private $userManager;
+
+ public function __construct(IUserManager $userManager) {
+ $this->userManager = $userManager;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ if ($loginData->getUser() === false) {
+ $users = $this->userManager->getByEmail($loginData->getUsername());
+ // we only allow login by email if unique
+ if (count($users) === 1) {
+ $username = $users[0]->getUID();
+ if ($username !== $loginData->getUsername()) {
+ $user = $this->userManager->checkPassword(
+ $username,
+ $loginData->getPassword()
+ );
+ if ($user !== false) {
+ $loginData->setUser($user);
+ $loginData->setUsername($username);
+ }
+ }
+ }
+ }
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OC\User\Session;
+
+class FinishRememberedLoginCommand extends ALoginCommand {
+
+ /** @var Session */
+ private $userSession;
+
+ public function __construct(Session $userSession) {
+ $this->userSession = $userSession;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ if ($loginData->isRememberLogin()) {
+ $this->userSession->createRememberMeToken($loginData->getUser());
+ }
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OC\Core\Controller\LoginController;
+use OCP\ILogger;
+
+class LoggedInCheckCommand extends ALoginCommand {
+
+ /** @var ILogger */
+ private $logger;
+
+ public function __construct(ILogger $logger) {
+ $this->logger = $logger;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ if ($loginData->getUser() === false) {
+ $username = $loginData->getUsername();
+ $ip = $loginData->getRequest()->getRemoteAddress();
+
+ $this->logger->warning("Login failed: $username (Remote IP: $ip)");
+
+ return LoginResult::failure($loginData, LoginController::LOGIN_MSG_INVALIDPASSWORD);
+ }
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OCP\IRequest;
+use OCP\IUser;
+
+class LoginData {
+
+ /** @var IRequest */
+ private $request;
+
+ /** @var string */
+ private $username;
+
+ /** @var string */
+ private $password;
+
+ /** @var string */
+ private $redirectUrl;
+
+ /** @var string */
+ private $timeZone;
+
+ /** @var string */
+ private $timeZoneOffset;
+
+ /** @var IUser|false|null */
+ private $user = null;
+
+ /** @var bool */
+ private $rememberLogin = true;
+
+ public function __construct(IRequest $request,
+ string $username,
+ string $password,
+ string $redirectUrl = null,
+ string $timeZone = '',
+ string $timeZoneOffset = '') {
+ $this->request = $request;
+ $this->username = $username;
+ $this->password = $password;
+ $this->redirectUrl = $redirectUrl;
+ $this->timeZone = $timeZone;
+ $this->timeZoneOffset = $timeZoneOffset;
+ }
+
+ public function getRequest(): IRequest {
+ return $this->request;
+ }
+
+ public function setUsername(string $username): void {
+ $this->username = $username;
+ }
+
+ public function getUsername(): string {
+ return $this->username;
+ }
+
+ public function getPassword(): string {
+ return $this->password;
+ }
+
+ public function getRedirectUrl(): ?string {
+ return $this->redirectUrl;
+ }
+
+ public function getTimeZone(): string {
+ return $this->timeZone;
+ }
+
+ public function getTimeZoneOffset(): string {
+ return $this->timeZoneOffset;
+ }
+
+ /**
+ * @param IUser|false|null $user
+ */
+ public function setUser($user) {
+ $this->user = $user;
+ }
+
+ /**
+ * @return false|IUser|null
+ */
+ public function getUser() {
+ return $this->user;
+ }
+
+ public function setRememberLogin(bool $rememberLogin): void {
+ $this->rememberLogin = $rememberLogin;
+ }
+
+ public function isRememberLogin(): bool {
+ return $this->rememberLogin;
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+class LoginResult {
+
+ /** @var bool */
+ private $success;
+
+ /** @var LoginData */
+ private $loginData;
+
+ /** @var string|null */
+ private $redirectUrl;
+
+ /** @var string|null */
+ private $errorMessage;
+
+ private function __construct(bool $success, LoginData $loginData) {
+ $this->success = $success;
+ $this->loginData = $loginData;
+ }
+
+ private function setRedirectUrl(string $url) {
+ $this->redirectUrl = $url;
+ }
+
+ private function setErrorMessage(string $msg) {
+ $this->errorMessage = $msg;
+ }
+
+ public static function success(LoginData $data, ?string $redirectUrl = null) {
+ $result = new static(true, $data);
+ if ($redirectUrl !== null) {
+ $result->setRedirectUrl($redirectUrl);
+ }
+ return $result;
+ }
+
+ public static function failure(LoginData $data, string $msg = null): LoginResult {
+ $result = new static(false, $data);
+ if ($msg !== null) {
+ $result->setErrorMessage($msg);
+ }
+ return $result;
+ }
+
+ public function isSuccess(): bool {
+ return $this->success;
+ }
+
+ public function getRedirectUrl(): ?string {
+ return $this->redirectUrl;
+ }
+
+ public function getErrorMessage(): ?string {
+ return $this->errorMessage;
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OC\Hooks\PublicEmitter;
+use OCP\IUserManager;
+
+class PreLoginHookCommand extends ALoginCommand {
+
+ /** @var IUserManager */
+ private $userManager;
+
+ public function __construct(IUserManager $userManager) {
+ $this->userManager = $userManager;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ if ($this->userManager instanceof PublicEmitter) {
+ $this->userManager->emit(
+ '\OC\User',
+ 'preLogin',
+ [
+ $loginData->getUsername(),
+ $loginData->getPassword(),
+ ]
+ );
+ }
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OCP\IConfig;
+use OCP\ISession;
+
+class SetUserTimezoneCommand extends ALoginCommand {
+
+ /** @var IConfig */
+ private $config;
+
+ /** @var ISession */
+ private $session;
+
+ public function __construct(IConfig $config,
+ ISession $session) {
+ $this->config = $config;
+ $this->session = $session;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ if ($loginData->getTimeZoneOffset() !== '') {
+ $this->config->setUserValue(
+ $loginData->getUser()->getUID(),
+ 'core',
+ 'timezone',
+ $loginData->getTimeZone()
+ );
+ $this->session->set(
+ 'timezone',
+ $loginData->getTimeZoneOffset()
+ );
+ }
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use function array_pop;
+use function count;
+use OC\Authentication\TwoFactorAuth\Manager;
+use OCP\Authentication\TwoFactorAuth\IProvider;
+use OCP\IURLGenerator;
+
+class TwoFactorCommand extends ALoginCommand {
+
+ /** @var Manager */
+ private $twoFactorManager;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ public function __construct(Manager $twoFactorManager,
+ IURLGenerator $urlGenerator) {
+ $this->twoFactorManager = $twoFactorManager;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ if (!$this->twoFactorManager->isTwoFactorAuthenticated($loginData->getUser())) {
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+ $this->twoFactorManager->prepareTwoFactorLogin($loginData->getUser(), $loginData->isRememberLogin());
+
+ $providers = $this->twoFactorManager->getProviderSet($loginData->getUser())->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 ($loginData->getRedirectUrl() !== null) {
+ $urlParams['redirect_url'] = $loginData->getRedirectUrl();
+ }
+
+ return LoginResult::success(
+ $loginData,
+ $this->urlGenerator->linkToRoute($url, $urlParams)
+ );
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OC\User\Manager;
+use OCP\IUser;
+
+class UidLoginCommand extends ALoginCommand {
+
+ /** @var Manager */
+ private $userManager;
+
+ public function __construct(Manager $userManager) {
+ $this->userManager = $userManager;
+ }
+
+ /**
+ * @param LoginData $loginData
+ *
+ * @return LoginResult
+ */
+ public function process(LoginData $loginData): LoginResult {
+ /* @var $loginResult IUser */
+ $user = $this->userManager->checkPasswordNoLogging(
+ $loginData->getUsername(),
+ $loginData->getPassword()
+ );
+
+ $loginData->setUser($user);
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OCP\ISession;
+
+class UpdateLastPasswordConfirmCommand extends ALoginCommand {
+
+ /** @var ISession */
+ private $session;
+
+ public function __construct(ISession $session) {
+ $this->session = $session;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ $this->session->set(
+ 'last-password-confirm',
+ $loginData->getUser()->getLastLogin()
+ );
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace OC\Authentication\Login;
+
+use OC\Core\Controller\LoginController;
+use OCP\ILogger;
+use OCP\IUserManager;
+
+class UserDisabledCheckCommand extends ALoginCommand {
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var ILogger */
+ private $logger;
+
+ public function __construct(IUserManager $userManager,
+ ILogger $logger) {
+ $this->userManager = $userManager;
+ $this->logger = $logger;
+ }
+
+ public function process(LoginData $loginData): LoginResult {
+ $user = $this->userManager->get($loginData->getUsername());
+ if ($user !== null && $user->isEnabled() === false) {
+ $username = $loginData->getUsername();
+ $ip = $loginData->getRequest()->getRemoteAddress();
+
+ $this->logger->warning("Login failed: $username disabled (Remote IP: $ip)");
+
+ return LoginResult::failure($loginData, LoginController::LOGIN_MSG_USERDISABLED);
+ }
+
+ return $this->processNextOrFinishSuccessfully($loginData);
+ }
+
+}
* @internal
* @param string $loginName
* @param string $password
- * @return mixed the User object on success, false otherwise
+ * @return IUser|false the User object on success, false otherwise
*/
public function checkPasswordNoLogging($loginName, $password) {
$loginName = str_replace("\0", '', $loginName);
namespace Tests\Core\Controller;
+use OC\Authentication\Login\Chain as LoginChain;
+use OC\Authentication\Login\LoginData;
+use OC\Authentication\Login\LoginResult;
use OC\Authentication\Token\IToken;
use OC\Authentication\TwoFactorAuth\Manager;
use OC\Authentication\TwoFactorAuth\ProviderSet;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
+use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class LoginControllerTest extends TestCase {
+
/** @var LoginController */
private $loginController;
- /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var IRequest|MockObject */
private $request;
- /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var IUserManager|MockObject */
private $userManager;
- /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var IConfig|MockObject */
private $config;
- /** @var ISession|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var ISession|MockObject */
private $session;
- /** @var Session|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var Session|MockObject */
private $userSession;
- /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var IURLGenerator|MockObject */
private $urlGenerator;
- /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var ILogger|MockObject */
private $logger;
- /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var Manager|MockObject */
private $twoFactorManager;
- /** @var Defaults|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var Defaults|MockObject */
private $defaults;
- /** @var Throttler|\PHPUnit_Framework_MockObject_MockObject */
+
+ /** @var Throttler|MockObject */
private $throttler;
+ /** @var LoginChain|MockObject */
+ private $chain;
+
public function setUp() {
parent::setUp();
$this->request = $this->createMock(IRequest::class);
$this->twoFactorManager = $this->createMock(Manager::class);
$this->defaults = $this->createMock(Defaults::class);
$this->throttler = $this->createMock(Throttler::class);
+ $this->chain = $this->createMock(LoginChain::class);
$this->request->method('getRemoteAddress')
->willReturn('1.2.3.4');
$this->userSession,
$this->urlGenerator,
$this->logger,
- $this->twoFactorManager,
$this->defaults,
- $this->throttler
+ $this->throttler,
+ $this->chain
);
}
$this->assertEquals($expectedResponse, $this->loginController->showLoginForm('LdapUser', '', ''));
}
- /**
- * Asserts that a disabled user can't login and gets the expected response.
- */
- public function testLoginForDisabledUser() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock(IUser::class);
- $user->method('getUID')
- ->willReturn('uid');
- $user->method('isEnabled')
- ->willReturn(false);
-
- $this->request
- ->expects($this->once())
- ->method('passesCSRFCheck')
- ->willReturn(true);
-
- $this->userSession
- ->method('isLoggedIn')
- ->willReturn(false);
-
- $loginName = 'iMDisabled';
- $password = 'secret';
-
- $this->session
- ->expects($this->once())
- ->method('set')
- ->with('loginMessages', [
- [LoginController::LOGIN_MSG_USERDISABLED], []
- ]);
-
- $this->userManager
- ->expects($this->once())
- ->method('get')
- ->with($loginName)
- ->willReturn($user);
-
- $expected = new RedirectResponse('');
- $expected->throttle(['user' => $loginName]);
-
- $response = $this->loginController->tryLogin(
- $loginName, $password, null, false, 'Europe/Berlin', '1'
- );
- $this->assertEquals($expected, $response);
- }
-
public function testShowLoginFormForUserNamed0() {
$this->userSession
->expects($this->once())
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(true);
- $this->userManager->expects($this->once())
- ->method('checkPasswordNoLogging')
- ->will($this->returnValue(false));
- $this->userManager->expects($this->once())
- ->method('getByEmail')
- ->with($user)
- ->willReturn([]);
+ $loginData = new LoginData(
+ $this->request,
+ $user,
+ $password,
+ '/apps/files'
+ );
+ $loginResult = LoginResult::failure($loginData, LoginController::LOGIN_MSG_INVALIDPASSWORD);
+ $this->chain->expects($this->once())
+ ->method('process')
+ ->with($this->equalTo($loginData))
+ ->willReturn($loginResult);
$this->urlGenerator->expects($this->once())
->method('linkToRoute')
->with('core.login.showLoginForm', [
- 'user' => 'MyUserName',
+ 'user' => $user,
'redirect_url' => '/apps/files',
])
->will($this->returnValue($loginPageUrl));
-
- $this->userSession->expects($this->never())
- ->method('createSessionToken');
- $this->userSession->expects($this->never())
- ->method('createRememberMeToken');
- $this->config->expects($this->never())
- ->method('deleteUserValue');
-
$expected = new \OCP\AppFramework\Http\RedirectResponse($loginPageUrl);
$expected->throttle(['user' => 'MyUserName']);
- $this->assertEquals($expected, $this->loginController->tryLogin($user, $password, '/apps/files'));
+
+ $response = $this->loginController->tryLogin($user, $password, '/apps/files');
+
+ $this->assertEquals($expected, $response);
}
public function testLoginWithValidCredentials() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock(IUser::class);
- $user->expects($this->any())
- ->method('getUID')
- ->will($this->returnValue('uid'));
- $loginName = 'loginli';
- $user->expects($this->any())
- ->method('getLastLogin')
- ->willReturn(123456);
+ $user = 'MyUserName';
$password = 'secret';
$indexPageUrl = \OC_Util::getDefaultPageUrl();
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(true);
- $this->userManager->expects($this->once())
- ->method('checkPasswordNoLogging')
- ->will($this->returnValue($user));
- $this->userSession->expects($this->once())
- ->method('completeLogin')
- ->with($user, ['loginName' => $loginName, 'password' => $password]);
- $this->userSession->expects($this->once())
- ->method('createSessionToken')
- ->with($this->request, $user->getUID(), $loginName, $password, IToken::REMEMBER);
- $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->config->expects($this->once())
- ->method('setUserValue')
- ->with('uid', 'core', 'timezone', 'Europe/Berlin');
- $this->config
- ->method('getSystemValue')
- ->with('remember_login_cookie_lifetime')
- ->willReturn(1234);
- $this->userSession->expects($this->never())
- ->method('createRememberMeToken');
-
- $this->session->expects($this->exactly(2))
- ->method('set')
- ->withConsecutive(
- ['last-password-confirm', 123456],
- ['timezone', '1']
- );
-
+ $loginData = new LoginData(
+ $this->request,
+ $user,
+ $password
+ );
+ $loginResult = LoginResult::success($loginData);
+ $this->chain->expects($this->once())
+ ->method('process')
+ ->with($this->equalTo($loginData))
+ ->willReturn($loginResult);
$expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
- $this->assertEquals($expected, $this->loginController->tryLogin($loginName, $password, null, false, 'Europe/Berlin', '1'));
- }
-
- public function testLoginWithValidCredentialsAndRememberMe() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock(IUser::class);
- $user->expects($this->any())
- ->method('getUID')
- ->will($this->returnValue('uid'));
- $loginName = 'loginli';
- $password = 'secret';
- $indexPageUrl = \OC_Util::getDefaultPageUrl();
- $this->request
- ->expects($this->once())
- ->method('passesCSRFCheck')
- ->willReturn(true);
- $this->userManager->expects($this->once())
- ->method('checkPasswordNoLogging')
- ->will($this->returnValue($user));
- $this->userSession->expects($this->once())
- ->method('completeLogin')
- ->with($user, ['loginName' => $loginName, 'password' => $password]);
- $this->userSession->expects($this->once())
- ->method('createSessionToken')
- ->with($this->request, $user->getUID(), $loginName, $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->config
- ->method('getSystemValue')
- ->with('remember_login_cookie_lifetime')
- ->willReturn(1234);
- $this->userSession->expects($this->once())
- ->method('createRememberMeToken')
- ->with($user);
+ $response = $this->loginController->tryLogin($user, $password);
- $expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
- $this->assertEquals($expected, $this->loginController->tryLogin($loginName, $password, null, true));
+ $this->assertEquals($expected, $response);
}
public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
+ /** @var IUser|MockObject $user */
$user = $this->createMock(IUser::class);
$user->expects($this->any())
->method('getUID')
}
public function testLoginWithoutPassedCsrfCheckAndLoggedIn() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
+ /** @var IUser|MockObject $user */
$user = $this->createMock(IUser::class);
$user->expects($this->any())
->method('getUID')
}
public function testLoginWithValidCredentialsAndRedirectUrl() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock(IUser::class);
- $user->expects($this->any())
- ->method('getUID')
- ->will($this->returnValue('jane'));
+ $user = 'MyUserName';
$password = 'secret';
- $originalUrl = 'another%20url';
- $redirectUrl = 'http://localhost/another url';
+ $indexPageUrl = \OC_Util::getDefaultPageUrl();
+ $redirectUrl = 'https://next.cloud/apps/mail';
$this->request
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(true);
- $this->userManager->expects($this->once())
- ->method('checkPasswordNoLogging')
- ->with('Jane', $password)
- ->will($this->returnValue($user));
- $this->userSession->expects($this->once())
- ->method('createSessionToken')
- ->with($this->request, $user->getUID(), 'Jane', $password, IToken::REMEMBER);
+ $loginData = new LoginData(
+ $this->request,
+ $user,
+ $password,
+ '%2Fapps%2Fmail'
+ );
+ $loginResult = LoginResult::success($loginData);
+ $this->chain->expects($this->once())
+ ->method('process')
+ ->with($this->equalTo($loginData))
+ ->willReturn($loginResult);
$this->userSession->expects($this->once())
->method('isLoggedIn')
- ->with()
- ->will($this->returnValue(true));
+ ->willReturn(true);
$this->urlGenerator->expects($this->once())
->method('getAbsoluteURL')
- ->with(urldecode($originalUrl))
+ ->with(urldecode('/apps/mail'))
->will($this->returnValue($redirectUrl));
- $this->config->expects($this->once())
- ->method('deleteUserValue')
- ->with('jane', 'core', 'lostpassword');
- $this->config
- ->method('getSystemValue')
- ->with('remember_login_cookie_lifetime')
- ->willReturn(1234);
-
- $expected = new \OCP\AppFramework\Http\RedirectResponse(urldecode($redirectUrl));
- $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
- }
-
- public function testLoginWithOneTwoFactorProvider() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock(IUser::class);
- $user->expects($this->any())
- ->method('getUID')
- ->will($this->returnValue('john'));
- $password = 'secret';
- $challengeUrl = 'challenge/url';
- $provider1 = $this->createMock(IProvider::class);
- $provider1->method('getId')->willReturn('u2f');
- $provider2 = $this->createMock(BackupCodesProvider::class);
- $provider2->method('getId')->willReturn('backup');
+ $expected = new \OCP\AppFramework\Http\RedirectResponse($redirectUrl);
- $this->request
- ->expects($this->once())
- ->method('passesCSRFCheck')
- ->willReturn(true);
- $this->userManager->expects($this->once())
- ->method('checkPasswordNoLogging')
- ->will($this->returnValue($user));
- $this->userSession->expects($this->once())
- ->method('completeLogin')
- ->with($user, ['loginName' => 'john@doe.com', 'password' => $password]);
- $this->userSession->expects($this->once())
- ->method('createSessionToken')
- ->with($this->request, $user->getUID(), 'john@doe.com', $password, IToken::REMEMBER);
- $this->twoFactorManager->expects($this->once())
- ->method('isTwoFactorAuthenticated')
- ->with($user)
- ->will($this->returnValue(true));
- $this->twoFactorManager->expects($this->once())
- ->method('prepareTwoFactorLogin')
- ->with($user);
- $providerSet = new ProviderSet([$provider1, $provider2], false);
- $this->twoFactorManager->expects($this->once())
- ->method('getProviderSet')
- ->with($user)
- ->willReturn($providerSet);
- $this->urlGenerator->expects($this->once())
- ->method('linkToRoute')
- ->with('core.TwoFactorChallenge.showChallenge', [
- 'challengeProviderId' => 'u2f',
- ])
- ->will($this->returnValue($challengeUrl));
- $this->config->expects($this->once())
- ->method('deleteUserValue')
- ->with('john', 'core', 'lostpassword');
- $this->config
- ->method('getSystemValue')
- ->with('remember_login_cookie_lifetime')
- ->willReturn(1234);
- $this->userSession->expects($this->never())
- ->method('createRememberMeToken');
+ $response = $this->loginController->tryLogin($user, $password, '%2Fapps%2Fmail');
- $expected = new RedirectResponse($challengeUrl);
- $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
+ $this->assertEquals($expected, $response);
}
- public function testLoginWithMultipleTwoFactorProviders() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock(IUser::class);
- $user->expects($this->any())
- ->method('getUID')
- ->will($this->returnValue('john'));
- $password = 'secret';
- $challengeUrl = 'challenge/url';
- $provider1 = $this->createMock(IProvider::class);
- $provider2 = $this->createMock(IProvider::class);
- $provider1->method('getId')->willReturn('prov1');
- $provider2->method('getId')->willReturn('prov2');
-
+ public function testToNotLeakLoginName() {
$this->request
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(true);
- $this->userManager->expects($this->once())
- ->method('checkPasswordNoLogging')
- ->will($this->returnValue($user));
- $this->userSession->expects($this->once())
- ->method('completeLogin')
- ->with($user, ['loginName' => 'john@doe.com', 'password' => $password]);
- $this->userSession->expects($this->once())
- ->method('createSessionToken')
- ->with($this->request, $user->getUID(), 'john@doe.com', $password, IToken::REMEMBER);
- $this->twoFactorManager->expects($this->once())
- ->method('isTwoFactorAuthenticated')
- ->with($user)
- ->will($this->returnValue(true));
- $this->twoFactorManager->expects($this->once())
- ->method('prepareTwoFactorLogin')
- ->with($user);
- $providerSet = new ProviderSet([$provider1, $provider2], false);
- $this->twoFactorManager->expects($this->once())
- ->method('getProviderSet')
- ->with($user)
- ->willReturn($providerSet);
+ $loginPageUrl = '/login?redirect_url=/apps/files';
+ $loginData = new LoginData(
+ $this->request,
+ 'john@doe.com',
+ 'just wrong',
+ '/apps/files'
+ );
+ $loginResult = LoginResult::failure($loginData, LoginController::LOGIN_MSG_INVALIDPASSWORD);
+ $this->chain->expects($this->once())
+ ->method('process')
+ ->with($this->equalTo($loginData))
+ ->willReturnCallback(function(LoginData $data) use ($loginResult) {
+ $data->setUsername('john');
+ return $loginResult;
+ });
$this->urlGenerator->expects($this->once())
->method('linkToRoute')
- ->with('core.TwoFactorChallenge.selectChallenge')
- ->will($this->returnValue($challengeUrl));
- $this->config->expects($this->once())
- ->method('deleteUserValue')
- ->with('john', 'core', 'lostpassword');
- $this->config
- ->method('getSystemValue')
- ->with('remember_login_cookie_lifetime')
- ->willReturn(1234);
- $this->userSession->expects($this->never())
- ->method('createRememberMeToken');
-
- $expected = new RedirectResponse($challengeUrl);
- $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
- }
-
- public function testToNotLeakLoginName() {
- /** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock(IUser::class);
- $user->expects($this->any())
- ->method('getUID')
- ->will($this->returnValue('john'));
-
- $this->userManager->expects($this->once())
- ->method('checkPasswordNoLogging')
- ->with('john@doe.com', 'just wrong')
- ->willReturn(false);
- $this->userManager->expects($this->once())
- ->method('checkPassword')
- ->with('john', 'just wrong')
- ->willReturn(false);
-
- $this->userManager->expects($this->once())
- ->method('getByEmail')
- ->with('john@doe.com')
- ->willReturn([$user]);
+ ->with('core.login.showLoginForm', [
+ 'user' => 'john@doe.com',
+ 'redirect_url' => '/apps/files',
+ ])
+ ->will($this->returnValue($loginPageUrl));
+ $expected = new \OCP\AppFramework\Http\RedirectResponse($loginPageUrl);
+ $expected->throttle(['user' => 'john']);
- $this->urlGenerator->expects($this->once())
- ->method('linkToRoute')
- ->with('core.login.showLoginForm', ['user' => 'john@doe.com'])
- ->will($this->returnValue(''));
- $this->request
- ->expects($this->once())
- ->method('passesCSRFCheck')
- ->willReturn(true);
- $this->config->expects($this->never())
- ->method('deleteUserValue');
- $this->userSession->expects($this->never())
- ->method('createRememberMeToken');
+ $response = $this->loginController->tryLogin(
+ 'john@doe.com',
+ 'just wrong',
+ '/apps/files'
+ );
- $expected = new RedirectResponse('');
- $expected->throttle(['user' => 'john']);
- $this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', 'just wrong', null));
+ $this->assertEquals($expected, $response);
}
}
--- /dev/null
+<?php
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\ALoginCommand;
+use OC\Authentication\Login\LoginData;
+use OCP\IRequest;
+use OCP\IUser;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+abstract class ALoginCommandTest extends TestCase {
+
+ /** @var IRequest|MockObject */
+ protected $request;
+
+ /** @var string */
+ protected $username = 'user123';
+
+ /** @var string */
+ protected $password = '123456';
+
+ /** @var string */
+ protected $redirectUrl = '/apps/contacts';
+
+ /** @var string */
+ protected $timezone = 'Europe/Vienna';
+
+ protected $timeZoneOffset = '2';
+
+ /** @var IUser|MockObject */
+ protected $user;
+
+ /** @var ALoginCommand */
+ protected $cmd;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->request = $this->createMock(IRequest::class);
+ $this->user = $this->createMock(IUser::class);
+ }
+
+ protected function getBasicLoginData(): LoginData {
+ return new LoginData(
+ $this->request,
+ $this->username,
+ $this->password
+ );
+ }
+
+ protected function getInvalidLoginData(): LoginData {
+ return new LoginData(
+ $this->request,
+ $this->username,
+ $this->password
+ );
+ }
+
+ protected function getFailedLoginData(): LoginData {
+ $data = new LoginData(
+ $this->request,
+ $this->username,
+ $this->password
+ );
+ $data->setUser(false);
+ return $data;
+ }
+
+ protected function getLoggedInLoginData(): LoginData {
+ $basic = $this->getBasicLoginData();
+ $basic->setUser($this->user);
+ return $basic;
+ }
+
+ protected function getLoggedInLoginDataWithRedirectUrl(): LoginData {
+ $data = new LoginData(
+ $this->request,
+ $this->username,
+ $this->password,
+ $this->redirectUrl
+ );
+ $data->setUser($this->user);
+ return $data;
+ }
+
+ protected function getLoggedInLoginDataWithTimezone(): LoginData {
+ $data = new LoginData(
+ $this->request,
+ $this->username,
+ $this->password,
+ null,
+ $this->timezone,
+ $this->timeZoneOffset
+ );
+ $data->setUser($this->user);
+ return $data;
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace Test\Authentication\Login;
+
+use lib\Authentication\Login\ALoginCommandTest;
+use OC\Authentication\Login\ClearLostPasswordTokensCommand;
+use OC\Authentication\Login\LoginData;
+use OCP\IConfig;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class ClearLostPasswordTokensCommandTest extends ALoginCommandTest {
+
+ /** @var IConfig|MockObject */
+ private $config;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+
+ $this->cmd = new ClearLostPasswordTokensCommand(
+ $this->config
+ );
+ }
+
+ public function testProcess() {
+ $data = $this->getLoggedInLoginData();
+ $this->user->expects($this->once())
+ ->method('getUID')
+ ->willReturn($this->username);
+ $this->config->expects($this->once())
+ ->method('deleteUserValue')
+ ->with(
+ $this->username,
+ 'core',
+ 'lostpassword'
+ );
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\CompleteLoginCommand;
+use OC\User\Session;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class CompleteLoginCommandTest extends ALoginCommandTest {
+
+ /** @var Session|MockObject */
+ private $session;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->session = $this->createMock(Session::class);
+
+ $this->cmd = new CompleteLoginCommand(
+ $this->session
+ );
+ }
+
+ public function testProcess() {
+ $data = $this->getLoggedInLoginData();
+ $this->session->expects($this->once())
+ ->method('completeLogin')
+ ->with(
+ $this->user,
+ $this->equalTo(
+ [
+ 'loginName' => $this->username,
+ 'password' => $this->password,
+ ]
+ )
+ );
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\CreateSessionTokenCommand;
+use OC\Authentication\Token\IToken;
+use OC\User\Session;
+use OCP\IConfig;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class CreateSessionTokenCommandTest extends ALoginCommandTest {
+
+ /** @var IConfig|MockObject */
+ private $config;
+
+ /** @var Session|MockObject */
+ private $userSession;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+ $this->userSession = $this->createMock(Session::class);
+
+ $this->cmd = new CreateSessionTokenCommand(
+ $this->config,
+ $this->userSession
+ );
+ }
+
+ public function testProcess() {
+ $data = $this->getLoggedInLoginData();
+ $this->config->expects($this->once())
+ ->method('getSystemValue')
+ ->with(
+ 'remember_login_cookie_lifetime',
+ 60 * 60 * 24 * 15
+ )
+ ->willReturn(100);
+ $this->user->expects($this->any())
+ ->method('getUID')
+ ->willReturn($this->username);
+ $this->userSession->expects($this->once())
+ ->method('createSessionToken')
+ ->with(
+ $this->request,
+ $this->username,
+ $this->username,
+ $this->password,
+ IToken::REMEMBER
+ );
+ $this->userSession->expects($this->once())
+ ->method('updateTokens')
+ ->with(
+ $this->username,
+ $this->username
+ );
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcessDoNotRemember() {
+ $data = $this->getLoggedInLoginData();
+ $this->config->expects($this->once())
+ ->method('getSystemValue')
+ ->with(
+ 'remember_login_cookie_lifetime',
+ 60 * 60 * 24 * 15
+ )
+ ->willReturn(0);
+ $this->user->expects($this->any())
+ ->method('getUID')
+ ->willReturn($this->username);
+ $this->userSession->expects($this->once())
+ ->method('createSessionToken')
+ ->with(
+ $this->request,
+ $this->username,
+ $this->username,
+ $this->password,
+ IToken::DO_NOT_REMEMBER
+ );
+ $this->userSession->expects($this->once())
+ ->method('updateTokens')
+ ->with(
+ $this->username,
+ $this->username
+ );
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertFalse($data->isRememberLogin());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\EmailLoginCommand;
+use OCP\IUser;
+use OCP\IUserManager;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class EmailLoginCommandTest extends ALoginCommandTest {
+
+ /** @var IUserManager|MockObject */
+ private $userManager;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->userManager = $this->createMock(IUserManager::class);
+
+ $this->cmd = new EmailLoginCommand(
+ $this->userManager
+ );
+ }
+
+ public function testProcessAlreadyLoggedIn() {
+ $data = $this->getLoggedInLoginData();
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcessNotAnEmailLogin() {
+ $data = $this->getFailedLoginData();
+ $this->userManager->expects($this->once())
+ ->method('getByEmail')
+ ->with($this->username)
+ ->willReturn([]);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcessDuplicateEmailLogin() {
+ $data = $this->getFailedLoginData();
+ $this->userManager->expects($this->once())
+ ->method('getByEmail')
+ ->with($this->username)
+ ->willReturn([
+ $this->createMock(IUser::class),
+ $this->createMock(IUser::class),
+ ]);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcessUidIsEmail() {
+ $email = 'user@domain.com';
+ $data = $this->getFailedLoginData();
+ $data->setUsername($email);
+ $emailUser = $this->createMock(IUser::class);
+ $emailUser->expects($this->any())
+ ->method('getUID')
+ ->willReturn($email);
+ $this->userManager->expects($this->once())
+ ->method('getByEmail')
+ ->with($email)
+ ->willReturn([
+ $emailUser,
+ ]);
+ $this->userManager->expects($this->never())
+ ->method('checkPassword');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertFalse($data->getUser());
+ $this->assertEquals($email, $data->getUsername());
+ }
+
+ public function testProcessWrongPassword() {
+ $email = 'user@domain.com';
+ $data = $this->getFailedLoginData();
+ $data->setUsername($email);
+ $emailUser = $this->createMock(IUser::class);
+ $emailUser->expects($this->any())
+ ->method('getUID')
+ ->willReturn('user2');
+ $this->userManager->expects($this->once())
+ ->method('getByEmail')
+ ->with($email)
+ ->willReturn([
+ $emailUser,
+ ]);
+ $this->userManager->expects($this->once())
+ ->method('checkPassword')
+ ->with(
+ 'user2',
+ $this->password
+ )
+ ->willReturn(false);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertFalse($data->getUser());
+ $this->assertEquals($email, $data->getUsername());
+ }
+
+ public function testProcess() {
+ $email = 'user@domain.com';
+ $data = $this->getFailedLoginData();
+ $data->setUsername($email);
+ $emailUser = $this->createMock(IUser::class);
+ $emailUser->expects($this->any())
+ ->method('getUID')
+ ->willReturn('user2');
+ $this->userManager->expects($this->once())
+ ->method('getByEmail')
+ ->with($email)
+ ->willReturn([
+ $emailUser,
+ ]);
+ $this->userManager->expects($this->once())
+ ->method('checkPassword')
+ ->with(
+ 'user2',
+ $this->password
+ )
+ ->willReturn($emailUser);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertEquals($emailUser, $data->getUser());
+ $this->assertEquals('user2', $data->getUsername());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\FinishRememberedLoginCommand;
+use OC\User\Session;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class FinishRememberedLoginCommandTest extends ALoginCommandTest {
+
+ /** @var Session|MockObject */
+ private $userSession;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->userSession = $this->createMock(Session::class);
+
+ $this->cmd = new FinishRememberedLoginCommand(
+ $this->userSession
+ );
+ }
+
+ public function testProcessNotRememberedLogin() {
+ $data = $this->getLoggedInLoginData();
+ $data->setRememberLogin(false);
+ $this->userSession->expects($this->never())
+ ->method('createRememberMeToken');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcess() {
+ $data = $this->getLoggedInLoginData();
+ $this->userSession->expects($this->once())
+ ->method('createRememberMeToken')
+ ->with($this->user);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\LoggedInCheckCommand;
+use OC\Core\Controller\LoginController;
+use OCP\ILogger;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class LoggedInCheckCommandTest extends ALoginCommandTest {
+
+ /** @var ILogger|MockObject */
+ private $logger;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->logger = $this->createMock(ILogger::class);
+
+ $this->cmd = new LoggedInCheckCommand(
+ $this->logger
+ );
+ }
+
+ public function testProcessSuccessfulLogin() {
+ $data = $this->getLoggedInLoginData();
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcessFailedLogin() {
+ $data = $this->getFailedLoginData();
+ $this->logger->expects($this->once())
+ ->method('warning');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertFalse($result->isSuccess());
+ $this->assertSame(LoginController::LOGIN_MSG_INVALIDPASSWORD, $result->getErrorMessage());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\PreLoginHookCommand;
+use OC\User\Manager;
+use OCP\IUserManager;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class PreLoginHookCommandTest extends ALoginCommandTest {
+
+ /** @var IUserManager|MockObject */
+ private $userManager;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->userManager = $this->createMock(Manager::class);
+
+ $this->cmd = new PreLoginHookCommand(
+ $this->userManager
+ );
+ }
+
+ public function testProcess() {
+ $data = $this->getBasicLoginData();
+ $this->userManager->expects($this->once())
+ ->method('emit')
+ ->with(
+ '\OC\User',
+ 'preLogin',
+ [
+ $this->username,
+ $this->password,
+ ]
+ );
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\SetUserTimezoneCommand;
+use OCP\IConfig;
+use OCP\ISession;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class SetUserTimezoneCommandTest extends ALoginCommandTest {
+
+ /** @var IConfig|MockObject */
+ private $config;
+
+ /** @var ISession|MockObject */
+ private $session;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+ $this->session = $this->createMock(ISession::class);
+
+ $this->cmd = new SetUserTimezoneCommand(
+ $this->config,
+ $this->session
+ );
+ }
+
+ public function testProcessNoTimezoneSet() {
+ $data = $this->getLoggedInLoginData();
+ $this->config->expects($this->never())
+ ->method('setUserValue');
+ $this->session->expects($this->never())
+ ->method('set');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcess() {
+ $data = $this->getLoggedInLoginDataWithTimezone();
+ $this->user->expects($this->once())
+ ->method('getUID')
+ ->willReturn($this->username);
+ $this->config->expects($this->once())
+ ->method('setUserValue')
+ ->with(
+ $this->username,
+ 'core',
+ 'timezone',
+ $this->timezone
+ );
+ $this->session->expects($this->once())
+ ->method('set')
+ ->with(
+ 'timezone',
+ $this->timeZoneOffset
+ );
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\TwoFactorCommand;
+use OC\Authentication\TwoFactorAuth\Manager;
+use OC\Authentication\TwoFactorAuth\ProviderSet;
+use OCP\Authentication\TwoFactorAuth\IProvider as ITwoFactorAuthProvider;
+use OCP\IURLGenerator;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class TwoFactorCommandTest extends ALoginCommandTest {
+
+ /** @var Manager|MockObject */
+ private $twoFactorManager;
+
+ /** @var IURLGenerator|MockObject */
+ private $urlGenerator;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->twoFactorManager = $this->createMock(Manager::class);
+ $this->urlGenerator = $this->createMock(IURLGenerator::class);
+
+ $this->cmd = new TwoFactorCommand(
+ $this->twoFactorManager,
+ $this->urlGenerator
+ );
+ }
+
+ public function testNotTwoFactorAuthenticated() {
+ $data = $this->getLoggedInLoginData();
+ $this->twoFactorManager->expects($this->once())
+ ->method('isTwoFactorAuthenticated')
+ ->willReturn(false);
+ $this->twoFactorManager->expects($this->never())
+ ->method('prepareTwoFactorLogin');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcessOneActiveProvider() {
+ $data = $this->getLoggedInLoginData();
+ $this->twoFactorManager->expects($this->once())
+ ->method('isTwoFactorAuthenticated')
+ ->willReturn(true);
+ $this->twoFactorManager->expects($this->once())
+ ->method('prepareTwoFactorLogin')
+ ->with(
+ $this->user,
+ $data->isRememberLogin()
+ );
+ $provider = $this->createMock(ITwoFactorAuthProvider::class);
+ $this->twoFactorManager->expects($this->once())
+ ->method('getProviderSet')
+ ->willReturn(new ProviderSet([
+ $provider,
+ ], false));
+ $provider->expects($this->once())
+ ->method('getId')
+ ->willReturn('test');
+ $this->urlGenerator->expects($this->once())
+ ->method('linkToRoute')
+ ->with(
+ 'core.TwoFactorChallenge.showChallenge',
+ [
+ 'challengeProviderId' => 'test'
+ ]
+ )
+ ->willReturn('two/factor/url');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertEquals('two/factor/url', $result->getRedirectUrl());
+ }
+
+ public function testProcessTwoActiveProviders() {
+ $data = $this->getLoggedInLoginData();
+ $this->twoFactorManager->expects($this->once())
+ ->method('isTwoFactorAuthenticated')
+ ->willReturn(true);
+ $this->twoFactorManager->expects($this->once())
+ ->method('prepareTwoFactorLogin')
+ ->with(
+ $this->user,
+ $data->isRememberLogin()
+ );
+ $provider1 = $this->createMock(ITwoFactorAuthProvider::class);
+ $provider2 = $this->createMock(ITwoFactorAuthProvider::class);
+ $provider1->expects($this->once())
+ ->method('getId')
+ ->willReturn('test1');
+ $provider2->expects($this->once())
+ ->method('getId')
+ ->willReturn('test2');
+ $this->twoFactorManager->expects($this->once())
+ ->method('getProviderSet')
+ ->willReturn(new ProviderSet([
+ $provider1,
+ $provider2,
+ ], false));
+ $this->urlGenerator->expects($this->once())
+ ->method('linkToRoute')
+ ->with(
+ 'core.TwoFactorChallenge.selectChallenge'
+ )
+ ->willReturn('two/factor/url');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertEquals('two/factor/url', $result->getRedirectUrl());
+ }
+
+ public function testProcessWithRedirectUrl() {
+ $data = $this->getLoggedInLoginDataWithRedirectUrl();
+ $this->twoFactorManager->expects($this->once())
+ ->method('isTwoFactorAuthenticated')
+ ->willReturn(true);
+ $this->twoFactorManager->expects($this->once())
+ ->method('prepareTwoFactorLogin')
+ ->with(
+ $this->user,
+ $data->isRememberLogin()
+ );
+ $provider = $this->createMock(ITwoFactorAuthProvider::class);
+ $this->twoFactorManager->expects($this->once())
+ ->method('getProviderSet')
+ ->willReturn(new ProviderSet([
+ $provider,
+ ], false));
+ $provider->expects($this->once())
+ ->method('getId')
+ ->willReturn('test');
+ $this->urlGenerator->expects($this->once())
+ ->method('linkToRoute')
+ ->with(
+ 'core.TwoFactorChallenge.showChallenge',
+ [
+ 'challengeProviderId' => 'test',
+ 'redirect_url' => $this->redirectUrl,
+ ]
+ )
+ ->willReturn('two/factor/url');
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertEquals('two/factor/url', $result->getRedirectUrl());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\UidCheckCommand;
+use OC\Authentication\Login\UidLoginCommand;
+use OC\User\Manager;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class UidLoginCommandTest extends ALoginCommandTest {
+
+ /** @var Manager|MockObject */
+ private $userManager;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->userManager = $this->createMock(Manager::class);
+
+ $this->cmd = new UidLoginCommand(
+ $this->userManager
+ );
+ }
+
+ public function testProcessFailingLogin() {
+ $data = $this->getBasicLoginData();
+ $this->userManager->expects($this->once())
+ ->method('checkPasswordNoLogging')
+ ->with(
+ $this->username,
+ $this->password
+ )
+ ->willReturn(false);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertFalse($data->getUser());
+ }
+
+ public function testProcess() {
+ $data = $this->getBasicLoginData();
+ $this->userManager->expects($this->once())
+ ->method('checkPasswordNoLogging')
+ ->with(
+ $this->username,
+ $this->password
+ )
+ ->willReturn($this->user);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ $this->assertEquals($this->user, $data->getUser());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\UpdateLastPasswordConfirmCommand;
+use OCP\ISession;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class UpdateLastPasswordConfirmCommandTest extends ALoginCommandTest {
+
+ /** @var ISession|MockObject */
+ private $session;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->session = $this->createMock(ISession::class);
+
+ $this->cmd = new UpdateLastPasswordConfirmCommand(
+ $this->session
+ );
+ }
+
+ public function testProcess() {
+ $data = $this->getLoggedInLoginData();
+ $this->user->expects($this->once())
+ ->method('getLastLogin')
+ ->willReturn(1234);
+ $this->session->expects($this->once())
+ ->method('set')
+ ->with(
+ 'last-password-confirm',
+ 1234
+ );
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+declare(strict_types=1);
+
+namespace lib\Authentication\Login;
+
+use OC\Authentication\Login\UserDisabledCheckCommand;
+use OC\Core\Controller\LoginController;
+use OCP\ILogger;
+use OCP\IUserManager;
+use PHPUnit\Framework\MockObject\MockObject;
+
+class UserDisabledCheckCommandTest extends ALoginCommandTest {
+
+ /** @var IUserManager|MockObject */
+ private $userManager;
+
+ /** @var ILogger|MockObject */
+ private $logger;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->userManager = $this->createMock(IUserManager::class);
+ $this->logger = $this->createMock(ILogger::class);
+
+ $this->cmd = new UserDisabledCheckCommand(
+ $this->userManager,
+ $this->logger
+ );
+ }
+
+ public function testProcessNonExistingUser() {
+ $data = $this->getBasicLoginData();
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($this->username)
+ ->willReturn(null);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+ public function testProcessDisabledUser() {
+ $data = $this->getBasicLoginData();
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($this->username)
+ ->willReturn($this->user);
+ $this->user->expects($this->once())
+ ->method('isEnabled')
+ ->willReturn(false);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertFalse($result->isSuccess());
+ $this->assertSame(LoginController::LOGIN_MSG_USERDISABLED, $result->getErrorMessage());
+ }
+
+ public function testProcess() {
+ $data = $this->getBasicLoginData();
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with($this->username)
+ ->willReturn($this->user);
+ $this->user->expects($this->once())
+ ->method('isEnabled')
+ ->willReturn(true);
+
+ $result = $this->cmd->process($data);
+
+ $this->assertTrue($result->isSuccess());
+ }
+
+}