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

github.com/nextcloud/twofactor_totp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2018-12-03 12:31:07 +0300
committerChristoph Wurst <christoph@winzerhof-wurst.at>2018-12-04 10:34:24 +0300
commit3ac1d325ecde5aab769435aa5e0a8ef6ae98956f (patch)
treeef7f913d84fe2329951c2db810742f9ba1d9e4e6
parent97b77e57efb0c41d1143f044c3fbb4f50afff5a0 (diff)
Make the provider deactivatable
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
-rw-r--r--lib/Activity/Provider.php3
-rw-r--r--lib/AppInfo/Application.php11
-rw-r--r--lib/Event/DisabledByAdmin.php35
-rw-r--r--lib/Listener/StateChangeActivity.php11
-rw-r--r--lib/Provider/TotpProvider.php13
-rw-r--r--lib/Service/ITotp.php2
-rw-r--r--lib/Service/Totp.php9
-rw-r--r--tests/Unit/Activity/ProviderTest.php1
-rw-r--r--tests/Unit/Listener/StateChangeActivityTest.php37
-rw-r--r--tests/Unit/Provider/TotpProviderTest.php9
10 files changed, 124 insertions, 7 deletions
diff --git a/lib/Activity/Provider.php b/lib/Activity/Provider.php
index e8d62fc..922ee64 100644
--- a/lib/Activity/Provider.php
+++ b/lib/Activity/Provider.php
@@ -57,6 +57,9 @@ class Provider implements IProvider {
case 'totp_disabled_subject':
$event->setSubject($l->t('You disabled TOTP two-factor authentication for your account'));
break;
+ case 'totp_disabled_by_admin':
+ $event->setSubject($l->t('TOTP two-factor authentication disabled by an admin'));
+ break;
}
return $event;
}
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 21fb05d..6b8536d 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace OCA\TwoFactorTOTP\AppInfo;
+use OCA\TwoFactorTOTP\Event\DisabledByAdmin;
use OCA\TwoFactorTOTP\Event\StateChanged;
use OCA\TwoFactorTOTP\Listener\IListener;
use OCA\TwoFactorTOTP\Listener\StateChangeActivity;
@@ -51,6 +52,16 @@ class Application extends App {
$listener->handle($event);
}
});
+ $dispatcher->addListener(DisabledByAdmin::class, function (DisabledByAdmin $event) use ($container) {
+ /** @var IListener[] $listeners */
+ $listeners = [
+ $container->query(StateChangeActivity::class),
+ ];
+
+ foreach ($listeners as $listener) {
+ $listener->handle($event);
+ }
+ });
}
}
diff --git a/lib/Event/DisabledByAdmin.php b/lib/Event/DisabledByAdmin.php
new file mode 100644
index 0000000..6f354ac
--- /dev/null
+++ b/lib/Event/DisabledByAdmin.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @copyright Copyright (c) 2018 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * Two-factor TOTP
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\TwoFactorTOTP\Event;
+
+use OCP\IUser;
+
+class DisabledByAdmin extends StateChanged {
+
+ public function __construct(IUser $user) {
+ parent::__construct($user, false);
+ }
+
+}
diff --git a/lib/Listener/StateChangeActivity.php b/lib/Listener/StateChangeActivity.php
index d60af3f..929b50f 100644
--- a/lib/Listener/StateChangeActivity.php
+++ b/lib/Listener/StateChangeActivity.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace OCA\TwoFactorTOTP\Listener;
+use OCA\TwoFactorTOTP\Event\DisabledByAdmin;
use OCA\TwoFactorTOTP\Event\StateChanged;
use OCP\Activity\IManager as ActivityManager;
use Symfony\Component\EventDispatcher\Event;
@@ -39,15 +40,19 @@ class StateChangeActivity implements IListener {
public function handle(Event $event) {
if ($event instanceof StateChanged) {
+ if ($event instanceof DisabledByAdmin) {
+ $subject = 'totp_disabled_by_admin';
+ } else {
+ $subject = $event->isEnabled() ? 'totp_enabled_subject' : 'totp_disabled_subject';
+ }
$user = $event->getUser();
- $subject = $event->isEnabled() ? 'totp_enabled_subject' : 'totp_disabled_subject';
$activity = $this->activityManager->generateEvent();
$activity->setApp('twofactor_totp')
->setType('security')
->setAuthor($user->getUID())
- ->setAffectedUser($user->getUID());
- $activity->setSubject($subject);
+ ->setAffectedUser($user->getUID())
+ ->setSubject($subject);
$this->activityManager->publish($activity);
}
}
diff --git a/lib/Provider/TotpProvider.php b/lib/Provider/TotpProvider.php
index 1e1b99d..94096c2 100644
--- a/lib/Provider/TotpProvider.php
+++ b/lib/Provider/TotpProvider.php
@@ -25,6 +25,7 @@ namespace OCA\TwoFactorTOTP\Provider;
use OCA\TwoFactorTOTP\Service\ITotp;
use OCA\TwoFactorTOTP\Settings\Personal;
+use OCP\Authentication\TwoFactorAuth\IDeactivatableByAdmin;
use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IProvidesIcons;
@@ -33,7 +34,7 @@ use OCP\IL10N;
use OCP\IUser;
use OCP\Template;
-class TotpProvider implements IProvider, IProvidesIcons, IProvidesPersonalSettings {
+class TotpProvider implements IProvider, IProvidesIcons, IProvidesPersonalSettings, IDeactivatableByAdmin {
/** @var ITotp */
private $totp;
@@ -101,4 +102,14 @@ class TotpProvider implements IProvider, IProvidesIcons, IProvidesPersonalSettin
public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
return new Personal($this->totp->hasSecret($user) ? ITotp::STATE_ENABLED : ITotp::STATE_DISABLED);
}
+
+ /**
+ * Disable this provider for the given user.
+ *
+ * @param IUser $user the user to deactivate this provider for
+ */
+ public function disableFor(IUser $user) {
+ $this->totp->deleteSecret($user, true);
+ }
+
}
diff --git a/lib/Service/ITotp.php b/lib/Service/ITotp.php
index 1864ec2..d27bef2 100644
--- a/lib/Service/ITotp.php
+++ b/lib/Service/ITotp.php
@@ -63,7 +63,7 @@ interface ITotp {
/**
* @param IUser $user
*/
- public function deleteSecret(IUser $user);
+ public function deleteSecret(IUser $user, bool $byAdmin = false);
/**
* @param IUser $user
diff --git a/lib/Service/Totp.php b/lib/Service/Totp.php
index f40716c..678797b 100644
--- a/lib/Service/Totp.php
+++ b/lib/Service/Totp.php
@@ -27,6 +27,7 @@ namespace OCA\TwoFactorTOTP\Service;
use Base32\Base32;
use OCA\TwoFactorTOTP\Db\TotpSecret;
use OCA\TwoFactorTOTP\Db\TotpSecretMapper;
+use OCA\TwoFactorTOTP\Event\DisabledByAdmin;
use OCA\TwoFactorTOTP\Event\StateChanged;
use OCA\TwoFactorTOTP\Exception\NoTotpSecretFoundException;
use OCP\AppFramework\Db\DoesNotExistException;
@@ -101,7 +102,7 @@ class Totp implements ITotp {
return true;
}
- public function deleteSecret(IUser $user) {
+ public function deleteSecret(IUser $user, bool $byAdmin = false) {
try {
// TODO: execute DELETE sql in mapper instead
$dbSecret = $this->secretMapper->getSecret($user);
@@ -110,7 +111,11 @@ class Totp implements ITotp {
// Ignore
}
- $this->eventDispatcher->dispatch(StateChanged::class, new StateChanged($user, false));
+ if ($byAdmin) {
+ $this->eventDispatcher->dispatch(DisabledByAdmin::class, new DisabledByAdmin($user));
+ } else {
+ $this->eventDispatcher->dispatch(StateChanged::class, new StateChanged($user, false));
+ }
}
public function validateSecret(IUser $user, $key): bool {
diff --git a/tests/Unit/Activity/ProviderTest.php b/tests/Unit/Activity/ProviderTest.php
index 5678fcc..d798fcf 100644
--- a/tests/Unit/Activity/ProviderTest.php
+++ b/tests/Unit/Activity/ProviderTest.php
@@ -65,6 +65,7 @@ class ProviderTest extends TestCase {
return [
['totp_enabled_subject'],
['totp_disabled_subject'],
+ ['totp_disabled_by_admin'],
];
}
diff --git a/tests/Unit/Listener/StateChangeActivityTest.php b/tests/Unit/Listener/StateChangeActivityTest.php
index 8b3e05e..540f864 100644
--- a/tests/Unit/Listener/StateChangeActivityTest.php
+++ b/tests/Unit/Listener/StateChangeActivityTest.php
@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace OCA\TwoFactorTOTP\Unit\Listener;
use ChristophWurst\Nextcloud\Testing\TestCase;
+use OCA\TwoFactorTOTP\Event\DisabledByAdmin;
use OCA\TwoFactorTOTP\Event\StateChanged;
use OCA\TwoFactorTOTP\Listener\StateChangeActivity;
use OCP\Activity\IEvent;
@@ -79,4 +80,40 @@ class StateChangeActivityTest extends TestCase {
$this->listener->handle($event);
}
+ public function testHandleDisabledByAdminEvent() {
+ $uid = 'user234';
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')->willReturn($uid);
+ $event = new DisabledByAdmin($user);
+ $activityEvent = $this->createMock(IEvent::class);
+ $this->activityManager->expects($this->once())
+ ->method('generateEvent')
+ ->willReturn($activityEvent);
+ $activityEvent->expects($this->once())
+ ->method('setApp')
+ ->with('twofactor_totp')
+ ->willReturnSelf();
+ $activityEvent->expects($this->once())
+ ->method('setType')
+ ->with('security')
+ ->willReturnSelf();
+ $activityEvent->expects($this->once())
+ ->method('setAuthor')
+ ->with($uid)
+ ->willReturnSelf();
+ $activityEvent->expects($this->once())
+ ->method('setAffectedUser')
+ ->with($uid)
+ ->willReturnSelf();
+ $activityEvent->expects($this->once())
+ ->method('setSubject')
+ ->with('totp_disabled_by_admin')
+ ->willReturnSelf();
+ $this->activityManager->expects($this->once())
+ ->method('publish')
+ ->with($activityEvent);
+
+ $this->listener->handle($event);
+ }
+
} \ No newline at end of file
diff --git a/tests/Unit/Provider/TotpProviderTest.php b/tests/Unit/Provider/TotpProviderTest.php
index 0f69343..2e8376e 100644
--- a/tests/Unit/Provider/TotpProviderTest.php
+++ b/tests/Unit/Provider/TotpProviderTest.php
@@ -113,4 +113,13 @@ class TotpProviderTest extends TestCase {
$this->assertEquals($expected, $actual);
}
+ public function testDeactivate() {
+ $user = $this->createMock(IUser::class);
+ $this->totp->expects($this->once())
+ ->method('deleteSecret')
+ ->with($user);
+
+ $this->provider->disableFor($user);
+ }
+
}