Add and remove user groups with SAML

Based on PR #95, however:
- Also removes groups based on the group attribute(s).
- Supports groups with spaces (which the previous PR didn't).
- Includes unit test

Signed-off-by: Sérgio Faria <sergio.faria@is4health.com>
This commit is contained in:
Sérgio Faria 2018-02-27 14:10:38 +00:00
parent 18aa824206
commit 423a76a843
2 changed files with 89 additions and 15 deletions

View file

@ -421,12 +421,18 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
self::$backends = $backends;
}
private function getAttributeValue($name, array $attributes) {
private function getAttributeKeys($name)
{
$keys = explode(' ', $this->config->getAppValue('user_saml', $name, ''));
if(count($keys) === 1 && $keys[0] === '') {
if (count($keys) === 1 && $keys[0] === '') {
throw new \InvalidArgumentException('Attribute is not configured');
}
return $keys;
}
private function getAttributeValue($name, array $attributes) {
$keys = $this->getAttributeKeys($name);
$value = '';
foreach($keys as $key) {
@ -450,6 +456,23 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
return $value;
}
private function getAttributeArrayValue($name, array $attributes) {
$keys = $this->getAttributeKeys($name);
$value = array();
foreach($keys as $key) {
if (isset($attributes[$key])) {
if (is_array($attributes[$key])) {
$value = array_merge($value, array_values($attributes[$key]));
} else {
$value[] = $attributes[$key];
}
}
}
return $value;
}
public function updateAttributes($uid,
array $attributes) {
$user = $this->userManager->get($uid);
@ -473,7 +496,7 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
}
try {
$newGroups = $this->getAttributeValue('saml-attribute-mapping-group_mapping', $attributes);
$newGroups = $this->getAttributeArrayValue('saml-attribute-mapping-group_mapping', $attributes);
} catch (\InvalidArgumentException $e) {
$newGroups = null;
}
@ -486,7 +509,7 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
$user->setEMailAddress($newEmail);
}
$currentDisplayname = (string)$this->getDisplayName($uid);
if($newDisplayname !== null
if ($newDisplayname !== null
&& $currentDisplayname !== $newDisplayname) {
\OC_Hook::emit('OC_User', 'changeUser',
[
@ -502,16 +525,22 @@ class UserBackend implements IApacheBackend, UserInterface, IUserBackend {
$user->setQuota($newQuota);
}
if ($newGroups !==null) {
$groups = explode(' ', $newGroups);
foreach ($groups as $group) {
if (!($this->groupManager->groupExists($group))) {
$this->groupManager->createGroup($group);
}
$groupInBackend = $this->groupManager->get($group);
if (!$groupInBackend->inGroup($user)) {
$groupInBackend->addUser($user);
if ($newGroups !== null) {
$groupManager = $this->groupManager;
$oldGroups = $groupManager->getUserGroupIds($user);
$groupsToAdd = array_unique(array_diff($newGroups, $oldGroups));
$groupsToRemove = array_diff($oldGroups, $newGroups);
foreach ($groupsToAdd as $group) {
if (!($groupManager->groupExists($group))) {
$groupManager->createGroup($group);
}
$groupManager->get($group)->addUser($user);
}
foreach ($groupsToRemove as $group) {
$groupManager->get($group)->removeUser($user);
}
}
}

View file

@ -24,11 +24,11 @@ namespace OCA\User_SAML\Tests\Settings;
use OCA\User_SAML\UserBackend;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserBackend;
use OCP\IUserManager;
use Test\TestCase;
@ -128,6 +128,8 @@ class UserBackendTest extends TestCase {
$this->getMockedBuilder(['getDisplayName', 'setDisplayName']);
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject $user */
$user = $this->createMock(IUser::class);
$groupA = $this->createMock(IGroup::class);
$groupC = $this->createMock(IGroup::class);
$this->config
->expects($this->at(0))
@ -144,6 +146,11 @@ class UserBackendTest extends TestCase {
->method('getAppValue')
->with('user_saml', 'saml-attribute-mapping-quota_mapping', '')
->willReturn('quota');
$this->config
->expects($this->at(3))
->method('getAppValue')
->with('user_saml', 'saml-attribute-mapping-group_mapping', '')
->willReturn('groups');
$this->userManager
->expects($this->once())
@ -171,7 +178,45 @@ class UserBackendTest extends TestCase {
->expects($this->once())
->method('setDisplayName')
->with('ExistingUser', 'New Displayname');
$this->userBackend->updateAttributes('ExistingUser', ['email' => 'new@example.com', 'displayname' => 'New Displayname', 'quota' => '50MB']);
$this->groupManager
->expects($this->once())
->method('getUserGroupIds')
->with($user)
->willReturn(['groupA', 'groupB']);
$this->groupManager
->expects($this->once())
->method('groupExists')
->with('groupC')
->willReturn(false);
$this->groupManager
->expects($this->once())
->method('createGroup')
->with('groupC');
// updateAttributes first adds new groups, then removes old ones
// In this test groupA is removed from the user, groupB is unchanged
// and groupC is added
$this->groupManager
->expects($this->exactly(2))
->method('get')
->withConsecutive(['groupC'], ['groupA'])
->willReturnOnConsecutiveCalls($groupC, $groupA);
$groupA
->expects($this->once())
->method('removeUser')
->with($user);
$groupC
->expects($this->once())
->method('addUser')
->with($user);
$this->userBackend->updateAttributes('ExistingUser', [
'email' => 'new@example.com',
'displayname' => 'New Displayname',
'quota' => '50MB',
'groups' => ['groupB', 'groupC'],
]);
}
public function testUpdateAttributesQuotaDefaultFallback() {