diff options
author | Carl Schwan <carl@carlschwan.eu> | 2022-07-07 09:12:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-07 09:12:38 +0200 |
commit | c8967c5b88377172da714c9462d0d732c53a303f (patch) | |
tree | 179f9990daa99ce5848a5aa9c3769e8704cf2051 | |
parent | b98bb78f8a413fa233639e2936dd52d974b6cf79 (diff) | |
parent | 3750160d9f820146100243c3e628e6b6a35b031d (diff) | |
download | nextcloud-server-c8967c5b88377172da714c9462d0d732c53a303f.tar.gz nextcloud-server-c8967c5b88377172da714c9462d0d732c53a303f.zip |
Merge pull request #33114 from nextcloud/backport/stable23/31194
[stable23] Allow to disable password policy enforcement for selected groups
-rw-r--r-- | apps/files_sharing/tests/CapabilitiesTest.php | 12 | ||||
-rw-r--r-- | apps/settings/js/admin.js | 6 | ||||
-rw-r--r-- | apps/settings/lib/Settings/Admin/Sharing.php | 9 | ||||
-rw-r--r-- | apps/settings/templates/settings/admin/sharing.php | 12 | ||||
-rw-r--r-- | apps/settings/tests/Settings/Admin/SharingTest.php | 4 | ||||
-rw-r--r-- | config/config.sample.php | 5 | ||||
-rw-r--r-- | lib/private/Share20/Manager.php | 14 | ||||
-rw-r--r-- | lib/private/legacy/OC_Util.php | 7 | ||||
-rw-r--r-- | lib/public/Share/IManager.php | 4 | ||||
-rw-r--r-- | lib/public/Util.php | 8 | ||||
-rw-r--r-- | tests/lib/Share20/ManagerTest.php | 34 |
11 files changed, 105 insertions, 10 deletions
diff --git a/apps/files_sharing/tests/CapabilitiesTest.php b/apps/files_sharing/tests/CapabilitiesTest.php index 01ef13a3e6c..673995c4216 100644 --- a/apps/files_sharing/tests/CapabilitiesTest.php +++ b/apps/files_sharing/tests/CapabilitiesTest.php @@ -139,6 +139,7 @@ class CapabilitiesTest extends \Test\TestCase { $map = [ ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertIsArray($result['public']); @@ -149,6 +150,7 @@ class CapabilitiesTest extends \Test\TestCase { $map = [ ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ['core', 'shareapi_enforce_links_password', 'no', 'yes'], ]; $result = $this->getResults($map); @@ -161,6 +163,7 @@ class CapabilitiesTest extends \Test\TestCase { $map = [ ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ['core', 'shareapi_enforce_links_password', 'no', 'no'], ]; $result = $this->getResults($map); @@ -174,6 +177,7 @@ class CapabilitiesTest extends \Test\TestCase { ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], ['core', 'shareapi_default_expire_date', 'no', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertArrayHasKey('expire_date', $result['public']); @@ -188,6 +192,7 @@ class CapabilitiesTest extends \Test\TestCase { ['core', 'shareapi_default_expire_date', 'no', 'yes'], ['core', 'shareapi_expire_after_n_days', '7', '7'], ['core', 'shareapi_enforce_expire_date', 'no', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertArrayHasKey('expire_date', $result['public']); @@ -203,6 +208,7 @@ class CapabilitiesTest extends \Test\TestCase { ['core', 'shareapi_allow_links', 'yes', 'yes'], ['core', 'shareapi_default_expire_date', 'no', 'yes'], ['core', 'shareapi_enforce_expire_date', 'no', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertArrayHasKey('expire_date', $result['public']); @@ -215,6 +221,7 @@ class CapabilitiesTest extends \Test\TestCase { ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], ['core', 'shareapi_allow_public_notification', 'no', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertTrue($result['public']['send_mail']); @@ -225,6 +232,7 @@ class CapabilitiesTest extends \Test\TestCase { ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], ['core', 'shareapi_allow_public_notification', 'no', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertFalse($result['public']['send_mail']); @@ -234,6 +242,7 @@ class CapabilitiesTest extends \Test\TestCase { $map = [ ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_resharing', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertTrue($result['resharing']); @@ -243,6 +252,7 @@ class CapabilitiesTest extends \Test\TestCase { $map = [ ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_resharing', 'yes', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertFalse($result['resharing']); @@ -253,6 +263,7 @@ class CapabilitiesTest extends \Test\TestCase { ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], ['core', 'shareapi_allow_public_upload', 'yes', 'yes'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertTrue($result['public']['upload']); @@ -264,6 +275,7 @@ class CapabilitiesTest extends \Test\TestCase { ['core', 'shareapi_enabled', 'yes', 'yes'], ['core', 'shareapi_allow_links', 'yes', 'yes'], ['core', 'shareapi_allow_public_upload', 'yes', 'no'], + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ]; $result = $this->getResults($map); $this->assertFalse($result['public']['upload']); diff --git a/apps/settings/js/admin.js b/apps/settings/js/admin.js index 20d9843fe14..5e3580c0760 100644 --- a/apps/settings/js/admin.js +++ b/apps/settings/js/admin.js @@ -1,5 +1,5 @@ window.addEventListener('DOMContentLoaded', function(){ - $('#excludedGroups,#linksExcludedGroups').each(function (index, element) { + $('#excludedGroups,#linksExcludedGroups,#passwordsExcludedGroups').each(function(index, element) { OC.Settings.setupGroupsSelect($(element)); $(element).change(function(ev) { var groups = ev.val || []; @@ -94,6 +94,10 @@ window.addEventListener('DOMContentLoaded', function(){ $("#setDefaultRemoteExpireDate").toggleClass('hidden', !this.checked); }); + $('#enforceLinkPassword').change(function() { + $('#selectPasswordsExcludedGroups').toggleClass('hidden', !this.checked) + }) + $('#publicShareDisclaimer').change(function() { $("#publicShareDisclaimerText").toggleClass('hidden', !this.checked); if(!this.checked) { diff --git a/apps/settings/lib/Settings/Admin/Sharing.php b/apps/settings/lib/Settings/Admin/Sharing.php index 11c102e2803..d3c6839b8f7 100644 --- a/apps/settings/lib/Settings/Admin/Sharing.php +++ b/apps/settings/lib/Settings/Admin/Sharing.php @@ -72,6 +72,11 @@ class Sharing implements IDelegatedSettings { $linksExcludeGroupsList = !is_null(json_decode($linksExcludedGroups)) ? implode('|', json_decode($linksExcludedGroups, true)) : ''; + $excludedPasswordGroups = $this->config->getAppValue('core', 'shareapi_enforce_links_password_excluded_groups', ''); + $excludedPasswordGroupsList = !is_null(json_decode($excludedPasswordGroups)) + ? implode('|', json_decode($excludedPasswordGroups, true)) : ''; + + $parameters = [ // Built-In Sharing 'sharingAppEnabled' => $this->appManager->isEnabledForUser('files_sharing'), @@ -87,7 +92,9 @@ class Sharing implements IDelegatedSettings { 'restrictUserEnumerationFullMatchUserId' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_userid', 'yes'), 'restrictUserEnumerationFullMatchEmail' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_email', 'yes'), 'restrictUserEnumerationFullMatchIgnoreSecondDN' => $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_full_match_ignore_second_dn', 'no'), - 'enforceLinkPassword' => Util::isPublicLinkPasswordRequired(), + 'enforceLinkPassword' => Util::isPublicLinkPasswordRequired(false), + 'passwordExcludedGroups' => $excludedPasswordGroupsList, + 'passwordExcludedGroupsFeatureEnabled' => $this->config->getSystemValueBool('sharing.allow_disabled_password_enforcement_groups', false), 'onlyShareWithGroupMembers' => $this->shareManager->shareWithGroupMembersOnly(), 'shareAPIEnabled' => $this->config->getAppValue('core', 'shareapi_enabled', 'yes'), 'shareDefaultExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no'), diff --git a/apps/settings/templates/settings/admin/sharing.php b/apps/settings/templates/settings/admin/sharing.php index b699e152198..b51f9339166 100644 --- a/apps/settings/templates/settings/admin/sharing.php +++ b/apps/settings/templates/settings/admin/sharing.php @@ -120,6 +120,18 @@ } ?> /> <label for="enforceLinkPassword"><?php p($l->t('Enforce password protection'));?></label><br/> +<?php if ($_['passwordExcludedGroupsFeatureEnabled']) { ?> + <div id="selectPasswordsExcludedGroups" class="indent <?php if (!$_['enforceLinkPassword']) { p('hidden'); } ?>"> + <div class="indent"> + <label for="shareapi_enforce_links_password_excluded_groups"><?php p($l->t('Exclude groups from password requirements:'));?> + <br /> + <input name="shareapi_enforce_links_password_excluded_groups" id="passwordsExcludedGroups" value="<?php p($_['passwordExcludedGroups']) ?>" style="width: 400px" class="noJSAutoUpdate"/> + </div> + </div> +<?php } ?> + + <input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox" value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') { print_unescaped('checked="checked"'); } ?> /> + <input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox" value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') { print_unescaped('checked="checked"'); diff --git a/apps/settings/tests/Settings/Admin/SharingTest.php b/apps/settings/tests/Settings/Admin/SharingTest.php index f69504b654a..a133e532bb9 100644 --- a/apps/settings/tests/Settings/Admin/SharingTest.php +++ b/apps/settings/tests/Settings/Admin/SharingTest.php @@ -140,6 +140,8 @@ class SharingTest extends TestCase { 'shareRemoteExpireAfterNDays' => '7', 'shareRemoteEnforceExpireDate' => 'no', 'allowLinksExcludeGroups' => '', + 'passwordExcludedGroups' => '', + 'passwordExcludedGroupsFeatureEnabled' => false, ], '' ); @@ -218,6 +220,8 @@ class SharingTest extends TestCase { 'shareRemoteExpireAfterNDays' => '7', 'shareRemoteEnforceExpireDate' => 'no', 'allowLinksExcludeGroups' => '', + 'passwordExcludedGroups' => '', + 'passwordExcludedGroupsFeatureEnabled' => false, ], '' ); diff --git a/config/config.sample.php b/config/config.sample.php index d7d97fe7feb..cd96f002bc9 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -1567,6 +1567,11 @@ $CONFIG = [ 'sharing.enable_share_mail' => true, /** + * Set to true to enable the feature to add exceptions for share password enforcement + */ +'sharing.allow_disabled_password_enforcement_groups' => false, + +/** * Set to true to always transfer incoming shares by default * when running "occ files:transfer-ownership". * Defaults to false, so incoming shares are not transferred if not specifically requested diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 79b2e9e103a..4626ee06a44 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -1778,9 +1778,21 @@ class Manager implements IManager { /** * Is password on public link requires * + * @param bool Check group membership exclusion * @return bool */ - public function shareApiLinkEnforcePassword() { + public function shareApiLinkEnforcePassword(bool $checkGroupMembership = true) { + $excludedGroups = $this->config->getAppValue('core', 'shareapi_enforce_links_password_excluded_groups', ''); + if ($excludedGroups !== '' && $checkGroupMembership) { + $excludedGroups = json_decode($excludedGroups); + $user = $this->userSession->getUser(); + if ($user) { + $userGroups = $this->groupManager->getUserGroupIds($user); + if ((bool)array_intersect($excludedGroups, $userGroups)) { + return false; + } + } + } return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes'; } diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 7df69262c00..290c54a6704 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -348,15 +348,16 @@ class OC_Util { } /** - * check if a password is required for each public link + * Check if a password is required for each public link * + * @param bool $checkGroupMembership Check group membership exclusion * @return boolean * @suppress PhanDeprecatedFunction */ - public static function isPublicLinkPasswordRequired() { + public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) { /** @var IManager $shareManager */ $shareManager = \OC::$server->get(IManager::class); - return $shareManager->shareApiLinkEnforcePassword(); + return $shareManager->shareApiLinkEnforcePassword($checkGroupMembership); } /** diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php index b2b54d77eca..1bcf4a4bcf3 100644 --- a/lib/public/Share/IManager.php +++ b/lib/public/Share/IManager.php @@ -317,10 +317,12 @@ interface IManager { /** * Is password on public link requires * + * @param bool $checkGroupMembership Check group membership exclusion * @return bool * @since 9.0.0 + * @since 24.0.0 Added optional $checkGroupMembership parameter */ - public function shareApiLinkEnforcePassword(); + public function shareApiLinkEnforcePassword(bool $checkGroupMembership = true); /** * Is default expire date enabled diff --git a/lib/public/Util.php b/lib/public/Util.php index 103b65fe874..7b48f81e852 100644 --- a/lib/public/Util.php +++ b/lib/public/Util.php @@ -482,12 +482,14 @@ class Util { } /** - * check if a password is required for each public link + * Check if a password is required for each public link + * + * @param bool $checkGroupMembership Check group membership exclusion * @return boolean * @since 7.0.0 */ - public static function isPublicLinkPasswordRequired() { - return \OC_Util::isPublicLinkPasswordRequired(); + public static function isPublicLinkPasswordRequired(bool $checkGroupMembership = true) { + return \OC_Util::isPublicLinkPasswordRequired($checkGroupMembership); } /** diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php index 93f33fe30b9..a5db95638f8 100644 --- a/tests/lib/Share20/ManagerTest.php +++ b/tests/lib/Share20/ManagerTest.php @@ -505,14 +505,46 @@ class ManagerTest extends \Test\TestCase { $this->expectExceptionMessage('Passwords are enforced for link and mail shares'); $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ['core', 'shareapi_enforce_links_password', 'no', 'yes'], ]); self::invokePrivate($this->manager, 'verifyPassword', [null]); } + public function testVerifyPasswordNotEnforcedGroup() { + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin"]'], + ['core', 'shareapi_enforce_links_password', 'no', 'yes'], + ]); + + // Create admin user + $user = $this->createMock(IUser::class); + $this->userSession->method('getUser')->willReturn($user); + $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['admin']); + + $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); + $this->assertNull($result); + } + + public function testVerifyPasswordNotEnforcedMultipleGroups() { + $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin", "special"]'], + ['core', 'shareapi_enforce_links_password', 'no', 'yes'], + ]); + + // Create admin user + $user = $this->createMock(IUser::class); + $this->userSession->method('getUser')->willReturn($user); + $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['special']); + + $result = self::invokePrivate($this->manager, 'verifyPassword', [null]); + $this->assertNull($result); + } + public function testVerifyPasswordNull() { $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ['core', 'shareapi_enforce_links_password', 'no', 'no'], ]); @@ -522,6 +554,7 @@ class ManagerTest extends \Test\TestCase { public function testVerifyPasswordHook() { $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ['core', 'shareapi_enforce_links_password', 'no', 'no'], ]); @@ -543,6 +576,7 @@ class ManagerTest extends \Test\TestCase { $this->expectExceptionMessage('password not accepted'); $this->config->method('getAppValue')->willReturnMap([ + ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''], ['core', 'shareapi_enforce_links_password', 'no', 'no'], ]); |