aboutsummaryrefslogtreecommitdiffstats
path: root/core/Command/TwoFactorAuth
diff options
context:
space:
mode:
Diffstat (limited to 'core/Command/TwoFactorAuth')
-rw-r--r--core/Command/TwoFactorAuth/Base.php47
-rw-r--r--core/Command/TwoFactorAuth/Cleanup.php44
-rw-r--r--core/Command/TwoFactorAuth/Disable.php52
-rw-r--r--core/Command/TwoFactorAuth/Enable.php52
-rw-r--r--core/Command/TwoFactorAuth/Enforce.php88
-rw-r--r--core/Command/TwoFactorAuth/State.php88
6 files changed, 371 insertions, 0 deletions
diff --git a/core/Command/TwoFactorAuth/Base.php b/core/Command/TwoFactorAuth/Base.php
new file mode 100644
index 00000000000..034ea36afca
--- /dev/null
+++ b/core/Command/TwoFactorAuth/Base.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Core\Command\TwoFactorAuth;
+
+use OCP\IUser;
+use OCP\IUserManager;
+use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
+
+class Base extends \OC\Core\Command\Base {
+ public function __construct(
+ ?string $name,
+ protected IUserManager $userManager,
+ ) {
+ parent::__construct($name);
+ }
+
+ /**
+ * Return possible values for the named option
+ *
+ * @param string $optionName
+ * @param CompletionContext $context
+ * @return string[]
+ */
+ public function completeOptionValues($optionName, CompletionContext $context) {
+ return [];
+ }
+
+ /**
+ * Return possible values for the named argument
+ *
+ * @param string $argumentName
+ * @param CompletionContext $context
+ * @return string[]
+ */
+ public function completeArgumentValues($argumentName, CompletionContext $context) {
+ if ($argumentName === 'uid') {
+ return array_map(function (IUser $user) {
+ return $user->getUID();
+ }, $this->userManager->search($context->getCurrentWord(), 100));
+ }
+ return [];
+ }
+}
diff --git a/core/Command/TwoFactorAuth/Cleanup.php b/core/Command/TwoFactorAuth/Cleanup.php
new file mode 100644
index 00000000000..f8f116af3fd
--- /dev/null
+++ b/core/Command/TwoFactorAuth/Cleanup.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Core\Command\TwoFactorAuth;
+
+use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\IUserManager;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Cleanup extends Base {
+ public function __construct(
+ private IRegistry $registry,
+ IUserManager $userManager,
+ ) {
+ parent::__construct(
+ null,
+ $userManager,
+ );
+ }
+
+ protected function configure() {
+ parent::configure();
+
+ $this->setName('twofactorauth:cleanup');
+ $this->setDescription('Clean up the two-factor user-provider association of an uninstalled/removed provider');
+ $this->addArgument('provider-id', InputArgument::REQUIRED);
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $providerId = $input->getArgument('provider-id');
+
+ $this->registry->cleanUp($providerId);
+
+ $output->writeln("<info>All user-provider associations for provider <options=bold>$providerId</> have been removed.</info>");
+ return 0;
+ }
+}
diff --git a/core/Command/TwoFactorAuth/Disable.php b/core/Command/TwoFactorAuth/Disable.php
new file mode 100644
index 00000000000..c60c1245735
--- /dev/null
+++ b/core/Command/TwoFactorAuth/Disable.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OC\Core\Command\TwoFactorAuth;
+
+use OC\Authentication\TwoFactorAuth\ProviderManager;
+use OCP\IUserManager;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Disable extends Base {
+ public function __construct(
+ private ProviderManager $manager,
+ IUserManager $userManager,
+ ) {
+ parent::__construct(
+ 'twofactorauth:disable',
+ $userManager,
+ );
+ }
+
+ protected function configure() {
+ parent::configure();
+
+ $this->setName('twofactorauth:disable');
+ $this->setDescription('Disable two-factor authentication for a user');
+ $this->addArgument('uid', InputArgument::REQUIRED);
+ $this->addArgument('provider_id', InputArgument::REQUIRED);
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $uid = $input->getArgument('uid');
+ $providerId = $input->getArgument('provider_id');
+ $user = $this->userManager->get($uid);
+ if (is_null($user)) {
+ $output->writeln('<error>Invalid UID</error>');
+ return 1;
+ }
+ if ($this->manager->tryDisableProviderFor($providerId, $user)) {
+ $output->writeln("Two-factor provider <options=bold>$providerId</> disabled for user <options=bold>$uid</>.");
+ return 0;
+ } else {
+ $output->writeln('<error>The provider does not support this operation.</error>');
+ return 2;
+ }
+ }
+}
diff --git a/core/Command/TwoFactorAuth/Enable.php b/core/Command/TwoFactorAuth/Enable.php
new file mode 100644
index 00000000000..215cb31397e
--- /dev/null
+++ b/core/Command/TwoFactorAuth/Enable.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OC\Core\Command\TwoFactorAuth;
+
+use OC\Authentication\TwoFactorAuth\ProviderManager;
+use OCP\IUserManager;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Enable extends Base {
+ public function __construct(
+ private ProviderManager $manager,
+ IUserManager $userManager,
+ ) {
+ parent::__construct(
+ 'twofactorauth:enable',
+ $userManager,
+ );
+ }
+
+ protected function configure() {
+ parent::configure();
+
+ $this->setName('twofactorauth:enable');
+ $this->setDescription('Enable two-factor authentication for a user');
+ $this->addArgument('uid', InputArgument::REQUIRED);
+ $this->addArgument('provider_id', InputArgument::REQUIRED);
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $uid = $input->getArgument('uid');
+ $providerId = $input->getArgument('provider_id');
+ $user = $this->userManager->get($uid);
+ if (is_null($user)) {
+ $output->writeln('<error>Invalid UID</error>');
+ return 1;
+ }
+ if ($this->manager->tryEnableProviderFor($providerId, $user)) {
+ $output->writeln("Two-factor provider <options=bold>$providerId</> enabled for user <options=bold>$uid</>.");
+ return 0;
+ } else {
+ $output->writeln('<error>The provider does not support this operation.</error>');
+ return 2;
+ }
+ }
+}
diff --git a/core/Command/TwoFactorAuth/Enforce.php b/core/Command/TwoFactorAuth/Enforce.php
new file mode 100644
index 00000000000..3315f045bc8
--- /dev/null
+++ b/core/Command/TwoFactorAuth/Enforce.php
@@ -0,0 +1,88 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Core\Command\TwoFactorAuth;
+
+use OC\Authentication\TwoFactorAuth\EnforcementState;
+use OC\Authentication\TwoFactorAuth\MandatoryTwoFactor;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use function implode;
+
+class Enforce extends Command {
+ public function __construct(
+ private MandatoryTwoFactor $mandatoryTwoFactor,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure() {
+ $this->setName('twofactorauth:enforce');
+ $this->setDescription('Enabled/disable enforced two-factor authentication');
+ $this->addOption(
+ 'on',
+ null,
+ InputOption::VALUE_NONE,
+ 'enforce two-factor authentication'
+ );
+ $this->addOption(
+ 'off',
+ null,
+ InputOption::VALUE_NONE,
+ 'don\'t enforce two-factor authenticaton'
+ );
+ $this->addOption(
+ 'group',
+ null,
+ InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
+ 'enforce only for the given group(s)'
+ );
+ $this->addOption(
+ 'exclude',
+ null,
+ InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
+ 'exclude mandatory two-factor auth for the given group(s)'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ if ($input->getOption('on')) {
+ $enforcedGroups = $input->getOption('group');
+ $excludedGroups = $input->getOption('exclude');
+ $this->mandatoryTwoFactor->setState(new EnforcementState(true, $enforcedGroups, $excludedGroups));
+ } elseif ($input->getOption('off')) {
+ $this->mandatoryTwoFactor->setState(new EnforcementState(false));
+ }
+
+ $state = $this->mandatoryTwoFactor->getState();
+ if ($state->isEnforced()) {
+ $this->writeEnforced($output, $state);
+ } else {
+ $this->writeNotEnforced($output);
+ }
+ return 0;
+ }
+
+ protected function writeEnforced(OutputInterface $output, EnforcementState $state) {
+ if (empty($state->getEnforcedGroups())) {
+ $message = 'Two-factor authentication is enforced for all users';
+ } else {
+ $message = 'Two-factor authentication is enforced for members of the group(s) ' . implode(', ', $state->getEnforcedGroups());
+ }
+ if (!empty($state->getExcludedGroups())) {
+ $message .= ', except members of ' . implode(', ', $state->getExcludedGroups());
+ }
+ $output->writeln($message);
+ }
+
+ protected function writeNotEnforced(OutputInterface $output) {
+ $output->writeln('Two-factor authentication is not enforced');
+ }
+}
diff --git a/core/Command/TwoFactorAuth/State.php b/core/Command/TwoFactorAuth/State.php
new file mode 100644
index 00000000000..ab2e8f2aecf
--- /dev/null
+++ b/core/Command/TwoFactorAuth/State.php
@@ -0,0 +1,88 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OC\Core\Command\TwoFactorAuth;
+
+use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\IUserManager;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class State extends Base {
+ public function __construct(
+ private IRegistry $registry,
+ IUserManager $userManager,
+ ) {
+ parent::__construct(
+ 'twofactorauth:state',
+ $userManager,
+ );
+ }
+
+ protected function configure() {
+ parent::configure();
+
+ $this->setName('twofactorauth:state');
+ $this->setDescription('Get the two-factor authentication (2FA) state of a user');
+ $this->addArgument('uid', InputArgument::REQUIRED);
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $uid = $input->getArgument('uid');
+ $user = $this->userManager->get($uid);
+ if (is_null($user)) {
+ $output->writeln('<error>Invalid UID</error>');
+ return 1;
+ }
+
+ $providerStates = $this->registry->getProviderStates($user);
+ $filtered = $this->filterEnabledDisabledUnknownProviders($providerStates);
+ [$enabled, $disabled] = $filtered;
+
+ if (!empty($enabled)) {
+ $output->writeln("Two-factor authentication is enabled for user $uid");
+ } else {
+ $output->writeln("Two-factor authentication is not enabled for user $uid");
+ }
+
+ $output->writeln('');
+ $this->printProviders('Enabled providers', $enabled, $output);
+ $this->printProviders('Disabled providers', $disabled, $output);
+
+ return 0;
+ }
+
+ private function filterEnabledDisabledUnknownProviders(array $providerStates): array {
+ $enabled = [];
+ $disabled = [];
+
+ foreach ($providerStates as $providerId => $isEnabled) {
+ if ($isEnabled) {
+ $enabled[] = $providerId;
+ } else {
+ $disabled[] = $providerId;
+ }
+ }
+
+ return [$enabled, $disabled];
+ }
+
+ private function printProviders(string $title, array $providers,
+ OutputInterface $output) {
+ if (empty($providers)) {
+ // Ignore and don't print anything
+ return;
+ }
+
+ $output->writeln($title . ':');
+ foreach ($providers as $provider) {
+ $output->writeln('- ' . $provider);
+ }
+ }
+}