ServiceSet: allow controlled/restricted access

fixes #1235
This commit is contained in:
Thomas Gelf 2017-10-12 16:26:50 +02:00
parent adb9cc47a4
commit 0e10545175
11 changed files with 158 additions and 19 deletions

View File

@ -310,11 +310,14 @@ class IcingaServiceForm extends DirectorObjectForm
$this->addNameElement()
->addDisabledElement()
->groupMainProperties()
->addCheckCommandElements(true)
->addCheckExecutionElements(true)
->addExtraInfoElements()
->setButtons();
->groupMainProperties();
if ($this->hasPermission('director/admin')) {
$this->addCheckCommandElements(true)
->addCheckExecutionElements(true)
->addExtraInfoElements()
->setButtons();
}
if ($this->hasBeenSent()) {
$name = $this->getSentOrObjectValue('object_name');

View File

@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use Icinga\Module\Director\Web\Form\Validate\NamePattern;
class IcingaServiceSetForm extends DirectorObjectForm
{
@ -32,6 +33,13 @@ class IcingaServiceSetForm extends DirectorObjectForm
'required' => true,
));
$rName = 'director/service_set/filter-by-name';
foreach ($this->getAuth()->getRestrictions($rName) as $restriction) {
$this->getElement('object_name')->addValidator(
new NamePattern($restriction)
);
}
$this->addHidden('object_type', 'template');
$this->addDescriptionElement()
->addAssignmentElements();
@ -110,6 +118,10 @@ class IcingaServiceSetForm extends DirectorObjectForm
protected function addAssignmentElements()
{
if (! $this->hasPermission('director/service_set/apply')) {
return $this;
}
$this->addAssignFilter([
'suggestionContext' => 'HostFilterColumns',
'description' => $this->translate(

View File

@ -13,6 +13,8 @@ $this->providePermission(
$this->providePermission('director/deploy', $this->translate('Allow to deploy configuration'));
$this->providePermission('director/hosts', $this->translate('Allow to configure hosts'));
$this->providePermission('director/services', $this->translate('Allow to configure services'));
$this->providePermission('director/servicesets', $this->translate('Allow to configure service sets'));
$this->providePermission('director/service_set/apply', $this->translate('Allow to define Service Set Apply Rules'));
$this->providePermission('director/users', $this->translate('Allow to configure users'));
$this->providePermission('director/notifications', $this->translate('Allow to configure notifications'));
$this->providePermission(
@ -44,6 +46,14 @@ $this->provideRestriction(
)
);
$this->provideRestriction(
'director/service_set/filter-by-name',
$this->translate(
'Filter available service set templates. Use asterisks (*) as wildcards,'
. ' like in DB* or *net*'
)
);
$this->provideSearchUrl($this->translate('Host configs'), 'director/hosts?limit=10', 60);
/*

View File

@ -12,10 +12,11 @@ before switching to a new version.
### Permissions and Restrictions
* FEATURE: Showing the executed SQL query now requires the `showsql` permission
* FEATURE: Grant access to Service Set in a controlled way
### UI features
* Admins have now access to JSON download links in many places
* Users equipped with related permissions can toggle "Show SQL" in the GUI
### User Interface
* FEATURE: Admins have now access to JSON download links in many places
* FEATURE: Users equipped with related permissions can toggle "Show SQL" in the GUI
1.4.1
-----

View File

@ -26,6 +26,6 @@ class ServiceSetsDashlet extends Dashlet
public function listRequiredPermissions()
{
return array('director/service_sets');
return array('director/servicesets');
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace Icinga\Module\Director\Restriction;
use dipl\Db\Zf1\FilterRenderer;
use Icinga\Authentication\Auth;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaObject;
use Zend_Db_Select as ZfSelect;
class FilterByNameRestriction extends ObjectRestriction
{
protected $type;
/** @var Filter */
protected $filter;
public function __construct(Db $connection, Auth $auth, $type)
{
parent::__construct($connection, $auth);
$this->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->prepareFilter()->matches([
(object) ['object_name' => $object->getObjectName()]
]);
}
public function getFilter()
{
if ($this->filter === null) {
$this->filter = $this->prepareFilter();
}
return $this->filter;
}
protected function filterQuery(ZfSelect $query, $tableAlias = 'o')
{
FilterRenderer::applyToQuery($this->getFilter(), $query);
}
protected function prepareFilter()
{
$filter = Filter::matchAll();
foreach ($this->auth->getRestrictions($this->name) as $restriction) {
$filter->addFilter(Filter::expression('object_name', '=', $restriction));
}
return $filter;
}
protected function preparePrefixedFilter($prefix)
{
$filter = Filter::matchAll();
foreach ($this->auth->getRestrictions($this->name) as $restriction) {
$filter->addFilter(
Filter::expression("$prefix.object_name", '=', $restriction)
);
}
return $filter;
}
}

View File

@ -116,7 +116,8 @@ abstract class ObjectController extends ActionController
public function renderAction()
{
$this->assertPermission('director/showconfig');
$this->assertTypePermission()
->assertPermission('director/showconfig');
$this->tabs()->activate('render');
$preview = new ObjectPreview($this->requireObject(), $this->getRequest());
if ($this->object->isExternal()) {
@ -127,7 +128,7 @@ abstract class ObjectController extends ActionController
public function cloneAction()
{
$this->assertPermission('director/' . strtolower($this->getPluralType()));
$this->assertTypePermission();
$object = $this->requireObject();
$form = IcingaCloneObjectForm::load()
->setObject($object)
@ -181,7 +182,9 @@ abstract class ObjectController extends ActionController
public function historyAction()
{
$this->assertPermission('director/audit')
$this
->assertTypePermission()
->assertPermission('director/audit')
->setAutorefreshInterval(10)
->tabs()->activate('history');
@ -268,7 +271,7 @@ abstract class ObjectController extends ActionController
protected function addObject()
{
$this->assertPermission('director/' . $this->getPluralType());
$this->assertTypePermission();
$imports = $this->params->get('imports');
if (is_string($imports) && strlen($imports)) {
$this->addTitle(
@ -322,6 +325,13 @@ abstract class ObjectController extends ActionController
return $this->translate(ucfirst($this->getType()));
}
protected function assertTypePermission()
{
return $this->assertPermission(
'director/' . strtolower($this->getPluralType())
);
}
protected function eventuallyLoadObject()
{
if (null !== $this->params->get('name') || $this->params->get('id')) {

View File

@ -215,7 +215,7 @@ abstract class ObjectsController extends ActionController
$type = $this->getType();
$tType = $this->translate(ucfirst($type));
$this
->assertPermission('director/' . $this->getBaseType() . '_sets')
->assertPermission('director/' . $this->getBaseType() . 'sets')
->addObjectsTabs()
->requireSupportFor('Sets')
->setAutorefreshInterval(10)
@ -240,7 +240,7 @@ abstract class ObjectsController extends ActionController
)
);
ObjectSetTable::create($type, $this->db())->renderTo($this);
ObjectSetTable::create($type, $this->db(), $this->getAuth())->renderTo($this);
}
protected function loadMultiObjectsFromParams()
@ -308,8 +308,8 @@ abstract class ObjectsController extends ActionController
{
// Strip final 's' and upcase an eventual 'group'
return preg_replace(
array('/group$/', '/period$/', '/argument$/', '/apiuser$/', '/dependencie$/'),
array('Group', 'Period', 'Argument', 'ApiUser', 'dependency'),
array('/group$/', '/period$/', '/argument$/', '/apiuser$/', '/dependencie$/', '/set$/'),
array('Group', 'Period', 'Argument', 'ApiUser', 'dependency', 'Set'),
str_replace(
'template',
'',

View File

@ -26,6 +26,7 @@ class NamePattern extends Zend_Validate_Abstract
{
if ($this->filter === null) {
$this->filter = new FilterMatch('prop', '=', $this->pattern);
$this->filter->setCaseSensitive(false);
}
return $this->filter->matches($value);

View File

@ -2,10 +2,12 @@
namespace Icinga\Module\Director\Web\Table;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Db;
use dipl\Html\Link;
use dipl\Web\Table\ZfQueryBasedTable;
use dipl\Web\Url;
use Icinga\Module\Director\Restriction\FilterByNameRestriction;
class ObjectSetTable extends ZfQueryBasedTable
{
@ -17,10 +19,14 @@ class ObjectSetTable extends ZfQueryBasedTable
private $type;
public static function create($type, Db $db)
/** @var Auth */
private $auth;
public static function create($type, Db $db, Auth $auth)
{
$table = new static($db);
$table->type = $type;
$table->auth = $auth;
return $table;
}
@ -79,6 +85,12 @@ class ObjectSetTable extends ZfQueryBasedTable
[]
);
$nameFilter = new FilterByNameRestriction(
$this->connection(),
$this->auth,
"${type}_set"
);
$nameFilter->applyToQuery($query, 'os');
// Disabled for now, check for correctness:
// $query->joinLeft(
// ['osi' => "icinga_${type}_set_inheritance"],
@ -98,4 +110,12 @@ class ObjectSetTable extends ZfQueryBasedTable
return $query;
}
/**
* @return Db
*/
public function connection()
{
return parent::connection();
}
}

View File

@ -70,7 +70,7 @@ class ObjectsTabs extends Tabs
));
}
}
if ($object->supportsSets() && $auth->hasPermission("director/${type}_sets")) {
if ($object->supportsSets() && $auth->hasPermission("director/${type}sets")) {
$this->add('sets', array(
'url' => sprintf('director/%s/sets', $plType),
'label' => $this->translate('Sets')