Add a login chain to reduce the complexity of LoginController::tryLogin
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
This commit is contained in:
parent
5893f218c2
commit
170582d4f5
34 changed files with 2487 additions and 456 deletions
|
@ -33,7 +33,8 @@
|
|||
|
||||
namespace OC\Core\Controller;
|
||||
|
||||
use OC\Authentication\Token\IToken;
|
||||
use OC\Authentication\Login\Chain;
|
||||
use OC\Authentication\Login\LoginData;
|
||||
use OC\Authentication\TwoFactorAuth\Manager;
|
||||
use OC\Security\Bruteforce\Throttler;
|
||||
use OC\User\Session;
|
||||
|
@ -44,17 +45,14 @@ use OCP\AppFramework\Http;
|
|||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\Authentication\TwoFactorAuth\IProvider;
|
||||
use OCP\Defaults;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IUserSession;
|
||||
use OC\Hooks\PublicEmitter;
|
||||
use OCP\Util;
|
||||
|
||||
class LoginController extends Controller {
|
||||
|
@ -74,27 +72,14 @@ class LoginController extends Controller {
|
|||
private $urlGenerator;
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
/** @var Manager */
|
||||
private $twoFactorManager;
|
||||
/** @var Defaults */
|
||||
private $defaults;
|
||||
/** @var Throttler */
|
||||
private $throttler;
|
||||
/** @var Chain */
|
||||
private $loginChain;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
* @param IRequest $request
|
||||
* @param IUserManager $userManager
|
||||
* @param IConfig $config
|
||||
* @param ISession $session
|
||||
* @param IUserSession $userSession
|
||||
* @param IURLGenerator $urlGenerator
|
||||
* @param ILogger $logger
|
||||
* @param Manager $twoFactorManager
|
||||
* @param Defaults $defaults
|
||||
* @param Throttler $throttler
|
||||
*/
|
||||
public function __construct($appName,
|
||||
public function __construct(?string $appName,
|
||||
IRequest $request,
|
||||
IUserManager $userManager,
|
||||
IConfig $config,
|
||||
|
@ -102,9 +87,9 @@ class LoginController extends Controller {
|
|||
IUserSession $userSession,
|
||||
IURLGenerator $urlGenerator,
|
||||
ILogger $logger,
|
||||
Manager $twoFactorManager,
|
||||
Defaults $defaults,
|
||||
Throttler $throttler) {
|
||||
Throttler $throttler,
|
||||
Chain $loginChain) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->userManager = $userManager;
|
||||
$this->config = $config;
|
||||
|
@ -112,9 +97,9 @@ class LoginController extends Controller {
|
|||
$this->userSession = $userSession;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->logger = $logger;
|
||||
$this->twoFactorManager = $twoFactorManager;
|
||||
$this->defaults = $defaults;
|
||||
$this->throttler = $throttler;
|
||||
$this->loginChain = $loginChain;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,8 +211,8 @@ class LoginController extends Controller {
|
|||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
private function setPasswordResetParameters(
|
||||
string $user = null, array $parameters): array {
|
||||
private function setPasswordResetParameters(?string $user,
|
||||
array $parameters): array {
|
||||
if ($user !== null && $user !== '') {
|
||||
$userObj = $this->userManager->get($user);
|
||||
} else {
|
||||
|
@ -250,12 +235,8 @@ class LoginController extends Controller {
|
|||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $redirectUrl
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
private function generateRedirect($redirectUrl) {
|
||||
if (!is_null($redirectUrl) && $this->userSession->isLoggedIn()) {
|
||||
private function generateRedirect(?string $redirectUrl): RedirectResponse {
|
||||
if ($redirectUrl !== null && $this->userSession->isLoggedIn()) {
|
||||
$location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl));
|
||||
// Deny the redirect if the URL contains a @
|
||||
// This prevents unvalidated redirects like ?redirect_url=:user@domain.com
|
||||
|
@ -275,16 +256,15 @@ class LoginController extends Controller {
|
|||
* @param string $user
|
||||
* @param string $password
|
||||
* @param string $redirect_url
|
||||
* @param boolean $remember_login
|
||||
* @param string $timezone
|
||||
* @param string $timezone_offset
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function tryLogin($user, $password, $redirect_url, $remember_login = true, $timezone = '', $timezone_offset = '') {
|
||||
if(!is_string($user)) {
|
||||
throw new \InvalidArgumentException('Username must be string');
|
||||
}
|
||||
|
||||
public function tryLogin(string $user,
|
||||
string $password,
|
||||
string $redirect_url = null,
|
||||
string $timezone = '',
|
||||
string $timezone_offset = ''): RedirectResponse {
|
||||
// If the user is already logged in and the CSRF check does not pass then
|
||||
// simply redirect the user to the correct page as required. This is the
|
||||
// case when an user has already logged-in, in another tab.
|
||||
|
@ -292,96 +272,27 @@ class LoginController extends Controller {
|
|||
return $this->generateRedirect($redirect_url);
|
||||
}
|
||||
|
||||
if ($this->userManager instanceof PublicEmitter) {
|
||||
$this->userManager->emit('\OC\User', 'preLogin', array($user, $password));
|
||||
$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()
|
||||
);
|
||||
}
|
||||
|
||||
$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);
|
||||
if ($result->getRedirectUrl() !== null) {
|
||||
return new RedirectResponse($result->getRedirectUrl());
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
if ($remember_login) {
|
||||
$this->userSession->createRememberMeToken($loginResult);
|
||||
}
|
||||
|
||||
return $this->generateRedirect($redirect_url);
|
||||
}
|
||||
|
||||
|
@ -398,8 +309,8 @@ class LoginController extends Controller {
|
|||
$user, $originalUser, $redirect_url, string $loginMessage) {
|
||||
// Read current user and append if possible we need to
|
||||
// return the unmodified user otherwise we will leak the login name
|
||||
$args = !is_null($user) ? ['user' => $originalUser] : [];
|
||||
if (!is_null($redirect_url)) {
|
||||
$args = $user !== null ? ['user' => $originalUser] : [];
|
||||
if ($redirect_url !== null) {
|
||||
$args['redirect_url'] = $redirect_url;
|
||||
}
|
||||
$response = new RedirectResponse(
|
||||
|
|
|
@ -506,6 +506,22 @@ return array(
|
|||
'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',
|
||||
|
|
|
@ -536,6 +536,22 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'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',
|
||||
|
|
47
lib/private/Authentication/Login/ALoginCommand.php
Normal file
47
lib/private/Authentication/Login/ALoginCommand.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?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;
|
||||
|
||||
}
|
111
lib/private/Authentication/Login/Chain.php
Normal file
111
lib/private/Authentication/Login/Chain.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
50
lib/private/Authentication/Login/CompleteLoginCommand.php
Normal file
50
lib/private/Authentication/Login/CompleteLoginCommand.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?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);
|
||||
}
|
||||
}
|
61
lib/private/Authentication/Login/EmailLoginCommand.php
Normal file
61
lib/private/Authentication/Login/EmailLoginCommand.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
53
lib/private/Authentication/Login/LoggedInCheckCommand.php
Normal file
53
lib/private/Authentication/Login/LoggedInCheckCommand.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
121
lib/private/Authentication/Login/LoginData.php
Normal file
121
lib/private/Authentication/Login/LoginData.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?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;
|
||||
}
|
||||
|
||||
}
|
83
lib/private/Authentication/Login/LoginResult.php
Normal file
83
lib/private/Authentication/Login/LoginResult.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?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;
|
||||
}
|
||||
|
||||
}
|
54
lib/private/Authentication/Login/PreLoginHookCommand.php
Normal file
54
lib/private/Authentication/Login/PreLoginHookCommand.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?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);
|
||||
}
|
||||
}
|
62
lib/private/Authentication/Login/SetUserTimezoneCommand.php
Normal file
62
lib/private/Authentication/Login/SetUserTimezoneCommand.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
79
lib/private/Authentication/Login/TwoFactorCommand.php
Normal file
79
lib/private/Authentication/Login/TwoFactorCommand.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?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)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
57
lib/private/Authentication/Login/UidLoginCommand.php
Normal file
57
lib/private/Authentication/Login/UidLoginCommand.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
<?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);
|
||||
}
|
||||
|
||||
}
|
|
@ -196,7 +196,7 @@ class Manager extends PublicEmitter implements IUserManager {
|
|||
* @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);
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
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;
|
||||
|
@ -39,32 +42,47 @@ use OCP\ISession;
|
|||
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);
|
||||
|
@ -77,6 +95,7 @@ class LoginControllerTest extends TestCase {
|
|||
$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');
|
||||
|
@ -95,9 +114,9 @@ class LoginControllerTest extends TestCase {
|
|||
$this->userSession,
|
||||
$this->urlGenerator,
|
||||
$this->logger,
|
||||
$this->twoFactorManager,
|
||||
$this->defaults,
|
||||
$this->throttler
|
||||
$this->throttler,
|
||||
$this->chain
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -292,51 +311,6 @@ class LoginControllerTest extends TestCase {
|
|||
$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())
|
||||
|
@ -386,43 +360,34 @@ class LoginControllerTest extends TestCase {
|
|||
->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();
|
||||
|
||||
|
@ -430,87 +395,25 @@ class LoginControllerTest extends TestCase {
|
|||
->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();
|
||||
$response = $this->loginController->tryLogin($user, $password);
|
||||
|
||||
$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);
|
||||
|
||||
$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')
|
||||
|
@ -536,7 +439,7 @@ class LoginControllerTest extends TestCase {
|
|||
}
|
||||
|
||||
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')
|
||||
|
@ -571,196 +474,76 @@ class LoginControllerTest extends TestCase {
|
|||
}
|
||||
|
||||
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($redirectUrl);
|
||||
|
||||
$expected = new \OCP\AppFramework\Http\RedirectResponse(urldecode($redirectUrl));
|
||||
$this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
|
||||
}
|
||||
$response = $this->loginController->tryLogin($user, $password, '%2Fapps%2Fmail');
|
||||
|
||||
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');
|
||||
|
||||
$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');
|
||||
|
||||
$expected = new RedirectResponse($challengeUrl);
|
||||
$this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
|
||||
}
|
||||
|
||||
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');
|
||||
|
||||
$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.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));
|
||||
$this->assertEquals($expected, $response);
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
$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');
|
||||
|
||||
$expected = new RedirectResponse('');
|
||||
$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.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->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', 'just wrong', null));
|
||||
|
||||
$response = $this->loginController->tryLogin(
|
||||
'john@doe.com',
|
||||
'just wrong',
|
||||
'/apps/files'
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $response);
|
||||
}
|
||||
}
|
||||
|
|
122
tests/lib/Authentication/Login/ALoginCommandTest.php
Normal file
122
tests/lib/Authentication/Login/ALoginCommandTest.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
67
tests/lib/Authentication/Login/CompleteLoginCommandTest.php
Normal file
67
tests/lib/Authentication/Login/CompleteLoginCommandTest.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
|
||||
}
|
121
tests/lib/Authentication/Login/CreateSessionTokenCommandTest.php
Normal file
121
tests/lib/Authentication/Login/CreateSessionTokenCommandTest.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
165
tests/lib/Authentication/Login/EmailLoginCommandTest.php
Normal file
165
tests/lib/Authentication/Login/EmailLoginCommandTest.php
Normal file
|
@ -0,0 +1,165 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
67
tests/lib/Authentication/Login/LoggedInCheckCommandTest.php
Normal file
67
tests/lib/Authentication/Login/LoggedInCheckCommandTest.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
66
tests/lib/Authentication/Login/PreLoginHookCommandTest.php
Normal file
66
tests/lib/Authentication/Login/PreLoginHookCommandTest.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
179
tests/lib/Authentication/Login/TwoFactorCommandTest.php
Normal file
179
tests/lib/Authentication/Login/TwoFactorCommandTest.php
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
80
tests/lib/Authentication/Login/UidLoginCommandTest.php
Normal file
80
tests/lib/Authentication/Login/UidLoginCommandTest.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?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());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue