Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for all group admins to impersonate their group memebers #134

Merged
merged 2 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
13 changes: 11 additions & 2 deletions js/settings-admin.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
$(document).ready(function () {
$("#impersonateIncludeGroups").change(function () {
$("#selectIncludedGroups").toggleClass('hidden', !this.checked);
$("#selectIncludedGroups").removeClass('hidden');
var val = $("#impersonateIncludeGroups").is(":checked");
OC.AppConfig.setValue('impersonate',$(this).attr('name'),val);
OC.AppConfig.setValue('impersonate', 'impersonate_include_groups', val);
OC.AppConfig.setValue('impersonate', 'impersonate_all_groupadmins', 'false')
});

$("#impersonateAllGroupAdmins").change(function () {
var val = $("#impersonateAllGroupAdmins").is(":checked");
$("#selectIncludedGroups").addClass('hidden');
OC.AppConfig.setValue('impersonate', 'impersonate_all_groupadmins', val);
OC.AppConfig.setValue('impersonate', 'impersonate_include_groups', 'false')
OC.AppConfig.setValue('impersonate', 'impersonate_include_groups_list', JSON.stringify([]));
});

$('#includedGroups').each(function (index, element) {
Expand Down
13 changes: 10 additions & 3 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_include_groups" id="impersonateIncludeGroups" class="checkbox"
value="1" <?php if (\OC::$server->getAppConfig()->getValue('impersonate', 'impersonate_include_groups', 'false') !== 'false') {
<input type="radio" name="groupadmins" id="impersonateAllGroupAdmins" class="radio"
<?php if (\OC::$server->getAppConfig()->getValue('impersonate', 'impersonate_all_groupadmins', 'false') !== 'false') {
print_unescaped('checked="checked"');
} ?> />
<label for="impersonateIncludeGroups"><?php p($l->t('Allow group admins to impersonate users from these groups'));?></label><br/>
<label for="impersonateAllGroupAdmins"><?php p($l->t('Allow all group admins to impersonate users within the groups they are admins of'))?></label><br/>

<input type="radio" name="groupadmins" id="impersonateIncludeGroups" class="radio"
<?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 of specific groups to impersonate the users within those 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')
);
}
}