Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/password_policy.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRoeland Jago Douma <roeland@famdouma.nl>2020-04-21 16:46:51 +0300
committerRoeland Jago Douma <roeland@famdouma.nl>2020-04-24 17:34:47 +0300
commitd4250cfac40e6d43ddc050f2cd49ebd74ab288b2 (patch)
tree4cbb43b7d742d494139b87eb1cc2023fb78a1f6e /lib
parentb617166503a1dcf4587876d199c2bebfc03c6132 (diff)
Disable account after failed login attempts
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
Diffstat (limited to 'lib')
-rw-r--r--lib/AppInfo/Application.php7
-rw-r--r--lib/FailedLoginCompliance.php88
-rw-r--r--lib/Listener/FailedLoginListener.php49
-rw-r--r--lib/Listener/SuccesfullLoginListener.php48
-rw-r--r--lib/PasswordPolicyConfig.php10
-rw-r--r--lib/Settings.php1
6 files changed, 203 insertions, 0 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 183d461..7d6c68e 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -27,8 +27,11 @@ namespace OCA\Password_Policy\AppInfo;
use OCA\Password_Policy\Capabilities;
use OCA\Password_Policy\ComplianceService;
use OCA\Password_Policy\Generator;
+use OCA\Password_Policy\Listener\FailedLoginListener;
+use OCA\Password_Policy\Listener\SuccesfullLoginListener;
use OCA\Password_Policy\PasswordValidator;
use OCP\AppFramework\App;
+use OCP\Authentication\Events\LoginFailedEvent;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
@@ -37,6 +40,7 @@ use OCP\Security\Events\ValidatePasswordPolicyEvent;
use OCP\User\Events\BeforePasswordUpdatedEvent;
use OCP\User\Events\BeforeUserLoggedInEvent;
use OCP\User\Events\PasswordUpdatedEvent;
+use OCP\User\Events\UserLoggedInEvent;
use Symfony\Component\EventDispatcher\GenericEvent;
class Application extends App {
@@ -109,6 +113,9 @@ class Application extends App {
}
);
+ $eventDispatcher->addServiceListener(LoginFailedEvent::class, FailedLoginListener::class);
+ $eventDispatcher->addServiceListener(UserLoggedInEvent::class, SuccesfullLoginListener::class);
+
// TODO: remove these two legacy event listeners
$symfonyDispatcher = $server->getEventDispatcher();
$symfonyDispatcher->addListener(
diff --git a/lib/FailedLoginCompliance.php b/lib/FailedLoginCompliance.php
new file mode 100644
index 0000000..618fead
--- /dev/null
+++ b/lib/FailedLoginCompliance.php
@@ -0,0 +1,88 @@
+<?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 OCA\Password_Policy;
+
+use OCP\IConfig;
+use OCP\IUser;
+use OCP\IUserManager;
+
+class FailedLoginCompliance {
+
+ /** @var IConfig */
+ private $config;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var PasswordPolicyConfig */
+ private $passwordPolicyConfig;
+
+ public function __construct(
+ IConfig $config,
+ IUserManager $userManager,
+ PasswordPolicyConfig $passwordPolicyConfig) {
+ $this->config = $config;
+ $this->userManager = $userManager;
+ $this->passwordPolicyConfig = $passwordPolicyConfig;
+ }
+
+ public function onFailedLogin(string $uid) {
+ $user = $this->userManager->get($uid);
+
+ if (!($user instanceof IUser)) {
+ return;
+ }
+
+ if ($user->isEnabled() === false) {
+ // Just ignore this user then
+ return;
+ }
+
+ $allowedAttempts = $this->passwordPolicyConfig->getMaximumLoginAttempts();
+
+ $attempts = $this->getAttempts($uid);
+ $attempts++;
+
+ if ($attempts >= $allowedAttempts) {
+ $this->setAttempts($uid, 0);
+ $user->setEnabled(false);
+ return;
+ }
+
+ $this->setAttempts($uid, $attempts);
+ }
+
+ public function onSucessfullLogin(IUser $user) {
+ $this->setAttempts($user->getUID(), 0);
+ }
+
+ private function getAttempts(string $uid): int {
+ return (int)$this->config->getUserValue($uid, 'password_policy', 'failedLoginAttempts', 0);
+ }
+
+ private function setAttempts(string $uid, int $attempts): void {
+ return $this->config->setUserValue($uid, 'password_policy', 'failedLoginAttempts', $attempts);
+ }
+}
diff --git a/lib/Listener/FailedLoginListener.php b/lib/Listener/FailedLoginListener.php
new file mode 100644
index 0000000..33a9d4d
--- /dev/null
+++ b/lib/Listener/FailedLoginListener.php
@@ -0,0 +1,49 @@
+<?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 OCA\Password_Policy\Listener;
+
+use OCA\Password_Policy\FailedLoginCompliance;
+use OCP\Authentication\Events\LoginFailedEvent;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+class FailedLoginListener implements IEventListener {
+
+ /** @var FailedLoginCompliance */
+ private $compliance;
+
+ public function __construct(FailedLoginCompliance $compliance) {
+ $this->compliance = $compliance;
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof LoginFailedEvent)) {
+ return;
+ }
+
+ $this->compliance->onFailedLogin($event->getUid());
+ }
+
+}
diff --git a/lib/Listener/SuccesfullLoginListener.php b/lib/Listener/SuccesfullLoginListener.php
new file mode 100644
index 0000000..55a93b0
--- /dev/null
+++ b/lib/Listener/SuccesfullLoginListener.php
@@ -0,0 +1,48 @@
+<?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 OCA\Password_Policy\Listener;
+
+use OCA\Password_Policy\FailedLoginCompliance;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\UserLoggedInEvent;
+
+class SuccesfullLoginListener implements IEventListener {
+ /** @var FailedLoginCompliance */
+ private $compliance;
+
+ public function __construct(FailedLoginCompliance $compliance) {
+ $this->compliance = $compliance;
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof UserLoggedInEvent)) {
+ return;
+ }
+
+ $this->compliance->onSucessfullLogin($event->getUser());
+ }
+
+}
diff --git a/lib/PasswordPolicyConfig.php b/lib/PasswordPolicyConfig.php
index 80188b9..a86ab1a 100644
--- a/lib/PasswordPolicyConfig.php
+++ b/lib/PasswordPolicyConfig.php
@@ -193,4 +193,14 @@ class PasswordPolicyConfig {
);
}
+ /**
+ * @return int if 0 then there is no limit
+ */
+ public function getMaximumLoginAttempts(): int {
+ return (int)$this->config->getAppValue(
+ 'password_policy',
+ 'maximumLoginAttempts',
+ 0
+ );
+ }
}
diff --git a/lib/Settings.php b/lib/Settings.php
index 60a6a4f..7ae59e3 100644
--- a/lib/Settings.php
+++ b/lib/Settings.php
@@ -47,6 +47,7 @@ class Settings implements ISettings {
'enforceHaveIBeenPwned' => $this->config->getEnforceHaveIBeenPwned(),
'historySize' => $this->config->getHistorySize(),
'expiration' => $this->config->getExpiryInDays(),
+ 'maximumLoginAttempts' => $this->config->getMaximumLoginAttempts(),
]);
return $response;