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; namespace Icinga\Module\Director\Controllers;
use gipfl\Web\Widget\Hint; use gipfl\Web\Widget\Hint;
use Icinga\Module\Director\Monitoring;
use ipl\Html\Html; use ipl\Html\Html;
use gipfl\IcingaWeb2\Link; use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Url; use gipfl\IcingaWeb2\Url;
@ -30,15 +31,59 @@ class HostController extends ObjectController
{ {
protected function checkDirectorPermissions() 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', 'servicesro',
'findservice', 'findservice',
'invalidservice' 'invalidservice',
])) { ]);
$this->assertPermission('director/monitoring/services-ro'); }
} else {
$this->assertPermission('director/hosts'); 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 Exception;
use Icinga\Module\Director\Forms\IcingaServiceForm; use Icinga\Module\Director\Forms\IcingaServiceForm;
use Icinga\Module\Director\Monitoring;
use Icinga\Module\Director\Web\Controller\ObjectController; use Icinga\Module\Director\Web\Controller\ObjectController;
use Icinga\Module\Director\Objects\IcingaServiceSet; use Icinga\Module\Director\Objects\IcingaServiceSet;
use Icinga\Module\Director\Objects\IcingaService; use Icinga\Module\Director\Objects\IcingaService;
@ -25,6 +26,10 @@ class ServiceController extends ObjectController
protected function checkDirectorPermissions() 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'); $this->assertPermission('director/hosts');
} }

View File

@ -33,6 +33,14 @@ $this->providePermission(
'director/monitoring/services-ro', 'director/monitoring/services-ro',
$this->translate('Allow readonly users to see where a Service came from') $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->providePermission('director/*', $this->translate('Allow unrestricted access to Icinga Director'));
$this->provideRestriction( $this->provideRestriction(
@ -41,6 +49,14 @@ $this->provideRestriction(
'Limit access to the given comma-separated list of hostgroups' '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( $this->providePermission(
'director/groups-for-restricted-hosts', 'director/groups-for-restricted-hosts',
$this->translate('Allow users with Hostgroup restrictions to access the Groups field') $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 ### Import and Sync
* FEATURE: introduce 'disable' as your purge action on Sync (#2285) * FEATURE: introduce 'disable' as your purge action on Sync (#2285)
### Permissions and Restrictions
* FEATURE: allow using monitoring module permissions (#2304)
### User Interface ### User Interface
* FIX: allow switching DB config while connection is failing (#2300) * FIX: allow switching DB config while connection is failing (#2300)
* FIX: show Override button when all Fields belong to Field Categories (#2303) * FIX: show Override button when all Fields belong to Field Categories (#2303)

View File

@ -3,6 +3,8 @@
namespace Icinga\Module\Director; namespace Icinga\Module\Director;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Authentication\Auth;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Module\Monitoring\Backend\MonitoringBackend;
class Monitoring class Monitoring
@ -29,43 +31,115 @@ class Monitoring
public function hasHost($hostname) public function hasHost($hostname)
{ {
return $this->backend->select()->from('hostStatus', array( return $this->backend->select()->from('hostStatus', [
'hostname' => 'host_name', '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) public function getHostState($hostname)
{ {
$hostStates = array( $hostStates = [
'0' => 'up', '0' => 'up',
'1' => 'down', '1' => 'down',
'2' => 'unreachable', '2' => 'unreachable',
'99' => 'pending', '99' => 'pending',
); ];
$query = $this->backend->select()->from('hostStatus', array( $query = $this->backend->select()->from('hostStatus', [
'hostname' => 'host_name', 'hostname' => 'host_name',
'state' => 'host_state', 'state' => 'host_state',
'problem' => 'host_problem', 'problem' => 'host_problem',
'acknowledged' => 'host_acknowledged', 'acknowledged' => 'host_acknowledged',
'in_downtime' => 'host_in_downtime', 'in_downtime' => 'host_in_downtime',
'output' => 'host_output', 'output' => 'host_output',
))->where('host_name', $hostname); ])->where('host_name', $hostname);
$res = $query->fetchRow(); $res = $query->fetchRow();
if ($res === false) { if ($res === false) {
$res = (object) array( $res = (object) [
'hostname' => $hostname, 'hostname' => $hostname,
'state' => '99', 'state' => '99',
'problem' => '0', 'problem' => '0',
'acknowledged' => '0', 'acknowledged' => '0',
'in_downtime' => '0', 'in_downtime' => '0',
'output' => null, 'output' => null,
); ];
} }
$res->state = $hostStates[$res->state]; $res->state = $hostStates[$res->state];
return $res; 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 Exception;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Db; use Icinga\Module\Director\Db;
use Icinga\Module\Director\Monitoring;
use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Util; use Icinga\Module\Director\Util;
use Icinga\Module\Monitoring\Hook\HostActionsHook; 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)) { 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( $actions[mt('director', 'Modify')] = Url::fromPath(
'director/host/edit', 'director/host/edit',
array('name' => $hostname) array('name' => $hostname)

View File

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