diff options
Diffstat (limited to '')
3 files changed, 382 insertions, 0 deletions
diff --git a/library/Director/Integration/BackendInterface.php b/library/Director/Integration/BackendInterface.php new file mode 100644 index 0000000..7b2b88c --- /dev/null +++ b/library/Director/Integration/BackendInterface.php @@ -0,0 +1,55 @@ +<?php + +namespace Icinga\Module\Director\Integration; + +use Icinga\Web\Url; + +interface BackendInterface +{ + /** + * Whether the backend has the given host + * + * @param ?string $hostName + * + * @return bool + */ + public function hasHost(?string $hostName): bool; + + /** + * Whether the backend has the given service of the specified host + * + * @param ?string $hostName + * @param ?string $serviceName + * + * @return bool + */ + public function hasService(?string $hostName, ?string $serviceName): bool; + + /** + * Whether an authenticated user has the permission (is not restricted) to modify given host + * + * @param ?string $hostName + * + * @return bool + */ + public function canModifyHost(?string $hostName): bool; + + /** + * Whether an authenticated user has the permission (is not restricted) to modify given service of specified host + * + * @param ?string $hostName + * @param ?string $serviceName + * + * @return bool + */ + public function canModifyService(?string $hostName, ?string $serviceName): bool; + + /** + * Get the url of given host + * + * @param ?string $hostName + * + * @return Url + */ + public function getHostUrl(?string $hostName): ?Url; +} diff --git a/library/Director/Integration/Icingadb/IcingadbBackend.php b/library/Director/Integration/Icingadb/IcingadbBackend.php new file mode 100644 index 0000000..874cddd --- /dev/null +++ b/library/Director/Integration/Icingadb/IcingadbBackend.php @@ -0,0 +1,127 @@ +<?php + +namespace Icinga\Module\Director\Integration\Icingadb; + +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Auth\Restriction; +use Icinga\Module\Director\Integration\BackendInterface; +use Icinga\Module\Icingadb\Common\Auth; +use Icinga\Module\Icingadb\Common\Database; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\Service; +use Icinga\Web\Url; +use ipl\Orm\Query; +use ipl\Stdlib\Filter; + +class IcingadbBackend implements BackendInterface +{ + use Database; + use Auth; + + public function hasHost(?string $hostName): bool + { + if ($hostName === null) { + return false; + } + + return $this->getHostQuery($hostName)->first() !== null; + } + + public function hasService(?string $hostName, ?string $serviceName): bool + { + if ($hostName === null || $serviceName === null) { + return false; + } + + return $this->getServiceQuery($hostName, $serviceName)->first() !== null; + } + + public function getHostUrl(?string $hostName): ?Url + { + if ($hostName === null) { + return null; + } + + return Url::fromPath('icingadb/host', ['name' => $hostName]); + } + + public function canModifyHost(?string $hostName): bool + { + if ($hostName === null + || ! $this->getAuth()->hasPermission(Permission::ICINGADB_HOSTS) + ) { + return false; + } + + $query = $this->getHostQuery($hostName); + + return $query->first() !== null; + } + + public function canModifyService(?string $hostName, ?string $serviceName): bool + { + if ($hostName === null + || $serviceName === null + || ! $this->getAuth()->hasPermission(Permission::ICINGADB_SERVICES) + ) { + return false; + } + + $query = $this->getServiceQuery($hostName, $serviceName); + + return $query->first() !== null; + } + + /** + * Get the query for given host + * + * @param string $hostName + * + * @return Query + */ + protected function getHostQuery(string $hostName): Query + { + $query = Host::on($this->getDb()) + ->filter(Filter::equal('host.name', $hostName)); + + $this->applyDirectorRestrictions($query); + + return $query; + } + + /** + * Get the query for given host and service + * + * @param string $hostName + * @param string $serviceName + * + * @return Query + */ + protected function getServiceQuery(string $hostName, string $serviceName): Query + { + $query = Service::on($this->getDb()) + ->filter(Filter::all( + Filter::equal('service.name', $serviceName), + Filter::equal('host.name', $hostName) + )); + + $this->applyDirectorRestrictions($query); + + return $query; + } + + /** + * Apply director restrictions on the given query + * + * @param Query $query + */ + protected function applyDirectorRestrictions(Query $query): void + { + $queryFilter = Filter::any(); + foreach ($this->getAuth()->getRestrictions(Restriction::ICINGADB_RW_OBJECT_FILTER) as $restriction) { + $queryFilter->add($this->parseRestriction($restriction, Restriction::ICINGADB_RW_OBJECT_FILTER)); + } + + $query->filter($queryFilter); + } +} diff --git a/library/Director/Integration/MonitoringModule/Monitoring.php b/library/Director/Integration/MonitoringModule/Monitoring.php new file mode 100644 index 0000000..5a2dfde --- /dev/null +++ b/library/Director/Integration/MonitoringModule/Monitoring.php @@ -0,0 +1,200 @@ +<?php + +namespace Icinga\Module\Director\Integration\MonitoringModule; + +use Exception; +use Icinga\Application\Icinga; +use Icinga\Authentication\Auth; +use Icinga\Data\Filter\Filter; +use Icinga\Exception\ConfigurationError; +use Icinga\Module\Director\Auth\MonitoringRestriction; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Auth\Restriction; +use Icinga\Module\Director\Integration\BackendInterface; +use Icinga\Module\Monitoring\Backend\MonitoringBackend; +use Icinga\Web\Url; + +class Monitoring implements BackendInterface +{ + /** @var ?MonitoringBackend */ + protected $backend; + + /** @var Auth */ + protected $auth; + + public function __construct(Auth $auth) + { + $this->auth = $auth; + $this->initializeMonitoringBackend(); + } + + public function getHostUrl(?string $hostName): ?Url + { + if ($hostName === null) { + return null; + } + + return Url::fromPath('monitoring/host/show', ['host' => $hostName]); + } + + public function hasHost(?string $hostName): bool + { + if ($hostName === null || ! $this->isAvailable()) { + return false; + } + + try { + return $this->selectHost($hostName)->fetchOne() === $hostName; + } catch (Exception $_) { + return false; + } + } + + public function hasService(?string $hostName, ?string $serviceName): bool + { + if ($hostName === null || $serviceName === null || ! $this->isAvailable()) { + return false; + } + + try { + return $this->rowIsService( + $this->selectService($hostName, $serviceName)->fetchRow(), + $hostName, + $serviceName + ); + } catch (Exception $_) { + return false; + } + } + + public function canModifyService(?string $hostName, ?string $serviceName): bool + { + if (! $this->isAvailable() || $hostName === null || $serviceName === null) { + return false; + } + if ($this->auth->hasPermission(Permission::MONITORING_SERVICES)) { + $restriction = null; + foreach ($this->auth->getRestrictions(Restriction::MONITORING_RW_OBJECT_FILTER) as $restriction) { + if ($this->hasServiceWithFilter($hostName, $serviceName, Filter::fromQueryString($restriction))) { + return true; + } + } + if ($restriction === null) { + return $this->hasService($hostName, $serviceName); + } + } + + return false; + } + + public function canModifyHost(?string $hostName): bool + { + if ($hostName !== null && $this->isAvailable() && $this->auth->hasPermission(Permission::MONITORING_HOSTS)) { + $restriction = null; + foreach ($this->auth->getRestrictions(Restriction::MONITORING_RW_OBJECT_FILTER) as $restriction) { + if ($this->hasHostWithFilter($hostName, Filter::fromQueryString($restriction))) { + return true; + } + } + if ($restriction === null) { + return $this->hasHost($hostName); + } + } + + return false; + } + + protected function hasHostWithFilter($hostname, Filter $filter): bool + { + try { + return $this->selectHost($hostname)->applyFilter($filter)->fetchOne() === $hostname; + } catch (Exception $e) { + return false; + } + } + + protected function hasServiceWithFilter($hostname, $service, Filter $filter): bool + { + try { + return $this->rowIsService( + $this->selectService($hostname, $service)->applyFilter($filter)->fetchRow(), + $hostname, + $service + ); + } catch (Exception $e) { + return false; + } + } + + protected function selectHost($hostname) + { + return $this->selectHostStatus($hostname, [ + 'hostname' => 'host_name', + ]); + } + + protected function selectHostStatus($hostname, $columns) + { + return $this->restrictQuery( + $this->backend + ->select() + ->from('hostStatus', $columns) + ->where('host_name', $hostname) + ); + } + + protected function selectService($hostname, $service) + { + return $this->selectServiceStatus($hostname, $service, [ + 'hostname' => 'host_name', + 'service' => 'service_description', + ]); + } + + protected function selectServiceStatus($hostname, $service, $columns) + { + return $this->restrictQuery( + $this->backend + ->select() + ->from('serviceStatus', $columns) + ->where('host_name', $hostname) + ->where('service_description', $service) + ); + } + + protected function restrictQuery($query) + { + $query->applyFilter(MonitoringRestriction::getObjectsFilter($this->auth)); + return $query; + } + + protected function rowIsService($row, $hostname, $service): bool + { + return (array) $row === [ + 'hostname' => $hostname, + 'service' => $service, + ]; + } + + protected function initializeMonitoringBackend() + { + $app = Icinga::app(); + $modules = $app->getModuleManager(); + if (!$modules->hasLoaded('monitoring') && $app->isCli()) { + $modules->loadEnabledModules(); + } + + if ($modules->hasLoaded('monitoring')) { + try { + $this->backend = MonitoringBackend::instance(); + } catch (ConfigurationError $e) { + $this->backend = null; + } + } + } + + protected function isAvailable(): bool + { + return $this->backend !== null; + } +} |