diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2018-09-10 17:02:37 +0200 |
---|---|---|
committer | Roeland Jago Douma <roeland@famdouma.nl> | 2018-09-25 09:54:20 +0200 |
commit | 7586b19e524761c1e8aab5170375a0d6c9e8f7a2 (patch) | |
tree | e2a0fc5fa9754c12cfd226bf7aa48964fce18237 /lib | |
parent | 92fa373314e77dc905036812253f6b776a9e1aaf (diff) | |
download | nextcloud-server-7586b19e524761c1e8aab5170375a0d6c9e8f7a2.tar.gz nextcloud-server-7586b19e524761c1e8aab5170375a0d6c9e8f7a2.zip |
Only allow 2FA state changs if providers support the operation
Ref https://github.com/nextcloud/server/issues/11019.
Add `twofactorauth:cleanup` command
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib')
8 files changed, 170 insertions, 25 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 849dca209d1..0379b767755 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -434,6 +434,7 @@ return array( 'OC\\Archive\\Archive' => $baseDir . '/lib/private/Archive/Archive.php', 'OC\\Archive\\TAR' => $baseDir . '/lib/private/Archive/TAR.php', 'OC\\Archive\\ZIP' => $baseDir . '/lib/private/Archive/ZIP.php', + 'OC\\Authentication\\Exceptions\\InvalidProviderException' => $baseDir . '/lib/private/Authentication/Exceptions/InvalidProviderException.php', 'OC\\Authentication\\Exceptions\\InvalidTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/InvalidTokenException.php', 'OC\\Authentication\\Exceptions\\LoginRequiredException' => $baseDir . '/lib/private/Authentication/Exceptions/LoginRequiredException.php', 'OC\\Authentication\\Exceptions\\PasswordLoginForbiddenException' => $baseDir . '/lib/private/Authentication/Exceptions/PasswordLoginForbiddenException.php', @@ -456,6 +457,7 @@ return array( 'OC\\Authentication\\TwoFactorAuth\\Db\\ProviderUserAssignmentDao' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php', 'OC\\Authentication\\TwoFactorAuth\\Manager' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Manager.php', 'OC\\Authentication\\TwoFactorAuth\\ProviderLoader' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/ProviderLoader.php', + 'OC\\Authentication\\TwoFactorAuth\\ProviderManager' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/ProviderManager.php', 'OC\\Authentication\\TwoFactorAuth\\ProviderSet' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/ProviderSet.php', 'OC\\Authentication\\TwoFactorAuth\\Registry' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Registry.php', 'OC\\Avatar' => $baseDir . '/lib/private/Avatar.php', @@ -571,6 +573,7 @@ return array( 'OC\\Core\\Command\\Security\\RemoveCertificate' => $baseDir . '/core/Command/Security/RemoveCertificate.php', 'OC\\Core\\Command\\Status' => $baseDir . '/core/Command/Status.php', 'OC\\Core\\Command\\TwoFactorAuth\\Base' => $baseDir . '/core/Command/TwoFactorAuth/Base.php', + 'OC\\Core\\Command\\TwoFactorAuth\\Cleanup' => $baseDir . '/core/Command/TwoFactorAuth/Cleanup.php', 'OC\\Core\\Command\\TwoFactorAuth\\Disable' => $baseDir . '/core/Command/TwoFactorAuth/Disable.php', 'OC\\Core\\Command\\TwoFactorAuth\\Enable' => $baseDir . '/core/Command/TwoFactorAuth/Enable.php', 'OC\\Core\\Command\\TwoFactorAuth\\State' => $baseDir . '/core/Command/TwoFactorAuth/State.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c802bf4c57c..0456e784427 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -464,6 +464,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Archive\\Archive' => __DIR__ . '/../../..' . '/lib/private/Archive/Archive.php', 'OC\\Archive\\TAR' => __DIR__ . '/../../..' . '/lib/private/Archive/TAR.php', 'OC\\Archive\\ZIP' => __DIR__ . '/../../..' . '/lib/private/Archive/ZIP.php', + 'OC\\Authentication\\Exceptions\\InvalidProviderException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/InvalidProviderException.php', 'OC\\Authentication\\Exceptions\\InvalidTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/InvalidTokenException.php', 'OC\\Authentication\\Exceptions\\LoginRequiredException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/LoginRequiredException.php', 'OC\\Authentication\\Exceptions\\PasswordLoginForbiddenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/PasswordLoginForbiddenException.php', @@ -486,6 +487,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Authentication\\TwoFactorAuth\\Db\\ProviderUserAssignmentDao' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php', 'OC\\Authentication\\TwoFactorAuth\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Manager.php', 'OC\\Authentication\\TwoFactorAuth\\ProviderLoader' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/ProviderLoader.php', + 'OC\\Authentication\\TwoFactorAuth\\ProviderManager' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/ProviderManager.php', 'OC\\Authentication\\TwoFactorAuth\\ProviderSet' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/ProviderSet.php', 'OC\\Authentication\\TwoFactorAuth\\Registry' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Registry.php', 'OC\\Avatar' => __DIR__ . '/../../..' . '/lib/private/Avatar.php', @@ -601,6 +603,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Command\\Security\\RemoveCertificate' => __DIR__ . '/../../..' . '/core/Command/Security/RemoveCertificate.php', 'OC\\Core\\Command\\Status' => __DIR__ . '/../../..' . '/core/Command/Status.php', 'OC\\Core\\Command\\TwoFactorAuth\\Base' => __DIR__ . '/../../..' . '/core/Command/TwoFactorAuth/Base.php', + 'OC\\Core\\Command\\TwoFactorAuth\\Cleanup' => __DIR__ . '/../../..' . '/core/Command/TwoFactorAuth/Cleanup.php', 'OC\\Core\\Command\\TwoFactorAuth\\Disable' => __DIR__ . '/../../..' . '/core/Command/TwoFactorAuth/Disable.php', 'OC\\Core\\Command\\TwoFactorAuth\\Enable' => __DIR__ . '/../../..' . '/core/Command/TwoFactorAuth/Enable.php', 'OC\\Core\\Command\\TwoFactorAuth\\State' => __DIR__ . '/../../..' . '/core/Command/TwoFactorAuth/State.php', diff --git a/lib/private/Authentication/Exceptions/InvalidProviderException.php b/lib/private/Authentication/Exceptions/InvalidProviderException.php new file mode 100644 index 00000000000..6cdd0947509 --- /dev/null +++ b/lib/private/Authentication/Exceptions/InvalidProviderException.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2018 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\Exceptions; + +use Exception; +use Throwable; + +class InvalidProviderException extends Exception { + + public function __construct(string $providerId, Throwable $previous = null) { + parent::__construct("The provider '$providerId' does not exist'", 0, $previous); + } + +} diff --git a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php index ce03eb09661..d8299a335a3 100644 --- a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php +++ b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php @@ -93,4 +93,13 @@ class ProviderUserAssignmentDao { } + public function deleteAll(string $providerId) { + $qb = $this->conn->getQueryBuilder(); + + $deleteQuery = $qb->delete(self::TABLE_NAME) + ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter($providerId))); + + $deleteQuery->execute(); + } + } diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php index 6fa41897e1e..71cc5874e5d 100644 --- a/lib/private/Authentication/TwoFactorAuth/Manager.php +++ b/lib/private/Authentication/TwoFactorAuth/Manager.php @@ -100,12 +100,6 @@ class Manager { * @return boolean */ public function isTwoFactorAuthenticated(IUser $user): bool { - $twoFactorEnabled = ((int) $this->config->getUserValue($user->getUID(), 'core', 'two_factor_auth_disabled', 0)) === 0; - - if (!$twoFactorEnabled) { - return false; - } - $providerStates = $this->providerRegistry->getProviderStates($user); $providers = $this->providerLoader->getProviders($user); $fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user); @@ -113,25 +107,7 @@ class Manager { $providerIds = array_keys($enabled); $providerIdsWithoutBackupCodes = array_diff($providerIds, [self::BACKUP_CODES_PROVIDER_ID]); - return $twoFactorEnabled && !empty($providerIdsWithoutBackupCodes); - } - - /** - * Disable 2FA checks for the given user - * - * @param IUser $user - */ - public function disableTwoFactorAuthentication(IUser $user) { - $this->config->setUserValue($user->getUID(), 'core', 'two_factor_auth_disabled', 1); - } - - /** - * Enable all 2FA checks for the given user - * - * @param IUser $user - */ - public function enableTwoFactorAuthentication(IUser $user) { - $this->config->deleteUserValue($user->getUID(), 'core', 'two_factor_auth_disabled'); + return !empty($providerIdsWithoutBackupCodes); } /** diff --git a/lib/private/Authentication/TwoFactorAuth/ProviderManager.php b/lib/private/Authentication/TwoFactorAuth/ProviderManager.php new file mode 100644 index 00000000000..234085b062d --- /dev/null +++ b/lib/private/Authentication/TwoFactorAuth/ProviderManager.php @@ -0,0 +1,98 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2018 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2018 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @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\TwoFactorAuth; + +use OC\Authentication\Exceptions\InvalidProviderException; +use OCP\Authentication\TwoFactorAuth\IActivatableByAdmin; +use OCP\Authentication\TwoFactorAuth\IDeactivableByAdmin; +use OCP\Authentication\TwoFactorAuth\IDeactivatableByAdmin; +use OCP\Authentication\TwoFactorAuth\IProvider; +use OCP\Authentication\TwoFactorAuth\IRegistry; +use OCP\IUser; + +class ProviderManager { + + /** @var ProviderLoader */ + private $providerLoader; + + /** @var IRegistry */ + private $providerRegistry; + + public function __construct(ProviderLoader $providerLoader, IRegistry $providerRegistry) { + $this->providerLoader = $providerLoader; + $this->providerRegistry = $providerRegistry; + } + + private function getProvider(string $providerId, IUser $user): IProvider { + $providers = $this->providerLoader->getProviders($user); + + if (!isset($providers[$providerId])) { + throw new InvalidProviderException($providerId); + } + + return $providers[$providerId]; + } + + /** + * Try to enable the provider with the given id for the given user + * + * @param IUser $user + * + * @return bool whether the provider supports this operation + */ + public function tryEnableProviderFor(string $providerId, IUser $user): bool { + $provider = $this->getProvider($providerId, $user); + + if ($provider instanceof IActivatableByAdmin) { + $provider->enableFor($user); + $this->providerRegistry->enableProviderFor($provider, $user); + return true; + } else { + return false; + } + } + + /** + * Try to disable the provider with the given id for the given user + * + * @param IUser $user + * + * @return bool whether the provider supports this operation + */ + public function tryDisableProviderFor(string $providerId, IUser $user): bool { + $provider = $this->getProvider($providerId, $user); + + if ($provider instanceof IDeactivatableByAdmin) { + $provider->disableFor($user); + $this->providerRegistry->disableProviderFor($provider, $user); + return true; + } else { + return false; + } + } + +} diff --git a/lib/private/Authentication/TwoFactorAuth/Registry.php b/lib/private/Authentication/TwoFactorAuth/Registry.php index 0cfb052440e..2fc90e5d6d9 100644 --- a/lib/private/Authentication/TwoFactorAuth/Registry.php +++ b/lib/private/Authentication/TwoFactorAuth/Registry.php @@ -52,4 +52,7 @@ class Registry implements IRegistry { $this->assignmentDao->persist($provider->getId(), $user->getUID(), 0); } + public function cleanUp(string $providerId) { + $this->assignmentDao->deleteAll($providerId); + } } diff --git a/lib/public/Authentication/TwoFactorAuth/IRegistry.php b/lib/public/Authentication/TwoFactorAuth/IRegistry.php index 5013892d402..5d97c57bcf2 100644 --- a/lib/public/Authentication/TwoFactorAuth/IRegistry.php +++ b/lib/public/Authentication/TwoFactorAuth/IRegistry.php @@ -62,4 +62,19 @@ interface IRegistry { * @since 14.0.0 */ public function disableProviderFor(IProvider $provider, IUser $user); + + /** + * Cleans up all entries of the provider with the given id. This is only + * necessary in edge-cases where an admin disabled and/or uninstalled a + * provider app. Invoking this method will make sure outdated provider + * associations are removed so that users can log in. + * + * @since 15.0.0 + * + * @param string $providerId + * + * @return void + */ + public function cleanUp(string $providerId); + } |