From f66ab8dae2f3d0418759f81a3a64dc9517a62449 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 14 Apr 2024 15:17:31 +0200 Subject: Adding upstream version 1.10.2. Signed-off-by: Daniel Baumann --- .../Restriction/FilterByNameRestriction.php | 64 ++++++++ .../Director/Restriction/HostgroupRestriction.php | 171 +++++++++++++++++++++ library/Director/Restriction/MatchingFilter.php | 40 +++++ library/Director/Restriction/ObjectRestriction.php | 84 ++++++++++ 4 files changed, 359 insertions(+) create mode 100644 library/Director/Restriction/FilterByNameRestriction.php create mode 100644 library/Director/Restriction/HostgroupRestriction.php create mode 100644 library/Director/Restriction/MatchingFilter.php create mode 100644 library/Director/Restriction/ObjectRestriction.php (limited to 'library/Director/Restriction') diff --git a/library/Director/Restriction/FilterByNameRestriction.php b/library/Director/Restriction/FilterByNameRestriction.php new file mode 100644 index 0000000..8c3b256 --- /dev/null +++ b/library/Director/Restriction/FilterByNameRestriction.php @@ -0,0 +1,64 @@ +setType($type); + } + + protected function setType($type) + { + $this->type = $type; + $this->setNameForType($type); + } + + protected function setNameForType($type) + { + $this->name = "director/${type}/filter-by-name"; + } + + public function allows(IcingaObject $object) + { + if (! $this->isRestricted()) { + return true; + } + + return $this->getFilter()->matches([ + (object) ['object_name' => $object->getObjectName()] + ]); + } + + public function getFilter() + { + if ($this->filter === null) { + $this->filter = MatchingFilter::forUser( + $this->auth->getUser(), + $this->name, + 'object_name' + ); + } + + return $this->filter; + } + + protected function filterQuery(ZfSelect $query, $tableAlias = 'o') + { + FilterRenderer::applyToQuery($this->getFilter(), $query); + } +} diff --git a/library/Director/Restriction/HostgroupRestriction.php b/library/Director/Restriction/HostgroupRestriction.php new file mode 100644 index 0000000..1a6792b --- /dev/null +++ b/library/Director/Restriction/HostgroupRestriction.php @@ -0,0 +1,171 @@ +allowsHost($object); + } elseif ($object instanceof IcingaHostGroup) { + return $this->allowsHostGroup($object); + } else { + return $this; + } + } + + protected function filterQuery(ZfSelect $query, $tableAlias = 'o') + { + $table = $this->getQueryTableByAlias($query, $tableAlias); + switch ($table) { + case 'icinga_host': + $this->filterHostsQuery($query, $tableAlias); + break; + case 'icinga_service': + // TODO: Alias is hardcoded + $this->filterHostsQuery($query, 'h'); + break; + case 'icinga_hostgroup': + $this->filterHostGroupsQuery($query, $tableAlias); + break; + // Hint: other tables are ignored, so please take care! + } + + return $query; + } + + /** + * Whether access to the given host is allowed + * + * @param IcingaHost $host + * @return bool + */ + public function allowsHost(IcingaHost $host) + { + if (! $this->isRestricted()) { + return true; + } + + // Hint: branched hosts have no id + if (! $host->hasBeenLoadedFromDb() || $host->hasModifiedGroups() || $host->get('id') === null) { + foreach ($this->listRestrictedHostgroups() as $group) { + if ($host->hasGroup($group)) { + return true; + } + } + + return false; + } + + $query = $this->db->select()->from( + ['o' => 'icinga_host'], + ['id'] + )->where('o.id = ?', $host->id); + + $this->filterHostsQuery($query); + return (int) $this->db->fetchOne($query) === (int) $host->get('id'); + } + + /** + * Whether access to the given hostgroup is allowed + * + * @param IcingaHostGroup $hostgroup + * @return bool + */ + public function allowsHostGroup(IcingaHostGroup $hostgroup) + { + if (! $this->isRestricted()) { + return true; + } + + $query = $this->db->select()->from( + ['h' => 'icinga_hostgroup'], + ['id'] + )->where('id = ?', $hostgroup->id); + + $this->filterHostGroupsQuery($query); + return (int) $this->db->fetchOne($query) === (int) $hostgroup->get('id'); + } + + /** + * Apply the restriction to the given Hosts Query + * + * We assume that the query wants to fetch hosts and that therefore the + * icinga_host table already exists in the given query, using the $tableAlias + * alias. + * + * @param ZfSelect $query + * @param string $tableAlias + */ + public function filterHostsQuery(ZfSelect $query, $tableAlias = 'o') + { + if (! $this->isRestricted()) { + return; + } + + IcingaObjectFilterHelper::filterByResolvedHostgroups( + $query, + 'host', + $this->listRestrictedHostgroups(), + $tableAlias + ); + } + + /** + * Apply the restriction to the given Hosts Query + * + * We assume that the query wants to fetch hosts and that therefore the + * icinga_host table already exists in the given query, using the $tableAlias + * alias. + * + * @param ZfSelect $query + * @param string $tableAlias + */ + protected function filterHostGroupsQuery(ZfSelect $query, $tableAlias = 'o') + { + if (! $this->isRestricted()) { + return; + } + $groups = $this->listRestrictedHostgroups(); + + if (empty($groups)) { + $query->where('(1 = 0)'); + } else { + $query->where("${tableAlias}.object_name IN (?)", $groups); + } + } + + /** + * Give a list of allowed Hostgroups + * + * When not restricted, null is returned. This might eventually also give + * an empty list, and therefore not allow any access at all + * + * @return array|null + */ + protected function listRestrictedHostgroups() + { + if ($restrictions = $this->auth->getRestrictions($this->getName())) { + $groups = array(); + foreach ($restrictions as $restriction) { + foreach ($this->gracefullySplitOnComma($restriction) as $group) { + $groups[$group] = $group; + } + } + + return array_keys($groups); + } else { + return null; + } + } +} diff --git a/library/Director/Restriction/MatchingFilter.php b/library/Director/Restriction/MatchingFilter.php new file mode 100644 index 0000000..162840c --- /dev/null +++ b/library/Director/Restriction/MatchingFilter.php @@ -0,0 +1,40 @@ +getRestrictions($restrictionName), + $columnName + ); + } +} diff --git a/library/Director/Restriction/ObjectRestriction.php b/library/Director/Restriction/ObjectRestriction.php new file mode 100644 index 0000000..9161ebb --- /dev/null +++ b/library/Director/Restriction/ObjectRestriction.php @@ -0,0 +1,84 @@ +db = $connection->getDbAdapter(); + $this->auth = $auth; + } + + abstract public function allows(IcingaObject $object); + + /** + * Apply the restriction to the given Hosts Query + * + * We assume that the query wants to fetch hosts and that therefore the + * icinga_host table already exists in the given query, using the $tableAlias + * alias. + * + * @param ZfSelect $query + * @param string $tableAlias + */ + abstract protected function filterQuery(ZfSelect $query, $tableAlias = 'o'); + + public function applyToQuery(ZfSelect $query, $tableAlias = 'o') + { + if ($this->isRestricted()) { + $this->filterQuery($query, $tableAlias); + } + + return $query; + } + + public function getName() + { + if ($this->name === null) { + throw new ProgrammingError('ObjectRestriction has no name'); + } + + return $this->name; + } + + public function isRestricted() + { + $restrictions = $this->auth->getRestrictions($this->getName()); + return ! empty($restrictions); + } + + protected function getQueryTableByAlias(ZfSelect $query, $tableAlias) + { + $from = $query->getPart(ZfSelect::FROM); + if (! array_key_exists($tableAlias, $from)) { + throw new ProgrammingError( + 'Cannot restrict query with alias "%s", got %s', + $tableAlias, + json_encode($from) + ); + } + + return $from[$tableAlias]['tableName']; + } + + protected function gracefullySplitOnComma($string) + { + return preg_split('/\s*,\s*/', $string, -1, PREG_SPLIT_NO_EMPTY); + } +} -- cgit v1.2.3