diff options
author | Joas Schilling <coding@schilljs.com> | 2017-01-23 12:10:06 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-23 12:10:06 +0100 |
commit | 5d486478d3d6d316b1895ea440a05f31488e2f9f (patch) | |
tree | 2eef0379b617d8a720d0c9f0b8a4d33a298f4b8e | |
parent | 16afaa783b8e7b0e728543556c92dcc93241ae4b (diff) | |
parent | 916cc57b0ee827ac9635a6c7b4b2fdbc47e03491 (diff) | |
download | nextcloud-server-5d486478d3d6d316b1895ea440a05f31488e2f9f.tar.gz nextcloud-server-5d486478d3d6d316b1895ea440a05f31488e2f9f.zip |
Merge pull request #3141 from nextcloud/subadmin-check-on-removing-user-from-group
Subadmin check on removing user from group
-rw-r--r-- | apps/provisioning_api/lib/Controller/UsersController.php | 48 | ||||
-rw-r--r-- | apps/provisioning_api/tests/Controller/UsersControllerTest.php | 214 | ||||
-rw-r--r-- | lib/private/SubAdmin.php | 2 | ||||
-rw-r--r-- | settings/ajax/togglegroups.php | 92 | ||||
-rw-r--r-- | settings/js/users/groups.js | 4 | ||||
-rw-r--r-- | settings/js/users/users.js | 75 |
6 files changed, 288 insertions, 147 deletions
diff --git a/apps/provisioning_api/lib/Controller/UsersController.php b/apps/provisioning_api/lib/Controller/UsersController.php index cc1d63d2d34..2e8a2ffe5ed 100644 --- a/apps/provisioning_api/lib/Controller/UsersController.php +++ b/apps/provisioning_api/lib/Controller/UsersController.php @@ -33,10 +33,10 @@ use \OC_Helper; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCS\OCSForbiddenException; -use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\AppFramework\OCSController; use OCP\Files\NotFoundException; use OCP\IConfig; +use OCP\IGroup; use OCP\IGroupManager; use OCP\ILogger; use OCP\IRequest; @@ -275,9 +275,9 @@ class UsersController extends OCSController { break; case 'quota': $quota = $value; - if($quota !== 'none' and $quota !== 'default') { + if($quota !== 'none' && $quota !== 'default') { if (is_numeric($quota)) { - $quota = floatval($quota); + $quota = (float) $quota; } else { $quota = \OCP\Util::computerFileSize($quota); } @@ -421,6 +421,7 @@ class UsersController extends OCSController { // Looking up someone else if($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) { // Return the group that the method caller is subadmin of for the user in question + /** @var IGroup[] $getSubAdminsGroups */ $getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser); foreach ($getSubAdminsGroups as $key => $group) { $getSubAdminsGroups[$key] = $group->getGID(); @@ -440,6 +441,8 @@ class UsersController extends OCSController { /** * @PasswordConfirmationRequired + * @NoAdminRequired + * * @param string $userId * @param string $groupid * @return DataResponse @@ -459,6 +462,13 @@ class UsersController extends OCSController { throw new OCSException('', 103); } + // If they're not an admin, check they are a subadmin of the group in question + $loggedInUser = $this->userSession->getUser(); + $subAdminManager = $this->groupManager->getSubAdmin(); + if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) { + throw new OCSException('', 104); + } + // Add user to group $group->addUser($targetUser); return new DataResponse(); @@ -492,25 +502,33 @@ class UsersController extends OCSController { // If they're not an admin, check they are a subadmin of the group in question $subAdminManager = $this->groupManager->getSubAdmin(); - if(!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminofGroup($loggedInUser, $group)) { + if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) { throw new OCSException('', 104); } + // Check they aren't removing themselves from 'admin' or their 'subadmin; group - if($userId === $loggedInUser->getUID()) { - if($this->groupManager->isAdmin($loggedInUser->getUID())) { - if($group->getGID() === 'admin') { + if ($userId === $loggedInUser->getUID()) { + if ($this->groupManager->isAdmin($loggedInUser->getUID())) { + if ($group->getGID() === 'admin') { throw new OCSException('Cannot remove yourself from the admin group', 105); } } else { - // Not an admin, check they are not removing themself from their subadmin group - $subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser); - foreach ($subAdminGroups as $key => $group) { - $subAdminGroups[$key] = $group->getGID(); - } + // Not an admin, so the user must be a subadmin of this group, but that is not allowed. + throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105); + } - if(in_array($group->getGID(), $subAdminGroups, true)) { - throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105); - } + } else if (!$this->groupManager->isAdmin($loggedInUser->getUID())) { + /** @var IGroup[] $subAdminGroups */ + $subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser); + $subAdminGroups = array_map(function (IGroup $subAdminGroup) { + return $subAdminGroup->getGID(); + }, $subAdminGroups); + $userGroups = $this->groupManager->getUserGroupIds($targetUser); + $userSubAdminGroups = array_intersect($subAdminGroups, $userGroups); + + if (count($userSubAdminGroups) <= 1) { + // Subadmin must not be able to remove a user from all their subadmin groups. + throw new OCSException('Cannot remove user from this group as this is the only remaining group you are a SubAdmin of', 105); } } diff --git a/apps/provisioning_api/tests/Controller/UsersControllerTest.php b/apps/provisioning_api/tests/Controller/UsersControllerTest.php index e04ee86feae..4d3da5fd33a 100644 --- a/apps/provisioning_api/tests/Controller/UsersControllerTest.php +++ b/apps/provisioning_api/tests/Controller/UsersControllerTest.php @@ -30,6 +30,9 @@ namespace OCA\Provisioning_API\Tests\Controller; use OCA\Provisioning_API\Controller\UsersController; +use OCP\AppFramework\Http\DataResponse; +use OCP\IGroup; +use OCP\IUser; use OCP\IUserManager; use OCP\IConfig; use OCP\IUserSession; @@ -1598,11 +1601,10 @@ class UsersControllerTest extends OriginalTest { * @expectedExceptionCode 102 */ public function testAddToGroupWithTargetGroupNotExisting() { - $this->groupManager - ->expects($this->once()) + $this->groupManager->expects($this->once()) ->method('get') ->with('GroupToAddTo') - ->will($this->returnValue(null)); + ->willReturn(null); $this->api->addToGroup('TargetUser', 'GroupToAddTo'); } @@ -1620,16 +1622,149 @@ class UsersControllerTest extends OriginalTest { * @expectedExceptionCode 103 */ public function testAddToGroupWithTargetUserNotExisting() { - $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); - $this->groupManager - ->expects($this->once()) + $targetGroup = $this->createMock(IGroup::class); + $this->groupManager->expects($this->once()) ->method('get') ->with('GroupToAddTo') - ->will($this->returnValue($targetGroup)); + ->willReturn($targetGroup); + + $this->api->addToGroup('TargetUser', 'GroupToAddTo'); + } + + /** + * @expectedException \OCP\AppFramework\OCS\OCSException + * @expectedExceptionCode 104 + */ + public function testAddToGroupNoSubadmin() { + $targetUser = $this->createMock(IUser::class); + $loggedInUser = $this->createMock(IUser::class); + $loggedInUser->expects($this->once()) + ->method('getUID') + ->willReturn('subadmin'); + + $targetGroup = $this->createMock(IGroup::class); + $targetGroup->expects($this->never()) + ->method('addUser') + ->with($targetUser); + + $this->groupManager->expects($this->once()) + ->method('get') + ->with('GroupToAddTo') + ->willReturn($targetGroup); + + + $subAdminManager = $this->createMock(\OC\SubAdmin::class); + $subAdminManager->expects($this->once()) + ->method('isSubAdminOfGroup') + ->with($loggedInUser, $targetGroup) + ->willReturn(false); + + $this->groupManager->expects($this->once()) + ->method('getSubAdmin') + ->willReturn($subAdminManager); + $this->groupManager->expects($this->once()) + ->method('isAdmin') + ->with('subadmin') + ->willReturn(false); + + $this->userManager->expects($this->once()) + ->method('get') + ->with('TargetUser') + ->willReturn($targetUser); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->willReturn($loggedInUser); $this->api->addToGroup('TargetUser', 'GroupToAddTo'); } + public function testAddToGroupSuccessAsSubadmin() { + $targetUser = $this->createMock(IUser::class); + $loggedInUser = $this->createMock(IUser::class); + $loggedInUser->expects($this->once()) + ->method('getUID') + ->willReturn('subadmin'); + + $targetGroup = $this->createMock(IGroup::class); + $targetGroup->expects($this->once()) + ->method('addUser') + ->with($targetUser); + + $this->groupManager->expects($this->once()) + ->method('get') + ->with('GroupToAddTo') + ->willReturn($targetGroup); + + + $subAdminManager = $this->createMock(\OC\SubAdmin::class); + $subAdminManager->expects($this->once()) + ->method('isSubAdminOfGroup') + ->with($loggedInUser, $targetGroup) + ->willReturn(true); + + $this->groupManager->expects($this->once()) + ->method('getSubAdmin') + ->willReturn($subAdminManager); + $this->groupManager->expects($this->once()) + ->method('isAdmin') + ->with('subadmin') + ->willReturn(false); + + $this->userManager->expects($this->once()) + ->method('get') + ->with('TargetUser') + ->willReturn($targetUser); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->willReturn($loggedInUser); + + $this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo')); + } + + public function testAddToGroupSuccessAsAdmin() { + $targetUser = $this->createMock(IUser::class); + $loggedInUser = $this->createMock(IUser::class); + $loggedInUser->expects($this->once()) + ->method('getUID') + ->willReturn('admin'); + + $targetGroup = $this->createMock(IGroup::class); + $targetGroup->expects($this->once()) + ->method('addUser') + ->with($targetUser); + + $this->groupManager->expects($this->once()) + ->method('get') + ->with('GroupToAddTo') + ->willReturn($targetGroup); + + + $subAdminManager = $this->createMock(\OC\SubAdmin::class); + $subAdminManager->expects($this->never()) + ->method('isSubAdminOfGroup'); + + $this->groupManager->expects($this->once()) + ->method('getSubAdmin') + ->willReturn($subAdminManager); + $this->groupManager->expects($this->once()) + ->method('isAdmin') + ->with('admin') + ->willReturn(true); + + $this->userManager->expects($this->once()) + ->method('get') + ->with('TargetUser') + ->willReturn($targetUser); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->willReturn($loggedInUser); + + $this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo')); + } + /** * @expectedException \OCP\AppFramework\OCS\OCSException * @expectedExceptionCode 101 @@ -1813,22 +1948,79 @@ class UsersControllerTest extends OriginalTest { ->method('isSubAdminofGroup') ->with($loggedInUser, $targetGroup) ->will($this->returnValue(true)); + $this->groupManager + ->expects($this->once()) + ->method('getSubAdmin') + ->will($this->returnValue($subAdminManager)); + $this->groupManager + ->expects($this->any()) + ->method('isAdmin') + ->with('subadmin') + ->will($this->returnValue(false)); + + $this->api->removeFromGroup('subadmin', 'subadmin'); + } + + /** + * @expectedException \OCP\AppFramework\OCS\OCSException + * @expectedExceptionCode 105 + * @expectedExceptionMessage Cannot remove user from this group as this is the only remaining group you are a SubAdmin of + */ + public function testRemoveFromGroupAsSubAdminFromLastSubAdminGroup() { + $loggedInUser = $this->getMockBuilder('\OCP\IUser')->disableOriginalConstructor()->getMock(); + $loggedInUser + ->expects($this->any()) + ->method('getUID') + ->will($this->returnValue('subadmin')); + $targetUser = $this->getMockBuilder('\OCP\IUser')->disableOriginalConstructor()->getMock(); + $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock(); + $targetGroup + ->expects($this->any()) + ->method('getGID') + ->will($this->returnValue('subadmin')); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($loggedInUser)); + $this->groupManager + ->expects($this->once()) + ->method('get') + ->with('subadmin') + ->will($this->returnValue($targetGroup)); + $this->userManager + ->expects($this->once()) + ->method('get') + ->with('AnotherUser') + ->will($this->returnValue($targetUser)); + $subAdminManager = $this->getMockBuilder('OC\SubAdmin') + ->disableOriginalConstructor()->getMock(); $subAdminManager ->expects($this->once()) - ->method('getSubAdminsGroups') - ->with($loggedInUser) - ->will($this->returnValue([$targetGroup])); + ->method('isSubAdminofGroup') + ->with($loggedInUser, $targetGroup) + ->will($this->returnValue(true)); $this->groupManager ->expects($this->once()) ->method('getSubAdmin') ->will($this->returnValue($subAdminManager)); + $subAdminManager + ->expects($this->once()) + ->method('getSubAdminsGroups') + ->with($loggedInUser) + ->will($this->returnValue([$targetGroup])); + $this->groupManager ->expects($this->any()) ->method('isAdmin') ->with('subadmin') ->will($this->returnValue(false)); + $this->groupManager + ->expects($this->once()) + ->method('getUserGroupIds') + ->with($targetUser) + ->willReturn(['subadmin', 'other group']); - $this->api->removeFromGroup('subadmin', 'subadmin'); + $this->api->removeFromGroup('AnotherUser', 'subadmin'); } public function testRemoveFromGroupSuccessful() { diff --git a/lib/private/SubAdmin.php b/lib/private/SubAdmin.php index 9a2beed09fe..0650c7c6c01 100644 --- a/lib/private/SubAdmin.php +++ b/lib/private/SubAdmin.php @@ -188,7 +188,7 @@ class SubAdmin extends PublicEmitter { * @param IGroup $group * @return bool */ - public function isSubAdminofGroup(IUser $user, IGroup $group) { + public function isSubAdminOfGroup(IUser $user, IGroup $group) { $qb = $this->dbConn->getQueryBuilder(); /* diff --git a/settings/ajax/togglegroups.php b/settings/ajax/togglegroups.php deleted file mode 100644 index b9958bef0c9..00000000000 --- a/settings/ajax/togglegroups.php +++ /dev/null @@ -1,92 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bart Visscher <bartv@thisnet.nl> - * @author Christopher Schäpers <kondou@ts.unde.re> - * @author Georg Ehrke <georg@owncloud.com> - * @author Jakob Sack <mail@jakobsack.de> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Robin Appelman <robin@icewind.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ -OC_JSON::checkSubAdminUser(); -OCP\JSON::callCheck(); - -$lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm'); -if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay - $l = \OC::$server->getL10N('core'); - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required')))); - exit(); -} - -$success = true; -$username = (string)$_POST['username']; -$group = (string)$_POST['group']; - -if($username === OC_User::getUser() && $group === "admin" && OC_User::isAdminUser($username)) { - $l = \OC::$server->getL10N('core'); - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Admins can\'t remove themself from the admin group')))); - exit(); -} - -$isUserAccessible = false; -$isGroupAccessible = false; -$currentUserObject = \OC::$server->getUserSession()->getUser(); -$targetUserObject = \OC::$server->getUserManager()->get($username); -$targetGroupObject = \OC::$server->getGroupManager()->get($group); -if($targetUserObject !== null && $currentUserObject !== null && $targetGroupObject !== null) { - $isUserAccessible = \OC::$server->getGroupManager()->getSubAdmin()->isUserAccessible($currentUserObject, $targetUserObject); - $isGroupAccessible = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdminofGroup($currentUserObject, $targetGroupObject); -} - -if(!OC_User::isAdminUser(OC_User::getUser()) - && (!$isUserAccessible - || !$isGroupAccessible)) { - $l = \OC::$server->getL10N('core'); - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Authentication error') ))); - exit(); -} - -if(!OC_Group::groupExists($group)) { - OC_Group::createGroup($group); -} - -$l = \OC::$server->getL10N('settings'); - -$error = $l->t("Unable to add user to group %s", $group); -$action = "add"; - -// Toggle group -if( OC_Group::inGroup( $username, $group )) { - $action = "remove"; - $error = $l->t("Unable to remove user from group %s", $group); - $success = OC_Group::removeFromGroup( $username, $group ); - $usersInGroup=OC_Group::usersInGroup($group); -} -else{ - $success = OC_Group::addToGroup( $username, $group ); -} - -// Return Success story -if( $success ) { - OC_JSON::success(array("data" => array( "username" => $username, "action" => $action, "groupname" => $group ))); -} -else{ - OC_JSON::error(array("data" => array( "message" => $error ))); -} diff --git a/settings/js/users/groups.js b/settings/js/users/groups.js index cfe01c17530..aac1609bce7 100644 --- a/settings/js/users/groups.js +++ b/settings/js/users/groups.js @@ -225,7 +225,9 @@ GroupList = { toggleAddGroup: function (event) { if (GroupList.isAddGroupButtonVisible()) { - event.stopPropagation(); + if (event) { + event.stopPropagation(); + } $('#newgroup-form').show(); $('#newgroup-init').hide(); $('#newgroupname').focus(); diff --git a/settings/js/users/users.js b/settings/js/users/users.js index a2ccc059f15..3cf7b5e810a 100644 --- a/settings/js/users/users.js +++ b/settings/js/users/users.js @@ -420,42 +420,63 @@ var UserList = { var $element = $(element); - var checkHandler = null; + var addUserToGroup = null, + removeUserFromGroup = null; if(user) { // Only if in a user row, and not the #newusergroups select - checkHandler = function (group) { - if (user === OC.currentUser && group === 'admin') { + var handleUserGroupMembership = function (group, add) { + if (user === OC.getCurrentUser().uid && group === 'admin') { return false; } if (!OC.isUserAdmin() && checked.length === 1 && checked[0] === group) { return false; } - $.post( - OC.filePath('settings', 'ajax', 'togglegroups.php'), - { - username: user, - group: group + + if (add && OC.isUserAdmin() && UserList.availableGroups.indexOf(group) === -1) { + GroupList.createGroup(group); + if (UserList.availableGroups.indexOf(group) === -1) { + UserList.availableGroups.push(group); + } + } + + $.ajax({ + url: OC.linkToOCS('cloud/users/' + user , 2) + 'groups', + data: { + groupid: group }, - function (response) { - if (response.status === 'success') { - GroupList.update(); - var groupName = response.data.groupname; - if (UserList.availableGroups.indexOf(groupName) === -1 && - response.data.action === 'add' - ) { - UserList.availableGroups.push(groupName); - } + type: add ? 'POST' : 'DELETE', + beforeSend: function (request) { + request.setRequestHeader('Accept', 'application/json'); + }, + success: function() { + GroupList.update(); + if (add && UserList.availableGroups.indexOf(group) === -1) { + UserList.availableGroups.push(group); + } - if (response.data.action === 'add') { - GroupList.incGroupCount(groupName); - } else { - GroupList.decGroupCount(groupName); - } + if (add) { + GroupList.incGroupCount(group); + } else { + GroupList.decGroupCount(group); } - if (response.data.message) { - OC.Notification.show(response.data.message); + }, + error: function() { + if (add) { + OC.Notification.show(t('settings', 'Unable to add user to group {group}', { + group: group + })); + } else { + OC.Notification.show(t('settings', 'Unable to remove user from group {group}', { + group: group + })); } } - ); + }); + }; + addUserToGroup = function (group) { + return handleUserGroupMembership(group, true); + }; + removeUserFromGroup = function (group) { + return handleUserGroupMembership(group, false); }; } var addGroup = function (select, group) { @@ -473,8 +494,8 @@ var UserList = { createText: label, selectedFirst: true, checked: checked, - oncheck: checkHandler, - onuncheck: checkHandler, + oncheck: addUserToGroup, + onuncheck: removeUserFromGroup, minWidth: 100 }); }, |