Skip to content

Commit

Permalink
Add option for all group admins to impersonate their group memebers
Browse files Browse the repository at this point in the history
Add an option for all group admins to impersonate
their group members.

Signed-off-by: Sujith H <[email protected]>
  • Loading branch information
sharidas committed Jan 4, 2019
1 parent d10bdd0 commit 9be6a99
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 52 deletions.
40 changes: 28 additions & 12 deletions controller/settingscontroller.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use OCP\IRequest;
use OCP\AppFramework\Controller;
use OCP\ISession;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use Symfony\Component\EventDispatcher\EventDispatcher;
Expand Down Expand Up @@ -98,17 +99,37 @@ public function __construct($appName, IRequest $request, IUserManager $userManag
public function getDataForImpersonateApp() {
$isEnabled = $this->config->getValue('impersonate', 'impersonate_include_groups', false);
$includedGroups = $this->config->getValue('impersonate', 'impersonate_include_groups_list', '[]');
$allowFullAccessSubAdmins = $this->config->getValue('impersonate', 'impersonate_all_groupadmins', false);
$currentUser = $this->userSession->getUser();
if ($currentUser === null) {
return new JSONResponse([$includedGroups, $isEnabled,
false, false]);
$allowFullAccessSubAdmins, false, false]);
}

return new JSONResponse([$includedGroups, $isEnabled,
$allowFullAccessSubAdmins,
$this->groupManager->isAdmin($currentUser->getUID()),
$this->subAdmin->isSubAdmin($currentUser)]);
}

/**
* Impersonate the user
* This method is called after the users capability to impersonate is decided
* in the method impersonate($target).
*
* @param string $impersonator, the current user
* @param string $target, the target user
* @param IUser $user, target user object
* @return JSONResponse
*/
private function impersonateUser($impersonator, $target, $user) {
$this->logger->info("User $impersonator impersonated user $target", ['app' => 'impersonate']);
$this->util->switchUser($user, $impersonator);
$startEvent = new GenericEvent(null, ['impersonator' => $impersonator, 'targetUser' => $target]);
$this->eventDispatcher->dispatch('user.afterimpersonate', $startEvent);
return new JSONResponse();
}

/**
* become another user
* @param string $target
Expand Down Expand Up @@ -164,25 +185,20 @@ public function impersonate($target) {
], http::STATUS_NOT_FOUND);
} else {
if ($this->groupManager->isAdmin($currentUser->getUID())) {
$this->logger->info("User $impersonator impersonated user $target", ['app' => 'impersonate']);
$this->util->switchUser($user, $impersonator);
$startEvent = new GenericEvent(null, ['impersonator' => $impersonator, 'targetUser' => $target]);
$this->eventDispatcher->dispatch('user.afterimpersonate', $startEvent);
return new JSONResponse();
return $this->impersonateUser($impersonator, $target, $user);
}

$includedGroups = $this->config->getValue('impersonate', 'impersonate_include_groups_list', '');
if ($includedGroups !== '') {
$allowSubAdminsImpersonate = $this->config->getValue('impersonate', 'impersonate_all_groupadmins', "false");
if ($allowSubAdminsImpersonate === "true") {
return $this->impersonateUser($impersonator, $target, $user);
} elseif ($includedGroups !== '') {
$includedGroups = \json_decode($includedGroups);

foreach ($includedGroups as $group) {
if ($this->groupManager->isInGroup($user->getUID(), $group)
&& $this->subAdmin->isSubAdminofGroup($this->userSession->getUser(), $this->groupManager->get($group))) {
$this->logger->info("User $impersonator impersonated user $target", ['app' => 'impersonate']);
$this->util->switchUser($user, $impersonator);
$startEvent = new GenericEvent(null, ['impersonator' => $impersonator, 'targetUser' => $target]);
$this->eventDispatcher->dispatch('user.afterimpersonate', $startEvent);
return new JSONResponse();
return $this->impersonateUser($impersonator, $target, $user);
}
}
}
Expand Down
37 changes: 21 additions & 16 deletions js/impersonate.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
var includedGroups,
groupEnabled,
adminUser,
subadminUser;
subadminUser, subAdminFullAccess;

var currentUser = OC.getCurrentUser().uid;

Expand All @@ -41,8 +41,9 @@
promiseGetData.then(function (result) {
includedGroups = $.parseJSON(result[0]);
groupEnabled = JSON.parse($.trim(result[1]));
adminUser = JSON.parse($.trim(result[2]));
subadminUser = JSON.parse($.trim(result[3]));
subAdminFullAccess = JSON.parse($.trim(result[2]));
adminUser = JSON.parse($.trim(result[3]));
subadminUser = JSON.parse($.trim(result[4]));
if (!$tr) {
return;
}
Expand All @@ -59,21 +60,25 @@
addImpersonateIcon($tr);

} else if (subadminUser) {
var found = false;
if(groupEnabled) {
for (var i = 0; i < includedGroups.length; i++) {
if ($.inArray($.trim(includedGroups[i]), groupsSelectedByUser) !== -1) {
found = true;
addImpersonateIcon($tr);
break;
if (subAdminFullAccess) {
addImpersonateIcon($tr);
} else {
var found = false;
if (groupEnabled) {
for (var i = 0; i < includedGroups.length; i++) {
if ($.inArray($.trim(includedGroups[i]), groupsSelectedByUser) !== -1) {
found = true;
addImpersonateIcon($tr);
break;
}
}
} else {
addImpersonateIcon($tr);
found = true;
}
if (found === false) {
removeImpersonateIcon($tr);
}
} else {
addImpersonateIcon($tr);
found = true;
}
if (found === false) {
removeImpersonateIcon($tr);
}
}
return $tr;
Expand Down
15 changes: 15 additions & 0 deletions js/settings-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,24 @@ $(document).ready(function () {
$("#impersonateIncludeGroups").change(function () {
$("#selectIncludedGroups").toggleClass('hidden', !this.checked);
var val = $("#impersonateIncludeGroups").is(":checked");
if (val === true) {
$("#impersonateAllGroupAdmins").attr('disabled', true);
} else {
$("#impersonateAllGroupAdmins").removeAttr('disabled');
}
OC.AppConfig.setValue('impersonate',$(this).attr('name'),val);
});

$("#impersonateAllGroupAdmins").change(function () {
var val = $("#impersonateAllGroupAdmins").is(":checked");
if (val === true) {
$("#impersonateIncludeGroups").attr('disabled', true);
} else {
$("#impersonateIncludeGroups").removeAttr('disabled');
}
OC.AppConfig.setValue('impersonate', $(this).attr('name'), val);
});

$('#includedGroups').each(function (index, element) {
OC.Settings.setupGroupsSelect($(element));
$(element).change(function(ev) {
Expand Down
7 changes: 7 additions & 0 deletions templates/settings-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@
<p class="<?php if (\OC::$server->getAppConfig()->getValue('impersonate', 'enabled', 'no') === 'no') {
p('hidden');
}?>">
<input type="checkbox" name="impersonate_all_groupadmins" id="impersonateAllGroupAdmins" class="checkbox"
value="0" <?php if (\OC::$server->getAppConfig()->getValue('impersonate', 'impersonate_all_groupadmins', 'false') !== 'false') {
print_unescaped('checked="checked"');
} ?> />
<label for="impersonateAllGroupAdmins"><?php p($l->t('Allow all group admins impresonate their users'))?></label><br/>

<input type="checkbox" name="impersonate_include_groups" id="impersonateIncludeGroups" class="checkbox"
value="1" <?php if (\OC::$server->getAppConfig()->getValue('impersonate', 'impersonate_include_groups', 'false') !== 'false') {
print_unescaped('checked="checked"');
} ?> />
<label for="impersonateIncludeGroups"><?php p($l->t('Allow group admins to impersonate users from these groups'));?></label><br/>

</p>
<p id="selectIncludedGroups" class="indent <?php if (\OC::$server->getAppConfig()->getValue('impersonate', 'impersonate_include_groups', 'false') === 'false') {
p('hidden');
Expand Down
95 changes: 71 additions & 24 deletions tests/controller/SettingsControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use OCP\IL10N;
use OCP\IRequest;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\ISession;
Expand Down Expand Up @@ -173,10 +174,12 @@ public function testImpersonate($query, $uid, $group) {
$this->controller->impersonate($query)
);
} elseif ($group === 'groupadmin') {
$this->config->expects($this->once())
$this->config
->method('getValue')
->with('impersonate', 'impersonate_include_groups_list', "")
->willReturn(\json_encode([$group]));
->will($this->returnValueMap([
['impersonate', 'impersonate_include_groups_list', "", \json_encode([$group])],
['impersonate', 'impersonate_all_groupadmins', "false", "false"]
]));

$iGroup = $this->createMock(IGroup::class);

Expand Down Expand Up @@ -209,10 +212,12 @@ function (GenericEvent $event) use (&$calledAfterImpersonate) {
$this->assertEquals('username', $calledAfterImpersonate[1]->getArgument('impersonator'));
$this->assertEquals('Username', $calledAfterImpersonate[1]->getArgument('targetUser'));
} elseif ($group === 'normaluser') {
$this->config->expects($this->once())
$this->config
->method('getValue')
->with('impersonate', 'impersonate_include_groups_list', "")
->willReturn("");
->will($this->returnValueMap([
['impersonate', 'impersonate_include_groups_list', "", ""],
['impersonate', 'impersonate_all_groupadmins', "false", "false"]
]));

$this->groupManger->expects($this->any())
->method('isAdmin')
Expand Down Expand Up @@ -253,10 +258,12 @@ public function testUserNotPartOfGroup() {
->method('getLastLogin')
->willReturn(1);

$this->config->expects($this->once())
$this->config
->method('getValue')
->with('impersonate', 'impersonate_include_groups_list', "")
->willReturn(\json_encode(['testgroup']));
->will($this->returnValueMap([
['impersonate', 'impersonate_include_groups_list', "", \json_encode(['testgroup'])],
['impersonate', 'impersonate_all_groupadmins', "false", "false"]
]));

$iGroup = $this->createMock(IGroup::class);

Expand Down Expand Up @@ -304,10 +311,12 @@ public function testWronglyConfiguredGroupListAllowsImpersonation() {
->method('getLastLogin')
->willReturn(1);

$this->config->expects($this->once())
$this->config
->method('getValue')
->with('impersonate', 'impersonate_include_groups_list', "")
->willReturn(\json_encode(['testgroup','testgroup2']));
->will($this->returnValueMap([
['impersonate', 'impersonate_include_groups_list', "", \json_encode(['testgroup','testgroup2'])],
['impersonate', 'impersonate_all_groupadmins', "false", "false"]
]));

$iGroup = $this->createMock(IGroup::class);

Expand Down Expand Up @@ -492,23 +501,29 @@ public function testRestrictNestedImpersonate($subadminUser, $subadminUid) {
/**
* @dataProvider providesGetDataForImpersonateApp
*/
public function testGetDataForImpersonateApp($enabled, $includedGroups, $currentUser, $isAdmin = false, $isSubAdmin = false) {
public function testGetDataForImpersonateApp($enabled, $includedGroups, $allowAllSubadminGroups, $currentUser, $isAdmin = false, $isSubAdmin = false) {
$map = [
['impersonate','impersonate_include_groups',false, $enabled],
['impersonate','impersonate_include_groups_list', '[]', $includedGroups]
['impersonate','impersonate_include_groups', false, $enabled],
['impersonate','impersonate_include_groups_list', '[]', $includedGroups],
['impersonate', 'impersonate_all_groupadmins', false, $allowAllSubadminGroups]
];
$this->config
->method('getValue')
->will($this->returnValueMap($map));

$user = $this->createMock('\OCP\IUser');
if ($currentUser === null) {
$user = null;
} else {
$user = $this->createMock('\OCP\IUser');
}
$this->userSession
->method('getUser')
->willReturn($user);
if ($currentUser === null) {
$user = null;
$this->assertEquals(
new JSONResponse([
$includedGroups, $enabled, false, false
$includedGroups, $enabled, $allowAllSubadminGroups, false, false
]),
$this->controller->getDataForImpersonateApp('test')
);
Expand All @@ -524,7 +539,7 @@ public function testGetDataForImpersonateApp($enabled, $includedGroups, $current
->willReturn($isSubAdmin);
$this->assertEquals(
new JSONResponse([
$includedGroups, $enabled, $isAdmin, $isSubAdmin
$includedGroups, $enabled, $allowAllSubadminGroups, $isAdmin, $isSubAdmin
]),
$this->controller->getDataForImpersonateApp('test')
);
Expand All @@ -533,12 +548,44 @@ public function testGetDataForImpersonateApp($enabled, $includedGroups, $current

public function providesGetDataForImpersonateApp() {
return [
[true, ['hello', 'world'], null],
[true, ['hello', 'world'], 'user', true, true],
[true, ['hello', 'world'], 'user', true, false],
[true, ['hello', 'world'], 'user', false, true],
[false, ['hello', 'world'], 'user', false, true],
[false, [], 'user', false, true],
[true, ['hello', 'world'], "true", null],
[true, ['hello', 'world'], "false", 'user', true, true],
[true, ['hello', 'world'], "false",'user', true, false],
[true, ['hello', 'world'], "false", 'user', false, true],
[false, ['hello', 'world'], "false", 'user', false, true],
[false, [], "true", 'user', false, true],
];
}

public function testImpersonateGrantAllSubadmin() {
$user = $this->createMock(IUser::class);
$user->method('getUID')
->willReturn('foo');

$this->userSession
->method('getUser')
->willReturn($user);

$targetUser = $this->createMock(IUser::class);
$targetUser->method('getLastLogin')
->willReturn(1);

$this->userManager->method('get')
->willReturn($targetUser);

$this->groupManger->method('isAdmin')
->willReturn(false);

$this->config
->method('getValue')
->will($this->returnValueMap([
['impersonate', 'impersonate_include_groups_list', "", ""],
['impersonate', 'impersonate_all_groupadmins', "false", "true"]
]));

$this->assertEquals(
new JSONResponse(),
$this->controller->impersonate('foo')
);
}
}

0 comments on commit 9be6a99

Please sign in to comment.