@@ -218,12 +218,12 @@ public function getDynamicGroupMembers($dnGroup) {
218218 */
219219 private function _groupMembers ($ dnGroup , &$ seen = null ) {
220220 if ($ seen === null ) {
221- $ seen = array () ;
221+ $ seen = [] ;
222222 }
223- $ allMembers = array () ;
223+ $ allMembers = [] ;
224224 if (array_key_exists ($ dnGroup , $ seen )) {
225225 // avoid loops
226- return array () ;
226+ return [] ;
227227 }
228228 // used extensively in cron job, caching makes sense for nested groups
229229 $ cacheKey = '_groupMembers ' .$ dnGroup ;
@@ -232,19 +232,12 @@ private function _groupMembers($dnGroup, &$seen = null) {
232232 return $ groupMembers ;
233233 }
234234 $ seen [$ dnGroup ] = 1 ;
235- $ members = $ this ->access ->readAttribute ($ dnGroup , $ this ->access ->connection ->ldapGroupMemberAssocAttr ,
236- $ this ->access ->connection ->ldapGroupFilter );
235+ $ members = $ this ->access ->readAttribute ($ dnGroup , $ this ->access ->connection ->ldapGroupMemberAssocAttr );
237236 if (is_array ($ members )) {
238- foreach ($ members as $ member ) {
239- $ allMembers [$ member ] = 1 ;
240- $ nestedGroups = $ this ->access ->connection ->ldapNestedGroups ;
241- if (!empty ($ nestedGroups )) {
242- $ subMembers = $ this ->_groupMembers ($ member , $ seen );
243- if ($ subMembers ) {
244- $ allMembers += $ subMembers ;
245- }
246- }
247- }
237+ $ fetcher = function ($ memberDN , &$ seen ) {
238+ return $ this ->_groupMembers ($ memberDN , $ seen );
239+ };
240+ $ allMembers = $ this ->walkNestedGroups ($ dnGroup , $ fetcher , $ members );
248241 }
249242
250243 $ allMembers += $ this ->getDynamicGroupMembers ($ dnGroup );
@@ -257,42 +250,69 @@ private function _groupMembers($dnGroup, &$seen = null) {
257250 * @param string $DN
258251 * @param array|null &$seen
259252 * @return array
253+ * @throws \OC\ServerNotAvailableException
260254 */
261255 private function _getGroupDNsFromMemberOf ($ DN ) {
262256 $ groups = $ this ->access ->readAttribute ($ DN , 'memberOf ' );
263257 if (!is_array ($ groups )) {
264- return array () ;
258+ return [] ;
265259 }
266- $ nestedGroups = (int ) $ this ->access ->connection ->ldapNestedGroups ;
267- if ($ nestedGroups === 1 ) {
268- $ seen = array ();
269- while ($ group = array_pop ($ groups )) {
270- if ($ group === $ DN || array_key_exists ($ group , $ seen )) {
271- // Prevent loops
272- continue ;
273- }
274- $ seen [$ group ] = 1 ;
275260
276- // Resolve nested groups
277- if (isset ($ cachedNestedGroups [$ group ])) {
278- $ nestedGroups = $ cachedNestedGroups [$ group ];
279- } else {
280- $ nestedGroups = $ this ->access ->readAttribute ($ group , 'memberOf ' );
281- if (!is_array ($ nestedGroups )) {
282- $ nestedGroups = [];
283- }
284- $ cachedNestedGroups [$ group ] = $ nestedGroups ;
285- }
286- foreach ($ nestedGroups as $ nestedGroup ) {
287- array_push ($ groups , $ nestedGroup );
261+ $ fetcher = function ($ groupDN ) {
262+ if (isset ($ this ->cachedNestedGroups [$ groupDN ])) {
263+ $ nestedGroups = $ this ->cachedNestedGroups [$ groupDN ];
264+ } else {
265+ $ nestedGroups = $ this ->access ->readAttribute ($ groupDN , 'memberOf ' );
266+ if (!is_array ($ nestedGroups )) {
267+ $ nestedGroups = [];
288268 }
269+ $ this ->cachedNestedGroups [$ groupDN ] = $ nestedGroups ;
289270 }
290- // Get unique group DN's from those we have visited in the loop
291- $ groups = array_keys ($ seen );
292- }
271+ return $ nestedGroups ;
272+ };
273+
274+ $ groups = $ this ->walkNestedGroups ($ DN , $ fetcher , $ groups );
293275 return $ this ->access ->groupsMatchFilter ($ groups );
294276 }
295277
278+ /**
279+ * @param string $dn
280+ * @param \Closure $fetcher args: string $dn, array $seen, returns: string[] of dns
281+ * @param array $list
282+ * @return array
283+ */
284+ private function walkNestedGroups (string $ dn , \Closure $ fetcher , array $ list ): array {
285+ $ nestedRecords = (int ) $ this ->access ->connection ->ldapNestedGroups ;
286+ if ($ nestedRecords !== 1 ) {
287+ return $ list ;
288+ }
289+ $ seen = [];
290+ $ recordMode = false ;
291+ while ($ record = array_pop ($ list )) {
292+ if (is_string ($ record )) {
293+ $ recordDN = $ record ;
294+ } else if (is_array ($ record ) && isset ($ record ['dn ' ][0 ])) {
295+ $ recordDN = $ record ['dn ' ][0 ];
296+ $ recordMode = true ;
297+ }
298+ if (!isset ($ recordDN )) {
299+ throw new \InvalidArgumentException ('Supplied list is incompatible ' );
300+ }
301+ if ($ recordDN === $ dn || array_key_exists ($ recordDN , $ seen )) {
302+ // Prevent loops
303+ continue ;
304+ }
305+ $ fetched = $ fetcher ($ record , $ seen );
306+ $ list = array_merge ($ list , $ fetched );
307+ $ seen [$ recordDN ] = $ record ;
308+ }
309+ // Get unique group DN's from those we have visited in the loop
310+ if ($ recordMode ) {
311+ return ($ seen );
312+ }
313+ return array_keys ($ seen );
314+ }
315+
296316 /**
297317 * translates a gidNumber into an ownCloud internal name
298318 * @param string $gid as given by gidNumber on POSIX LDAP
@@ -753,34 +773,28 @@ public function getUserGroups($uid) {
753773 */
754774 private function getGroupsByMember ($ dn , &$ seen = null ) {
755775 if ($ seen === null ) {
756- $ seen = array () ;
776+ $ seen = [] ;
757777 }
758- $ allGroups = array ();
759778 if (array_key_exists ($ dn , $ seen )) {
760779 // avoid loops
761- return array () ;
780+ return [] ;
762781 }
782+ $ allGroups = [];
763783 $ seen [$ dn ] = true ;
764- $ filter = $ this ->access ->combineFilterWithAnd (array (
765- $ this ->access ->connection ->ldapGroupFilter ,
766- $ this ->access ->connection ->ldapGroupMemberAssocAttr .'= ' .$ dn
767- ));
784+ $ filter = $ this ->access ->connection ->ldapGroupMemberAssocAttr .'= ' .$ dn ;
768785 $ groups = $ this ->access ->fetchListOfGroups ($ filter ,
769- array ( $ this ->access ->connection ->ldapGroupDisplayName , 'dn ' ) );
786+ [ $ this ->access ->connection ->ldapGroupDisplayName , 'dn ' ] );
770787 if (is_array ($ groups )) {
771- foreach ($ groups as $ groupobj ) {
772- $ groupDN = $ groupobj ['dn ' ][0 ];
773- $ allGroups [$ groupDN ] = $ groupobj ;
774- $ nestedGroups = $ this ->access ->connection ->ldapNestedGroups ;
775- if (!empty ($ nestedGroups )) {
776- $ supergroups = $ this ->getGroupsByMember ($ groupDN , $ seen );
777- if (is_array ($ supergroups ) && (count ($ supergroups )>0 )) {
778- $ allGroups = array_merge ($ allGroups , $ supergroups );
779- }
788+ $ fetcher = function ($ dn , &$ seen ) {
789+ if (is_array ($ dn ) && isset ($ dn ['dn ' ][0 ])) {
790+ $ dn = $ dn ['dn ' ][0 ];
780791 }
781- }
792+ return $ this ->getGroupsByMember ($ dn , $ seen );
793+ };
794+ $ allGroups = $ this ->walkNestedGroups ($ dn , $ fetcher , $ groups );
782795 }
783- return $ allGroups ;
796+ $ visibleGroups = $ this ->access ->groupsMatchFilter (array_keys ($ allGroups ));
797+ return array_intersect ($ allGroups , array_flip ($ visibleGroups ));
784798 }
785799
786800 /**
@@ -827,7 +841,7 @@ public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
827841
828842 $ primaryUsers = $ this ->getUsersInPrimaryGroup ($ groupDN , $ search , $ limit , $ offset );
829843 $ posixGroupUsers = $ this ->getUsersInGidNumber ($ groupDN , $ search , $ limit , $ offset );
830- $ members = array_keys ( $ this ->_groupMembers ($ groupDN) );
844+ $ members = $ this ->_groupMembers ($ groupDN );
831845 if (!$ members && empty ($ posixGroupUsers ) && empty ($ primaryUsers )) {
832846 //in case users could not be retrieved, return empty result set
833847 $ this ->access ->connection ->writeToCache ($ cacheKey , []);
0 commit comments