diff options
Diffstat (limited to 'apps/user_ldap/lib/Group_LDAP.php')
-rw-r--r-- | apps/user_ldap/lib/Group_LDAP.php | 114 |
1 files changed, 78 insertions, 36 deletions
diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php index 85d9e38e03e..f05c8fb8ca4 100644 --- a/apps/user_ldap/lib/Group_LDAP.php +++ b/apps/user_ldap/lib/Group_LDAP.php @@ -85,6 +85,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * is user in group? + * * @param string $uid uid of the user * @param string $gid gid of the group * @return bool @@ -95,7 +96,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD if (!$this->enabled) { return false; } - $cacheKey = 'inGroup'.$uid.':'.$gid; + $cacheKey = 'inGroup' . $uid . ':' . $gid; $inGroup = $this->access->connection->getFromCache($cacheKey); if (!is_null($inGroup)) { return (bool)$inGroup; @@ -108,7 +109,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD return $isInGroup; } - $cacheKeyMembers = 'inGroup-members:'.$gid; + $cacheKeyMembers = 'inGroup-members:' . $gid; $members = $this->access->connection->getFromCache($cacheKeyMembers); if (!is_null($members)) { $this->cachedGroupMembers[$gid] = $members; @@ -199,13 +200,13 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD $pos = strpos($memberURLs[0], '('); if ($pos !== false) { $memberUrlFilter = substr($memberURLs[0], $pos); - $foundMembers = $this->access->searchUsers($memberUrlFilter,'dn'); + $foundMembers = $this->access->searchUsers($memberUrlFilter, 'dn'); $dynamicMembers = []; foreach ($foundMembers as $value) { $dynamicMembers[$value['dn'][0]] = 1; } } else { - \OCP\Util::writeLog('user_ldap', 'No search filter found on member url '. + \OCP\Util::writeLog('user_ldap', 'No search filter found on member url ' . 'of group ' . $dnGroup, ILogger::DEBUG); } } @@ -228,7 +229,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD return []; } // used extensively in cron job, caching makes sense for nested groups - $cacheKey = '_groupMembers'.$dnGroup; + $cacheKey = '_groupMembers' . $dnGroup; $groupMembers = $this->access->connection->getFromCache($cacheKey); if ($groupMembers !== null) { return $groupMembers; @@ -274,7 +275,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD }; $groups = $this->walkNestedGroups($DN, $fetcher, $groups); - return $this->access->groupsMatchFilter($groups); + return $this->filterValidGroups($groups); } /** @@ -284,7 +285,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD * @return array */ private function walkNestedGroups(string $dn, \Closure $fetcher, array $list): array { - $nesting = (int) $this->access->connection->ldapNestedGroups; + $nesting = (int)$this->access->connection->ldapNestedGroups; // depending on the input, we either have a list of DNs or a list of LDAP records // also, the output expects either DNs or records. Testing the first element should suffice. $recordMode = is_array($list) && isset($list[0]) && is_array($list[0]) && isset($list[0]['dn'][0]); @@ -319,6 +320,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * translates a gidNumber into an ownCloud internal name + * * @param string $gid as given by gidNumber on POSIX LDAP * @param string $dn a DN that belongs to the same domain as the group * @return string|bool @@ -354,6 +356,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * returns the entry's gidNumber + * * @param string $dn * @param string $attribute * @return string|bool @@ -368,6 +371,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * returns the group's primary ID + * * @param string $dn * @return string|bool */ @@ -377,6 +381,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * returns the user's gidNumber + * * @param string $dn * @return string|bool */ @@ -410,7 +415,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD if ($search !== '') { $filterParts[] = $this->access->getFilterPartForUserSearch($search); } - $filterParts[] = $this->access->connection->ldapGidNumber .'=' . $groupID; + $filterParts[] = $this->access->connection->ldapGidNumber . '=' . $groupID; return $this->access->combineFilterWithAnd($filterParts); } @@ -460,6 +465,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * gets the gidNumber of a user + * * @param string $dn * @return string */ @@ -477,6 +483,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * translates a primary group ID into an Nextcloud internal name + * * @param string $gid as given by primaryGroupID on AD * @param string $dn a DN that belongs to the same domain as the group * @return string|bool @@ -516,6 +523,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * returns the entry's primary group ID + * * @param string $dn * @param string $attribute * @return string|bool @@ -530,6 +538,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * returns the group's primary ID + * * @param string $dn * @return string|bool */ @@ -539,6 +548,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * returns the user's primary group ID + * * @param string $dn * @return string|bool */ @@ -622,6 +632,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * gets the primary group of a user + * * @param string $dn * @return string */ @@ -639,6 +650,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * Get all groups a user belongs to + * * @param string $uid Name of the user * @return array with group names * @@ -651,7 +663,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD if (!$this->enabled) { return []; } - $cacheKey = 'getUserGroups'.$uid; + $cacheKey = 'getUserGroups' . $uid; $userGroups = $this->access->connection->getFromCache($cacheKey); if (!is_null($userGroups)) { return $userGroups; @@ -671,14 +683,14 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD if (!empty($dynamicGroupMemberURL)) { // look through dynamic groups to add them to the result array if needed $groupsToMatch = $this->access->fetchListOfGroups( - $this->access->connection->ldapGroupFilter,['dn',$dynamicGroupMemberURL]); + $this->access->connection->ldapGroupFilter, ['dn', $dynamicGroupMemberURL]); foreach ($groupsToMatch as $dynamicGroup) { if (!array_key_exists($dynamicGroupMemberURL, $dynamicGroup)) { continue; } $pos = strpos($dynamicGroup[$dynamicGroupMemberURL][0], '('); if ($pos !== false) { - $memberUrlFilter = substr($dynamicGroup[$dynamicGroupMemberURL][0],$pos); + $memberUrlFilter = substr($dynamicGroup[$dynamicGroupMemberURL][0], $pos); // apply filter via ldap search to see if this user is in this // dynamic group $userMatch = $this->access->readAttribute( @@ -696,7 +708,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD } } } else { - \OCP\Util::writeLog('user_ldap', 'No search filter found on member url '. + \OCP\Util::writeLog('user_ldap', 'No search filter found on member url ' . 'of group ' . print_r($dynamicGroup, true), ILogger::DEBUG); } } @@ -708,7 +720,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD if ((int)$this->access->connection->hasMemberOfFilterSupport === 1 && (int)$this->access->connection->useMemberOfToDetectMembership === 1 && strtolower($this->access->connection->ldapGroupMemberAssocAttr) !== 'memberuid' - ) { + ) { $groupDNs = $this->_getGroupDNsFromMemberOf($userDN); if (is_array($groupDNs)) { foreach ($groupDNs as $dn) { @@ -739,7 +751,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD } elseif (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') { $result = $this->access->readAttribute($userDN, 'uid'); if ($result === false) { - \OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on '. + \OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on ' . $this->access->connection->ldapHost, ILogger::DEBUG); $uid = false; } else { @@ -789,9 +801,9 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD } $allGroups = []; $seen[$dn] = true; - $filter = $this->access->connection->ldapGroupMemberAssocAttr.'='.$dn; + $filter = $this->access->connection->ldapGroupMemberAssocAttr . '=' . $dn; $groups = $this->access->fetchListOfGroups($filter, - [$this->access->connection->ldapGroupDisplayName, 'dn']); + [strtolower($this->access->connection->ldapGroupMemberAssocAttr), $this->access->connection->ldapGroupDisplayName, 'dn']); if (is_array($groups)) { $fetcher = function ($dn, &$seen) { if (is_array($dn) && isset($dn['dn'][0])) { @@ -801,8 +813,8 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD }; $allGroups = $this->walkNestedGroups($dn, $fetcher, $groups); } - $visibleGroups = $this->access->groupsMatchFilter(array_keys($allGroups)); - return array_intersect_key($allGroups, array_flip($visibleGroups)); + $visibleGroups = $this->filterValidGroups($allGroups); + return array_intersect_key($allGroups, $visibleGroups); } /** @@ -823,7 +835,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD return []; } $search = $this->access->escapeFilterPart($search, true); - $cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset; + $cacheKey = 'usersInGroup-' . $gid . '-' . $search . '-' . $limit . '-' . $offset; // check for cache of the exact query $groupUsers = $this->access->connection->getFromCache($cacheKey); if (!is_null($groupUsers)) { @@ -831,7 +843,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD } // check for cache of the query without limit and offset - $groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search); + $groupUsers = $this->access->connection->getFromCache('usersInGroup-' . $gid . '-' . $search); if (!is_null($groupUsers)) { $groupUsers = array_slice($groupUsers, $offset, $limit); $this->access->connection->writeToCache($cacheKey, $groupUsers); @@ -907,7 +919,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD $groupUsers = array_unique(array_merge($groupUsers, $primaryUsers, $posixGroupUsers)); natsort($groupUsers); - $this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers); + $this->access->connection->writeToCache('usersInGroup-' . $gid . '-' . $search, $groupUsers); $groupUsers = array_slice($groupUsers, $offset, $limit); $this->access->connection->writeToCache($cacheKey, $groupUsers); @@ -917,6 +929,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * returns the number of users in a group, who match the search term + * * @param string $gid the internal group name * @param string $search optional, a search string * @return int|bool @@ -926,7 +939,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD return $this->groupPluginManager->countUsersInGroup($gid, $search); } - $cacheKey = 'countUsersInGroup-'.$gid.'-'.$search; + $cacheKey = 'countUsersInGroup-' . $gid . '-' . $search; if (!$this->enabled || !$this->groupExists($gid)) { return false; } @@ -958,7 +971,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD $search = $this->access->escapeFilterPart($search, true); $isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) - === 'memberuid'); + === 'memberuid'); //we need to apply the search filter //alternatives that need to be checked: @@ -1015,10 +1028,10 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD if (!$this->enabled) { return []; } - $cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset; + $cacheKey = 'getGroups-' . $search . '-' . $limit . '-' . $offset; //Check cache before driving unnecessary searches - \OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, ILogger::DEBUG); + \OCP\Util::writeLog('user_ldap', 'getGroups ' . $cacheKey, ILogger::DEBUG); $ldap_groups = $this->access->connection->getFromCache($cacheKey); if (!is_null($ldap_groups)) { return $ldap_groups; @@ -1033,11 +1046,11 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD $this->access->connection->ldapGroupFilter, $this->access->getFilterPartForGroupSearch($search) ]); - \OCP\Util::writeLog('user_ldap', 'getGroups Filter '.$filter, ILogger::DEBUG); + \OCP\Util::writeLog('user_ldap', 'getGroups Filter ' . $filter, ILogger::DEBUG); $ldap_groups = $this->access->fetchListOfGroups($filter, - [$this->access->connection->ldapGroupDisplayName, 'dn'], - $limit, - $offset); + [$this->access->connection->ldapGroupDisplayName, 'dn'], + $limit, + $offset); $ldap_groups = $this->access->nextcloudGroupNames($ldap_groups); $this->access->connection->writeToCache($cacheKey, $ldap_groups); @@ -1078,7 +1091,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD $chunkLimit = min($pagingSize, $overallLimit - $chunkOffset); $ldapGroups = $this->getGroupsChunk($search, $chunkLimit, $chunkOffset); $nread = count($ldapGroups); - \OCP\Util::writeLog('user_ldap', 'getGroups('.$search.'): read '.$nread.' at offset '.$chunkOffset.' (limit: '.$chunkLimit.')', ILogger::DEBUG); + \OCP\Util::writeLog('user_ldap', 'getGroups(' . $search . '): read ' . $nread . ' at offset ' . $chunkOffset . ' (limit: ' . $chunkLimit . ')', ILogger::DEBUG); if ($nread) { $allGroups = array_merge($allGroups, $ldapGroups); $chunkOffset += $nread; @@ -1100,11 +1113,12 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * check if a group exists + * * @param string $gid * @return bool */ public function groupExists($gid) { - $groupExists = $this->access->connection->getFromCache('groupExists'.$gid); + $groupExists = $this->access->connection->getFromCache('groupExists' . $gid); if (!is_null($groupExists)) { return (bool)$groupExists; } @@ -1113,22 +1127,43 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD //only, requires more checking. $dn = $this->access->groupname2dn($gid); if (!$dn) { - $this->access->connection->writeToCache('groupExists'.$gid, false); + $this->access->connection->writeToCache('groupExists' . $gid, false); + return false; + } + + if (!$this->access->isDNPartOfBase($dn, $this->access->connection->ldapBaseGroups)) { + $this->access->connection->writeToCache('groupExists' . $gid, false); return false; } //if group really still exists, we will be able to read its objectclass - if (!is_array($this->access->readAttribute($dn, ''))) { - $this->access->connection->writeToCache('groupExists'.$gid, false); + if (!is_array($this->access->readAttribute($dn, '', $this->access->connection->ldapGroupFilter))) { + $this->access->connection->writeToCache('groupExists' . $gid, false); return false; } - $this->access->connection->writeToCache('groupExists'.$gid, true); + $this->access->connection->writeToCache('groupExists' . $gid, true); return true; } + protected function filterValidGroups(array $listOfGroups): array { + $validGroupDNs = []; + foreach ($listOfGroups as $key => $item) { + $dn = is_string($item) ? $item : $item['dn'][0]; + $gid = $this->access->dn2groupname($dn); + if (!$gid) { + continue; + } + if ($this->groupExists($gid)) { + $validGroupDNs[$key] = $item; + } + } + return $validGroupDNs; + } + /** * Check if backend implements actions + * * @param int $actions bitwise-or'ed actions * @return boolean * @@ -1142,6 +1177,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * Return access for LDAP interaction. + * * @return Access instance of Access for LDAP interaction */ public function getLDAPAccess($gid) { @@ -1150,6 +1186,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * create a group + * * @param string $gid * @return bool * @throws \Exception @@ -1177,6 +1214,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * delete a group + * * @param string $gid gid of the group to delete * @return bool * @throws \Exception @@ -1186,7 +1224,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD if ($ret = $this->groupPluginManager->deleteGroup($gid)) { #delete group in nextcloud internal db $this->access->getGroupMapper()->unmap($gid); - $this->access->connection->writeToCache("groupExists".$gid, false); + $this->access->connection->writeToCache("groupExists" . $gid, false); } return $ret; } @@ -1195,6 +1233,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * Add a user to a group + * * @param string $uid Name of the user to add to group * @param string $gid Name of the group in which add the user * @return bool @@ -1213,6 +1252,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * Removes a user from a group + * * @param string $uid Name of the user to remove from group * @param string $gid Name of the group from which remove the user * @return bool @@ -1231,6 +1271,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD /** * Gets group details + * * @param string $gid Name of the group * @return array | false * @throws \Exception @@ -1246,6 +1287,7 @@ class Group_LDAP extends BackendUtility implements \OCP\GroupInterface, IGroupLD * Return LDAP connection resource from a cloned connection. * The cloned connection needs to be closed manually. * of the current access. + * * @param string $gid * @return resource of the LDAP connection */ |