Merge branch 'feature/protected-menu-8720'

resolves #8720
This commit is contained in:
Eric Lippmann 2015-03-13 04:26:19 +01:00
commit e36c430bb3
7 changed files with 107 additions and 42 deletions

View File

@ -37,7 +37,7 @@ class ConfigController extends ActionController
$tabs = $this->getTabs(); $tabs = $this->getTabs();
$auth = $this->Auth(); $auth = $this->Auth();
$allowedActions = array(); $allowedActions = array();
if ($auth->hasPermission('system/config/application')) { if ($auth->hasPermission('config/application/general')) {
$tabs->add('application', array( $tabs->add('application', array(
'title' => $this->translate('Adjust the general configuration of Icinga Web 2'), 'title' => $this->translate('Adjust the general configuration of Icinga Web 2'),
'label' => $this->translate('Application'), 'label' => $this->translate('Application'),
@ -45,7 +45,7 @@ class ConfigController extends ActionController
)); ));
$allowedActions[] = 'application'; $allowedActions[] = 'application';
} }
if ($auth->hasPermission('system/config/authentication')) { if ($auth->hasPermission('config/application/authentication')) {
$tabs->add('authentication', array( $tabs->add('authentication', array(
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'), 'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
'label' => $this->translate('Authentication'), 'label' => $this->translate('Authentication'),
@ -53,7 +53,7 @@ class ConfigController extends ActionController
)); ));
$allowedActions[] = 'authentication'; $allowedActions[] = 'authentication';
} }
if ($auth->hasPermission('system/config/resources')) { if ($auth->hasPermission('config/application/resources')) {
$tabs->add('resource', array( $tabs->add('resource', array(
'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'), 'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'),
'label' => $this->translate('Resources'), 'label' => $this->translate('Resources'),
@ -61,7 +61,7 @@ class ConfigController extends ActionController
)); ));
$allowedActions[] = 'resource'; $allowedActions[] = 'resource';
} }
if ($auth->hasPermission('system/config/roles')) { if ($auth->hasPermission('config/application/roles')) {
$tabs->add('roles', array( $tabs->add('roles', array(
'title' => $this->translate( 'title' => $this->translate(
'Configure roles to permit or restrict users and groups accessing Icinga Web 2' 'Configure roles to permit or restrict users and groups accessing Icinga Web 2'
@ -102,7 +102,7 @@ class ConfigController extends ActionController
*/ */
public function applicationAction() public function applicationAction()
{ {
$this->assertPermission('system/config/application'); $this->assertPermission('config/application/general');
$form = new GeneralConfigForm(); $form = new GeneralConfigForm();
$form->setIniConfig(Config::app()); $form->setIniConfig(Config::app());
$form->handleRequest(); $form->handleRequest();
@ -158,7 +158,7 @@ class ConfigController extends ActionController
*/ */
public function moduleenableAction() public function moduleenableAction()
{ {
$this->assertPermission('system/config/modules'); $this->assertPermission('config/modules');
$module = $this->getParam('name'); $module = $this->getParam('name');
$manager = Icinga::app()->getModuleManager(); $manager = Icinga::app()->getModuleManager();
try { try {
@ -178,7 +178,7 @@ class ConfigController extends ActionController
*/ */
public function moduledisableAction() public function moduledisableAction()
{ {
$this->assertPermission('system/config/modules'); $this->assertPermission('config/modules');
$module = $this->getParam('name'); $module = $this->getParam('name');
$manager = Icinga::app()->getModuleManager(); $manager = Icinga::app()->getModuleManager();
try { try {
@ -198,7 +198,7 @@ class ConfigController extends ActionController
*/ */
public function authenticationAction() public function authenticationAction()
{ {
$this->assertPermission('system/config/authentication'); $this->assertPermission('config/application/authentication');
$form = new AuthenticationBackendReorderForm(); $form = new AuthenticationBackendReorderForm();
$form->setIniConfig(Config::app('authentication')); $form->setIniConfig(Config::app('authentication'));
$form->handleRequest(); $form->handleRequest();
@ -213,7 +213,7 @@ class ConfigController extends ActionController
*/ */
public function createauthenticationbackendAction() public function createauthenticationbackendAction()
{ {
$this->assertPermission('system/config/authentication'); $this->assertPermission('config/application/authentication');
$form = new AuthenticationBackendConfigForm(); $form = new AuthenticationBackendConfigForm();
$form->setTitle($this->translate('Create New Authentication Backend')); $form->setTitle($this->translate('Create New Authentication Backend'));
$form->addDescription($this->translate( $form->addDescription($this->translate(
@ -235,7 +235,7 @@ class ConfigController extends ActionController
*/ */
public function editauthenticationbackendAction() public function editauthenticationbackendAction()
{ {
$this->assertPermission('system/config/authentication'); $this->assertPermission('config/application/authentication');
$form = new AuthenticationBackendConfigForm(); $form = new AuthenticationBackendConfigForm();
$form->setTitle($this->translate('Edit Backend')); $form->setTitle($this->translate('Edit Backend'));
$form->setIniConfig(Config::app('authentication')); $form->setIniConfig(Config::app('authentication'));
@ -253,7 +253,7 @@ class ConfigController extends ActionController
*/ */
public function removeauthenticationbackendAction() public function removeauthenticationbackendAction()
{ {
$this->assertPermission('system/config/authentication'); $this->assertPermission('config/application/authentication');
$form = new ConfirmRemovalForm(array( $form = new ConfirmRemovalForm(array(
'onSuccess' => function ($form) { 'onSuccess' => function ($form) {
$configForm = new AuthenticationBackendConfigForm(); $configForm = new AuthenticationBackendConfigForm();
@ -291,7 +291,7 @@ class ConfigController extends ActionController
*/ */
public function resourceAction() public function resourceAction()
{ {
$this->assertPermission('system/config/resources'); $this->assertPermission('config/application/resources');
$this->view->resources = Config::app('resources', true)->keys(); $this->view->resources = Config::app('resources', true)->keys();
$this->view->tabs->activate('resource'); $this->view->tabs->activate('resource');
} }
@ -301,7 +301,7 @@ class ConfigController extends ActionController
*/ */
public function createresourceAction() public function createresourceAction()
{ {
$this->assertPermission('system/config/resources'); $this->assertPermission('config/application/resources');
$form = new ResourceConfigForm(); $form = new ResourceConfigForm();
$form->setTitle($this->translate('Create A New Resource')); $form->setTitle($this->translate('Create A New Resource'));
$form->addDescription($this->translate('Resources are entities that provide data to Icinga Web 2.')); $form->addDescription($this->translate('Resources are entities that provide data to Icinga Web 2.'));
@ -318,7 +318,7 @@ class ConfigController extends ActionController
*/ */
public function editresourceAction() public function editresourceAction()
{ {
$this->assertPermission('system/config/resources'); $this->assertPermission('config/application/resources');
$form = new ResourceConfigForm(); $form = new ResourceConfigForm();
$form->setTitle($this->translate('Edit Existing Resource')); $form->setTitle($this->translate('Edit Existing Resource'));
$form->setIniConfig(Config::app('resources')); $form->setIniConfig(Config::app('resources'));
@ -334,7 +334,7 @@ class ConfigController extends ActionController
*/ */
public function removeresourceAction() public function removeresourceAction()
{ {
$this->assertPermission('system/config/resources'); $this->assertPermission('config/application/resources');
$form = new ConfirmRemovalForm(array( $form = new ConfirmRemovalForm(array(
'onSuccess' => function ($form) { 'onSuccess' => function ($form) {
$configForm = new ResourceConfigForm(); $configForm = new ResourceConfigForm();

View File

@ -20,24 +20,24 @@ class RolesController extends ActionController
*/ */
public function init() public function init()
{ {
$this->assertPermission('system/config/roles'); $this->assertPermission('config/application/roles');
$tabs = $this->getTabs(); $tabs = $this->getTabs();
$auth = $this->Auth(); $auth = $this->Auth();
if ($auth->hasPermission('system/config/application')) { if ($auth->hasPermission('config/application/general')) {
$tabs->add('application', array( $tabs->add('application', array(
'title' => $this->translate('Adjust the general configuration of Icinga Web 2'), 'title' => $this->translate('Adjust the general configuration of Icinga Web 2'),
'label' => $this->translate('Application'), 'label' => $this->translate('Application'),
'url' => 'config' 'url' => 'config'
)); ));
} }
if ($auth->hasPermission('system/config/authentication')) { if ($auth->hasPermission('config/application/authentication')) {
$tabs->add('authentication', array( $tabs->add('authentication', array(
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'), 'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
'label' => $this->translate('Authentication'), 'label' => $this->translate('Authentication'),
'url' => 'config/authentication' 'url' => 'config/authentication'
)); ));
} }
if ($auth->hasPermission('system/config/resources')) { if ($auth->hasPermission('config/application/resources')) {
$tabs->add('resource', array( $tabs->add('resource', array(
'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'), 'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'),
'label' => $this->translate('Resources'), 'label' => $this->translate('Resources'),

View File

@ -21,13 +21,14 @@ class RoleForm extends ConfigForm
* @var array * @var array
*/ */
protected $providedPermissions = array( protected $providedPermissions = array(
'*' => '*', '*' => '*',
'system/config/*' => 'system/config/*', 'config/*' => 'config/*',
'system/config/application' => 'system/config/application', 'config/application/*' => 'config/application/*',
'system/config/authentication' => 'system/config/authentication', 'config/application/general' => 'config/application/general',
'system/config/modules' => 'system/config/modules', 'config/application/authentication' => 'config/application/authentication',
'system/config/resources' => 'system/config/resources', 'config/application/resources' => 'config/application/resources',
'system/config/roles' => 'system/config/roles' 'config/application/roles' => 'config/application/roles',
'config/modules' => 'config/modules'
); );
/** /**
@ -38,8 +39,7 @@ class RoleForm extends ConfigForm
protected $providedRestrictions = array(); protected $providedRestrictions = array();
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::init() For the method documentation.
*/ */
public function init() public function init()
{ {
@ -68,8 +68,7 @@ class RoleForm extends ConfigForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::createElements() For the method documentation.
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
@ -253,8 +252,7 @@ class RoleForm extends ConfigForm
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Zend_Form::getValues() For the method documentation.
*/ */
public function getValues($suppressArrayNotation = false) public function getValues($suppressArrayNotation = false)
{ {

View File

@ -422,8 +422,16 @@ class User
if (isset($this->permissions['*']) || isset($this->permissions[$permission])) { if (isset($this->permissions['*']) || isset($this->permissions[$permission])) {
return true; return true;
} }
// If the permission to check contains a wildcard, grant the permission if any permit related to the permission
// matches
$any = strpos($permission, '*');
foreach ($this->permissions as $permitted) { foreach ($this->permissions as $permitted) {
$wildcard = strpos($permitted, '*'); if ($any !== false) {
$wildcard = $any;
} else {
// If the permit contains a wildcard, grant the permission if it's related to the permit
$wildcard = strpos($permitted, '*');
}
if ($wildcard !== false) { if ($wildcard !== false) {
if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) { if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) {
return true; return true;

View File

@ -75,6 +75,17 @@ class Menu implements RecursiveIterator
*/ */
protected $parent; protected $parent;
/**
* Permission a user is required to have granted to display the menu item
*
* If a permission is set, authentication is of course required.
*
* Note that only one required permission can be set yet.
*
* @var string|null
*/
protected $permission;
/** /**
* Create a new menu * Create a new menu
* *
@ -221,12 +232,14 @@ class Menu implements RecursiveIterator
'priority' => 200 'priority' => 200
)); ));
$section->add(t('Configuration'), array( $section->add(t('Configuration'), array(
'url' => 'config', 'url' => 'config',
'priority' => 300 'permission' => 'config/application/*',
'priority' => 300
)); ));
$section->add(t('Modules'), array( $section->add(t('Modules'), array(
'url' => 'config/modules', 'url' => 'config/modules',
'priority' => 400 'permission' => 'config/modules',
'priority' => 400
)); ));
if (Logger::writesToFile()) { if (Logger::writesToFile()) {
@ -442,15 +455,27 @@ class Menu implements RecursiveIterator
} }
/** /**
* Set required Permissions * Get the permission a user is required to have granted to display the menu item
* *
* @param $permission * @return string|null
*/
public function getPermission()
{
return $this->permission;
}
/**
* Set permission a user is required to have granted to display the menu item
*
* If a permission is set, authentication is of course required.
*
* @param string $permission
* *
* @return $this * @return $this
*/ */
public function requirePermission($permission) public function setPermission($permission)
{ {
// Not implemented yet $this->permission = (string) $permission;
return $this; return $this;
} }

View File

@ -0,0 +1,33 @@
<?php
namespace Icinga\Web\Menu;
use RecursiveFilterIterator;
use Icinga\Authentication\Manager;
use Icinga\Web\Menu;
class PermittedMenuItemFilter extends RecursiveFilterIterator
{
/**
* Accept menu items that are permitted to the user
*
* @return bool Whether the user has the required permission granted to display the menu item
*/
public function accept()
{
$item = $this->current();
/** @var Menu $item */
if (($permission = $item->getPermission()) !== null) {
$auth = Manager::getInstance();
if (! $auth->isAuthenticated()) {
// Don't accept menu item because user is not authenticated and the menu item requires a permission
return false;
}
if (! $auth->getUser()->can($permission)) {
return false;
}
}
// Accept menu item if it does not require a permission
return true;
}
}

View File

@ -6,6 +6,7 @@ namespace Icinga\Web;
use Exception; use Exception;
use RecursiveIteratorIterator; use RecursiveIteratorIterator;
use Icinga\Application\Logger; use Icinga\Application\Logger;
use Icinga\Web\Menu\PermittedMenuItemFilter;
/** /**
* A renderer to draw a menu with its sub-menus using an unordered html list * A renderer to draw a menu with its sub-menus using an unordered html list
@ -44,7 +45,7 @@ class MenuRenderer extends RecursiveIteratorIterator
} else { } else {
$this->url = Url::fromPath($url); $this->url = Url::fromPath($url);
} }
parent::__construct($menu, RecursiveIteratorIterator::CHILD_FIRST); parent::__construct(new PermittedMenuItemFilter($menu), RecursiveIteratorIterator::CHILD_FIRST);
} }
/** /**