From 375345f8378a8988b9b2d56b1dd42dcf5c98da80 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 09:06:10 +0100 Subject: [PATCH 01/58] lib: Add SecurityException All assertPermission() calls must throw this exception. --- library/Icinga/Security/SecurityException.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 library/Icinga/Security/SecurityException.php diff --git a/library/Icinga/Security/SecurityException.php b/library/Icinga/Security/SecurityException.php new file mode 100644 index 000000000..168d4a9be --- /dev/null +++ b/library/Icinga/Security/SecurityException.php @@ -0,0 +1,12 @@ + Date: Fri, 30 Jan 2015 09:31:05 +0100 Subject: [PATCH 02/58] Return HTTP 403 in case a SecurityException was thrown --- application/controllers/ErrorController.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/application/controllers/ErrorController.php b/application/controllers/ErrorController.php index 23051bd9a..0548b5c9c 100644 --- a/application/controllers/ErrorController.php +++ b/application/controllers/ErrorController.php @@ -1,12 +1,9 @@ getResponse()->setHttpResponseCode(403); + $this->view->message = $exception->getMessage(); + break; + } + // Move to default default: $title = preg_replace('/\r?\n.*$/s', '', $exception->getMessage()); $this->getResponse()->setHttpResponseCode(500); From 63305fdf9aca81a477f677659062b12136325446 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 09:32:08 +0100 Subject: [PATCH 03/58] Add Icinga\Application\Config::saveIni() Simplifies saving INI files. Icinga\File\Ini\IniWriter does already require an instance of Icinga\Application\Config so it's obvious to give "Config" the task to initialize the writer.. We do also have a central place to handle creating missing ancestor directories now. refs #8219 --- .../controllers/DashboardController.php | 41 ++++++++------- application/forms/ConfigForm.php | 12 +---- .../views/scripts/dashboard/error.phtml | 14 ++--- library/Icinga/Application/Config.php | 51 +++++++++++++++++++ .../User/Preferences/Store/IniStore.php | 39 +------------- library/Icinga/Web/Widget/Dashboard.php | 21 ++------ .../library/Monitoring/BackendStep.php | 17 ++----- .../library/Monitoring/InstanceStep.php | 9 ++-- .../library/Monitoring/SecurityStep.php | 9 ++-- .../Setup/Steps/AuthenticationStep.php | 17 +++---- .../library/Setup/Steps/GeneralConfigStep.php | 9 ++-- .../library/Setup/Steps/ResourceStep.php | 10 ++-- 12 files changed, 109 insertions(+), 140 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index ba2125e12..7c70c9c5a 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -2,14 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -use Icinga\Application\Logger; +use Exception; use Icinga\Exception\ProgrammingError; use Icinga\Forms\ConfirmRemovalForm; use Icinga\Forms\Dashboard\DashletForm; use Icinga\Web\Form; use Icinga\Web\Notification; use Icinga\Web\Controller\ActionController; -use Icinga\Web\Request; use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Widget\Tabextension\DashboardSettings; @@ -56,11 +55,12 @@ class DashboardController extends ActionController $dashlet = new Dashboard\Dashlet($form->getValue('dashlet'), $form->getValue('url'), $pane); $dashlet->setUserWidget(); $pane->addDashlet($dashlet); + $dashboardConfig = $dashboard->getConfig(); try { - $dashboard->write(); - } catch (\Zend_Config_Exception $e) { + $dashboardConfig->saveIni(); + } catch (Exception $e) { $action->view->error = $e; - $action->view->config = $dashboard->createWriter(); + $action->view->config = $dashboardConfig; $action->render('error'); return false; } @@ -117,11 +117,12 @@ class DashboardController extends ActionController $oldPane = $dashboard->getPane($form->getValue('org_pane')); $oldPane->removeDashlet($dashlet->getTitle()); } + $dashboardConfig = $dashboard->getConfig(); try { - $dashboard->write(); - } catch (\Zend_Config_Exception $e) { + $dashboardConfig->saveIni(); + } catch (Exception $e) { $action->view->error = $e; - $action->view->config = $dashboard->createWriter(); + $action->view->config = $dashboardConfig; $action->render('error'); return false; } @@ -158,15 +159,16 @@ class DashboardController extends ActionController $dashlet = $this->_request->getParam('dashlet'); $action = $this; $form->setOnSuccess(function (Form $form) use ($dashboard, $dashlet, $pane, $action) { + $pane = $dashboard->getPane($pane); + $pane->removeDashlet($dashlet); + $dashboardConfig = $dashboard->getConfig(); try { - $pane = $dashboard->getPane($pane); - $pane->removeDashlet($dashlet); - $dashboard->write(); + $dashboardConfig->saveIni(); Notification::success(t('Dashlet has been removed from') . ' ' . $pane->getTitle()); return true; - } catch (\Zend_Config_Exception $e) { + } catch (Exception $e) { $action->view->error = $e; - $action->view->config = $dashboard->createWriter(); + $action->view->config = $dashboardConfig; $action->render('error'); return false; } catch (ProgrammingError $e) { @@ -196,15 +198,16 @@ class DashboardController extends ActionController $pane = $this->_request->getParam('pane'); $action = $this; $form->setOnSuccess(function (Form $form) use ($dashboard, $pane, $action) { + $pane = $dashboard->getPane($pane); + $dashboard->removePane($pane->getTitle()); + $dashboardConfig = $dashboard->getConfig(); try { - $pane = $dashboard->getPane($pane); - $dashboard->removePane($pane->getTitle()); - $dashboard->write(); + $dashboardConfig->saveIni(); Notification::success(t('Dashboard has been removed') . ': ' . $pane->getTitle()); return true; - } catch (\Zend_Config_Exception $e) { + } catch (Exception $e) { $action->view->error = $e; - $action->view->config = $dashboard->createWriter(); + $action->view->config = $dashboardConfig; $action->render('error'); return false; } catch (ProgrammingError $e) { @@ -241,7 +244,7 @@ class DashboardController extends ActionController $this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard'; if ($this->hasParam('remove')) { $this->dashboard->getActivePane()->removeDashlet($this->getParam('remove')); - $this->dashboard->write(); + $this->dashboard->getConfig()->saveIni(); $this->redirectNow(URL::fromRequest()->remove('remove')); } $this->view->tabs->add( diff --git a/application/forms/ConfigForm.php b/application/forms/ConfigForm.php index 28d3111ea..224633f1f 100644 --- a/application/forms/ConfigForm.php +++ b/application/forms/ConfigForm.php @@ -8,7 +8,6 @@ use Exception; use Zend_Form_Decorator_Abstract; use Icinga\Web\Form; use Icinga\Application\Config; -use Icinga\File\Ini\IniWriter; /** * Form base-class providing standard functionality for configuration forms @@ -44,21 +43,14 @@ class ConfigForm extends Form */ public function save() { - $writer = new IniWriter( - array( - 'config' => $this->config, - 'filename' => $this->config->getConfigFile() - ) - ); - try { - $writer->write(); + $this->config->saveIni(); } catch (Exception $e) { $this->addDecorator('ViewScript', array( 'viewModule' => 'default', 'viewScript' => 'showConfiguration.phtml', 'errorMessage' => $e->getMessage(), - 'configString' => $writer->render(), + 'configString' => $this->config, 'filePath' => $this->config->getConfigFile(), 'placement' => Zend_Form_Decorator_Abstract::PREPEND )); diff --git a/application/views/scripts/dashboard/error.phtml b/application/views/scripts/dashboard/error.phtml index e5a0f3939..56e32faf4 100644 --- a/application/views/scripts/dashboard/error.phtml +++ b/application/views/scripts/dashboard/error.phtml @@ -1,13 +1,13 @@
-

+

translate('Could not persist dashboard'); ?>

- - config->getFilename(); ?>;. + translate('Please copy the following dashboard snippet to '); ?> + config->getConfigFile(); ?>;.
- + translate('Make sure that the webserver can write to this file.'); ?>

-
config->render(); ?>
+
config; ?>

-

+

translate('Error details'); ?>

error->getMessage(); ?>

-
+ \ No newline at end of file diff --git a/library/Icinga/Application/Config.php b/library/Icinga/Application/Config.php index 361f5f11d..8d4914316 100644 --- a/library/Icinga/Application/Config.php +++ b/library/Icinga/Application/Config.php @@ -6,8 +6,10 @@ namespace Icinga\Application; use Iterator; use Countable; +use LogicException; use UnexpectedValueException; use Icinga\Data\ConfigObject; +use Icinga\File\Ini\IniWriter; use Icinga\Exception\NotReadableError; /** @@ -299,6 +301,45 @@ class Config implements Countable, Iterator return $emptyConfig; } + /** + * Save configuration to the given INI file + * + * @param string|null $filePath The path to the INI file or null in case this config's path should be used + * @param int $fileMode The file mode to store the file with + * + * @throws LogicException In case this config has no path and none is passed in either + * @throws NotWritableError In case the INI file cannot be written + * + * @todo create basepath and throw NotWritableError in case its not possible + */ + public function saveIni($filePath = null, $fileMode = 0660) + { + if ($filePath === null && $this->configFile) { + $filePath = $this->configFile; + } elseif ($filePath === null) { + throw new LogicException('You need to pass $filePath or set a path using Config::setConfigFile()'); + } + + $this->getIniWriter($filePath, $fileMode)->write(); + } + + /** + * Return a IniWriter for this config + * + * @param string|null $filePath + * @param int $fileMode + * + * @return IniWriter + */ + protected function getIniWriter($filePath = null, $fileMode = null) + { + return new IniWriter(array( + 'config' => $this, + 'filename' => $filePath, + 'filemode' => $fileMode + )); + } + /** * Prepend configuration base dir to the given relative path * @@ -354,4 +395,14 @@ class Config implements Countable, Iterator return $moduleConfigs[$configname]; } + + /** + * Return this config rendered as a INI structured string + * + * @return string + */ + public function __toString() + { + return $this->getIniWriter()->render(); + } } diff --git a/library/Icinga/User/Preferences/Store/IniStore.php b/library/Icinga/User/Preferences/Store/IniStore.php index 1ba780184..1a096ea7b 100644 --- a/library/Icinga/User/Preferences/Store/IniStore.php +++ b/library/Icinga/User/Preferences/Store/IniStore.php @@ -7,10 +7,8 @@ namespace Icinga\User\Preferences\Store; use Icinga\Application\Config; use Icinga\Exception\NotReadableError; use Icinga\Exception\NotWritableError; -use Icinga\File\Ini\IniWriter; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; -use Icinga\Util\File; /** * Load and save user preferences from and to INI files @@ -31,13 +29,6 @@ class IniStore extends PreferencesStore */ protected $preferences = array(); - /** - * Writer which stores the preferences - * - * @var IniWriter - */ - protected $writer; - /** * Initialize the store */ @@ -98,35 +89,7 @@ class IniStore extends PreferencesStore */ public function write() { - if ($this->writer === null) { - if (! file_exists($this->preferencesFile)) { - if (! is_writable($this->getStoreConfig()->location)) { - throw new NotWritableError( - 'Path to the preferences INI files %s is not writable', - $this->getStoreConfig()->location - ); - } - - File::create($this->preferencesFile, 0664); - } - - if (! is_writable($this->preferencesFile)) { - throw new NotWritableError( - 'Preferences INI file %s for user %s is not writable', - $this->preferencesFile, - $this->getUser()->getUsername() - ); - } - - $this->writer = new IniWriter( - array( - 'config' => Config::fromArray($this->preferences), - 'filename' => $this->preferencesFile - ) - ); - } - - $this->writer->write(); + Config::fromArray($this->preferences)->saveIni($this->preferencesFile); } /** diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 45e1e6830..fe4bba803 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -6,12 +6,10 @@ namespace Icinga\Web\Widget; use Icinga\Application\Icinga; use Icinga\Application\Config; -use Icinga\Data\ConfigObject; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; use Icinga\Exception\ProgrammingError; use Icinga\Exception\SystemPermissionException; -use Icinga\File\Ini\IniWriter; use Icinga\User; use Icinga\Web\Widget\Dashboard\Pane; use Icinga\Web\Widget\Dashboard\Dashlet as DashboardDashlet; @@ -86,13 +84,12 @@ class Dashboard extends AbstractWidget } /** - * Create a writer object + * Create and return a Config object for this dashboard * - * @return IniWriter + * @return Config */ - public function createWriter() + public function getConfig() { - $configFile = $this->getConfigFile(); $output = array(); foreach ($this->panes as $pane) { if ($pane->isUserWidget() === true) { @@ -105,17 +102,7 @@ class Dashboard extends AbstractWidget } } - $co = new ConfigObject($output); - $config = new Config($co); - return new IniWriter(array('config' => $config, 'filename' => $configFile)); - } - - /** - * Write user specific dashboards to disk - */ - public function write() - { - $this->createWriter()->write(); + return Config::fromArray($output)->setConfigFile($this->getConfigFile()); } /** diff --git a/modules/monitoring/library/Monitoring/BackendStep.php b/modules/monitoring/library/Monitoring/BackendStep.php index c0dc3d4ea..7f9fc11cf 100644 --- a/modules/monitoring/library/Monitoring/BackendStep.php +++ b/modules/monitoring/library/Monitoring/BackendStep.php @@ -7,7 +7,6 @@ namespace Icinga\Module\Monitoring; use Exception; use Icinga\Module\Setup\Step; use Icinga\Application\Config; -use Icinga\File\Ini\IniWriter; class BackendStep extends Step { @@ -38,11 +37,9 @@ class BackendStep extends Step ); try { - $writer = new IniWriter(array( - 'config' => Config::fromArray($config), - 'filename' => Config::resolvePath('modules/monitoring/backends.ini') - )); - $writer->write(); + Config::fromArray($config) + ->setConfigFile(Config::resolvePath('modules/monitoring/backends.ini')) + ->saveIni(); } catch (Exception $e) { $this->backendIniError = $e; return false; @@ -61,13 +58,7 @@ class BackendStep extends Step try { $config = Config::app('resources', true); $config->setSection($resourceName, $resourceConfig); - - $writer = new IniWriter(array( - 'config' => $config, - 'filename' => Config::resolvePath('resources.ini'), - 'filemode' => 0660 - )); - $writer->write(); + $config->saveIni(); } catch (Exception $e) { $this->resourcesIniError = $e; return false; diff --git a/modules/monitoring/library/Monitoring/InstanceStep.php b/modules/monitoring/library/Monitoring/InstanceStep.php index 2cb8d7d8d..ab54b6548 100644 --- a/modules/monitoring/library/Monitoring/InstanceStep.php +++ b/modules/monitoring/library/Monitoring/InstanceStep.php @@ -7,7 +7,6 @@ namespace Icinga\Module\Monitoring; use Exception; use Icinga\Module\Setup\Step; use Icinga\Application\Config; -use Icinga\File\Ini\IniWriter; class InstanceStep extends Step { @@ -27,11 +26,9 @@ class InstanceStep extends Step unset($instanceConfig['name']); try { - $writer = new IniWriter(array( - 'config' => Config::fromArray(array($instanceName => $instanceConfig)), - 'filename' => Config::resolvePath('modules/monitoring/instances.ini') - )); - $writer->write(); + Config::fromArray(array($instanceName => $instanceConfig)) + ->setConfigFile(Config::resolvePath('modules/monitoring/instances.ini')) + ->saveIni(); } catch (Exception $e) { $this->error = $e; return false; diff --git a/modules/monitoring/library/Monitoring/SecurityStep.php b/modules/monitoring/library/Monitoring/SecurityStep.php index 4a2c0f846..b3eda02c4 100644 --- a/modules/monitoring/library/Monitoring/SecurityStep.php +++ b/modules/monitoring/library/Monitoring/SecurityStep.php @@ -7,7 +7,6 @@ namespace Icinga\Module\Monitoring; use Exception; use Icinga\Module\Setup\Step; use Icinga\Application\Config; -use Icinga\File\Ini\IniWriter; class SecurityStep extends Step { @@ -26,11 +25,9 @@ class SecurityStep extends Step $config['security'] = $this->data['securityConfig']; try { - $writer = new IniWriter(array( - 'config' => Config::fromArray($config), - 'filename' => Config::resolvePath('modules/monitoring/config.ini') - )); - $writer->write(); + Config::fromArray($config) + ->setConfigFile(Config::resolvePath('modules/monitoring/config.ini')) + ->saveIni(); } catch (Exception $e) { $this->error = $e; return false; diff --git a/modules/setup/library/Setup/Steps/AuthenticationStep.php b/modules/setup/library/Setup/Steps/AuthenticationStep.php index ce0b49f58..c06b4e294 100644 --- a/modules/setup/library/Setup/Steps/AuthenticationStep.php +++ b/modules/setup/library/Setup/Steps/AuthenticationStep.php @@ -6,7 +6,6 @@ namespace Icinga\Module\Setup\Steps; use Exception; use Icinga\Application\Config; -use Icinga\File\Ini\IniWriter; use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Authentication\Backend\DbUserBackend; @@ -50,11 +49,9 @@ class AuthenticationStep extends Step } try { - $writer = new IniWriter(array( - 'config' => Config::fromArray($config), - 'filename' => Config::resolvePath('authentication.ini') - )); - $writer->write(); + Config::fromArray($config) + ->setConfigFile(Config::resolvePath('authentication.ini')) + ->saveIni(); } catch (Exception $e) { $this->authIniError = $e; return false; @@ -73,11 +70,9 @@ class AuthenticationStep extends Step ); try { - $writer = new IniWriter(array( - 'config' => Config::fromArray($config), - 'filename' => Config::resolvePath('permissions.ini') - )); - $writer->write(); + Config::fromArray($config) + ->setConfigFile(Config::resolvePath('permissions.ini')) + ->saveIni(); } catch (Exception $e) { $this->permIniError = $e; return false; diff --git a/modules/setup/library/Setup/Steps/GeneralConfigStep.php b/modules/setup/library/Setup/Steps/GeneralConfigStep.php index 39c160628..bf3d8cb89 100644 --- a/modules/setup/library/Setup/Steps/GeneralConfigStep.php +++ b/modules/setup/library/Setup/Steps/GeneralConfigStep.php @@ -7,7 +7,6 @@ namespace Icinga\Module\Setup\Steps; use Exception; use Icinga\Application\Logger; use Icinga\Application\Config; -use Icinga\File\Ini\IniWriter; use Icinga\Module\Setup\Step; class GeneralConfigStep extends Step @@ -35,11 +34,9 @@ class GeneralConfigStep extends Step } try { - $writer = new IniWriter(array( - 'config' => Config::fromArray($config), - 'filename' => Config::resolvePath('config.ini') - )); - $writer->write(); + Config::fromArray($config) + ->setConfigFile(Config::resolvePath('config.ini')) + ->saveIni(); } catch (Exception $e) { $this->error = $e; return false; diff --git a/modules/setup/library/Setup/Steps/ResourceStep.php b/modules/setup/library/Setup/Steps/ResourceStep.php index c04cdbc79..aae1c3aca 100644 --- a/modules/setup/library/Setup/Steps/ResourceStep.php +++ b/modules/setup/library/Setup/Steps/ResourceStep.php @@ -6,7 +6,6 @@ namespace Icinga\Module\Setup\Steps; use Exception; use Icinga\Application\Config; -use Icinga\File\Ini\IniWriter; use Icinga\Module\Setup\Step; class ResourceStep extends Step @@ -38,12 +37,9 @@ class ResourceStep extends Step } try { - $writer = new IniWriter(array( - 'config' => Config::fromArray($resourceConfig), - 'filename' => Config::resolvePath('resources.ini'), - 'filemode' => 0660 - )); - $writer->write(); + Config::fromArray($resourceConfig) + ->setConfigFile(Config::resolvePath('resources.ini')) + ->saveIni(); } catch (Exception $e) { $this->error = $e; return false; From 2faf5f0ca16aefdac755ecfb22c72b4a83d2e179 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 09:34:19 +0100 Subject: [PATCH 04/58] Throw SecurityException in ActionController::assertPermission() --- .../Web/Controller/ActionController.php | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/library/Icinga/Web/Controller/ActionController.php b/library/Icinga/Web/Controller/ActionController.php index 78fcaf7bf..87d293be6 100644 --- a/library/Icinga/Web/Controller/ActionController.php +++ b/library/Icinga/Web/Controller/ActionController.php @@ -1,23 +1,22 @@ Auth()->hasPermission($name)) { - // TODO: Shall this be an Auth Exception? Or a 404? - throw new IcingaException( - 'Auth error, no permission for "%s"', - $name - ); + if (! $this->Auth()->hasPermission($permission)) { + throw new SecurityException('No permission for %s', $permission); } } From df29dd0e7ca587cc42656dc70c59b33d821c806d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 09:35:01 +0100 Subject: [PATCH 05/58] Implement Form::hasPermission() and Form::getPermission() --- library/Icinga/Web/Form.php | 50 +++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 1f3e0d4bd..daa6dcf40 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -1,6 +1,4 @@ create(); return parent::render($view); } + + /** + * Get the authentication manager + * + * @return Manager + */ + public function Auth() + { + if ($this->auth === null) { + $this->auth = Manager::getInstance(); + } + return $this->auth; + } + + /** + * Whether the current user has the given permission + * + * @param string $permission Name of the permission + * + * @return bool + */ + public function hasPermission($permission) + { + return $this->Auth()->hasPermission($permission); + } + + /** + * Assert that the current user has the given permission + * + * @param string $permission Name of the permission + * + * @throws SecurityException If the current user lacks the given permission + */ + public function assertPermission($permission) + { + if (! $this->Auth()->hasPermission($permission)) { + throw new SecurityException('No permission for %s', $permission); + } + } } From 0108d44d635e628004c6bc5b711ef9ba2f0e6f36 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 09:38:59 +0100 Subject: [PATCH 06/58] Fix "The use of non compound name 'Exception'..." --- application/controllers/DashboardController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 7c70c9c5a..49a58426f 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -use Exception; +use \Exception; use Icinga\Exception\ProgrammingError; use Icinga\Forms\ConfirmRemovalForm; use Icinga\Forms\Dashboard\DashletForm; From d19e36d9370542e8a62fb8c1ed0f2b41a5fbc5eb Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 09:57:31 +0100 Subject: [PATCH 07/58] monitoring/security: Require monitoring/command/feature/instance permission for disabling notifications --- modules/monitoring/application/controllers/ProcessController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/monitoring/application/controllers/ProcessController.php b/modules/monitoring/application/controllers/ProcessController.php index bb5a4e5c2..5530f9c52 100644 --- a/modules/monitoring/application/controllers/ProcessController.php +++ b/modules/monitoring/application/controllers/ProcessController.php @@ -92,6 +92,7 @@ class Monitoring_ProcessController extends Controller */ public function disableNotificationsAction() { + $this->assertPermission('monitoring/command/feature/instance'); $this->view->title = $this->translate('Disable Notifications'); $programStatus = $this->backend ->select() From 7dbb8c684195b5e586ba34479a9452c04441cdbe Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 09:58:10 +0100 Subject: [PATCH 08/58] monitoring/security: Require monitoring/command/feature/instance permission for toggling instance features --- .../forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php index 469c1b6eb..97a64dbd7 100644 --- a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php @@ -191,6 +191,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm */ public function onSuccess() { + $this->assertPermission('monitoring/command/feature/instance'); foreach ($this->getValues() as $feature => $enabled) { $toggleFeature = new ToggleInstanceFeatureCommand(); $toggleFeature From 26613a010662f7b9e71eaa9a2bb0d2c8f9f3cd11 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 09:58:30 +0100 Subject: [PATCH 09/58] monitoring/security: Rename permission monitoring/command/feature/program to monitoring/command/feature/instance --- modules/monitoring/configuration.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php index 72df4e73f..7eb3bbedf 100644 --- a/modules/monitoring/configuration.php +++ b/modules/monitoring/configuration.php @@ -47,8 +47,8 @@ $this->providePermission( $this->translate('Allow processing host and service check results') ); $this->providePermission( - 'monitoring/command/feature/program', - $this->translate('Allow processing commands for toggling features on a program-wide basis') + 'monitoring/command/feature/instance', + $this->translate('Allow processing commands for toggling features on an instance-wide basis') ); $this->providePermission( 'monitoring/command/feature/object', From 3716be4a48ba79a0c2c9dffcdf048819a7202bdf Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 10:01:03 +0100 Subject: [PATCH 10/58] monitoring/security: Disable toggling instance features if user lacks the permission monitoring/command/feature/instance --- .../ToggleInstanceFeaturesCommandForm.php | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php index 97a64dbd7..997bd378c 100644 --- a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php @@ -73,13 +73,15 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm } else { $notificationDescription = null; } + $toggleDisabled = ! $this->hasPermission('monitoring/command/feature/instance'); $this->addElements(array( array( 'checkbox', ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS, array( 'label' => $this->translate('Active Host Checks Being Executed'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -87,7 +89,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS, array( 'label' => $this->translate('Active Service Checks Being Executed'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -95,7 +98,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS, array( 'label' => $this->translate('Event Handlers Enabled'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -103,7 +107,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION, array( 'label' => $this->translate('Flap Detection Enabled'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -122,7 +127,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ), 'Label', array('HtmlTag', array('tag' => 'div')) - ) + ), + 'disabled' => $toggleDisabled ) ), array( @@ -130,7 +136,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING, array( 'label' => $this->translate('Obsessing Over Hosts'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -138,7 +145,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING, array( 'label' => $this->translate('Obsessing Over Services'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -146,7 +154,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS, array( 'label' => $this->translate('Passive Host Checks Being Accepted'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -154,7 +163,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS, array( 'label' => $this->translate('Passive Service Checks Being Accepted'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -162,7 +172,8 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA, array( 'label' => $this->translate('Performance Data Being Processed'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ) )); From 35b33647cf5bf72610289cbcfa93e4fb84144233 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 10:26:43 +0100 Subject: [PATCH 11/58] monitoring/security: Guard the link for disabling notifications on an instance-wide basis The link in the monitoring health view will only be shown if the user has the permission monitoring/command/feature/instance. --- .../ToggleInstanceFeaturesCommandForm.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php index 997bd378c..d99db37c4 100644 --- a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php @@ -59,12 +59,16 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm public function createElements(array $formData = array()) { if ((bool) $this->status->notifications_enabled) { - $notificationDescription = sprintf( - '%s', - $this->translate('Disable notifications for a specific time on a program-wide basis'), - $this->getView()->href('monitoring/process/disable-notifications'), - $this->translate('Disable temporarily') - ); + if ($this->hasPermission('monitoring/command/feature/instance')) { + $notificationDescription = sprintf( + '%s', + $this->translate('Disable notifications for a specific time on a program-wide basis'), + $this->getView()->href('monitoring/process/disable-notifications'), + $this->translate('Disable temporarily') + ); + } else { + $notificationDescription = null; + } } elseif ($this->status->disable_notif_expire_time) { $notificationDescription = sprintf( $this->translate('Notifications will be re-enabled in %s'), From bdc637ff67af3506fa57eb71761bf61bb54d5fe9 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 10:31:49 +0100 Subject: [PATCH 12/58] monitoring/security: Guard toggling object features Toggling object features will only be possible if the user has the permission monitoring/command/feature/object. --- .../forms/Command/Object/ToggleObjectFeaturesCommandForm.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php index bf0a1d8b1..46858555f 100644 --- a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php @@ -107,6 +107,7 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm */ public function onSuccess() { + $this->assertPermission('monitoring/command/feature/object'); foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ foreach ($this->getValues() as $feature => $enabled) { From 1681f746c1ef5df9c1c14584a790a2b22757f389 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 10:46:24 +0100 Subject: [PATCH 13/58] monitoring/security: Disable toggling object features if user lacks the permission monitoring/command/feature/object --- .../ToggleObjectFeaturesCommandForm.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php index 46858555f..d3cc63ecf 100644 --- a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php @@ -28,13 +28,15 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm */ public function createElements(array $formData = array()) { + $toggleDisabled = $this->hasPermission('monitoring/command/feature/instance') ? null : ''; $this->addElements(array( array( 'checkbox', ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS, array( 'label' => $this->translate('Active Checks'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -42,7 +44,8 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS, array( 'label' => $this->translate('Passive Checks'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -50,7 +53,8 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm ToggleObjectFeatureCommand::FEATURE_OBSESSING, array( 'label' => $this->translate('Obsessing'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -58,7 +62,8 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS, array( 'label' => $this->translate('Notifications'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -66,7 +71,8 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER, array( 'label' => $this->translate('Event Handler'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ), array( @@ -74,7 +80,8 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION, array( 'label' => $this->translate('Flap Detection'), - 'autosubmit' => true + 'autosubmit' => true, + 'disabled' => $toggleDisabled ) ) )); From 127ce7abfe402c5102d070be342c56cf6f647dd4 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 10:47:02 +0100 Subject: [PATCH 14/58] monitoring/security: Fix that toggling instance features is always disabled In HTML5 the presence of a boolean attribute on an element represents the true value, and the absence of the attribute represents the false value. In Zend we have to set null for the absence of the attribute and the empty string for the presence of the attribute. --- .../Command/Instance/ToggleInstanceFeaturesCommandForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php index d99db37c4..60486307e 100644 --- a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php @@ -77,7 +77,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm } else { $notificationDescription = null; } - $toggleDisabled = ! $this->hasPermission('monitoring/command/feature/instance'); + $toggleDisabled = $this->hasPermission('monitoring/command/feature/instance') ? null : ''; $this->addElements(array( array( 'checkbox', From e5b0b528747c2ff76b0568f8ca6929e61b072495 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 11:20:05 +0100 Subject: [PATCH 15/58] lib: Reduce else { if { to elseif { in User::can() --- library/Icinga/User.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/Icinga/User.php b/library/Icinga/User.php index db80c929a..bdc49275b 100644 --- a/library/Icinga/User.php +++ b/library/Icinga/User.php @@ -426,13 +426,11 @@ class User foreach ($this->permissions as $permitted) { $wildcard = strpos($permitted, '*'); if ($wildcard !== false) { - if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) { - return true; - } else { - if ($permission === $permitted) { - return true; - } - } + } + if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) { + return true; + } elseif ($permission === $permitted) { + return true; } } return false; From c8640cbae9eeec5f8e9269dfa691947ded14e09e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 12:44:34 +0100 Subject: [PATCH 16/58] rpm: Remove php5-imagick dependency for SUSE packages --- icingaweb2.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icingaweb2.spec b/icingaweb2.spec index cd1ee485f..0d3766fdd 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -82,7 +82,7 @@ Requires: %{php} >= 5.3.0 Requires: %{php}-gd %{php}-intl %{?fedora:Requires: php-pecl-imagick} %{?rhel:Requires: php-pecl-imagick} -%{?suse_version:Requires: %{php}-gettext %{php}-openssl php5-imagick} +%{?suse_version:Requires: %{php}-gettext %{php}-openssl} %description -n php-Icinga Icinga Web 2 PHP library From 932496c58c2e4a437772e99f968275398740cefe Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 12:51:06 +0100 Subject: [PATCH 17/58] rpm: Require json and posix PHP extensions for SUSE packages --- icingaweb2.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icingaweb2.spec b/icingaweb2.spec index 0d3766fdd..312d6ee39 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -82,7 +82,7 @@ Requires: %{php} >= 5.3.0 Requires: %{php}-gd %{php}-intl %{?fedora:Requires: php-pecl-imagick} %{?rhel:Requires: php-pecl-imagick} -%{?suse_version:Requires: %{php}-gettext %{php}-openssl} +%{?suse_version:Requires: %{php}-gettext %{php}-json %{php}-openssl %{php}-posix} %description -n php-Icinga Icinga Web 2 PHP library From e8619686aef903c82a3eb2acc327b70b2df2a098 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 13:01:40 +0100 Subject: [PATCH 18/58] Add the sockets module as optional requirement of the monitoring module --- .../library/Monitoring/MonitoringWizard.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/library/Monitoring/MonitoringWizard.php b/modules/monitoring/library/Monitoring/MonitoringWizard.php index d7a3671a4..43061e608 100644 --- a/modules/monitoring/library/Monitoring/MonitoringWizard.php +++ b/modules/monitoring/library/Monitoring/MonitoringWizard.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Monitoring; use Icinga\Application\Icinga; +use Icinga\Application\Platform; use Icinga\Web\Form; use Icinga\Web\Wizard; use Icinga\Web\Request; @@ -139,6 +140,22 @@ class MonitoringWizard extends Wizard implements SetupWizard */ public function getRequirements() { - return new Requirements(); + $requirements = new Requirements(); + + $requirements->addOptional( + 'existing_php_mod_sockets', + mt('monitoring', 'PHP Module: Sockets'), + mt( + 'monitoring', + 'In case it\'s desired that a TCP connection is being used by Icinga Web 2 to' + . ' access a Livestatus interface, the Sockets module for PHP is required.' + ), + Platform::extensionLoaded('sockets'), + Platform::extensionLoaded('sockets') ? mt('monitoring', 'The PHP Module sockets is available.') : ( + mt('monitoring', 'The PHP Module sockets is not available.') + ) + ); + + return $requirements; } } From 9dd179d8f387f7214a8c7b4b8b550acdbbd002c9 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 13:18:29 +0100 Subject: [PATCH 19/58] rpm: Fix shadow-utils requirement on SUSE --- icingaweb2.spec | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/icingaweb2.spec b/icingaweb2.spec index 312d6ee39..ca1345dc2 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -29,7 +29,6 @@ Packager: Icinga Team %endif %endif - %if 0%{?suse_version} %define wwwconfigdir %{_sysconfdir}/apache2/conf.d %define wwwuser wwwrun @@ -43,15 +42,17 @@ Requires: apache2-mod_php5 %endif %endif -Requires(pre): shadow-utils -Requires: %{name}-common = %{version}-%{release} -Requires: php-Icinga = %{version}-%{release} -Requires: %{name}-vendor-dompdf -Requires: %{name}-vendor-HTMLPurifier -Requires: %{name}-vendor-JShrink -Requires: %{name}-vendor-lessphp -Requires: %{name}-vendor-Parsedown -Requires: %{zend} +%{?fedora:Requires(pre): shadow-utils} +%{?rhel:Requires(pre): shadow-utils} +%{?suse_version:Requires(pre): pwdutils} +Requires: %{name}-common = %{version}-%{release} +Requires: php-Icinga = %{version}-%{release} +Requires: %{name}-vendor-dompdf +Requires: %{name}-vendor-HTMLPurifier +Requires: %{name}-vendor-JShrink +Requires: %{name}-vendor-lessphp +Requires: %{name}-vendor-Parsedown +Requires: %{zend} %description @@ -68,8 +69,11 @@ Icinga Web 2 %package common -Summary: Common files for Icinga Web 2 and the Icinga CLI -Group: Applications/System +Summary: Common files for Icinga Web 2 and the Icinga CLI +Group: Applications/System +%{?fedora:Requires(pre): shadow-utils} +%{?rhel:Requires(pre): shadow-utils} +%{?suse_version:Requires(pre): pwdutils} %description common Common files for Icinga Web 2 and the Icinga CLI From 65a2c47506588c0e48827bf89f37b681da8d30d3 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 13:29:47 +0100 Subject: [PATCH 20/58] security: Provide permissions for our config actions --- application/forms/Security/RoleForm.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/application/forms/Security/RoleForm.php b/application/forms/Security/RoleForm.php index f32c0cab4..18926972c 100644 --- a/application/forms/Security/RoleForm.php +++ b/application/forms/Security/RoleForm.php @@ -21,7 +21,14 @@ class RoleForm extends ConfigForm * * @type array */ - protected $providedPermissions = array('*' => '*'); + protected $providedPermissions = array( + '*' => '*', + 'system/config/*' => 'system/config/*', + 'system/config/application' => 'system/config/application', + 'system/config/authentication' => 'system/config/authentication', + 'system/config/resources' => 'system/config/resources', + 'system/config/roles' => 'system/config/roles' + ); /** * Provided restrictions by currently loaded modules From 72a616ede61c2bf3e25a32292593d55d0720ff42 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 13:30:18 +0100 Subject: [PATCH 21/58] spec: Fix license of Icinga Web 2 Vendor packages not yet concerned. --- icingaweb2.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icingaweb2.spec b/icingaweb2.spec index ca1345dc2..f747c3327 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -5,7 +5,7 @@ Version: 2.0.0 Release: %{revision}%{?dist} Summary: Icinga Web 2 Group: Applications/System -License: GPL +License: GPLv2+ URL: https://icinga.org Source0: https://github.com/Icinga/%{name}/archive/v%{version}.tar.gz BuildArch: noarch From d72e506202931488fb69740b47575272236549e0 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 13:45:55 +0100 Subject: [PATCH 22/58] spec: Add lincese tag to vendor packages --- icingaweb2.spec | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/icingaweb2.spec b/icingaweb2.spec index f747c3327..94d280fb8 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -110,6 +110,7 @@ Version: 0.6.1 Release: 1%{?dist} Summary: Icinga Web 2 vendor library dompdf Group: Development/Libraries +License: LGPLv2.1 Requires: %{php} >= 5.3.0 %description vendor-dompdf @@ -121,6 +122,7 @@ Version: 4.6.0 Release: 1%{?dist} Summary: Icinga Web 2 vendor library HTMLPurifier Group: Development/Libraries +License: LGPLv2.1 Requires: %{php} >= 5.3.0 %description vendor-HTMLPurifier @@ -132,6 +134,7 @@ Version: 1.0.1 Release: 1%{?dist} Summary: Icinga Web 2 vendor library JShrink Group: Development/Libraries +License: BSD Requires: %{php} >= 5.3.0 %description vendor-JShrink @@ -143,6 +146,7 @@ Version: 0.4.0 Release: 1%{?dist} Summary: Icinga Web 2 vendor library lessphp Group: Development/Libraries +License: MIT Requires: %{php} >= 5.3.0 %description vendor-lessphp @@ -154,6 +158,7 @@ Version: 1.0.0 Release: 1%{?dist} Summary: Icinga Web 2 vendor library Parsedown Group: Development/Libraries +License: MIT Requires: %{php} >= 5.3.0 %description vendor-Parsedown @@ -165,6 +170,7 @@ Version: 1.12.9 Release: 1%{?dist} Summary: Icinga Web 2 vendor library Zend Framework Group: Development/Libraries +License: BSD Requires: %{php} >= 5.3.0 %description vendor-Zend From 17b6d8512b54c27bc9afd3b0614965a6772501cf Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 30 Jan 2015 13:46:49 +0100 Subject: [PATCH 23/58] spec: Add MIT and BSD to the license tag We ship jquery and some jquery plugins w/ Icinga Web 2. Their licenses must be noted too. --- icingaweb2.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icingaweb2.spec b/icingaweb2.spec index 94d280fb8..a012751ea 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -5,7 +5,7 @@ Version: 2.0.0 Release: %{revision}%{?dist} Summary: Icinga Web 2 Group: Applications/System -License: GPLv2+ +License: GPLv2+ and MIT and BSD URL: https://icinga.org Source0: https://github.com/Icinga/%{name}/archive/v%{version}.tar.gz BuildArch: noarch From 6ec2ee753d2212b1a4c77505a06bfd3d6a846853 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Fri, 30 Jan 2015 14:50:25 +0100 Subject: [PATCH 24/58] Render error messages in the container itself fixes #6280 --- application/controllers/ErrorController.php | 1 + application/views/scripts/error/error.phtml | 5 +++-- public/js/icinga/loader.js | 16 +--------------- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/application/controllers/ErrorController.php b/application/controllers/ErrorController.php index 0548b5c9c..e198eca1c 100644 --- a/application/controllers/ErrorController.php +++ b/application/controllers/ErrorController.php @@ -19,6 +19,7 @@ class ErrorController extends ActionController { $error = $this->_getParam('error_handler'); $exception = $error->exception; + $this->getTabs()->showOnlyCloseButton(); Logger::error($exception); Logger::error('Stacktrace: %s', $exception->getTraceAsString()); diff --git a/application/views/scripts/error/error.phtml b/application/views/scripts/error/error.phtml index 2a900651b..8e61e80f8 100644 --- a/application/views/scripts/error/error.phtml +++ b/application/views/scripts/error/error.phtml @@ -1,8 +1,9 @@ -title): ?>
+tabs->render($this) ?> +title): ?>

escape($title) ?>

-
+
message): ?>

escape($message)) ?>

diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 31a0d10a8..95ac5beeb 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -594,18 +594,7 @@ onFailure: function (req, textStatus, errorThrown) { var url = req.url; - if (req.status === 500) { - if (this.exception === null) { - req.$target.addClass('impact'); - - this.exception = this.createNotice( - 'error', - $('h1', $(req.responseText)).first().html(), - true - ); - this.icinga.ui.fixControls(); - } - } else if (req.status > 0) { + if (req.status > 0) { this.icinga.logger.error( req.status, errorThrown + ':', @@ -617,9 +606,6 @@ req.action, req.autorefresh ); - - // Header example: - // Icinga.debug(req.getResponseHeader('X-Icinga-Redirect')); } else { if (errorThrown === 'abort') { this.icinga.logger.debug( From 7b8332ccd89d102ea672a6d3eb4c48045969f97a Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Fri, 30 Jan 2015 15:25:03 +0100 Subject: [PATCH 25/58] Notifications do not disappear after autorefresh This is not affected anymore because the errors goes directly into the container. But this commit fixes the codes if someone use the notifications in the loader. Also remove unused variable this.exception. fixes #6278 --- public/js/icinga/loader.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 95ac5beeb..7d590757b 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -24,8 +24,6 @@ this.failureNotice = null; - this.exception = null; - /** * Pending requests */ @@ -313,15 +311,12 @@ onResponse: function (data, textStatus, req) { var self = this; if (this.failureNotice !== null) { - this.failureNotice.remove(); + if (! this.failureNotice.hasClass('fading-out')) { + this.failureNotice.remove(); + } this.failureNotice = null; } - if (this.exception !== null) { - this.exception.remove(); - this.exception = null; - } - // Remove 'impact' class if there was such if (req.$target.hasClass('impact')) { req.$target.removeClass('impact'); @@ -646,7 +641,13 @@ var $notice = $( '
  • ' + message + '
  • ' ).appendTo($('#notifications')); + this.icinga.ui.fixControls(); + + if (!persist) { + this.icinga.ui.fadeNotificationsAway(); + } + return $notice; }, From fdcec046e057f0eb4a765459caa71ebd2e3affce Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 15:42:22 +0100 Subject: [PATCH 26/58] Make File::create(.., $recursive = true) create missing nested directories refs #8219 --- library/Icinga/Util/File.php | 72 +++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/library/Icinga/Util/File.php b/library/Icinga/Util/File.php index 9ce1ec893..99421b33d 100644 --- a/library/Icinga/Util/File.php +++ b/library/Icinga/Util/File.php @@ -23,6 +23,13 @@ class File extends SplFileObject */ protected $openMode; + /** + * The access mode to use when creating directories + * + * @var int + */ + public static $dirMode = 1528; // 2770 + /** * @see SplFileObject::__construct() */ @@ -37,21 +44,74 @@ class File extends SplFileObject } /** - * Create a file with an access mode + * Create a file using the given access mode and return a instance of File open for writing * * @param string $path The path to the file * @param int $accessMode The access mode to set + * @param bool $recursive Whether missing nested directories of the given path should be created + * + * @return File * * @throws RuntimeException In case the file cannot be created or the access mode cannot be set + * @throws NotWritableError In case the path's (existing) parent is not writable */ - public static function create($path, $accessMode) + public static function create($path, $accessMode, $recursive = true) { - if (!@touch($path)) { - throw new RuntimeException('Cannot create file "' . $path . '" with acces mode "' . $accessMode . '"'); + $dirPath = dirname($path); + if ($recursive && !is_dir($dirPath)) { + static::createDirectories($dirPath); + } elseif (! is_writable($dirPath)) { + throw new NotWritableError(sprintf('Path "%s" is not writable', $dirPath)); } - if (!@chmod($path, $accessMode)) { - throw new RuntimeException('Cannot set access mode "' . $accessMode . '" on file "' . $path . '"'); + $file = new static($path, 'x'); + + if (! @chmod($path, $accessMode)) { + $error = error_get_last(); + throw new RuntimeException(sprintf( + 'Cannot set access mode "%s" on file "%s" (%s)', + decoct($accessMode), + $path, + $error['message'] + )); + } + + return $file; + } + + /** + * Create missing directories + * + * @param string $path + * + * @throws RuntimeException In case a directory cannot be created or the access mode cannot be set + */ + protected static function createDirectories($path) + { + $part = strpos($path, DIRECTORY_SEPARATOR) === 0 ? DIRECTORY_SEPARATOR : ''; + foreach (explode(DIRECTORY_SEPARATOR, ltrim($path, DIRECTORY_SEPARATOR)) as $dir) { + $part .= $dir . DIRECTORY_SEPARATOR; + + if (! is_dir($part)) { + if (! @mkdir($part, static::$dirMode)) { + $error = error_get_last(); + throw new RuntimeException(sprintf( + 'Failed to create missing directory "%s" (%s)', + $part, + $error['message'] + )); + } + + if (! @chmod($part, static::$dirMode)) { + $error = error_get_last(); + throw new RuntimeException(sprintf( + 'Failed to set access mode "%s" for directory "%s" (%s)', + decoct(static::$dirMode), + $part, + $error['message'] + )); + } + } } } From 9426a5bd234ef75eb468cdb98d2468029dd0a57b Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 15:43:02 +0100 Subject: [PATCH 27/58] Use File::create() in Config::saveIni() to create missing nested directories refs #8219 --- library/Icinga/Application/Config.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/Icinga/Application/Config.php b/library/Icinga/Application/Config.php index 8d4914316..484cff6df 100644 --- a/library/Icinga/Application/Config.php +++ b/library/Icinga/Application/Config.php @@ -8,6 +8,7 @@ use Iterator; use Countable; use LogicException; use UnexpectedValueException; +use Icinga\Util\File; use Icinga\Data\ConfigObject; use Icinga\File\Ini\IniWriter; use Icinga\Exception\NotReadableError; @@ -320,6 +321,10 @@ class Config implements Countable, Iterator throw new LogicException('You need to pass $filePath or set a path using Config::setConfigFile()'); } + if (! file_exists($filePath)) { + File::create($filePath, $fileMode); + } + $this->getIniWriter($filePath, $fileMode)->write(); } From 6416fc421c8c4d89edf92d4db5734b9a6131e4ab Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 15:43:39 +0100 Subject: [PATCH 28/58] Do not create directories which are created automatically if necessary refs #8219 --- .../library/Monitoring/MonitoringWizard.php | 4 ---- modules/setup/library/Setup/WebWizard.php | 12 +----------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/modules/monitoring/library/Monitoring/MonitoringWizard.php b/modules/monitoring/library/Monitoring/MonitoringWizard.php index d7a3671a4..f02faa4f3 100644 --- a/modules/monitoring/library/Monitoring/MonitoringWizard.php +++ b/modules/monitoring/library/Monitoring/MonitoringWizard.php @@ -4,14 +4,12 @@ namespace Icinga\Module\Monitoring; -use Icinga\Application\Icinga; use Icinga\Web\Form; use Icinga\Web\Wizard; use Icinga\Web\Request; use Icinga\Module\Setup\Setup; use Icinga\Module\Setup\SetupWizard; use Icinga\Module\Setup\Requirements; -use Icinga\Module\Setup\Utils\MakeDirStep; use Icinga\Module\Setup\Forms\SummaryPage; use Icinga\Module\Monitoring\Forms\Setup\WelcomePage; use Icinga\Module\Monitoring\Forms\Setup\BackendPage; @@ -108,8 +106,6 @@ class MonitoringWizard extends Wizard implements SetupWizard $pageData = $this->getPageData(); $setup = new Setup(); - $setup->addStep(new MakeDirStep(array(Icinga::app()->getConfigDir() . '/modules/monitoring'), 2770)); - $setup->addStep( new BackendStep(array( 'backendConfig' => $pageData['setup_monitoring_backend'], diff --git a/modules/setup/library/Setup/WebWizard.php b/modules/setup/library/Setup/WebWizard.php index 8ae7344ea..c073723a3 100644 --- a/modules/setup/library/Setup/WebWizard.php +++ b/modules/setup/library/Setup/WebWizard.php @@ -334,17 +334,7 @@ class WebWizard extends Wizard implements SetupWizard ); } - $configDir = Icinga::app()->getConfigDir(); - $setup->addStep( - new MakeDirStep( - array( - $configDir . DIRECTORY_SEPARATOR . 'modules', - $configDir . DIRECTORY_SEPARATOR . 'preferences', - $configDir . DIRECTORY_SEPARATOR . 'enabledModules' - ), - 2770 - ) - ); + $setup->addStep(new MakeDirStep(array(Config::resolvePath('enabledModules')), 2770)); foreach ($this->getWizards() as $wizard) { if ($wizard->isComplete()) { From d2dd66c9fd25b63287ae94363415f73007a3c64b Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 15:47:11 +0100 Subject: [PATCH 29/58] Revert "setup: Fix octdec for directory modes" This reverts commit c0444a81b24aea332b07eb1409af168c1c53f0c9. --- modules/setup/library/Setup/Utils/MakeDirStep.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setup/library/Setup/Utils/MakeDirStep.php b/modules/setup/library/Setup/Utils/MakeDirStep.php index d7813541b..27919820b 100644 --- a/modules/setup/library/Setup/Utils/MakeDirStep.php +++ b/modules/setup/library/Setup/Utils/MakeDirStep.php @@ -21,7 +21,7 @@ class MakeDirStep extends Step public function __construct($paths, $dirmode) { $this->paths = $paths; - $this->dirmode = octdec((string) $dirmode); + $this->dirmode = octdec($dirmode); $this->errors = array(); } From a95fd561cd09c91f094bfd65f58560945863c92b Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 15:47:21 +0100 Subject: [PATCH 30/58] Revert "setup: Convert octal directory mode to decimal notation" This reverts commit e93e8f633045d7fd0f844e797848d4d6fe32ca9e. --- modules/setup/library/Setup/Utils/MakeDirStep.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/setup/library/Setup/Utils/MakeDirStep.php b/modules/setup/library/Setup/Utils/MakeDirStep.php index 27919820b..b758ccd79 100644 --- a/modules/setup/library/Setup/Utils/MakeDirStep.php +++ b/modules/setup/library/Setup/Utils/MakeDirStep.php @@ -16,12 +16,12 @@ class MakeDirStep extends Step /** * @param array $paths - * @param int $dirmode Directory mode in octal notation + * @param int $dirmode */ public function __construct($paths, $dirmode) { $this->paths = $paths; - $this->dirmode = octdec($dirmode); + $this->dirmode = $dirmode; $this->errors = array(); } From f5a651664c2a2085c761aa8fbbff927c11fb310f Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 30 Jan 2015 16:16:12 +0100 Subject: [PATCH 31/58] Create the enabledModules directory when necessary only as well refs #8219 --- .../Icinga/Application/Modules/Manager.php | 46 +++++++++---------- modules/setup/library/Setup/WebWizard.php | 2 - 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php index 7ee2461f9..0a1b23f78 100644 --- a/library/Icinga/Application/Modules/Manager.php +++ b/library/Icinga/Application/Modules/Manager.php @@ -103,25 +103,22 @@ class Manager */ private function detectEnabledModules() { - $canonical = $this->enableDir; - if ($canonical === false || ! file_exists($canonical)) { - // TODO: I guess the check for false has something to do with a - // call to realpath no longer present + if (! file_exists($this->enableDir)) { return; } - if (!is_dir($this->enableDir)) { + if (! is_dir($this->enableDir)) { throw new NotReadableError( 'Cannot read enabled modules. Module directory "%s" is not a directory', $this->enableDir ); } - if (!is_readable($this->enableDir)) { + if (! is_readable($this->enableDir)) { throw new NotReadableError( 'Cannot read enabled modules. Module directory "%s" is not readable', $this->enableDir ); } - if (($dh = opendir($canonical)) !== false) { + if (($dh = opendir($this->enableDir)) !== false) { $this->enabledDirs = array(); while (($file = readdir($dh)) !== false) { @@ -129,7 +126,7 @@ class Manager continue; } - $link = $this->enableDir . '/' . $file; + $link = $this->enableDir . DIRECTORY_SEPARATOR . $file; if (! is_link($link)) { Logger::warning( 'Found invalid module in enabledModule directory "%s": "%s" is not a symlink', @@ -140,7 +137,7 @@ class Manager } $dir = realpath($link); - if (!file_exists($dir) || !is_dir($dir)) { + if (! file_exists($dir) || !is_dir($dir)) { Logger::warning( 'Found invalid module in enabledModule directory "%s": "%s" points to non existing path "%s"', $this->enableDir, @@ -208,7 +205,7 @@ class Manager */ public function enableModule($name) { - if (!$this->hasInstalled($name)) { + if (! $this->hasInstalled($name)) { throw new ConfigurationError( 'Cannot enable module "%s". Module is not installed.', $name @@ -217,11 +214,16 @@ class Manager clearstatcache(true); $target = $this->installedBaseDirs[$name]; - $link = $this->enableDir . '/' . $name; + $link = $this->enableDir . DIRECTORY_SEPARATOR . $name; - if (! is_dir($this->enableDir)) { - throw new NotFoundError('Cannot enable module "%s". Path "%s" not found.', $name, $this->enableDir); - } elseif (!is_writable($this->enableDir)) { + if (! is_dir($this->enableDir) && !@mkdir($this->enableDir, 02770, true)) { + $error = error_get_last(); + throw new SystemPermissionException( + 'Failed to create enabledModule directory "%s" (%s)', + $this->enableDir, + $error['message'] + ); + } elseif (! is_writable($this->enableDir)) { throw new SystemPermissionException( 'Cannot enable module "%s". Insufficient system permissions for enabling modules.', $name @@ -232,7 +234,7 @@ class Manager return $this; } - if (!@symlink($target, $link)) { + if (! @symlink($target, $link)) { $error = error_get_last(); if (strstr($error["message"], "File exists") === false) { throw new SystemPermissionException( @@ -246,9 +248,7 @@ class Manager } $this->enabledDirs[$name] = $link; - $this->loadModule($name); - return $this; } @@ -264,22 +264,22 @@ class Manager */ public function disableModule($name) { - if (!$this->hasEnabled($name)) { + if (! $this->hasEnabled($name)) { return $this; } - if (!is_writable($this->enableDir)) { + if (! is_writable($this->enableDir)) { throw new SystemPermissionException( 'Could not disable module. Module path is not writable.' ); } - $link = $this->enableDir . '/' . $name; - if (!file_exists($link)) { + $link = $this->enableDir . DIRECTORY_SEPARATOR . $name; + if (! file_exists($link)) { throw new ConfigurationError( 'Could not disable module. The module %s was not found.', $name ); } - if (!is_link($link)) { + if (! is_link($link)) { throw new ConfigurationError( 'Could not disable module. The module "%s" is not a symlink. ' . 'It looks like you have installed this module manually and moved it to your module folder. ' @@ -290,7 +290,7 @@ class Manager } if (file_exists($link) && is_link($link)) { - if (!@unlink($link)) { + if (! @unlink($link)) { $error = error_get_last(); throw new SystemPermissionException( 'Could not disable module "%s" due to file system errors. ' diff --git a/modules/setup/library/Setup/WebWizard.php b/modules/setup/library/Setup/WebWizard.php index c073723a3..b580101ed 100644 --- a/modules/setup/library/Setup/WebWizard.php +++ b/modules/setup/library/Setup/WebWizard.php @@ -334,8 +334,6 @@ class WebWizard extends Wizard implements SetupWizard ); } - $setup->addStep(new MakeDirStep(array(Config::resolvePath('enabledModules')), 2770)); - foreach ($this->getWizards() as $wizard) { if ($wizard->isComplete()) { $setup->addSteps($wizard->getSetup()->getSteps()); From ad4ebf8fa5b40d224b8d681440554b1357ee6237 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Sun, 1 Feb 2015 23:30:48 +0100 Subject: [PATCH 32/58] monitoring: Fix that selecting a hostgroup displays its services instead of its hosts fixes #8273 --- .../application/views/scripts/list/hostgroups.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/hostgroups.phtml b/modules/monitoring/application/views/scripts/list/hostgroups.phtml index cd3e68d7f..7d67c9d3a 100644 --- a/modules/monitoring/application/views/scripts/list/hostgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/hostgroups.phtml @@ -28,7 +28,7 @@ - + services_critical_last_state_change_unhandled): ?> translate('CRITICAL'); ?> @@ -84,7 +84,7 @@ - services_total; ?> + qlink($h->services_total, 'monitoring/list/services', array('hostgroup' => $h->hostgroup)) ?> services_ok): ?> From f2d639108f15f75796129d2005163ae2bea46c77 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 00:08:25 +0100 Subject: [PATCH 33/58] monitoring: Move "Service Grid" beneath "Problems" The service grid is filtered by problems by default. Thus it makes sense to move it beneath the problems section. --- modules/monitoring/configuration.php | 39 +++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php index 7eb3bbedf..f34b4b0f5 100644 --- a/modules/monitoring/configuration.php +++ b/modules/monitoring/configuration.php @@ -87,29 +87,36 @@ $this->provideSearchUrl($this->translate('Servicegroups'), 'monitoring/list/serv * Problems Section */ $section = $this->menuSection($this->translate('Problems'), array( - 'renderer' => 'ProblemMenuItemRenderer', - 'icon' => 'block', - 'priority' => 20 + 'renderer' => 'ProblemMenuItemRenderer', + 'icon' => 'block', + 'priority' => 20 )); $section->add($this->translate('Unhandled Hosts'), array( - 'renderer' => 'UnhandledHostMenuItemRenderer', - 'url' => 'monitoring/list/hosts?host_problem=1&host_handled=0', - 'priority' => 40 + 'renderer' => 'UnhandledHostMenuItemRenderer', + 'url' => 'monitoring/list/hosts?host_problem=1&host_handled=0', + 'priority' => 30 )); $section->add($this->translate('Unhandled Services'), array( - 'renderer' => 'UnhandledServiceMenuItemRenderer', - 'url' => 'monitoring/list/services?service_problem=1&service_handled=0&sort=service_severity', - 'priority' => 40 + 'renderer' => 'UnhandledServiceMenuItemRenderer', + 'url' => 'monitoring/list/services?service_problem=1&service_handled=0&sort=service_severity', + 'priority' => 40 )); $section->add($this->translate('Host Problems'), array( - 'url' => 'monitoring/list/hosts?host_problem=1&sort=host_severity', - 'priority' => 50 + 'url' => 'monitoring/list/hosts?host_problem=1&sort=host_severity', + 'priority' => 50 )); $section->add($this->translate('Service Problems'), array( - 'url' => 'monitoring/list/services?service_problem=1&sort=service_severity&dir=desc', - 'priority' => 50 + 'url' => 'monitoring/list/services?service_problem=1&sort=service_severity&dir=desc', + 'priority' => 60 +)); +$section->add($this->translate('Service Grid'), array( + 'url' => 'monitoring/list/servicegrid?service_problem=1', + 'priority' => 70 +)); +$section->add($this->translate('Current Downtimes'), array( + 'url' => 'monitoring/list/downtimes?downtime_is_in_effect=1', + 'priority' => 80 )); -$section->add($this->translate('Current Downtimes'))->setUrl('monitoring/list/downtimes?downtime_is_in_effect=1'); /* * Overview Section @@ -130,10 +137,6 @@ $section->add($this->translate('Services'), array( 'url' => 'monitoring/list/services', 'priority' => 50 )); -$section->add($this->translate('Service Grid'), array( - 'url' => 'monitoring/list/servicegrid?service_problem=1', - 'priority' => 51 -)); $section->add($this->translate('Servicegroups'), array( 'url' => 'monitoring/list/servicegroups', 'priority' => 60 From 734c7b35466c42da5509ed3d0605190f69d9357e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:04:41 +0100 Subject: [PATCH 34/58] monitoring: Show close button when updating an instance --- .../application/views/scripts/config/editinstance.phtml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/application/views/scripts/config/editinstance.phtml b/modules/monitoring/application/views/scripts/config/editinstance.phtml index b12f262c3..2c91ee656 100644 --- a/modules/monitoring/application/views/scripts/config/editinstance.phtml +++ b/modules/monitoring/application/views/scripts/config/editinstance.phtml @@ -1,2 +1,5 @@ +
    + showOnlyCloseButton() ?> +

    translate('Edit Existing Instance'); ?>

    - \ No newline at end of file + From d7cbfebbd0c9b0c7a3e3db66b0d3725691b9b63a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:05:32 +0100 Subject: [PATCH 35/58] monitoring: Show close button when removing an instance --- .../application/views/scripts/config/removeinstance.phtml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/application/views/scripts/config/removeinstance.phtml b/modules/monitoring/application/views/scripts/config/removeinstance.phtml index 306d41815..eee29fb02 100644 --- a/modules/monitoring/application/views/scripts/config/removeinstance.phtml +++ b/modules/monitoring/application/views/scripts/config/removeinstance.phtml @@ -1,4 +1,7 @@ +
    + showOnlyCloseButton() ?> +

    translate('Remove Existing Instance'); ?>

    translate('Are you sure you want to remove this instance?'); ?>

    translate('If you have still any environments or views referring to this instance, you won\'t be able to send commands anymore after deletion.'); ?>

    - \ No newline at end of file + From cbc1a0313ab129e87a68672e93ac02a9df493f02 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:05:50 +0100 Subject: [PATCH 36/58] monitoring: Show close button when creating a backend --- .../application/views/scripts/config/createbackend.phtml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/application/views/scripts/config/createbackend.phtml b/modules/monitoring/application/views/scripts/config/createbackend.phtml index 0ef51cd6a..10ee02541 100644 --- a/modules/monitoring/application/views/scripts/config/createbackend.phtml +++ b/modules/monitoring/application/views/scripts/config/createbackend.phtml @@ -1,2 +1,5 @@ +
    + showOnlyCloseButton() ?> +

    translate('Add New Backend'); ?>

    - \ No newline at end of file + From 42fe7079eee7ce804a890c7edef656ce4dcec211 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:06:20 +0100 Subject: [PATCH 37/58] monitoring: Show close button when creating an instance --- .../application/views/scripts/config/createinstance.phtml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/views/scripts/config/createinstance.phtml b/modules/monitoring/application/views/scripts/config/createinstance.phtml index 49c8b5ec5..3515514df 100644 --- a/modules/monitoring/application/views/scripts/config/createinstance.phtml +++ b/modules/monitoring/application/views/scripts/config/createinstance.phtml @@ -1,2 +1,5 @@ -

    translate('Add New Instance'); ?>

    - \ No newline at end of file +
    + showOnlyCloseButton() ?> +
    +

    translate('Add New Instance') ?>

    + From a62acb4a8205972998604c6f9cf9f90e35a48a5e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:06:40 +0100 Subject: [PATCH 38/58] monitoring: Show close button when updating a backend --- .../application/views/scripts/config/editbackend.phtml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/views/scripts/config/editbackend.phtml b/modules/monitoring/application/views/scripts/config/editbackend.phtml index 58b6c18f1..630cb83f2 100644 --- a/modules/monitoring/application/views/scripts/config/editbackend.phtml +++ b/modules/monitoring/application/views/scripts/config/editbackend.phtml @@ -1,2 +1,5 @@ -

    translate('Edit Existing Backend'); ?>

    - \ No newline at end of file +
    + showOnlyCloseButton() ?> +
    +

    translate('Edit Existing Backend') ?>

    + From cf944a7daf5708e001b4f8f7b732970f2ebf489e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:07:01 +0100 Subject: [PATCH 39/58] monitoring: Show close button when removing a backend --- .../application/views/scripts/config/removebackend.phtml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/views/scripts/config/removebackend.phtml b/modules/monitoring/application/views/scripts/config/removebackend.phtml index fc7da17e3..d297f615b 100644 --- a/modules/monitoring/application/views/scripts/config/removebackend.phtml +++ b/modules/monitoring/application/views/scripts/config/removebackend.phtml @@ -1,2 +1,5 @@ -

    translate('Remove Existing Backend'); ?>

    - \ No newline at end of file +
    + showOnlyCloseButton() ?> +
    +

    translate('Remove Existing Backend') ?>

    + From cfe6701a924e08e012195704db8bc6bcc730767a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:08:27 +0100 Subject: [PATCH 40/58] Show close button when creating a role refs #8087 --- application/views/scripts/roles/new.phtml | 1 + 1 file changed, 1 insertion(+) diff --git a/application/views/scripts/roles/new.phtml b/application/views/scripts/roles/new.phtml index d7b277008..4c21c6f6b 100644 --- a/application/views/scripts/roles/new.phtml +++ b/application/views/scripts/roles/new.phtml @@ -1,4 +1,5 @@
    + showOnlyCloseButton() ?>

    translate('New Role') ?>

    From 3818f1faec3d323cf064787bafb071f0ffb80f8e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:08:56 +0100 Subject: [PATCH 41/58] Show close button when removing a role refs #8087 --- application/views/scripts/roles/remove.phtml | 1 + 1 file changed, 1 insertion(+) diff --git a/application/views/scripts/roles/remove.phtml b/application/views/scripts/roles/remove.phtml index e2d01ed62..4abff566a 100644 --- a/application/views/scripts/roles/remove.phtml +++ b/application/views/scripts/roles/remove.phtml @@ -1,4 +1,5 @@
    + showOnlyCloseButton() ?>

    translate('Remove Role %s'), $name) ?>

    From d64ca3da99e6e8277e5f5d1bba37bc61efa489b2 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:09:13 +0100 Subject: [PATCH 42/58] Show close button when updating a role fixes #8087 --- application/views/scripts/roles/update.phtml | 1 + 1 file changed, 1 insertion(+) diff --git a/application/views/scripts/roles/update.phtml b/application/views/scripts/roles/update.phtml index 44f756b06..f48f1ca69 100644 --- a/application/views/scripts/roles/update.phtml +++ b/application/views/scripts/roles/update.phtml @@ -1,4 +1,5 @@
    + showOnlyCloseButton() ?>

    translate('Update Role %s'), $name) ?>

    From f9047e85c50ca8b70851cbe2be78dad9286b503d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 11:12:27 +0100 Subject: [PATCH 43/58] monitoring: Fix wrong unhandled service problems count in the hosts overview The query was missing the is_active = 1 condition. I'll open an issue for the other affected queries. fixes #8013 --- .../Backend/Ido/Query/StatusQuery.php | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php index 0cc807ac8..cd7d0aef7 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php @@ -518,31 +518,35 @@ class StatusQuery extends IdoQuery protected function joinServiceproblemsummary() { - $sub = new Zend_Db_Expr('(SELECT' - . ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 0 ELSE 1 END) AS unhandled_services_count,' - . ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END) AS handled_services_count,' - . ' s.host_object_id FROM icinga_servicestatus ss' - . ' JOIN icinga_services s' - . ' ON s.service_object_id = ss.service_object_id' - . ' AND ss.current_state > 0' - . ' JOIN icinga_hoststatus hs' - . ' ON hs.host_object_id = s.host_object_id' - . ' GROUP BY s.host_object_id)'); + $select = <<<'SQL' +SELECT + SUM( + CASE WHEN(ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 + THEN 0 + ELSE 1 + END + ) AS unhandled_services_count, + SUM( + CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0) ) > 0 + THEN 1 + ELSE 0 + END + ) AS handled_services_count, + s.host_object_id +FROM + icinga_servicestatus ss + JOIN icinga_objects o ON o.object_id = ss.service_object_id + JOIN icinga_services s ON s.service_object_id = o.object_id + JOIN icinga_hoststatus hs ON hs.host_object_id = s.host_object_id +WHERE + o.is_active = 1 + AND o.objecttype_id = 2 + AND ss.current_state > 0 +GROUP BY + s.host_object_id +SQL; $this->select->joinLeft( - array('sps' => $sub), - 'sps.host_object_id = hs.host_object_id', - array() - ); - return; - - $this->select->joinleft( - array ('sps' => new \Zend_Db_Expr( - '(SELECT COUNT(s.service_object_id) as unhandled_service_count, s.host_object_id as host_object_id '. - 'FROM icinga_services s INNER JOIN icinga_servicestatus ss ON ss.current_state != 0 AND '. - 'ss.problem_has_been_acknowledged = 0 AND ss.scheduled_downtime_depth = 0 AND '. - 'ss.service_object_id = s.service_object_id '. - 'GROUP BY s.host_object_id'. - ')')), + array('sps' => new Zend_Db_Expr('(' . $select . ')')), 'sps.host_object_id = hs.host_object_id', array() ); From c0c0e7d9e53e1153e7ca7b873e8e39e9e2a37616 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Mon, 2 Feb 2015 11:57:50 +0100 Subject: [PATCH 44/58] Dashboard: Always replace title This is needed if an error occurs and the exception title was rendered into the container. --- public/js/icinga/loader.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 7d590757b..507a914e3 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -708,11 +708,12 @@ // $container.html(content); } else { - if ($container.closest('.dashboard').length && - ! $('h1', $content).length + if ($container.closest('.dashboard').length ) { - var title = $('h1', $container).first().detach(); - $('h1', $content).first().detach(); + if (! $('h1', $content).length) { + var title = $('h1', $container).first().detach(); + $('h1', $content).first().detach(); + } $container.html(title).append(content); } else if (action === 'replace') { $container.html(content); From d1f13819e4e6e0a97b6dfed2c957f56c4ee1354a Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Mon, 2 Feb 2015 12:01:40 +0100 Subject: [PATCH 45/58] Revert "Dashboard: Always replace title" This reverts commit c0c0e7d9e53e1153e7ca7b873e8e39e9e2a37616. Syntax error --- public/js/icinga/loader.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 507a914e3..7d590757b 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -708,12 +708,11 @@ // $container.html(content); } else { - if ($container.closest('.dashboard').length + if ($container.closest('.dashboard').length && + ! $('h1', $content).length ) { - if (! $('h1', $content).length) { - var title = $('h1', $container).first().detach(); - $('h1', $content).first().detach(); - } + var title = $('h1', $container).first().detach(); + $('h1', $content).first().detach(); $container.html(title).append(content); } else if (action === 'replace') { $container.html(content); From 190c1e8f042262f956d1d23019eb33d35feba0ca Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Mon, 2 Feb 2015 12:04:28 +0100 Subject: [PATCH 46/58] Revert "Revert "Dashboard: Always replace title"" This reverts commit d1f13819e4e6e0a97b6dfed2c957f56c4ee1354a. Please do not ask. This was no syntax error. --- public/js/icinga/loader.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 7d590757b..507a914e3 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -708,11 +708,12 @@ // $container.html(content); } else { - if ($container.closest('.dashboard').length && - ! $('h1', $content).length + if ($container.closest('.dashboard').length ) { - var title = $('h1', $container).first().detach(); - $('h1', $content).first().detach(); + if (! $('h1', $content).length) { + var title = $('h1', $container).first().detach(); + $('h1', $content).first().detach(); + } $container.html(title).append(content); } else if (action === 'replace') { $container.html(content); From 8c24dde17bce31cbf9e7e25a7d5f13dd588f8126 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Mon, 2 Feb 2015 12:08:20 +0100 Subject: [PATCH 47/58] Error Controller: Move close tab creation to template --- application/controllers/ErrorController.php | 1 - application/views/scripts/error/error.phtml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/application/controllers/ErrorController.php b/application/controllers/ErrorController.php index e198eca1c..0548b5c9c 100644 --- a/application/controllers/ErrorController.php +++ b/application/controllers/ErrorController.php @@ -19,7 +19,6 @@ class ErrorController extends ActionController { $error = $this->_getParam('error_handler'); $exception = $error->exception; - $this->getTabs()->showOnlyCloseButton(); Logger::error($exception); Logger::error('Stacktrace: %s', $exception->getTraceAsString()); diff --git a/application/views/scripts/error/error.phtml b/application/views/scripts/error/error.phtml index 8e61e80f8..d9422474c 100644 --- a/application/views/scripts/error/error.phtml +++ b/application/views/scripts/error/error.phtml @@ -1,5 +1,5 @@
    -tabs->render($this) ?> +tabs->showOnlyCloseButton() ?> title): ?>

    escape($title) ?>

    From 8c758a9f126f81cc50fe290691d284947ec1804d Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Mon, 2 Feb 2015 13:32:40 +0100 Subject: [PATCH 48/58] Failure requests: Fix auto refresh and history Allow to change url's in history and stop auto auto refresh if the container URL is not up to date. --- public/js/icinga/loader.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 507a914e3..4c273ffdb 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -107,7 +107,8 @@ url : url, data : data, headers: headers, - context: self + context: self, + failure: false }); req.$target = $target; @@ -553,7 +554,7 @@ // Update history when necessary. Don't do so for requests triggered // by history or autorefresh events if (! req.historyTriggered && ! req.autorefresh) { - if (req.$target.hasClass('container')) { + if (req.$target.hasClass('container') && req.failure === false) { // We only want to care about top-level containers if (req.$target.parent().closest('.container').length === 0) { this.icinga.history.pushCurrentState(); @@ -589,6 +590,17 @@ onFailure: function (req, textStatus, errorThrown) { var url = req.url; + req.failure = true; + + /* + * Test if a manual actions comes in and autorefresh is active: Stop refreshing + */ + if (! req.historyTriggered && ! req.autorefresh && req.$target.data('icingaRefresh') > 0 + && req.$target.data('icingaUrl') !== url) { + req.$target.data('icingaRefresh', 0); + req.$target.data('icingaUrl', url); + } + if (req.status > 0) { this.icinga.logger.error( req.status, From 53e7b44308a43b9b67fcecdaeef05e7adbf69722 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 13:29:55 +0100 Subject: [PATCH 49/58] security: Provide a permission for module configuration --- application/forms/Security/RoleForm.php | 1 + 1 file changed, 1 insertion(+) diff --git a/application/forms/Security/RoleForm.php b/application/forms/Security/RoleForm.php index 18926972c..cc5f4037e 100644 --- a/application/forms/Security/RoleForm.php +++ b/application/forms/Security/RoleForm.php @@ -26,6 +26,7 @@ class RoleForm extends ConfigForm 'system/config/*' => 'system/config/*', 'system/config/application' => 'system/config/application', 'system/config/authentication' => 'system/config/authentication', + 'system/config/modules' => 'system/config/modules', 'system/config/resources' => 'system/config/resources', 'system/config/roles' => 'system/config/roles' ); From 7a81133ad33231c62967ba721b4ca6147a54a8e7 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 13:30:52 +0100 Subject: [PATCH 50/58] security: Guard configuring roles --- application/controllers/RolesController.php | 58 ++++++++++++++++----- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/application/controllers/RolesController.php b/application/controllers/RolesController.php index 90163812e..f4c6aeed2 100644 --- a/application/controllers/RolesController.php +++ b/application/controllers/RolesController.php @@ -1,6 +1,4 @@ view->tabs = Widget::create('tabs')->add('index', array( - 'title' => $this->translate('Application'), - 'url' => 'config' - ))->add('authentication', array( - 'title' => $this->translate('Authentication'), - 'url' => 'config/authentication' - ))->add('resources', array( - 'title' => $this->translate('Resources'), - 'url' => 'config/resource' - ))->add('roles', array( + $this->assertPermission('system/config/roles'); + $tabs = $this->getTabs(); + $auth = $this->Auth(); + if ($auth->hasPermission('system/config/application')) { + $tabs->add('application', array( + 'title' => $this->translate('Application'), + 'url' => 'config' + )); + } + if ($auth->hasPermission('system/config/authentication')) { + $tabs->add('authentication', array( + 'title' => $this->translate('Authentication'), + 'url' => 'config/authentication' + )); + } + if ($auth->hasPermission('system/config/resources')) { + $tabs->add('resource', array( + 'title' => $this->translate('Resources'), + 'url' => 'config/resource' + )); + } + $tabs->add('roles', array( 'title' => $this->translate('Roles'), 'url' => 'roles' )); } + /** + * List roles + */ public function indexAction() { $this->view->tabs->activate('roles'); $this->view->roles = Config::app('roles', true); } + /** + * Create a new role + */ public function newAction() { $role = new RoleForm(array( @@ -61,6 +85,11 @@ class RolesController extends ActionController $this->view->form = $role; } + /** + * Update a role + * + * @throws Zend_Controller_Action_Exception If the required parameter 'role' is missing or the role does not exist + */ public function updateAction() { $name = $this->_request->getParam('role'); @@ -105,6 +134,11 @@ class RolesController extends ActionController $this->view->form = $role; } + /** + * Remove a role + * + * @throws Zend_Controller_Action_Exception If the required parameter 'role' is missing or the role does not exist + */ public function removeAction() { $name = $this->_request->getParam('role'); From 5a1ebf9c89f96afb8ba1e9ed8b04763826e55197 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 13:32:09 +0100 Subject: [PATCH 51/58] lib: Implement Tab::getUrl() --- library/Icinga/Web/Widget/Tab.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/Icinga/Web/Widget/Tab.php b/library/Icinga/Web/Widget/Tab.php index a06389b98..7eb5abeb1 100644 --- a/library/Icinga/Web/Widget/Tab.php +++ b/library/Icinga/Web/Widget/Tab.php @@ -138,6 +138,16 @@ class Tab extends AbstractWidget $this->url = $url; } + /** + * Get the tab's target URL + * + * @return Url + */ + public function getUrl() + { + return $this->url; + } + /** * Set the parameters to be set for this tabs Url * From 9ac93421070bd7696cec8f003c44da7ed08515f7 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 13:41:02 +0100 Subject: [PATCH 52/58] Revert "lib: Reduce else { if { to elseif { in User::can()" This reverts commit e5b0b528747c2ff76b0568f8ca6929e61b072495. --- library/Icinga/User.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/library/Icinga/User.php b/library/Icinga/User.php index bdc49275b..db80c929a 100644 --- a/library/Icinga/User.php +++ b/library/Icinga/User.php @@ -426,11 +426,13 @@ class User foreach ($this->permissions as $permitted) { $wildcard = strpos($permitted, '*'); if ($wildcard !== false) { - } - if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) { - return true; - } elseif ($permission === $permitted) { - return true; + if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) { + return true; + } else { + if ($permission === $permitted) { + return true; + } + } } } return false; From 94193abdc02a20ce6d4ed8ef62498f6e091d50d7 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 13:44:54 +0100 Subject: [PATCH 53/58] lib: Fix User::can() --- library/Icinga/User.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/Icinga/User.php b/library/Icinga/User.php index db80c929a..54b3e7632 100644 --- a/library/Icinga/User.php +++ b/library/Icinga/User.php @@ -428,11 +428,9 @@ class User if ($wildcard !== false) { if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) { return true; - } else { - if ($permission === $permitted) { - return true; - } } + } elseif ($permission === $permitted) { + return true; } } return false; From 4bac5dfc3779291a6da9b10e18c7a73a5454bf9a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 13:46:35 +0100 Subject: [PATCH 54/58] security: Guard application and module configuration --- application/controllers/ConfigController.php | 139 +++++++++++++----- .../config/{index.phtml => application.phtml} | 0 2 files changed, 102 insertions(+), 37 deletions(-) rename application/views/scripts/config/{index.phtml => application.phtml} (100%) diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index 15ba0a6ff..078503346 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -1,41 +1,70 @@ view->tabs = Widget::create('tabs')->add('index', array( - 'title' => $this->translate('Application'), - 'url' => 'config' - ))->add('authentication', array( - 'title' => $this->translate('Authentication'), - 'url' => 'config/authentication' - ))->add('resources', array( - 'title' => $this->translate('Resources'), - 'url' => 'config/resource' - ))->add('roles', array( - 'title' => $this->translate('Roles'), - 'url' => 'roles' - )); + $tabs = $this->getTabs(); + $auth = $this->Auth(); + $allowedActions = array(); + if ($auth->hasPermission('system/config/application')) { + $tabs->add('application', array( + 'title' => $this->translate('Application'), + 'url' => 'config/application' + )); + $allowedActions[] = 'application'; + } + if ($auth->hasPermission('system/config/authentication')) { + $tabs->add('authentication', array( + 'title' => $this->translate('Authentication'), + 'url' => 'config/authentication' + )); + $allowedActions[] = 'authentication'; + } + if ($auth->hasPermission('system/config/resources')) { + $tabs->add('resource', array( + 'title' => $this->translate('Resources'), + 'url' => 'config/resource' + )); + $allowedActions[] = 'resource'; + } + if ($auth->hasPermission('system/config/roles')) { + $tabs->add('roles', array( + 'title' => $this->translate('Roles'), + 'url' => 'roles' + )); + $allowedActions[] = 'roles'; + } + $this->firstAllowedAction = array_shift($allowedActions); } public function devtoolsAction() @@ -44,16 +73,35 @@ class ConfigController extends ActionController } /** - * Index action, entry point for configuration + * Forward or redirect to the first allowed configuration action */ public function indexAction() { + if ($this->firstAllowedAction === null) { + throw new SecurityException('No permission for configuration'); + } + $action = $this->getTabs()->get($this->firstAllowedAction); + if (substr($action->getUrl()->getPath(), 0, 7) === 'config/') { + $this->forward($this->firstAllowedAction); + } else { + $this->redirectNow($action->getUrl()); + } + } + + /** + * Application configuration + * + * @throws SecurityException If the user lacks the permission for configuring the application + */ + public function applicationAction() + { + $this->assertPermission('system/config/application'); $form = new GeneralConfigForm(); $form->setIniConfig(Config::app()); $form->handleRequest(); $this->view->form = $form; - $this->view->tabs->activate('index'); + $this->view->tabs->activate('application'); } /** @@ -61,16 +109,19 @@ class ConfigController extends ActionController */ public function modulesAction() { - $this->view->tabs = Widget::create('tabs')->add('modules', array( - 'title' => $this->translate('Modules'), - 'url' => 'config/modules' - )); - - $this->view->tabs->activate('modules'); + // Overwrite tabs created in init + // @TODO(el): This seems not natural to me. Module configuration should have its own controller. + $this->view->tabs = Widget::create('tabs') + ->add('modules', array( + 'title' => $this->translate('Modules'), + 'url' => 'config/modules' + )) + ->activate('modules'); $this->view->modules = Icinga::app()->getModuleManager()->select() ->from('modules') ->order('enabled', 'desc') - ->order('name')->paginate(); + ->order('name') + ->paginate(); } public function moduleAction() @@ -79,8 +130,12 @@ class ConfigController extends ActionController $app = Icinga::app(); $manager = $app->getModuleManager(); if ($manager->hasInstalled($name)) { - $this->view->moduleData = Icinga::app()->getModuleManager()->select() - ->from('modules')->where('name', $name)->fetchRow(); + $this->view->moduleData = Icinga::app() + ->getModuleManager() + ->select() + ->from('modules') + ->where('name', $name) + ->fetchRow(); $module = new Module($app, $name, $manager->getModuleDir($name)); $this->view->module = $module; } else { @@ -94,6 +149,7 @@ class ConfigController extends ActionController */ public function moduleenableAction() { + $this->assertPermission('system/config/modules'); $module = $this->getParam('name'); $manager = Icinga::app()->getModuleManager(); try { @@ -114,6 +170,7 @@ class ConfigController extends ActionController */ public function moduledisableAction() { + $this->assertPermission('system/config/modules'); $module = $this->getParam('name'); $manager = Icinga::app()->getModuleManager(); try { @@ -133,6 +190,7 @@ class ConfigController extends ActionController */ public function authenticationAction() { + $this->assertPermission('system/config/authentication'); $form = new AuthenticationBackendReorderForm(); $form->setIniConfig(Config::app('authentication')); $form->handleRequest(); @@ -147,6 +205,7 @@ class ConfigController extends ActionController */ public function createauthenticationbackendAction() { + $this->assertPermission('system/config/authentication'); $form = new AuthenticationBackendConfigForm(); $form->setIniConfig(Config::app('authentication')); $form->setResourceConfig(ResourceFactory::getResourceConfigs()); @@ -163,6 +222,7 @@ class ConfigController extends ActionController */ public function editauthenticationbackendAction() { + $this->assertPermission('system/config/authentication'); $form = new AuthenticationBackendConfigForm(); $form->setIniConfig(Config::app('authentication')); $form->setResourceConfig(ResourceFactory::getResourceConfigs()); @@ -179,6 +239,7 @@ class ConfigController extends ActionController */ public function removeauthenticationbackendAction() { + $this->assertPermission('system/config/authentication'); $form = new ConfirmRemovalForm(array( 'onSuccess' => function ($form) { $configForm = new AuthenticationBackendConfigForm(); @@ -215,8 +276,9 @@ class ConfigController extends ActionController */ public function resourceAction() { + $this->assertPermission('system/config/resources'); $this->view->resources = Config::app('resources', true)->keys(); - $this->view->tabs->activate('resources'); + $this->view->tabs->activate('resource'); } /** @@ -224,6 +286,7 @@ class ConfigController extends ActionController */ public function createresourceAction() { + $this->assertPermission('system/config/resources'); $form = new ResourceConfigForm(); $form->setIniConfig(Config::app('resources')); $form->setRedirectUrl('config/resource'); @@ -238,6 +301,7 @@ class ConfigController extends ActionController */ public function editresourceAction() { + $this->assertPermission('system/config/resources'); $form = new ResourceConfigForm(); $form->setIniConfig(Config::app('resources')); $form->setRedirectUrl('config/resource'); @@ -252,6 +316,7 @@ class ConfigController extends ActionController */ public function removeresourceAction() { + $this->assertPermission('system/config/resources'); $form = new ConfirmRemovalForm(array( 'onSuccess' => function ($form) { $configForm = new ResourceConfigForm(); diff --git a/application/views/scripts/config/index.phtml b/application/views/scripts/config/application.phtml similarity index 100% rename from application/views/scripts/config/index.phtml rename to application/views/scripts/config/application.phtml From 52c40bdc5b3bf3b32cbddf46bfa1039e7952b978 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 14:15:09 +0100 Subject: [PATCH 55/58] lib/SimpleQuery: Increase default limit to 25 Please follow the referenced issues. fixes #8337 refs #8339 --- library/Icinga/Data/SimpleQuery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Data/SimpleQuery.php b/library/Icinga/Data/SimpleQuery.php index 41d050ea2..e865d86fa 100644 --- a/library/Icinga/Data/SimpleQuery.php +++ b/library/Icinga/Data/SimpleQuery.php @@ -320,7 +320,7 @@ class SimpleQuery implements QueryInterface, Queryable // Detect parameters from request $request = Icinga::app()->getFrontController()->getRequest(); if ($itemsPerPage === null) { - $itemsPerPage = $request->getParam('limit', 20); + $itemsPerPage = $request->getParam('limit', 25); } if ($pageNumber === null) { $pageNumber = $request->getParam('page', 0); From bfb2f710a1353407fe1f88f6fa23d39fb9003e4f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 14:28:47 +0100 Subject: [PATCH 56/58] monitoring: Fix exception in the alert summary report when using the "One month" interval fixes #8220 --- .../application/controllers/AlertsummaryController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/controllers/AlertsummaryController.php b/modules/monitoring/application/controllers/AlertsummaryController.php index a4ef76b44..d9cc798a7 100644 --- a/modules/monitoring/application/controllers/AlertsummaryController.php +++ b/modules/monitoring/application/controllers/AlertsummaryController.php @@ -375,7 +375,7 @@ class Monitoring_AlertsummaryController extends Controller $query->order('notification_start_time', 'asc'); - $records = $query->getQuery()->fetchAll(); + $records = $query->getQuery()->fetchAll(); $interval = $this->getInterval(); $period = $this->createPeriod($interval); @@ -582,7 +582,7 @@ class Monitoring_AlertsummaryController extends Controller } elseif ($interval === '1w') { return new DatePeriod($this->getBeginDate($interval), new DateInterval('P1D'), 7); } elseif ($interval === '1m') { - return new DatePeriod($this->getBeginDate($interval), new DateInterval('P1D'), 30); + return new DatePeriod($this->getBeginDate($interval), new DateInterval('P1D'), 31); } elseif ($interval === '1y') { return new DatePeriod($this->getBeginDate($interval), new DateInterval('P1M'), 12); } From 6555a2ec0a2d2c527dd7ca002f44bc9127073e51 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Mon, 2 Feb 2015 15:03:00 +0100 Subject: [PATCH 57/58] Menu: Move request handling to complete If a failure occur the menu is still working. --- public/js/icinga/loader.js | 66 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index 4c273ffdb..1a8aadca5 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -342,42 +342,11 @@ var rendered = false; var classes; - if (! req.autorefresh) { - // TODO: Hook for response/url? - var $forms = $('[action="' + this.icinga.utils.parseUrl(url).path + '"]'); - var $matches = $.merge($('[href="' + url + '"]'), $forms); - $matches.each(function (idx, el) { - if ($(el).closest('#menu').length) { - if (req.$target[0].id === 'col1') { - self.icinga.behaviors.navigation.resetActive(); - } - } else if ($(el).closest('table.action').length) { - $(el).closest('table.action').find('.active').removeClass('active'); - } - }); - - $matches.each(function (idx, el) { - var $el = $(el); - if ($el.closest('#menu').length) { - if ($el.is('form')) { - $('input', $el).addClass('active'); - } else { - if (req.$target[0].id === 'col1') { - self.icinga.behaviors.navigation.setActive($el); - } - } - // Interrupt .each, only on menu item shall be active - return false; - } else if ($(el).closest('table.action').length) { - $el.addClass('active'); - } - }); - } else { + if (req.autorefresh) { // TODO: next container url active = $('[href].active', req.$target).attr('href'); } - var target = req.getResponseHeader('X-Icinga-Container'); var newBody = false; var oldNotifications = false; @@ -551,6 +520,39 @@ * Regardless of whether a request succeeded of failed, clean up */ onComplete: function (req, textStatus) { + if (! req.autorefresh) { + // TODO: Hook for response/url? + var url = req.url; + var $forms = $('[action="' + this.icinga.utils.parseUrl(url).path + '"]'); + var $matches = $.merge($('[href="' + url + '"]'), $forms); + $matches.each(function (idx, el) { + if ($(el).closest('#menu').length) { + if (req.$target[0].id === 'col1') { + self.icinga.behaviors.navigation.resetActive(); + } + } else if ($(el).closest('table.action').length) { + $(el).closest('table.action').find('.active').removeClass('active'); + } + }); + + $matches.each(function (idx, el) { + var $el = $(el); + if ($el.closest('#menu').length) { + if ($el.is('form')) { + $('input', $el).addClass('active'); + } else { + if (req.$target[0].id === 'col1') { + self.icinga.behaviors.navigation.setActive($el); + } + } + // Interrupt .each, only on menu item shall be active + return false; + } else if ($(el).closest('table.action').length) { + $el.addClass('active'); + } + }); + } + // Update history when necessary. Don't do so for requests triggered // by history or autorefresh events if (! req.historyTriggered && ! req.autorefresh) { From 9d6906bd6449a21598614a633adcb711e8bfca62 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 2 Feb 2015 15:05:47 +0100 Subject: [PATCH 58/58] Save user dashboards to Icinga Web 2's configuration directory fixes #8056 --- .../controllers/DashboardController.php | 4 +-- library/Icinga/Web/Widget/Dashboard.php | 25 ++----------------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 49a58426f..12a5180c8 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -24,11 +24,11 @@ class DashboardController extends ActionController * @var Dashboard; */ private $dashboard; - + public function init() { $this->dashboard = new Dashboard(); - $this->dashboard->setUser($this->getRequest()->getUser()); + $this->dashboard->setUser($this->Auth()->getUser()); $this->dashboard->load(); } diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index fe4bba803..bb62cc8f9 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -9,7 +9,6 @@ use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; use Icinga\Exception\ProgrammingError; -use Icinga\Exception\SystemPermissionException; use Icinga\User; use Icinga\Web\Widget\Dashboard\Pane; use Icinga\Web\Widget\Dashboard\Dashlet as DashboardDashlet; @@ -425,28 +424,8 @@ class Dashboard extends AbstractWidget public function getConfigFile() { if ($this->user === null) { - return ''; + throw new ProgrammingError('Can\'t load dashboards. User is not set'); } - - $baseDir = '/var/lib/icingaweb'; - - if (! file_exists($baseDir)) { - throw new NotReadableError('Could not read: ' . $baseDir); - } - - $userDir = $baseDir . '/' . $this->user->getUsername(); - - if (! file_exists($userDir)) { - $success = @mkdir($userDir); - if (!$success) { - throw new SystemPermissionException('Could not create: ' . $userDir); - } - } - - if (! file_exists($userDir)) { - throw new NotReadableError('Could not read: ' . $userDir); - } - - return $userDir . '/dashboard.ini'; + return Config::resolvePath('dashboards/' . $this->user->getUsername() . '/dashboard.ini'); } }