'OCP\\App\\AppPathNotFoundException' => $baseDir . '/lib/public/App/AppPathNotFoundException.php',
'OCP\\App\\IAppManager' => $baseDir . '/lib/public/App/IAppManager.php',
'OCP\\App\\ManagerEvent' => $baseDir . '/lib/public/App/ManagerEvent.php',
+ 'OCP\\Authentication\\Events\\LoginFailedEvent' => $baseDir . '/lib/public/Authentication/Events/LoginFailedEvent.php',
'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => $baseDir . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php',
'OCP\\Authentication\\Exceptions\\PasswordUnavailableException' => $baseDir . '/lib/public/Authentication/Exceptions/PasswordUnavailableException.php',
'OCP\\Authentication\\IApacheBackend' => $baseDir . '/lib/public/Authentication/IApacheBackend.php',
'OC\\Archive\\TAR' => $baseDir . '/lib/private/Archive/TAR.php',
'OC\\Archive\\ZIP' => $baseDir . '/lib/private/Archive/ZIP.php',
'OC\\Authentication\\Events\\ARemoteWipeEvent' => $baseDir . '/lib/private/Authentication/Events/ARemoteWipeEvent.php',
+ 'OC\\Authentication\\Events\\LoginFailed' => $baseDir . '/lib/private/Authentication/Events/LoginFailed.php',
'OC\\Authentication\\Events\\RemoteWipeFinished' => $baseDir . '/lib/private/Authentication/Events/RemoteWipeFinished.php',
'OC\\Authentication\\Events\\RemoteWipeStarted' => $baseDir . '/lib/private/Authentication/Events/RemoteWipeStarted.php',
'OC\\Authentication\\Exceptions\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php',
'OC\\Authentication\\Exceptions\\TwoFactorAuthRequiredException' => $baseDir . '/lib/private/Authentication/Exceptions/TwoFactorAuthRequiredException.php',
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => $baseDir . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
'OC\\Authentication\\Exceptions\\WipeTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/WipeTokenException.php',
+ 'OC\\Authentication\\Listeners\\LoginFailedListener' => $baseDir . '/lib/private/Authentication/Listeners/LoginFailedListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeActivityListener' => $baseDir . '/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeEmailListener' => $baseDir . '/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeNotificationsListener' => $baseDir . '/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php',
'OCP\\App\\AppPathNotFoundException' => __DIR__ . '/../../..' . '/lib/public/App/AppPathNotFoundException.php',
'OCP\\App\\IAppManager' => __DIR__ . '/../../..' . '/lib/public/App/IAppManager.php',
'OCP\\App\\ManagerEvent' => __DIR__ . '/../../..' . '/lib/public/App/ManagerEvent.php',
+ 'OCP\\Authentication\\Events\\LoginFailedEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/Events/LoginFailedEvent.php',
'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php',
'OCP\\Authentication\\Exceptions\\PasswordUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/PasswordUnavailableException.php',
'OCP\\Authentication\\IApacheBackend' => __DIR__ . '/../../..' . '/lib/public/Authentication/IApacheBackend.php',
'OC\\Archive\\TAR' => __DIR__ . '/../../..' . '/lib/private/Archive/TAR.php',
'OC\\Archive\\ZIP' => __DIR__ . '/../../..' . '/lib/private/Archive/ZIP.php',
'OC\\Authentication\\Events\\ARemoteWipeEvent' => __DIR__ . '/../../..' . '/lib/private/Authentication/Events/ARemoteWipeEvent.php',
+ 'OC\\Authentication\\Events\\LoginFailed' => __DIR__ . '/../../..' . '/lib/private/Authentication/Events/LoginFailed.php',
'OC\\Authentication\\Events\\RemoteWipeFinished' => __DIR__ . '/../../..' . '/lib/private/Authentication/Events/RemoteWipeFinished.php',
'OC\\Authentication\\Events\\RemoteWipeStarted' => __DIR__ . '/../../..' . '/lib/private/Authentication/Events/RemoteWipeStarted.php',
'OC\\Authentication\\Exceptions\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php',
'OC\\Authentication\\Exceptions\\TwoFactorAuthRequiredException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/TwoFactorAuthRequiredException.php',
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
'OC\\Authentication\\Exceptions\\WipeTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/WipeTokenException.php',
+ 'OC\\Authentication\\Listeners\\LoginFailedListener' => __DIR__ . '/../../..' . '/lib/private/Authentication/Listeners/LoginFailedListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeActivityListener' => __DIR__ . '/../../..' . '/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeEmailListener' => __DIR__ . '/../../..' . '/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeNotificationsListener' => __DIR__ . '/../../..' . '/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php',
--- /dev/null
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @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/>.
+ *
+ */
+
+namespace OC\Authentication\Events;
+
+use OCP\EventDispatcher\Event;
+
+class LoginFailed extends Event {
+
+ /** @var string */
+ private $loginName;
+
+ public function __construct(string $loginName) {
+ parent::__construct();
+
+ $this->loginName = $loginName;
+ }
+
+ public function getLoginName(): string {
+ return $this->loginName;
+ }
+}
--- /dev/null
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @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/>.
+ *
+ */
+
+namespace OC\Authentication\Listeners;
+
+use OC\Authentication\Events\LoginFailed;
+use OCP\Authentication\Events\LoginFailedEvent;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IUserManager;
+use OCP\Util;
+
+class LoginFailedListener implements IEventListener {
+
+ /** @var IEventDispatcher */
+ private $dispatcher;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ public function __construct(IEventDispatcher $dispatcher, IUserManager $userManager) {
+ $this->dispatcher = $dispatcher;
+ $this->userManager = $userManager;
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof LoginFailed)) {
+ return;
+ }
+
+ $uid = $event->getLoginName();
+ Util::emitHook(
+ '\OCA\Files_Sharing\API\Server2Server',
+ 'preLoginNameUsedAsUserName',
+ ['uid' => &$uid]
+ );
+ if($this->userManager->userExists($uid)) {
+ $this->dispatcher->dispatchTyped(new LoginFailedEvent($uid));
+ }
+ }
+
+}
namespace OC\Authentication\Login;
+use OC\Authentication\Events\LoginFailed;
use OC\Core\Controller\LoginController;
+use OCP\Authentication\Events\LoginFailedEvent;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
+use OCP\IUserManager;
+use OCP\Util;
class LoggedInCheckCommand extends ALoginCommand {
/** @var ILogger */
private $logger;
+ /** @var IEventDispatcher */
+ private $dispatcher;
+ /** @var IUserManager */
+ private $userManager;
- public function __construct(ILogger $logger) {
+ public function __construct(ILogger $logger, IEventDispatcher $dispatcher) {
$this->logger = $logger;
+ $this->dispatcher = $dispatcher;
}
public function process(LoginData $loginData): LoginResult {
if ($loginData->getUser() === false) {
- $username = $loginData->getUsername();
+ $loginName = $loginData->getUsername();
$ip = $loginData->getRequest()->getRemoteAddress();
- $this->logger->warning("Login failed: $username (Remote IP: $ip)");
+ $this->logger->warning("Login failed: $loginName (Remote IP: $ip)");
+
+ $this->dispatcher->dispatchTyped(new LoginFailed($loginName));
return LoginResult::failure($loginData, LoginController::LOGIN_MSG_INVALIDPASSWORD);
}
use OC\AppFramework\Http\Request;
use OC\AppFramework\Utility\SimpleContainer;
use OC\AppFramework\Utility\TimeFactory;
+use OC\Authentication\Events\LoginFailed;
+use OC\Authentication\Listeners\LoginFailedListener;
use OC\Authentication\LoginCredentials\Store;
use OC\Authentication\Token\IProvider;
use OC\Avatar\AvatarManager;
// no avatar to remove
}
});
+
+ /** @var IEventDispatcher $eventDispatched */
+ $eventDispatched = $this->query(IEventDispatcher::class);
+ $eventDispatched->addServiceListener(LoginFailed::class, LoginFailedListener::class);
}
/**
use OC_Util;
use OCA\DAV\Connector\Sabre\Auth;
use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Authentication\Events\LoginFailedEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\NotPermittedException;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
use OCP\IUser;
+use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Lockdown\ILockdownManager;
use OCP\Security\ISecureRandom;
ISecureRandom $random,
ILockdownManager $lockdownManager,
ILogger $logger,
- IEventDispatcher $dispatcher) {
+ IEventDispatcher $dispatcher
+ ) {
$this->manager = $manager;
$this->session = $session;
$this->timeFactory = $timeFactory;
$this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
$throttler->registerAttempt('login', $request->getRemoteAddress(), ['user' => $user]);
+
+ $this->dispatcher->dispatchTyped(new OC\Authentication\Events\LoginFailed($user));
+
if ($currentDelay === 0) {
$throttler->sleepDelay($request->getRemoteAddress(), 'login');
}
--- /dev/null
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @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/>.
+ *
+ */
+
+namespace OCP\Authentication\Events;
+
+use OCP\EventDispatcher\Event;
+
+/**
+ * Class LoginFailedEvent
+ *
+ * @package OCP\Authentication\Events
+ *
+ * @since 19.0.0
+ */
+class LoginFailedEvent extends Event {
+
+ /** @var string */
+ private $uid;
+
+ /**
+ * @since 19.0.0
+ */
+ public function __construct(string $uid) {
+ parent::__construct();
+
+ $this->uid = $uid;
+ }
+
+ /**
+ * returns the uid of the user that was tried to login against
+ *
+ * @since 19.0.0
+ */
+ public function getUid(): string {
+ return $this->uid;
+ }
+}
namespace lib\Authentication\Login;
+use Hoa\Iterator\Mock;
use OC\Authentication\Login\LoggedInCheckCommand;
use OC\Core\Controller\LoginController;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use PHPUnit\Framework\MockObject\MockObject;
/** @var ILogger|MockObject */
private $logger;
+ /** @var IEventDispatcher|MockObject */
+ private $dispatcher;
+
protected function setUp(): void {
parent::setUp();
$this->logger = $this->createMock(ILogger::class);
+ $this->dispatcher = $this->createMock(IEventDispatcher::class);
$this->cmd = new LoggedInCheckCommand(
- $this->logger
+ $this->logger,
+ $this->dispatcher
);
}