diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2018-10-11 12:20:18 +0200 |
---|---|---|
committer | Christoph Wurst <christoph@winzerhof-wurst.at> | 2018-10-15 08:22:52 +0200 |
commit | 83e994c11fcc25a525e604bf7cc100f574794e02 (patch) | |
tree | 7ee44e5ad7bee886e98d7d6f14a4805bc16da611 /lib/private/Authentication/TwoFactorAuth | |
parent | 82a5833217d8fb1a74e7838b3e2ccf2cb9e1b90c (diff) | |
download | nextcloud-server-83e994c11fcc25a525e604bf7cc100f574794e02.tar.gz nextcloud-server-83e994c11fcc25a525e604bf7cc100f574794e02.zip |
Make it possible to enforce mandatory 2FA for groups
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib/private/Authentication/TwoFactorAuth')
3 files changed, 158 insertions, 6 deletions
diff --git a/lib/private/Authentication/TwoFactorAuth/EnforcementState.php b/lib/private/Authentication/TwoFactorAuth/EnforcementState.php new file mode 100644 index 00000000000..11a3d2c4105 --- /dev/null +++ b/lib/private/Authentication/TwoFactorAuth/EnforcementState.php @@ -0,0 +1,85 @@ +<?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 JsonSerializable; + +class EnforcementState implements JsonSerializable { + + /** @var bool */ + private $enforced; + + /** @var array */ + private $enforcedGroups; + + /** @var array */ + private $excludedGroups; + + /** + * EnforcementState constructor. + * + * @param bool $enforced + * @param string[] $enforcedGroups + * @param string[] $excludedGroups + */ + public function __construct(bool $enforced, + array $enforcedGroups = [], + array $excludedGroups = []) { + $this->enforced = $enforced; + $this->enforcedGroups = $enforcedGroups; + $this->excludedGroups = $excludedGroups; + } + + /** + * @return string[] + */ + public function isEnforced(): bool { + return $this->enforced; + } + + /** + * @return string[] + */ + public function getEnforcedGroups(): array { + return $this->enforcedGroups; + } + + /** + * @return string[] + */ + public function getExcludedGroups(): array { + return $this->excludedGroups; + } + + public function jsonSerialize(): array { + return [ + 'enforced' => $this->enforced, + 'enforcedGroups' => $this->enforcedGroups, + 'excludedGroups' => $this->excludedGroups, + ]; + } + +} diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php index 2307a731002..56fca8a745c 100644 --- a/lib/private/Authentication/TwoFactorAuth/Manager.php +++ b/lib/private/Authentication/TwoFactorAuth/Manager.php @@ -106,7 +106,7 @@ class Manager { * @return boolean */ public function isTwoFactorAuthenticated(IUser $user): bool { - if ($this->mandatoryTwoFactor->isEnforced()) { + if ($this->mandatoryTwoFactor->isEnforcedFor($user)) { return true; } diff --git a/lib/private/Authentication/TwoFactorAuth/MandatoryTwoFactor.php b/lib/private/Authentication/TwoFactorAuth/MandatoryTwoFactor.php index a23a10a1be6..45dcb8655c1 100644 --- a/lib/private/Authentication/TwoFactorAuth/MandatoryTwoFactor.php +++ b/lib/private/Authentication/TwoFactorAuth/MandatoryTwoFactor.php @@ -27,22 +27,89 @@ declare(strict_types=1); namespace OC\Authentication\TwoFactorAuth; use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IUser; class MandatoryTwoFactor { /** @var IConfig */ private $config; - public function __construct(IConfig $config) { + /** @var IGroupManager */ + private $groupManager; + + public function __construct(IConfig $config, IGroupManager $groupManager) { $this->config = $config; + $this->groupManager = $groupManager; } - public function isEnforced(): bool { - return $this->config->getSystemValue('twofactor_enforced', 'false') === 'true'; + /** + * Get the state of enforced two-factor auth + */ + public function getState(): EnforcementState { + return new EnforcementState( + $this->config->getSystemValue('twofactor_enforced', 'false') === 'true', + $this->config->getSystemValue('twofactor_enforced_groups', []), + $this->config->getSystemValue('twofactor_enforced_excluded_groups', []) + ); } - public function setEnforced(bool $enforced) { - $this->config->setSystemValue('twofactor_enforced', $enforced ? 'true' : 'false'); + /** + * Set the state of enforced two-factor auth + */ + public function setState(EnforcementState $state) { + $this->config->setSystemValue('twofactor_enforced', $state->isEnforced() ? 'true' : 'false'); + $this->config->setSystemValue('twofactor_enforced_groups', $state->getEnforcedGroups()); + $this->config->setSystemValue('twofactor_enforced_excluded_groups', $state->getExcludedGroups()); } + /** + * Check if two-factor auth is enforced for a specific user + * + * The admin(s) can enforce two-factor auth system-wide, for certain groups only + * and also have the option to exclude users of certain groups. This method will + * check their membership of those groups. + * + * @param IUser $user + * + * @return bool + */ + public function isEnforcedFor(IUser $user): bool { + $state = $this->getState(); + if (!$state->isEnforced()) { + return false; + } + $uid = $user->getUID(); + + /* + * If there is a list of enforced groups, we only enforce 2FA for members of those groups. + * For all the other users it is not enforced (overruling the excluded groups list). + */ + if (!empty($state->getEnforcedGroups())) { + foreach ($state->getEnforcedGroups() as $group) { + if ($this->groupManager->isInGroup($uid, $group)) { + return true; + } + } + // Not a member of any of these groups -> no 2FA enforced + return false; + } + + /** + * If the user is member of an excluded group, 2FA won't be enforced. + */ + foreach ($state->getExcludedGroups() as $group) { + if ($this->groupManager->isInGroup($uid, $group)) { + return false; + } + } + + /** + * No enforced groups configured and user not member of an excluded groups, + * so 2FA is enforced. + */ + return true; + } + + } |