diff options
author | Roeland Jago Douma <rullzer@users.noreply.github.com> | 2020-03-31 22:17:40 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-31 22:17:40 +0200 |
commit | b39fb55ee0b4bc4c4bd0fcedca3f836a17586495 (patch) | |
tree | 17089677aeeace2d6e4c488b0a0558be69564430 /lib | |
parent | 09d56e9d3db7893a73b32d7cc420dcb450f1bb79 (diff) | |
parent | 84f3d2ddebbda3d565a61f38d9d79e66072ab692 (diff) | |
download | nextcloud-server-b39fb55ee0b4bc4c4bd0fcedca3f836a17586495.tar.gz nextcloud-server-b39fb55ee0b4bc4c4bd0fcedca3f836a17586495.zip |
Merge pull request #19845 from nextcloud/enh/events/loginFailedEvent
Event for failed login attempts
Diffstat (limited to 'lib')
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 3 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 3 | ||||
-rw-r--r-- | lib/private/Authentication/Events/LoginFailed.php | 43 | ||||
-rw-r--r-- | lib/private/Authentication/Listeners/LoginFailedListener.php | 64 | ||||
-rw-r--r-- | lib/private/Authentication/Login/LoggedInCheckCommand.php | 18 | ||||
-rw-r--r-- | lib/private/Server.php | 6 | ||||
-rw-r--r-- | lib/private/User/Session.php | 8 | ||||
-rw-r--r-- | lib/public/Authentication/Events/LoginFailedEvent.php | 58 |
8 files changed, 199 insertions, 4 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 388c7906eb8..78e461132a0 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -74,6 +74,7 @@ return array( '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', @@ -592,6 +593,7 @@ return array( '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', @@ -604,6 +606,7 @@ return array( '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', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index cfc6d9842df..6d6a2055fcc 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -103,6 +103,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c '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', @@ -621,6 +622,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c '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', @@ -633,6 +635,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c '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', diff --git a/lib/private/Authentication/Events/LoginFailed.php b/lib/private/Authentication/Events/LoginFailed.php new file mode 100644 index 00000000000..cc5a547fdef --- /dev/null +++ b/lib/private/Authentication/Events/LoginFailed.php @@ -0,0 +1,43 @@ +<?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; + } +} diff --git a/lib/private/Authentication/Listeners/LoginFailedListener.php b/lib/private/Authentication/Listeners/LoginFailedListener.php new file mode 100644 index 00000000000..d4f46d9547f --- /dev/null +++ b/lib/private/Authentication/Listeners/LoginFailedListener.php @@ -0,0 +1,64 @@ +<?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)); + } + } + +} diff --git a/lib/private/Authentication/Login/LoggedInCheckCommand.php b/lib/private/Authentication/Login/LoggedInCheckCommand.php index 9c1e45e0db7..78f27bfa937 100644 --- a/lib/private/Authentication/Login/LoggedInCheckCommand.php +++ b/lib/private/Authentication/Login/LoggedInCheckCommand.php @@ -25,24 +25,36 @@ declare(strict_types=1); 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); } diff --git a/lib/private/Server.php b/lib/private/Server.php index 27268981c2b..b9155563c0f 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -62,6 +62,8 @@ use OC\App\AppStore\Fetcher\CategoryFetcher; 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; @@ -1416,6 +1418,10 @@ class Server extends ServerContainer implements IServerContainer { // no avatar to remove } }); + + /** @var IEventDispatcher $eventDispatched */ + $eventDispatched = $this->query(IEventDispatcher::class); + $eventDispatched->addServiceListener(LoginFailed::class, LoginFailedListener::class); } /** diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 3d97ddce7f9..9129fb7054b 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -51,6 +51,7 @@ use OC_User; 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; @@ -58,6 +59,7 @@ use OCP\ILogger; use OCP\IRequest; use OCP\ISession; use OCP\IUser; +use OCP\IUserManager; use OCP\IUserSession; use OCP\Lockdown\ILockdownManager; use OCP\Security\ISecureRandom; @@ -137,7 +139,8 @@ class Session implements IUserSession, Emitter { ISecureRandom $random, ILockdownManager $lockdownManager, ILogger $logger, - IEventDispatcher $dispatcher) { + IEventDispatcher $dispatcher + ) { $this->manager = $manager; $this->session = $session; $this->timeFactory = $timeFactory; @@ -467,6 +470,9 @@ class Session implements IUserSession, Emitter { $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'); } diff --git a/lib/public/Authentication/Events/LoginFailedEvent.php b/lib/public/Authentication/Events/LoginFailedEvent.php new file mode 100644 index 00000000000..15c8fb31bce --- /dev/null +++ b/lib/public/Authentication/Events/LoginFailedEvent.php @@ -0,0 +1,58 @@ +<?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; + } +} |