diff options
author | Côme Chilliet <come.chilliet@nextcloud.com> | 2021-12-13 12:17:06 +0100 |
---|---|---|
committer | Carl Schwan <carl@carlschwan.eu> | 2022-10-20 12:09:06 +0200 |
commit | d07f43dc12addf21aaa76e6b330560b42d8f3ced (patch) | |
tree | d8a65caef71633a9a1a09da26de85af36289374b /apps/user_ldap/lib/Group_LDAP.php | |
parent | 6522f8a6d98f81a10f68cd01294201997d51c3a0 (diff) | |
download | nextcloud-server-d07f43dc12addf21aaa76e6b330560b42d8f3ced.tar.gz nextcloud-server-d07f43dc12addf21aaa76e6b330560b42d8f3ced.zip |
Refactor _groupMembers to correctly use cache on intermediate results
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
Diffstat (limited to 'apps/user_ldap/lib/Group_LDAP.php')
-rw-r--r-- | apps/user_ldap/lib/Group_LDAP.php | 63 |
1 files changed, 28 insertions, 35 deletions
diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php index c2259c42aba..3962b064fde 100644 --- a/apps/user_ldap/lib/Group_LDAP.php +++ b/apps/user_ldap/lib/Group_LDAP.php @@ -240,26 +240,15 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I /** * Get group members from dn. - * @psalm-param array<string, int|array|string> $seen List of DN that have already been processed. + * @psalm-param array<string, bool> $seen List of DN that have already been processed. * @throws ServerNotAvailableException */ - private function _groupMembers(string $dnGroup, ?array &$seen = null): array { - if ($seen === null) { - $seen = []; - // the root entry has to be marked as processed to avoid infinite loops, - // but not included in the results later on - $excludeFromResult = $dnGroup; - } - // cache only base groups, otherwise groups get additional unwarranted members - $shouldCacheResult = count($seen) === 0; - - /** @psalm-var array<string, string[]|bool> $rawMemberReads */ - static $rawMemberReads = []; // runtime cache for intermediate ldap read results - $allMembers = []; - - if (array_key_exists($dnGroup, $seen)) { + private function _groupMembers(string $dnGroup, array &$seen = []): array { + if (isset($seen[$dnGroup])) { return []; } + $seen[$dnGroup] = true; + // used extensively in cron job, caching makes sense for nested groups $cacheKey = '_groupMembers' . $dnGroup; $groupMembers = $this->access->connection->getFromCache($cacheKey); @@ -288,40 +277,43 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I return $carry; }, []); if ($this->access->connection->ldapMatchingRuleInChainState === Configuration::LDAP_SERVER_FEATURE_AVAILABLE) { + $this->access->connection->writeToCache($cacheKey, $result); return $result; } elseif (!empty($memberRecords)) { $this->access->connection->ldapMatchingRuleInChainState = Configuration::LDAP_SERVER_FEATURE_AVAILABLE; $this->access->connection->saveConfiguration(); + $this->access->connection->writeToCache($cacheKey, $result); return $result; } // when feature availability is unknown, and the result is empty, continue and test with original approach } - $seen[$dnGroup] = 1; - $members = $rawMemberReads[$dnGroup] ?? null; - if ($members === null) { - $members = $this->access->readAttribute($dnGroup, $this->access->connection->ldapGroupMemberAssocAttr); - $rawMemberReads[$dnGroup] = $members; - } + $allMembers = []; + $members = $this->access->readAttribute($dnGroup, $this->access->connection->ldapGroupMemberAssocAttr); if (is_array($members)) { - $fetcher = function (string $memberDN) use (&$seen) { - return $this->_groupMembers($memberDN, $seen); - }; - $allMembers = $this->walkNestedGroupsReturnDNs($dnGroup, $fetcher, $members, $seen); + if ((int)$this->access->connection->ldapNestedGroups === 1) { + while ($recordDn = array_shift($members)) { + $nestedMembers = $this->_groupMembers($recordDn, $seen); + $members = array_merge($members, $nestedMembers); + $allMembers[] = $recordDn; + } + } else { + $allMembers = $members; + } } $allMembers += $this->getDynamicGroupMembers($dnGroup); - if (isset($excludeFromResult)) { - $index = array_search($excludeFromResult, $allMembers, true); - if ($index !== false) { - unset($allMembers[$index]); - } - } - if ($shouldCacheResult) { - $this->access->connection->writeToCache($cacheKey, $allMembers); - unset($rawMemberReads[$dnGroup]); + $allMembers = array_unique($allMembers); + + // A group cannot be a member of itself + $index = array_search($dnGroup, $allMembers, true); + if ($index !== false) { + unset($allMembers[$index]); } + + $this->access->connection->writeToCache($cacheKey, $allMembers); + if (isset($attemptedLdapMatchingRuleInChain) && $this->access->connection->ldapMatchingRuleInChainState === Configuration::LDAP_SERVER_FEATURE_UNKNOWN && !empty($allMembers) @@ -329,6 +321,7 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I $this->access->connection->ldapMatchingRuleInChainState = Configuration::LDAP_SERVER_FEATURE_UNAVAILABLE; $this->access->connection->saveConfiguration(); } + return $allMembers; } |