Signed-off-by: Carl Schwan <carl@carlschwan.eu>tags/v26.0.0beta1
@@ -64,6 +64,9 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I | |||
protected GroupPluginManager $groupPluginManager; | |||
protected LoggerInterface $logger; | |||
/** @psalm-var array<string, string[]|bool> $rawMemberReads */ | |||
protected $rawMemberReads = []; // runtime cache for intermediate ldap read results | |||
/** | |||
* @var string $ldapGroupMemberAssocAttr contains the LDAP setting (in lower case) with the same name | |||
*/ | |||
@@ -289,12 +292,10 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I | |||
$allMembers = []; | |||
/** @psalm-var array<string, string[]|bool> $rawMemberReads */ | |||
static $rawMemberReads = []; // runtime cache for intermediate ldap read results | |||
$members = $rawMemberReads[$dnGroup] ?? null; | |||
$members = $this->rawMemberReads[$dnGroup] ?? null; | |||
if ($members === null) { | |||
$members = $this->access->readAttribute($dnGroup, $this->access->connection->ldapGroupMemberAssocAttr); | |||
$rawMemberReads[$dnGroup] = $members; | |||
$this->rawMemberReads[$dnGroup] = $members; | |||
} | |||
if (is_array($members)) { | |||
@@ -780,8 +781,6 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I | |||
// getGroupsByMember is a recursive method and the results stored in | |||
// the cache depends on the already seen groups. This breaks when we | |||
// have circular groups | |||
$this->cachedGroupsByMember = new CappedMemoryCache(); | |||
$groupsByMember = array_values($this->getGroupsByMember($uid)); | |||
$groupsByMember = $this->access->nextcloudGroupNames($groupsByMember); | |||
$groups = array_merge($groups, $groupsByMember); | |||
@@ -809,10 +808,11 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I | |||
if (isset($seen[$dn])) { | |||
return []; | |||
} | |||
$cacheKey = $dn . implode('-', array_keys($seen)); | |||
$seen[$dn] = true; | |||
if ($this->cachedGroupsByMember[$dn]) { | |||
return $this->cachedGroupsByMember[$dn]; | |||
if ($this->cachedGroupsByMember[$cacheKey]) { | |||
return $this->cachedGroupsByMember[$cacheKey]; | |||
} | |||
$filter = $this->access->connection->ldapGroupMemberAssocAttr . '=' . $dn; | |||
@@ -843,7 +843,7 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I | |||
} | |||
$visibleGroups = $this->filterValidGroups($allGroups); | |||
$this->cachedGroupsByMember[$dn] = $visibleGroups; | |||
$this->cachedGroupsByMember[$cacheKey] = $visibleGroups; | |||
return $visibleGroups; | |||
} | |||
@@ -27,9 +27,9 @@ | |||
namespace OCA\User_LDAP\Mapping; | |||
use Doctrine\DBAL\Exception; | |||
use OC\DB\QueryBuilder\QueryBuilder; | |||
use OCP\DB\IPreparedStatement; | |||
use OCP\DB\QueryBuilder\IQueryBuilder; | |||
use Doctrine\DBAL\Platforms\SqlitePlatform; | |||
/** | |||
* Class AbstractMapping | |||
@@ -219,12 +219,12 @@ abstract class AbstractMapping { | |||
$qb = $this->dbc->getQueryBuilder(); | |||
$qb->select('owncloud_name', 'ldap_dn_hash', 'ldap_dn') | |||
->from($this->getTableName(false)) | |||
->where($qb->expr()->in('ldap_dn_hash', $qb->createNamedParameter($hashList, QueryBuilder::PARAM_STR_ARRAY))); | |||
->where($qb->expr()->in('ldap_dn_hash', $qb->createNamedParameter($hashList, IQueryBuilder::PARAM_STR_ARRAY))); | |||
return $qb; | |||
} | |||
protected function collectResultsFromListOfIdsQuery(IQueryBuilder $qb, array &$results): void { | |||
$stmt = $qb->execute(); | |||
$stmt = $qb->executeQuery(); | |||
while ($entry = $stmt->fetch(\Doctrine\DBAL\FetchMode::ASSOCIATIVE)) { | |||
$results[$entry['ldap_dn']] = $entry['owncloud_name']; | |||
$this->cache[$entry['ldap_dn']] = $entry['owncloud_name']; | |||
@@ -239,7 +239,7 @@ abstract class AbstractMapping { | |||
public function getListOfIdsByDn(array $fdns): array { | |||
$totalDBParamLimit = 65000; | |||
$sliceSize = 1000; | |||
$maxSlices = $totalDBParamLimit / $sliceSize; | |||
$maxSlices = $this->dbc->getDatabasePlatform() instanceof SqlitePlatform ? 9 : $totalDBParamLimit / $sliceSize; | |||
$results = []; | |||
$slice = 1; | |||
@@ -261,7 +261,7 @@ abstract class AbstractMapping { | |||
} | |||
if (!empty($fdnsSlice)) { | |||
$qb->orWhere($qb->expr()->in('ldap_dn_hash', $qb->createNamedParameter($fdnsSlice, QueryBuilder::PARAM_STR_ARRAY))); | |||
$qb->orWhere($qb->expr()->in('ldap_dn_hash', $qb->createNamedParameter($fdnsSlice, IQueryBuilder::PARAM_STR_ARRAY))); | |||
} | |||
if ($slice % $maxSlices === 0) { |
@@ -941,7 +941,7 @@ class Group_LDAPTest extends TestCase { | |||
$access->connection = $this->createMock(Connection::class); | |||
$access->connection->expects($this->any()) | |||
->method('__get') | |||
->willReturnCallback(function ($name) use ($nestedGroups, $groupFilter) { | |||
->willReturnCallback(function (string $name) use ($nestedGroups, $groupFilter) { | |||
switch ($name) { | |||
case 'useMemberOfToDetectMembership': | |||
return 0; | |||
@@ -1013,10 +1013,7 @@ class Group_LDAPTest extends TestCase { | |||
} | |||
[$memberFilter] = explode('&', $filter); | |||
if ($memberFilter === 'member='.$dn) { | |||
if ($firstRun) { | |||
$firstRun = false; | |||
return [$group1, $group2]; | |||
} | |||
return []; | |||
} elseif ($memberFilter === 'member='.$group2['dn'][0]) { | |||
return [$group3]; | |||
@@ -1365,12 +1362,10 @@ class Group_LDAPTest extends TestCase { | |||
} | |||
/** | |||
* @param string $groupDN | |||
* @param string[] $expectedMembers | |||
* @param array $groupsInfo | |||
* @dataProvider groupMemberProvider | |||
*/ | |||
public function testGroupMembers($groupDN, $expectedMembers, $groupsInfo = null) { | |||
public function testGroupMembers(string $groupDN, array $expectedMembers, $groupsInfo = null) { | |||
$access = $this->getAccessMock(); | |||
$access->expects($this->any()) | |||
->method('readAttribute') | |||
@@ -1384,7 +1379,7 @@ class Group_LDAPTest extends TestCase { | |||
$access->connection = $this->createMock(Connection::class); | |||
$access->connection->expects($this->any()) | |||
->method('__get') | |||
->willReturnCallback(function ($name) { | |||
->willReturnCallback(function (string $name) { | |||
if ($name === 'ldapNestedGroups') { | |||
return 1; | |||
} elseif ($name === 'ldapGroupMemberAssocAttr') { |