@@ -64,10 +64,7 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I
6464 protected $ groupPluginManager ;
6565 /** @var LoggerInterface */
6666 protected $ logger ;
67-
68- /**
69- * @var string $ldapGroupMemberAssocAttr contains the LDAP setting (in lower case) with the same name
70- */
67+ /** @var string $ldapGroupMemberAssocAttr contains the LDAP setting (in lower case) with the same name */
7168 protected $ ldapGroupMemberAssocAttr ;
7269
7370 public function __construct (Access $ access , GroupPluginManager $ groupPluginManager ) {
@@ -304,7 +301,7 @@ private function _groupMembers(string $dnGroup, ?array &$seen = null): array {
304301 $ fetcher = function ($ memberDN ) use (&$ seen ) {
305302 return $ this ->_groupMembers ($ memberDN , $ seen );
306303 };
307- $ allMembers = $ this ->walkNestedGroups ($ dnGroup , $ fetcher , $ members , $ seen );
304+ $ allMembers = $ this ->walkNestedGroupsReturnDNs ($ dnGroup , $ fetcher , $ members , $ seen );
308305 }
309306
310307 $ allMembers += $ this ->getDynamicGroupMembers ($ dnGroup );
@@ -351,29 +348,11 @@ private function _getGroupDNsFromMemberOf(string $dn): array {
351348 return $ nestedGroups ;
352349 };
353350
354- $ groups = $ this ->walkNestedGroups ($ dn , $ fetcher , $ groups );
351+ $ groups = $ this ->walkNestedGroupsReturnDNs ($ dn , $ fetcher , $ groups );
355352 return $ this ->filterValidGroups ($ groups );
356353 }
357354
358- private function walkNestedGroups (string $ dn , Closure $ fetcher , array $ list , array &$ seen = []): array {
359- $ nesting = (int )$ this ->access ->connection ->ldapNestedGroups ;
360- // depending on the input, we either have a list of DNs or a list of LDAP records
361- // also, the output expects either DNs or records. Testing the first element should suffice.
362- $ recordMode = is_array ($ list ) && isset ($ list [0 ]) && is_array ($ list [0 ]) && isset ($ list [0 ]['dn ' ][0 ]);
363-
364- if ($ nesting !== 1 ) {
365- if ($ recordMode ) {
366- // the keys are numeric, but should hold the DN
367- return array_reduce ($ list , function ($ transformed , $ record ) use ($ dn ) {
368- if ($ record ['dn ' ][0 ] != $ dn ) {
369- $ transformed [$ record ['dn ' ][0 ]] = $ record ;
370- }
371- return $ transformed ;
372- }, []);
373- }
374- return $ list ;
375- }
376-
355+ private function processListFromWalkingNestedGroups (array &$ list , array &$ seen , string $ dn , Closure $ fetcher ): void {
377356 while ($ record = array_shift ($ list )) {
378357 $ recordDN = $ record ['dn ' ][0 ] ?? $ record ;
379358 if ($ recordDN === $ dn || array_key_exists ($ recordDN , $ seen )) {
@@ -386,9 +365,35 @@ private function walkNestedGroups(string $dn, Closure $fetcher, array $list, arr
386365 $ seen [$ recordDN ] = $ record ;
387366 }
388367 }
368+ }
369+
370+ private function walkNestedGroupsReturnDNs (string $ dn , Closure $ fetcher , array $ list , array &$ seen = []): array {
371+ $ nesting = (int )$ this ->access ->connection ->ldapNestedGroups ;
372+
373+ if ($ nesting !== 1 ) {
374+ return $ list ;
375+ }
376+
377+ $ this ->processListFromWalkingNestedGroups ($ list , $ seen , $ dn , $ fetcher );
378+ return array_keys ($ seen );
379+ }
380+
381+ private function walkNestedGroupsReturnRecords (string $ dn , Closure $ fetcher , array $ list , array &$ seen = []): array {
382+ $ nesting = (int )$ this ->access ->connection ->ldapNestedGroups ;
383+
384+ if ($ nesting !== 1 ) {
385+ // the keys are numeric, but we need them to hold the DN
386+ return array_reduce ($ list , function ($ transformed , $ record ) use ($ dn ) {
387+ if ($ record ['dn ' ][0 ] != $ dn ) {
388+ $ transformed [$ record ['dn ' ][0 ]] = $ record ;
389+ }
390+ return $ transformed ;
391+ }, []);
392+ }
389393
390- // on record mode, filter out intermediate state
391- return $ recordMode ? array_filter ($ seen , 'is_array ' ) : array_keys ($ seen );
394+ $ this ->processListFromWalkingNestedGroups ($ list , $ seen , $ dn , $ fetcher );
395+ // filter out intermediate state
396+ return array_filter ($ seen , 'is_array ' );
392397 }
393398
394399 /**
@@ -847,6 +852,9 @@ private function getGroupsByMember(string $dn, array &$seen = null): array {
847852 // avoid loops
848853 return [];
849854 }
855+ if ($ this ->cachedGroupsByMember [$ dn ]) {
856+ return $ this ->cachedGroupsByMember [$ dn ];
857+ }
850858 $ allGroups = [];
851859 $ seen [$ dn ] = true ;
852860 $ filter = $ this ->access ->connection ->ldapGroupMemberAssocAttr . '= ' . $ dn ;
@@ -871,14 +879,12 @@ private function getGroupsByMember(string $dn, array &$seen = null): array {
871879 return $ this ->getGroupsByMember ($ dn , $ seen );
872880 };
873881
874- if (empty ($ dn )) {
875- $ dn = "" ;
876- }
877-
878- $ allGroups = $ this ->walkNestedGroups ($ dn , $ fetcher , $ groups , $ seen );
882+ $ allGroups = $ this ->walkNestedGroupsReturnRecords ($ dn , $ fetcher , $ groups , $ seen );
879883 }
880884 $ visibleGroups = $ this ->filterValidGroups ($ allGroups );
881- return array_intersect_key ($ allGroups , $ visibleGroups );
885+ $ effectiveGroups = array_intersect_key ($ allGroups , $ visibleGroups );
886+ $ this ->cachedGroupsByMember [$ dn ] = $ effectiveGroups ;
887+ return $ effectiveGroups ;
882888 }
883889
884890 /**
@@ -1184,7 +1190,12 @@ protected function filterValidGroups(array $listOfGroups): array {
11841190 $ validGroupDNs = [];
11851191 foreach ($ listOfGroups as $ key => $ item ) {
11861192 $ dn = is_string ($ item ) ? $ item : $ item ['dn ' ][0 ];
1187- $ gid = $ this ->access ->dn2groupname ($ dn );
1193+ if (is_array ($ item ) && !isset ($ item [$ this ->access ->connection ->ldapGroupDisplayName ][0 ])) {
1194+ // group details were fetched, but a name attribute was not set: do not bother to re-fetch
1195+ continue ;
1196+ }
1197+ $ name = $ item [$ this ->access ->connection ->ldapGroupDisplayName ][0 ] ?? null ;
1198+ $ gid = $ this ->access ->dn2groupname ($ dn , $ name );
11881199 if (!$ gid ) {
11891200 continue ;
11901201 }
0 commit comments