Monitoring, various: use monitoring permissions

fixes #2304
This commit is contained in:
Thomas Gelf 2021-03-18 07:01:42 +01:00
parent 29097463be
commit c27d9c7387
8 changed files with 184 additions and 20 deletions

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Controllers;
use gipfl\Web\Widget\Hint;
use Icinga\Module\Director\Monitoring;
use ipl\Html\Html;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Url;
@ -30,15 +31,59 @@ class HostController extends ObjectController
{
protected function checkDirectorPermissions()
{
if (in_array($this->getRequest()->getActionName(), [
if ($this->isServiceAction() && (new Monitoring())->authCanEditService(
$this->Auth(),
$this->getParam('name'),
$this->getParam('service')
)) {
return;
}
if ($this->isServicesReadOnlyAction()) {
$this->assertPermission('director/monitoring/services-ro');
return;
}
if ($this->hasPermission('director/hosts')) { // faster
return;
}
if ($this->canModifyHostViaMonitoringPermissions($this->getParam('name'))) {
return;
}
$this->assertPermission('director/hosts'); // complain about default hosts permission
}
protected function isServicesReadOnlyAction()
{
return in_array($this->getRequest()->getActionName(), [
'servicesro',
'findservice',
'invalidservice'
])) {
$this->assertPermission('director/monitoring/services-ro');
} else {
$this->assertPermission('director/hosts');
'invalidservice',
]);
}
protected function isServiceAction()
{
return in_array($this->getRequest()->getActionName(), [
'servicesro',
'findservice',
'invalidservice',
'servicesetservice',
'appliedservice',
'inheritedservice',
]);
}
protected function canModifyHostViaMonitoringPermissions($hostname)
{
if ($this->hasPermission('director/monitoring/hosts')) {
$monitoring = new Monitoring();
return $monitoring->authCanEditHost($this->Auth(), $hostname);
}
return false;
}
/**

View File

@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Controllers;
use Exception;
use Icinga\Module\Director\Forms\IcingaServiceForm;
use Icinga\Module\Director\Monitoring;
use Icinga\Module\Director\Web\Controller\ObjectController;
use Icinga\Module\Director\Objects\IcingaServiceSet;
use Icinga\Module\Director\Objects\IcingaService;
@ -25,6 +26,10 @@ class ServiceController extends ObjectController
protected function checkDirectorPermissions()
{
if ($this->hasPermission('director/monitoring/services')) {
$monitoring = new Monitoring();
return $monitoring->authCanEditService($this->Auth(), $this->getParam('host'), $this->getParam('name'));
}
$this->assertPermission('director/hosts');
}

View File

@ -33,6 +33,14 @@ $this->providePermission(
'director/monitoring/services-ro',
$this->translate('Allow readonly users to see where a Service came from')
);
$this->providePermission(
'director/monitoring/hosts',
$this->translate('Allow users to modify Hosts they are allowed to see in the monitoring module')
);
$this->providePermission(
'director/monitoring/services',
$this->translate('Allow users to modify Service they are allowed to see in the monitoring module')
);
$this->providePermission('director/*', $this->translate('Allow unrestricted access to Icinga Director'));
$this->provideRestriction(
@ -41,6 +49,14 @@ $this->provideRestriction(
'Limit access to the given comma-separated list of hostgroups'
)
);
$this->provideRestriction(
'director/monitoring/rw-object-filter',
$this->translate(
'Additional (monitoring module) object filter to further restrict write access'
)
);
$this->providePermission(
'director/groups-for-restricted-hosts',
$this->translate('Allow users with Hostgroup restrictions to access the Groups field')

View File

@ -14,6 +14,9 @@ next (will be 1.9.0)
### Import and Sync
* FEATURE: introduce 'disable' as your purge action on Sync (#2285)
### Permissions and Restrictions
* FEATURE: allow using monitoring module permissions (#2304)
### User Interface
* FIX: allow switching DB config while connection is failing (#2300)
* FIX: show Override button when all Fields belong to Field Categories (#2303)

View File

@ -3,6 +3,8 @@
namespace Icinga\Module\Director;
use Icinga\Application\Icinga;
use Icinga\Authentication\Auth;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
class Monitoring
@ -29,43 +31,115 @@ class Monitoring
public function hasHost($hostname)
{
return $this->backend->select()->from('hostStatus', array(
return $this->backend->select()->from('hostStatus', [
'hostname' => 'host_name',
))->where('host_name', $hostname)->fetchOne() === $hostname;
])->where('host_name', $hostname)->fetchOne() === $hostname;
}
public function hasService($hostname, $service)
{
return (array) $this->prepareServiceKeyColumnQuery($hostname, $service)->fetchRow() === [
'hostname' => $hostname,
'service' => $service,
];
}
public function authCanEditHost(Auth $auth, $hostname)
{
if ($auth->hasPermission('director/monitoring/hosts')) {
$restriction = null;
foreach ($auth->getRestrictions('director/monitoring/rw-object-filter') as $restriction) {
if ($this->hasHostWithExtraFilter($hostname, Filter::fromQueryString($restriction))) {
return true;
}
}
if ($restriction === null) {
return $this->hasHost($hostname);
}
}
return false;
}
public function authCanEditService(Auth $auth, $hostname, $service)
{
if ($auth->hasPermission('director/monitoring/services')) {
$restriction = null;
foreach ($auth->getRestrictions('director/monitoring/rw-object-filter') as $restriction) {
if ($this->hasServiceWithExtraFilter($hostname, $service, Filter::fromQueryString($restriction))) {
return true;
}
}
if ($restriction === null) {
return $this->hasService($hostname, $service);
}
}
return false;
}
public function hasHostWithExtraFilter($hostname, Filter $filter)
{
return $this->backend->select()->from('hostStatus', [
'hostname' => 'host_name',
])->where('host_name', $hostname)->applyFilter($filter)->fetchOne() === $hostname;
}
public function hasServiceWithExtraFilter($hostname, $service, Filter $filter)
{
return (array) $this
->prepareServiceKeyColumnQuery($hostname, $service)
->applyFilter($filter)
->fetchRow() === [
'hostname' => $hostname,
'service' => $service,
];
}
public function getHostState($hostname)
{
$hostStates = array(
$hostStates = [
'0' => 'up',
'1' => 'down',
'2' => 'unreachable',
'99' => 'pending',
);
];
$query = $this->backend->select()->from('hostStatus', array(
$query = $this->backend->select()->from('hostStatus', [
'hostname' => 'host_name',
'state' => 'host_state',
'problem' => 'host_problem',
'acknowledged' => 'host_acknowledged',
'in_downtime' => 'host_in_downtime',
'output' => 'host_output',
))->where('host_name', $hostname);
])->where('host_name', $hostname);
$res = $query->fetchRow();
if ($res === false) {
$res = (object) array(
$res = (object) [
'hostname' => $hostname,
'state' => '99',
'problem' => '0',
'acknowledged' => '0',
'in_downtime' => '0',
'output' => null,
);
];
}
$res->state = $hostStates[$res->state];
return $res;
}
protected function prepareServiceKeyColumnQuery($hostname, $service)
{
return $this->backend
->select()
->from('serviceStatus', [
'hostname' => 'host_name',
'service' => 'service_description',
])
->where('host_name', $hostname)
->where('service_description', $service);
}
}

View File

@ -4,7 +4,9 @@ namespace Icinga\Module\Director\ProvidedHook\Monitoring;
use Exception;
use Icinga\Application\Config;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Monitoring;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Util;
use Icinga\Module\Monitoring\Hook\HostActionsHook;
@ -37,7 +39,19 @@ class HostActions extends HostActionsHook
);
}
$allowEdit = false;
if (Util::hasPermission('director/hosts') && IcingaHost::exists($hostname, $db)) {
$allowEdit = true;
}
$auth = Auth::getInstance();
if (Util::hasPermission('director/monitoring/hosts')) {
$monitoring = new Monitoring();
if ($monitoring->authCanEditHost($auth, $hostname)) {
$allowEdit = IcingaHost::exists($hostname, $db);
}
}
if ($allowEdit) {
$actions[mt('director', 'Modify')] = Url::fromPath(
'director/host/edit',
array('name' => $hostname)

View File

@ -4,7 +4,9 @@ namespace Icinga\Module\Director\ProvidedHook\Monitoring;
use Exception;
use Icinga\Application\Config;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Monitoring;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Util;
use Icinga\Module\Monitoring\Hook\ServiceActionsHook;
@ -36,6 +38,7 @@ class ServiceActions extends ServiceActionsHook
}
$hostname = $service->host_name;
$serviceName = $service->service_description;
if (Util::hasPermission('director/inspect')) {
$actions[mt('director', 'Inspect')] = Url::fromPath('director/inspect/object', [
'type' => 'service',
@ -43,23 +46,27 @@ class ServiceActions extends ServiceActionsHook
'name' => sprintf(
'%s!%s',
$hostname,
$service->service_description
$serviceName
)
]);
}
$title = null;
if (Util::hasPermission('director/hosts')) {
$title = mt('director', 'Modify');
} elseif (Util::hasPermission('director/monitoring/services')) {
$monitoring = new Monitoring();
if ($monitoring->authCanEditService(Auth::getInstance(), $hostname, $serviceName)) {
$title = mt('director', 'Modify');
}
} elseif (Util::hasPermission('director/monitoring/services-ro')) {
$title = mt('director', 'Configuration');
} else {
return $actions;
}
if (IcingaHost::exists($hostname, $db)) {
if ($title && IcingaHost::exists($hostname, $db)) {
$actions[$title] = Url::fromPath('director/host/findservice', [
'name' => $hostname,
'service' => $service->service_description
'service' => $serviceName
]);
}

View File

@ -138,7 +138,7 @@ class ObjectTabs extends Tabs
]);
}
if ($object->getShortTableName() === 'host') {
if ($object->getShortTableName() === 'host' && $auth->hasPermission('director/hosts')) {
$this->add('agent', [
'url' => 'director/host/agent',
'urlParams' => $params,