Skip to content

Commit

Permalink
when nesting is not enabled, the group filter can be applied right away
Browse files Browse the repository at this point in the history
- helps performance, but skipping unnecessary entries
- reduces reoccuring info-level log output against groups that do not
  qualify ("no or empty name")

Signed-off-by: Arthur Schiwon <[email protected]>
  • Loading branch information
blizzz authored and backportbot[bot] committed Oct 19, 2020
1 parent 90f4948 commit 99a6261
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 7 deletions.
2 changes: 1 addition & 1 deletion apps/user_ldap/lib/Group_LDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ private function walkNestedGroups(string $dn, \Closure $fetcher, array $list): a
}

$seen = [];
while ($record = array_pop($list)) {
while ($record = array_shift($list)) {
$recordDN = $recordMode ? $record['dn'][0] : $record;
if ($recordDN === $dn || array_key_exists($recordDN, $seen)) {
// Prevent loops
Expand Down
42 changes: 36 additions & 6 deletions apps/user_ldap/tests/Group_LDAPTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -727,23 +727,36 @@ public function testGetUserGroupsMemberOfDisabled() {
$groupBackend->getUserGroups('userX');
}

public function testGetGroupsByMember() {
public function nestedGroupsProvider(): array {
return [
[ true ],
[ false ],
];
}

/**
* @dataProvider nestedGroupsProvider
*/
public function testGetGroupsByMember(bool $nestedGroups) {
$access = $this->getAccessMock();
$pluginManager = $this->getPluginManagerMock();

$groupFilter = '(&(objectclass=nextcloudGroup)(nextcloudEnabled=TRUE))';
$access->connection = $this->createMock(Connection::class);
$access->connection->expects($this->any())
->method('__get')
->willReturnCallback(function ($name) {
->willReturnCallback(function ($name) use ($nestedGroups, $groupFilter) {
switch ($name) {
case 'useMemberOfToDetectMembership':
return 0;
case 'ldapDynamicGroupMemberURL':
return '';
case 'ldapNestedGroups':
return false;
return $nestedGroups;
case 'ldapGroupMemberAssocAttr':
return 'member';
case 'ldapGroupFilter':
return $groupFilter;
}
return 1;
});
Expand All @@ -756,10 +769,15 @@ public function testGetGroupsByMember() {
$access->expects($this->exactly(2))
->method('username2dn')
->willReturn($dn);

$access->expects($this->any())
->method('readAttribute')
->willReturn([]);
$access->expects($this->any())
->method('combineFilterWithAnd')
->willReturnCallback(function (array $filterParts) {
// ⚠ returns a pseudo-filter only, not real LDAP Filter syntax
return implode('&', $filterParts);
});

$group1 = [
'cn' => 'group1',
Expand All @@ -774,9 +792,21 @@ public function testGetGroupsByMember() {
->method('nextcloudGroupNames')
->with([$group1, $group2])
->willReturn(['group1', 'group2']);
$access->expects($this->once())
$access->expects($nestedGroups ? $this->atLeastOnce() : $this->once())
->method('fetchListOfGroups')
->willReturn([$group1, $group2]);
->willReturnCallback(function ($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2) {
static $firstRun = true;
if (!$nestedGroups) {
// When nested groups are enabled, groups cannot be filtered early as it would
// exclude intermediate groups. But we can, and should, when working with flat groups.
$this->assertTrue(strpos($filter, $groupFilter) !== false);
}
if ($firstRun) {
$firstRun = false;
return [$group1, $group2];
}
return [];
});
$access->expects($this->any())
->method('dn2groupname')
->willReturnCallback(function (string $dn) {
Expand Down

0 comments on commit 99a6261

Please sign in to comment.