mirror of
https://github.com/nextcloud/server.git
synced 2026-06-11 01:30:50 -04:00
Allow to disable password policy enforcement for selected groups
Signed-off-by: Carl Schwan <carl@carlschwan.eu> Co-authored-by: Vincent Petry <vincent@nextcloud.com> Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
This commit is contained in:
parent
14af5f3c26
commit
3750160d9f
11 changed files with 105 additions and 10 deletions
|
|
@ -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']);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -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"');
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
],
|
||||
''
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1566,6 +1566,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".
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
]);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue