From 746a5fb7e07c806af7f0e9b0ebb3f72d823452a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 26 Jul 2022 09:39:48 +0200 Subject: Fix LDAP recursive nested group support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/user_ldap/lib/Group_LDAP.php | 11 +++++++---- apps/user_ldap/tests/Group_LDAPTest.php | 29 ++++++++++++++--------------- 2 files changed, 21 insertions(+), 19 deletions(-) (limited to 'apps') diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php index 70cc7a0107a..d5d715d1b51 100644 --- a/apps/user_ldap/lib/Group_LDAP.php +++ b/apps/user_ldap/lib/Group_LDAP.php @@ -62,7 +62,7 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I protected CappedMemoryCache $cachedGroupsByMember; /** @var CappedMemoryCache $cachedNestedGroups array of groups with gid (DN) as key */ protected CappedMemoryCache $cachedNestedGroups; - protected GroupInterface $groupPluginManager; + protected GroupPluginManager $groupPluginManager; protected LoggerInterface $logger; /** @@ -243,8 +243,9 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I * @psalm-param array $seen List of DN that have already been processed. * @throws ServerNotAvailableException */ - private function _groupMembers(string $dnGroup, array &$seen = []): array { + private function _groupMembers(string $dnGroup, array $seen = [], bool &$recursive = false): array { if (isset($seen[$dnGroup])) { + $recursive = true; return []; } $seen[$dnGroup] = true; @@ -293,7 +294,7 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I if (is_array($members)) { if ((int)$this->access->connection->ldapNestedGroups === 1) { while ($recordDn = array_shift($members)) { - $nestedMembers = $this->_groupMembers($recordDn, $seen); + $nestedMembers = $this->_groupMembers($recordDn, $seen, $recursive); if (!empty($nestedMembers)) { // Group, queue its members for processing $members = array_merge($members, $nestedMembers); @@ -317,7 +318,9 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I unset($allMembers[$index]); } - $this->access->connection->writeToCache($cacheKey, $allMembers); + if (!$recursive) { + $this->access->connection->writeToCache($cacheKey, $allMembers); + } if (isset($attemptedLdapMatchingRuleInChain) && $this->access->connection->ldapMatchingRuleInChainState === Configuration::LDAP_SERVER_FEATURE_UNKNOWN diff --git a/apps/user_ldap/tests/Group_LDAPTest.php b/apps/user_ldap/tests/Group_LDAPTest.php index d9bfe81e63c..edcb4be8819 100644 --- a/apps/user_ldap/tests/Group_LDAPTest.php +++ b/apps/user_ldap/tests/Group_LDAPTest.php @@ -1322,35 +1322,32 @@ class Group_LDAPTest extends TestCase { return [ [ #0 – test DNs - 'cn=Birds,' . $base, - $birdsDn, + ['cn=Birds,' . $base => $birdsDn], ['cn=Birds,' . $base => $birdsDn] ], [ #1 – test uids - 'cn=Birds,' . $base, - $birdsUid, + ['cn=Birds,' . $base => $birdsUid], ['cn=Birds,' . $base => $birdsUid] ], [ #2 – test simple nested group - 'cn=Animals,' . $base, - array_merge($birdsDn, $animalsDn), + ['cn=Animals,' . $base => array_merge($birdsDn, $animalsDn)], [ 'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn), 'cn=Birds,' . $base => $birdsDn, ] ], [ #3 – test recursive nested group - 'cn=Animals,' . $base, - // Because of complicated nesting the group gets returned as a member - array_merge(['cn=Birds,' . $base], $birdsDn, $animalsDn), + [ + 'cn=Animals,' . $base => array_merge($birdsDn, $animalsDn), + 'cn=Birds,' . $base => array_merge($birdsDn, $animalsDn), + ], [ 'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base,'cn=Birds,' . $base,'cn=Animals,' . $base], $animalsDn), 'cn=Birds,' . $base => array_merge(['cn=Animals,' . $base,'cn=Birds,' . $base], $birdsDn), ] ], [ #4 – Complicated nested group - 'cn=Things,' . $base, - array_merge($birdsDn, $animalsDn, $thingsDn, $plantsDn), + ['cn=Things,' . $base => array_merge($birdsDn, $animalsDn, $thingsDn, $plantsDn)], [ 'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn), 'cn=Birds,' . $base => $birdsDn, @@ -1365,11 +1362,11 @@ class Group_LDAPTest extends TestCase { * @param string[] $expectedMembers * @dataProvider groupMemberProvider */ - public function testGroupMembers(string $groupDN, array $expectedMembers, $groupsInfo = null) { + public function testGroupMembers(array $expectedResult, array $groupsInfo = null) { $access = $this->getAccessMock(); $access->expects($this->any()) ->method('readAttribute') - ->willReturnCallback(function ($group) use ($groupDN, $expectedMembers, $groupsInfo) { + ->willReturnCallback(function ($group) use ($groupsInfo) { if (isset($groupsInfo[$group])) { return $groupsInfo[$group]; } @@ -1392,9 +1389,11 @@ class Group_LDAPTest extends TestCase { $pluginManager = $this->createMock(GroupPluginManager::class); $ldap = new GroupLDAP($access, $pluginManager); - $resultingMembers = $this->invokePrivate($ldap, '_groupMembers', [$groupDN]); + foreach ($expectedResult as $groupDN => $expectedMembers) { + $resultingMembers = $this->invokePrivate($ldap, '_groupMembers', [$groupDN]); - $this->assertEqualsCanonicalizing($expectedMembers, $resultingMembers); + $this->assertEqualsCanonicalizing($expectedMembers, $resultingMembers); + } } public function displayNameProvider() { -- cgit v1.2.3