summaryrefslogtreecommitdiffstats
path: root/apps/user_ldap/lib/Group_LDAP.php
diff options
context:
space:
mode:
authorCôme Chilliet <come.chilliet@nextcloud.com>2021-12-13 12:17:06 +0100
committerCarl Schwan <carl@carlschwan.eu>2022-10-20 12:09:06 +0200
commitd07f43dc12addf21aaa76e6b330560b42d8f3ced (patch)
treed8a65caef71633a9a1a09da26de85af36289374b /apps/user_ldap/lib/Group_LDAP.php
parent6522f8a6d98f81a10f68cd01294201997d51c3a0 (diff)
downloadnextcloud-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.php63
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;
}