Merge branch 'bugfix/rebuild-form-builder-5525' into bugfix/commands-6593

Conflicts:
	library/Icinga/Web/Form.php
	modules/monitoring/application/forms/Config/SecurityForm.php
This commit is contained in:
Eric Lippmann 2014-08-28 13:58:02 +02:00
commit 4ca1eaa7ce
51 changed files with 2433 additions and 3178 deletions

@ -14,7 +14,6 @@ use Icinga\Exception\AuthenticationException;
use Icinga\Exception\NotReadableError;
use Icinga\Exception\ConfigurationError;
use Icinga\User;
use Icinga\Web\Session;
use Icinga\Web\Url;
/**
@ -36,7 +35,6 @@ class AuthenticationController extends ActionController
{
$auth = $this->Auth();
$this->view->form = $form = new LoginForm();
$form->setRequest($this->_request);
$this->view->title = $this->translate('Icingaweb Login');
try {
@ -55,27 +53,17 @@ class AuthenticationController extends ActionController
$config = Config::app('authentication');
} catch (NotReadableError $e) {
throw new ConfigurationError(
$this->translate(
'Could not read your authentiction.ini, no authentication methods are available.'
)
$this->translate('Could not read your authentiction.ini, no authentication methods are available.'),
0,
$e
);
}
$chain = new AuthChain($config);
if ($this->getRequest()->isGet()) {
$user = new User('');
foreach ($chain as $backend) {
if ($backend instanceof AutoLoginBackend) {
$authenticated = $backend->authenticate($user);
if ($authenticated === true) {
$auth->setAuthenticated($user);
$this->rerenderLayout()->redirectNow($redirectUrl);
}
}
}
} elseif ($form->isSubmittedAndValid()) {
$user = new User($form->getValue('username'));
$password = $form->getValue('password');
$request = $this->getRequest();
if ($request->isPost() && $this->view->form->isValid($request->getPost())) {
$user = new User($this->view->form->getValue('username'));
$password = $this->view->form->getValue('password');
$backendsTried = 0;
$backendsWithError = 0;
@ -121,14 +109,25 @@ class AuthenticationController extends ActionController
);
}
if ($backendsWithError) {
$form->addNote(
$this->view->form->getElement('username')->addError(
$this->translate(
'Please note that not all authentication methods where available.'
. ' Check the system log or Icinga Web 2 log for more information.'
)
);
}
$form->getElement('password')->addError($this->translate('Incorrect username or password'));
$this->view->form->getElement('password')->addError($this->translate('Incorrect username or password'));
} elseif ($request->isGet()) {
$user = new User('');
foreach ($chain as $backend) {
if ($backend instanceof AutoLoginBackend) {
$authenticated = $backend->authenticate($user);
if ($authenticated === true) {
$auth->setAuthenticated($user);
$this->rerenderLayout()->redirectNow($redirectUrl);
}
}
}
}
} catch (Exception $e) {
$this->view->errorInfo = $e->getMessage();

@ -3,23 +3,22 @@
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Controller\BaseConfigController;
use Icinga\Web\Widget\Tab;
use Icinga\Web\Widget\AlertMessageBox;
use Icinga\Web\Notification;
use Icinga\Application\Modules\Module;
use Icinga\Web\Url;
use Icinga\Web\Form;
use Icinga\Web\Widget;
use Icinga\Application\Icinga;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Data\ResourceFactory;
use Icinga\Form\Config\GeneralForm;
use Icinga\Form\Config\Authentication\ReorderForm;
use Icinga\Form\Config\Authentication\LdapBackendForm;
use Icinga\Form\Config\Authentication\DbBackendForm;
use Icinga\Form\Config\Authentication\AutologinBackendForm;
use Icinga\Form\Config\ResourceForm;
use Icinga\Form\Config\LoggingForm;
use Icinga\Form\Config\ConfirmRemovalForm;
use Icinga\Config\PreservingIniWriter;
use Icinga\Exception\ConfigurationError;
/**
@ -27,13 +26,6 @@ use Icinga\Config\PreservingIniWriter;
*/
class ConfigController extends BaseConfigController
{
/**
* The resource types that are available.
*
* @var array
*/
private $resourceTypes = array('livestatus', 'ido', 'statusdat', 'ldap');
public function init()
{
$this->view->tabs = Widget::create('tabs')->add('index', array(
@ -45,9 +37,6 @@ class ConfigController extends BaseConfigController
))->add('resources', array(
'title' => 'Resources',
'url' => 'config/resource'
))->add('logging', array(
'title' => 'Logging',
'url' => 'config/logging'
));
}
@ -63,39 +52,20 @@ class ConfigController extends BaseConfigController
{
$this->view->messageBox = new AlertMessageBox(true);
$this->view->tabs->activate('index');
$form = new GeneralForm();
$form->setConfiguration(IcingaConfig::app());
$form->setRequest($this->_request);
if ($form->isSubmittedAndValid()) {
if (!$this->writeConfigFile($form->getConfig(), 'config')) {
return;
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
if ($this->writeConfigFile($form->getConfiguration(), 'config')) {
Notification::success($this->translate('New configuration has successfully been stored'));
$this->redirectNow('config');
}
}
Notification::success('New configuration has successfully been stored');
$form->setConfiguration(IcingaConfig::app(), true);
$this->redirectNow('config/index');
} else {
$form->setConfiguration(IcingaConfig::app());
}
$this->view->form = $form;
}
/**
* Form for modifying the logging configuration
*/
public function loggingAction()
{
$this->view->messageBox = new AlertMessageBox(true);
$this->view->tabs->activate('logging');
$form = new LoggingForm();
$form->setConfiguration(IcingaConfig::app());
$form->setRequest($this->_request);
if ($form->isSubmittedAndValid()) {
if (!$this->writeConfigFile($form->getConfig(), 'config')) {
return;
}
Notification::success('New configuration has sucessfully been stored');
$form->setConfiguration(IcingaConfig::app(), true);
$this->redirectNow('config/logging');
}
$this->view->form = $form;
}
@ -172,40 +142,47 @@ class ConfigController extends BaseConfigController
}
/**
* Action for creating a new authentication backend
* Action for reordering authentication backends
*/
public function authenticationAction()
{
$config = IcingaConfig::app('authentication', true);
$this->view->messageBox = new AlertMessageBox(true);
$this->view->tabs->activate('authentication');
$order = array_keys($config->toArray());
$this->view->messageBox = new AlertMessageBox(true);
$backends = array();
foreach ($order as $backend) {
$form = new ReorderForm();
$form->setName('form_reorder_backend_' . $backend);
$form->setBackendName($backend);
$form->setCurrentOrder($order);
$form->setRequest($this->_request);
if ($form->isSubmittedAndValid()) {
if ($this->writeAuthenticationFile($form->getReorderedConfig($config))) {
Notification::success('Authentication Order Updated');
$this->redirectNow('config/authentication');
$config = IcingaConfig::app('authentication');
$backendOrder = array_keys($config->toArray());
$form = new Form();
$form->setName('form_reorder_authbackend');
$request = $this->getRequest();
if ($request->isPost()) {
$requestData = $request->getPost();
if ($form->isValid($requestData)) { // Validate the CSRF token
$reordered = false;
foreach ($backendOrder as $backendName) {
if (isset($requestData[$backendName])) {
array_splice($backendOrder, array_search($backendName, $backendOrder), 1);
array_splice($backendOrder, $requestData[$backendName], 0, $backendName);
$reordered = true;
break;
}
}
return;
}
if ($reordered) {
$reorderedConfig = array();
foreach ($backendOrder as $backendName) {
$reorderedConfig[$backendName] = $config->{$backendName};
}
$backends[] = (object) array(
'name' => $backend,
'reorderForm' => $form
);
if ($this->writeAuthenticationFile($reorderedConfig)) {
Notification::success($this->translate('Authentication order updated!'));
$this->redirectNow('config/authentication');
}
}
}
}
$this->view->backends = $backends;
$this->view->form = $form->create(); // Necessary in case its a GET request
$this->view->backendNames = $backendOrder;
}
/**
@ -214,38 +191,56 @@ class ConfigController extends BaseConfigController
public function createauthenticationbackendAction()
{
$this->view->messageBox = new AlertMessageBox(true);
$this->view->tabs->activate('authentication');
if ($this->getRequest()->getParam('type') === 'ldap') {
$form = new LdapBackendForm();
} else {
$form = new DbBackendForm();
}
if ($this->getParam('auth_backend')) {
$form->setBackendName($this->getParam('auth_backend'));
}
$form->setRequest($this->getRequest());
if ($form->isSubmittedAndValid()) {
$backendCfg = IcingaConfig::app('authentication')->toArray();
foreach ($backendCfg as $backendName => $settings) {
unset($backendCfg[$backendName]['name']);
$backendType = $this->getRequest()->getParam('type');
$authenticationConfig = IcingaConfig::app('authentication')->toArray();
try {
switch ($backendType) {
case 'ldap':
$form = new LdapBackendForm();
break;
case 'db':
$form = new DbBackendForm();
break;
case 'autologin':
foreach ($authenticationConfig as $ac) {
if (array_key_exists('backend', $ac) && $ac['backend'] === 'autologin') {
throw new ConfigurationError(
$this->translate('An autologin backend already exists')
);
}
}
$form = new AutologinBackendForm();
break;
default:
$this->addErrorMessage(sprintf(
$this->translate('There is no backend type `%s\''),
$backendType
));
$this->redirectNow('config/configurationerror');
}
foreach ($form->getConfig() as $backendName => $settings) {
unset($settings->{'name'});
if (isset($backendCfg[$backendName])) {
$this->addErrorMessage('Backend name already exists');
$this->view->form = $form;
$this->render('authentication/create');
return;
} catch (ConfigurationError $e) {
$this->addErrorMessage($e->getMessage());
$this->redirectNow('config/configurationerror');
}
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
list($backendName, $backendConfig) = $form->getBackendConfig();
if (isset($authenticationConfig[$backendName])) {
$this->addErrorMessage(
$this->translate('Backend name already exists')
);
} else {
$authenticationConfig[$backendName] = $backendConfig;
if ($this->writeConfigFile($authenticationConfig, 'authentication')) {
$this->addSuccessMessage(
$this->translate('Backend Modification Written.')
);
$this->redirectNow('config/authentication');
}
$backendCfg[$backendName] = $settings;
}
if ($this->writeAuthenticationFile($backendCfg)) {
// redirect to overview with success message
Notification::success('Backend Modification Written.');
$this->redirectNow("config/authentication");
}
return;
}
$this->view->messageBox->addForm($form);
@ -266,18 +261,21 @@ class ConfigController extends BaseConfigController
$configArray = IcingaConfig::app('authentication', true)->toArray();
$authBackend = $this->getParam('auth_backend');
if (!isset($configArray[$authBackend])) {
$this->addErrorMessage('Can\'t edit: Unknown Authentication Backend Provided');
$this->configurationerrorAction();
return;
}
if (!array_key_exists('resource', $configArray[$authBackend])) {
$this->addErrorMessage('Configuration error: Backend "' . $authBackend . '" has no Resource');
$this->configurationerrorAction();
return;
if (false === isset($configArray[$authBackend])) {
$this->addErrorMessage(
$this->translate('Can\'t edit: Unknown Authentication Backend Provided')
);
$this->redirectNow('config/configurationerror');
}
$type = ResourceFactory::getResourceConfig($configArray[$authBackend]['resource'])->type;
if (false === array_key_exists('backend', $configArray[$authBackend])) {
$this->addErrorMessage(sprintf(
$this->translate('Backend "%s" has no `backend\' setting'),
$authBackend
));
$this->redirectNow('config/configurationerror');
}
$type = $configArray[$authBackend]['backend'];
switch ($type) {
case 'ldap':
$form = new LdapBackendForm();
@ -285,32 +283,37 @@ class ConfigController extends BaseConfigController
case 'db':
$form = new DbBackendForm();
break;
case 'autologin':
$form = new AutologinBackendForm();
break;
default:
$this->addErrorMessage('Can\'t edit: backend type "' . $type . '" of given resource not supported.');
$this->configurationerrorAction();
return;
$this->addErrorMessage(sprintf(
$this->translate('Can\'t edit: backend type "%s" of given resource not supported.'),
$type
));
$this->redirectNow('config/configurationerror');
}
$form->setBackendName($this->getParam('auth_backend'));
$form->setBackend(IcingaConfig::app('authentication', true)->$authBackend);
$form->setRequest($this->getRequest());
if ($form->isSubmittedAndValid()) {
$backendCfg = IcingaConfig::app('authentication')->toArray();
foreach ($form->getConfig() as $backendName => $settings) {
$backendCfg[$backendName] = $settings;
// Remove the old section if the backend is renamed
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
list($backendName, $backendConfig) = $form->getBackendConfig();
$configArray[$backendName] = $backendConfig;
if ($backendName != $authBackend) {
unset($backendCfg[$authBackend]);
unset($configArray[$authBackend]);
}
unset($settings['name']);
if ($this->writeAuthenticationFile($configArray)) {
// redirect to overview with success message
Notification::success(sprintf(
$this->translate('Backend "%s" saved'),
$backendName
));
$this->redirectNow('config/authentication');
}
return;
}
if ($this->writeAuthenticationFile($backendCfg)) {
// redirect to overview with success message
Notification::success('Backend "' . $authBackend . '" created');
$this->redirectNow("config/authentication");
}
return;
} else {
$form->setBackendConfig($authBackend, $configArray[$authBackend]);
}
$this->view->messageBox->addForm($form);
@ -330,23 +333,25 @@ class ConfigController extends BaseConfigController
$configArray = IcingaConfig::app('authentication', true)->toArray();
$authBackend = $this->getParam('auth_backend');
if (!isset($configArray[$authBackend])) {
Notification::error('Can\'t perform removal: Unknown Authentication Backend Provided');
$this->render('authentication/remove');
return;
if (false === array_key_exists($authBackend, $configArray)) {
$this->addErrorMessage(
$this->translate('Can\'t perform removal: Unknown authentication backend provided')
);
$this->redirectNow('config/configurationerror');
}
$form = new ConfirmRemovalForm();
$form->setRequest($this->getRequest());
$form->setRemoveTarget('auth_backend', $authBackend);
$request = $this->getRequest();
if ($form->isSubmittedAndValid()) {
if ($request->isPost() && $form->isValid($request->getPost())) {
unset($configArray[$authBackend]);
if ($this->writeAuthenticationFile($configArray)) {
Notification::success('Authentication Backend "' . $authBackend . '" Removed');
$this->redirectNow("config/authentication");
Notification::success(sprintf(
$this->translate('Authentication Backend "%s" Removed'),
$authBackend
));
$this->redirectNow('config/authentication');
}
return;
}
$this->view->form = $form;
@ -354,116 +359,130 @@ class ConfigController extends BaseConfigController
$this->render('authentication/remove');
}
public function resourceAction($showOnly = false)
/**
* Display all available resources and a link to create a new one
*/
public function resourceAction()
{
$this->view->messageBox = new AlertMessageBox(true);
$this->view->tabs->activate('resources');
$this->view->messageBox = new AlertMessageBox(true);
$this->view->resources = IcingaConfig::app('resources', true)->toArray();
$this->render('resource');
}
/**
* Display a form to create a new resource
*/
public function createresourceAction()
{
$this->view->resourceTypes = $this->resourceTypes;
$resources = IcingaConfig::app('resources', true);
$this->view->messageBox = new AlertMessageBox(true);
$form = new ResourceForm();
$form->setRequest($this->_request);
if ($form->isSubmittedAndValid()) {
$name = $form->getName();
if (isset($resources->{$name})) {
$this->addErrorMessage('Resource name "' . $name .'" already in use.');
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
list($name, $config) = $form->getResourceConfig();
$resources = IcingaConfig::app('resources')->toArray();
if (array_key_exists($name, $resources)) {
$this->addErrorMessage(sprintf($this->translate('Resource name "%s" already in use.'), $name));
} else {
$resources->{$name} = $form->getConfig();
$resources[$name] = $config;
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage('Resource "' . $name . '" created.');
$this->redirectNow("config/resource");
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully created.'), $name));
$this->redirectNow('config/resource');
}
}
}
$this->view->messageBox = new AlertMessageBox(true);
$this->view->messageBox->addForm($form);
$this->view->form = $form;
$this->view->messageBox->addForm($form);
$this->render('resource/create');
}
/**
* Display a form to edit a existing resource
*/
public function editresourceAction()
{
$this->view->messageBox = new AlertMessageBox(true);
$resources = ResourceFactory::getResourceConfigs();
$name = $this->getParam('resource');
if ($resources->get($name) === null) {
$this->addErrorMessage('Can\'t edit: Unknown Resource Provided');
$this->render('resource/modify');
return;
}
$form = new ResourceForm();
if ($this->_request->isPost() === false) {
$form->setOldName($name);
$form->setName($name);
}
$form->setRequest($this->_request);
$form->setResource($resources->get($name));
if ($form->isSubmittedAndValid()) {
$oldName = $form->getOldName();
$name = $form->getName();
if ($oldName !== $name) {
unset($resources->{$oldName});
}
$resources->{$name} = $form->getConfig();
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage('Resource "' . $name . '" edited.');
$this->redirectNow("config/resource");
}
return;
// Fetch the resource to be edited
$resources = IcingaConfig::app('resources')->toArray();
$name = $this->getParam('resource');
if (false === array_key_exists($name, $resources)) {
$this->addErrorMessage(sprintf($this->translate('Cannot edit "%s". Resource not found.'), $name));
$this->redirectNow('config/configurationerror');
}
$form = new ResourceForm();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
list($newName, $config) = $form->getResourceConfig();
if ($newName !== $name) {
// Resource name has changed
unset($resources[$name]); // We can safely use unset as all values are part of the form
}
$resources[$newName] = $config;
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully edited.'), $name));
$this->redirectNow('config/resource');
}
}
} else {
$form->setResourceConfig($name, $resources[$name]);
}
$this->view->messageBox->addForm($form);
$this->view->form = $form;
$this->view->name = $name;
$this->view->messageBox->addForm($form);
$this->render('resource/modify');
}
/**
* Display a confirmation form to remove a resource
*/
public function removeresourceAction()
{
$this->view->messageBox = new AlertMessageBox(true);
$resources = ResourceFactory::getResourceConfigs()->toArray();
$name = $this->getParam('resource');
if (!isset($resources[$name])) {
$this->addSuccessMessage('Can\'t remove: Unknown resource provided');
$this->render('resource/remove');
return;
// Fetch the resource to be removed
$resources = IcingaConfig::app('resources')->toArray();
$name = $this->getParam('resource');
if (false === array_key_exists($name, $resources)) {
$this->addErrorMessage(sprintf($this->translate('Cannot remove "%s". Resource not found.'), $name));
$this->redirectNow('config/configurationerror');
}
// Check if selected resource is currently used for authentication
$authConfig = IcingaConfig::app('authentication')->toArray();
foreach ($authConfig as $backendName => $config) {
if (array_key_exists('resource', $config) && $config['resource'] === $name) {
$this->addWarningMessage(
sprintf(
$this->translate(
'The resource "%s" is currently in use by the authentication backend "%s". ' .
'Removing the resource can result in noone being able to log in any longer.'
),
$name,
$backendName
)
);
}
}
$form = new ConfirmRemovalForm();
$form->setRequest($this->getRequest());
$form->setRemoveTarget('resource', $name);
// Check if selected resource is currently used for authentication
$authConfig = IcingaConfig::app('authentication', true)->toArray();
foreach ($authConfig as $backendName => $config) {
if (array_key_exists('resource', $config) && $config['resource'] === $name) {
$this->addErrorMessage(
'Warning: The resource "' . $name . '" is currently used for user authentication by "' . $backendName . '". ' .
' Deleting it could eventally make login impossible.'
);
}
}
if ($form->isSubmittedAndValid()) {
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
unset($resources[$name]);
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage('Resource "' . $name . '" removed.');
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully removed.'), $name));
$this->redirectNow('config/resource');
}
return;
}
$this->view->name = $name;
$this->view->form = $form;
$this->view->messageBox->addForm($form);
$this->render('resource/remove');
}

@ -82,25 +82,29 @@ class DashboardController extends ActionController
)->activate('addurl');
$form = new AddUrlForm();
$form->setRequest($this->getRequest());
$form->setAction(Url::fromRequest()->setParams(array())->getAbsoluteUrl());
$this->view->form = $form;
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost()) && $form->isSubmitted()) {
$dashboard = $this->getDashboard();
$dashboard->setComponentUrl(
$form->getValue('pane'),
$form->getValue('component'),
ltrim($form->getValue('url'), '/')
);
if ($form->isSubmittedAndValid()) {
$dashboard = $this->getDashboard();
$dashboard->setComponentUrl(
$form->getValue('pane'),
$form->getValue('component'),
ltrim($form->getValue('url'), '/')
);
$configFile = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) {
$this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))));
} else {
$this->render('show-configuration');
$configFile = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) {
$this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))));
} else {
$this->render('show-configuration');
return;
}
}
} else {
$form->create()->setDefault('url', htmlspecialchars_decode($request->getParam('url', '')));
}
$this->view->form = $form;
}
/**

@ -4,7 +4,6 @@
use Icinga\Web\Controller\BasePreferenceController;
use Icinga\Web\Widget\Tab;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Url;
use Icinga\Form\Preference\GeneralForm;
use Icinga\Web\Notification;
@ -38,23 +37,29 @@ class PreferenceController extends BasePreferenceController
*/
public function indexAction()
{
$form = new GeneralForm();
$this->getTabs()->activate('general');
$form->setConfiguration(IcingaConfig::app())
->setRequest($this->getRequest());
if ($form->isSubmittedAndValid()) {
try {
$this->savePreferences($form->getPreferences());
Notification::success(t('Preferences updated successfully'));
// Recreate form to show new values
// TODO(el): It must sufficient to call $form->populate(...)
$form = new GeneralForm();
$form->setConfiguration(IcingaConfig::app());
$form->setRequest($this->getRequest());
} catch (Exception $e) {
Notification::error(sprintf(t('Failed to persist preferences. (%s)'), $e->getMessage()));
$form = new GeneralForm();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
try {
$this->savePreferences($form->getPreferences()->toArray());
Notification::success($this->translate('Preferences updated successfully'));
$this->redirectNow('preference');
} catch (Exception $e) {
Notification::error(
sprintf(
$this->translate('Failed to persist preferences. (%s)'),
$e->getMessage()
)
);
}
}
} else {
$form->setPreferences($request->getUser()->getPreferences());
}
$this->view->form = $form;
}
}

@ -13,36 +13,47 @@ use Icinga\Web\Url;
class LoginForm extends Form
{
/**
* Interface how the form should be created
* Initialize this login form
*/
protected function create()
public function init()
{
$url = Url::fromRequest()->without('renderLayout');
$this->setName('form_login');
$this->addElement('text', 'username', array(
'label' => t('Username'),
'placeholder' => t('Please enter your username...'),
'required' => true,
));
$redir = $this->addElement('hidden', 'redirect');
$redirectUrl = $url->shift('redirect');
if ($redirectUrl) {
$this->setDefault('redirect', $redirectUrl);
}
$this->setSubmitLabel(t('Login'));
}
$this->addElement('password', 'password', array(
'label' => t('Password'),
'placeholder' => t('...and your password'),
'required' => true
));
// TODO: We need a place to intercept filled forms before rendering
if ($this->getRequest()->getPost('username') !== null) {
$this->getElement('password')->setAttrib('class', 'autofocus');
} else {
$this->getElement('username')->setAttrib('class', 'autofocus');
}
$this->setAction((string) $url);
$this->setSubmitLabel('Login');
/**
* @see Form::createElements()
*/
public function createElements($formData)
{
return array(
$this->createElement(
'text',
'username',
array(
'required' => true,
'label' => t('Username'),
'placeholder' => t('Please enter your username...'),
'class' => false === isset($formData['username']) ? 'autofocus' : ''
)
),
$this->createElement(
'password',
'password',
array(
'required' => true,
'label' => t('Password'),
'placeholder' => t('...and your password'),
'class' => isset($formData['username']) ? 'autofocus' : ''
)
),
$this->createElement(
'hidden',
'redirect',
array(
'value' => Url::fromRequest()->getParam('redirect')
)
)
);
}
}

@ -0,0 +1,89 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Authentication;
use Zend_Validate_Callback;
/**
* Form class for adding/modifying autologin authentication backends
*/
class AutologinBackendForm extends BaseBackendForm
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_authentication_autologin');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
return array(
$this->createElement(
'text',
'name',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Backend Name'),
'helptext' => t('The name of this authentication backend'),
'validators' => array(
array(
'Regex',
false,
array(
'pattern' => '/^[^\\[\\]:]+$/',
'messages' => array(
'regexNotMatch' => 'The backend name cannot contain \'[\', \']\' or \':\'.'
)
)
)
)
)
),
$this->createElement(
'text',
'strip_username_regexp',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Backend Domain Pattern'),
'helptext' => t('The domain pattern of this authentication backend'),
'value' => '/\@[^$]+$/',
'validators' => array(
new Zend_Validate_Callback(function ($value) {
return @preg_match($value, '') !== false;
})
)
)
),
$this->createElement(
'hidden',
'backend',
array(
'required' => true,
'value' => 'autologin'
)
)
);
}
/**
* Validate the configuration state of this backend
*
* Returns just true as autologins are being handled externally by the webserver.
*
* @return true
*/
public function isValidAuthenticationBackend()
{
return true;
}
}

@ -4,11 +4,7 @@
namespace Icinga\Form\Config\Authentication;
use \Zend_Config;
use \Zend_Form_Element_Checkbox;
use Icinga\Web\Form;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Decorator\HelpText;
/**
* Base form for authentication backend forms
@ -16,149 +12,83 @@ use Icinga\Web\Form\Decorator\HelpText;
abstract class BaseBackendForm extends Form
{
/**
* The name of the backend currently displayed in this form
* Return whether the given values are complete/valid and check whether it is possible to connect to the backend
*
* Will be the section in the authentication.ini file
* If connection validation fails, a checkbox is prepended to the form to allow users to skip it.
*
* @var string
*/
protected $backendName = '';
/**
* The backend configuration as a Zend_Config object
* @param array $data The data to validate
*
* @var Zend_Config
*/
protected $backend;
/**
* The resources to use instead of the factory provided ones (use for testing)
*
* @var Zend_Config
*/
protected $resources;
/**
* Set the name of the currently displayed backend
*
* @param string $name The name to be stored as the section when persisting
*/
public function setBackendName($name)
{
$this->backendName = $name;
}
/**
* Return the backend name of this form
*
* @return string
*/
public function getBackendName()
{
return $this->backendName;
}
/**
* Return the backend configuration or a empty Zend_Config object if none is given
*
* @return Zend_Config
*/
public function getBackend()
{
return ($this->backend !== null) ? $this->backend : new Zend_Config(array());
}
/**
* Set the backend configuration for initial population
*
* @param Zend_Config $backend The backend to display in this form
*/
public function setBackend(Zend_Config $backend)
{
$this->backend = $backend;
}
/**
* Set an alternative array of resources that should be used instead of the DBFactory resource set
*
* @param array $resources The resources to use for populating the db selection field
*/
public function setResources(array $resources)
{
$this->resources = $resources;
}
/**
* Return content of the resources.ini or previously set resources
*
* @return array
*/
public function getResources()
{
if ($this->resources === null) {
return ResourceFactory::getResourceConfigs()->toArray();
} else {
return $this->resources;
}
}
/**
* Add checkbox at the beginning of the form which allows to skip logic connection validation
*/
protected function addForceCreationCheckbox()
{
$checkbox = new Zend_Form_Element_Checkbox(
array(
'name' => 'backend_force_creation',
'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation'),
'order' => 0
)
);
$checkbox->addDecorator(new HelpText());
$this->addElement($checkbox);
}
/**
* Validate this form with the Zend validation mechanism and perform a logic validation of the connection.
*
* If logic validation fails, the 'backend_force_creation' checkbox is prepended to the form to allow users to
* skip the logic connection validation.
*
* @param array $data The form input to validate
*
* @return bool Whether validation succeeded or not
* @return bool Whether the validation succeeded or not
*/
public function isValid($data)
{
if (!parent::isValid($data)) {
if (false === parent::isValid($data)) {
return false;
}
if (isset($data['backend_force_creation']) && $data['backend_force_creation']) {
return true;
}
if (!$this->isValidAuthenticationBackend()) {
if (
(false === isset($data['force_creation']) || false === $data['force_creation'])
&& false === $this->isValidAuthenticationBackend()
) {
$this->addForceCreationCheckbox();
return false;
}
return true;
}
/**
* Return an array containing all sections defined by this form as the key and all settings
* as an key-value sub-array
*
* @return array
*/
abstract public function getConfig();
/**
* Validate the configuration state of this backend with the concrete authentication backend.
*
* An implementation should not throw any exception, but use the add/setErrorMessages method of
* Zend_Form. If the 'backend_force_creation' checkbox is set, this method won't be called.
* An implementation should not throw any exception, but use the add/setErrorMessages method
* of Zend_Form. If the 'force_creation' checkbox is set, this method won't be called.
*
* @return bool Whether validation succeeded or not
*/
abstract public function isValidAuthenticationBackend();
/**
* Return the backend's configuration values and its name
*
* The first value is the name and the second one the values as array.
*
* @return array
*/
public function getBackendConfig()
{
$values = $this->getValues();
$name = $values['name'];
unset($values['name']);
return array($name, $values);
}
/**
* Populate the form with the given configuration values
*
* @param string $name The name of the backend
* @param array $config The configuration values
*/
public function setBackendConfig($name, array $config)
{
$config['name'] = $name;
$this->populate($config);
}
/**
* Add a checkbox to be displayed at the beginning of the form
* which allows the user to skip the connection validation
*/
protected function addForceCreationCheckbox()
{
$this->addElement(
'checkbox',
'force_creation',
array(
'order' => 0,
'ignore' => true,
'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation')
)
);
}
}

@ -4,10 +4,9 @@
namespace Icinga\Form\Config\Authentication;
use \Exception;
use \Zend_Config;
use Exception;
use Icinga\Data\ResourceFactory;
use Icinga\Authentication\DbConnection;
use Icinga\Exception\ConfigurationError;
use Icinga\Authentication\Backend\DbUserBackend;
/**
@ -16,89 +15,72 @@ use Icinga\Authentication\Backend\DbUserBackend;
class DbBackendForm extends BaseBackendForm
{
/**
* Return content of the resources.ini or previously set resources
* The available database resources prepared to be used as select input data
*
* @return array
* @var array
*/
public function getResources()
protected $resources;
/**
* Initialize this form
*
* Populates $this->resources.
*
* @throws ConfigurationError In case no database resources can be found
*/
public function init()
{
if ($this->resources === null) {
$res = ResourceFactory::getResourceConfigs('db')->toArray();
$this->setName('form_config_authentication_db');
$this->setSubmitLabel(t('Save Changes'));
foreach (array_keys($res) as $key) {
$res[$key] = $key;
}
$dbResources = array_keys(
ResourceFactory::getResourceConfigs('db')->toArray()
);
return $res;
} else {
return $this->resources;
if (empty($dbResources)) {
throw new ConfigurationError(
t('There are no database resources')
);
}
// array_combine() is necessary in order to use the array as select input data
$this->resources = array_combine($dbResources, $dbResources);
}
/**
* Create this form and add all required elements
*
* @see Form::create()
* @see Form::createElements()
*/
public function create()
public function createElements(array $formData)
{
$this->setName('form_modify_backend');
$name = $this->filterName($this->getBackendName());
$this->addElement(
'text',
'backend_' . $name . '_name',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Backend Name'),
'helptext' => t('The name of this authentication provider'),
'value' => $this->getBackendName()
return array(
$this->createElement(
'text',
'name',
array(
'required' => true,
'label' => t('Backend Name'),
'helptext' => t('The name of this authentication provider'),
)
),
$this->createElement(
'select',
'resource',
array(
'required' => true,
'label' => t('Database Connection'),
'helptext' => t('The database connection to use for authenticating with this provider'),
'multiOptions' => $this->resources
)
),
$this->createElement(
'hidden',
'backend',
array(
'required' => true,
'value' => 'db'
)
)
);
$this->addElement(
'select',
'backend_' . $name . '_resource',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Database Connection'),
'helptext' => t('The database connection to use for authenticating with this provider'),
'value' => $this->getBackend()->get('resource'),
'multiOptions' => $this->getResources()
)
);
$this->addElement(
'button',
'btn_submit',
array(
'type' => 'submit',
'value' => '1',
'escape' => false,
'class' => 'btn btn-cta btn-wide',
'label' => '<i class="icinga-icon-save"></i> Save Backend'
)
);
}
/**
* Return the datatbase authentication backend configuration for this form
*
* @return array
*
* @see BaseBackendForm::getConfig()
*/
public function getConfig()
{
$prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_';
$section = $this->getValue($prefix . 'name');
$cfg = array(
'backend' => 'db',
'resource' => $this->getValue($prefix . 'resource'),
);
return array($section => $cfg);
}
/**
@ -106,23 +88,24 @@ class DbBackendForm extends BaseBackendForm
*
* @return bool Whether validation succeeded or not
*
* @see BaseBackendForm::isValidAuthenticationBackend
* @see BaseBackendForm::isValidAuthenticationBackend()
*/
public function isValidAuthenticationBackend()
{
try {
$testConnection = ResourceFactory::createResource(ResourceFactory::getResourceConfig(
$this->getValue('backend_' . $this->filterName($this->getBackendName()) . '_resource')
$this->getValue('resource')
));
$dbUserBackend = new DbUserBackend($testConnection);
if ($dbUserBackend->count() < 1) {
$this->addErrorMessage(t("No users found under the specified database backend"));
$this->addErrorMessage(t('No users found under the specified database backend'));
return false;
}
} catch (Exception $e) {
$this->addErrorMessage(sprintf(t('Using the specified backend failed: %s'), $e->getMessage()));
return false;
}
return true;
}
}

@ -4,10 +4,9 @@
namespace Icinga\Form\Config\Authentication;
use \Exception;
use \Zend_Config;
use Icinga\Web\Form;
use Exception;
use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError;
use Icinga\Authentication\Backend\LdapUserBackend;
/**
@ -16,154 +15,122 @@ use Icinga\Authentication\Backend\LdapUserBackend;
class LdapBackendForm extends BaseBackendForm
{
/**
* Return content of the resources.ini or previously set resources
* The available ldap resources prepared to be used as select input data
*
* @return array
* @var array
*/
public function getResources()
protected $resources;
/**
* Initialize this form
*
* Populates $this->resources.
*
* @throws ConfigurationError In case no database resources can be found
*/
public function init()
{
if ($this->resources === null) {
$res = ResourceFactory::getResourceConfigs('ldap')->toArray();
$this->setName('form_config_authentication_ldap');
$this->setSubmitLabel(t('Save Changes'));
foreach (array_keys($res) as $key) {
$res[$key] = $key;
}
$ldapResources = array_keys(
ResourceFactory::getResourceConfigs('ldap')->toArray()
);
return $res;
} else {
return $this->resources;
if (empty($ldapResources)) {
throw new ConfigurationError(
t('There are no LDAP resources')
);
}
// array_combine() is necessary in order to use the array as select input data
$this->resources = array_combine($ldapResources, $ldapResources);
}
/**
* Create this form and add all required elements
*
* @see Form::create()
* @see Form::createElements()
*/
public function create()
public function createElements(array $formData)
{
$this->setName('form_modify_backend');
$name = $this->filterName($this->getBackendName());
$backend = $this->getBackend();
$this->addElement(
'text',
'backend_' . $name . '_name',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Backend Name'),
'helptext' => t('The name of this authentication backend'),
'value' => $this->getBackendName()
)
);
$this->addElement(
'select',
'backend_' . $name . '_resource',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('LDAP Resource'),
'helptext' => t('The resource to use for authenticating with this provider'),
'value' => $this->getBackend()->get('resource'),
'multiOptions' => $this->getResources()
)
);
$this->addElement(
'text',
'backend_' . $name . '_user_class',
array(
'required' => true,
'label' => t('LDAP User Object Class'),
'helptext' => t('The object class used for storing users on the ldap server'),
'value' => $backend->get('user_class', 'inetOrgPerson')
)
);
$this->addElement(
'text',
'backend_' . $name . '_user_name_attribute',
array(
'required' => true,
'label' => t('LDAP User Name Attribute'),
'helptext' => t('The attribute name used for storing the user name on the ldap server'),
'value' => $backend->get('user_name_attribute', 'uid')
)
);
$this->addElement(
'button',
'btn_submit',
array(
'type' => 'submit',
'value' => '1',
'escape' => false,
'class' => 'btn btn-cta btn-wide',
'label' => '<i class="icinga-icon-save"></i> Save Backend'
return array(
$this->createElement(
'text',
'name',
array(
'required' => true,
'label' => t('Backend Name'),
'helptext' => t('The name of this authentication backend')
)
),
$this->createElement(
'select',
'resource',
array(
'required' => true,
'label' => t('LDAP Resource'),
'helptext' => t('The resource to use for authenticating with this provider'),
'multiOptions' => $this->resources
)
),
$this->createElement(
'text',
'user_class',
array(
'required' => true,
'label' => t('LDAP User Object Class'),
'helptext' => t('The object class used for storing users on the ldap server'),
'value' => 'inetOrgPerson'
)
),
$this->createElement(
'text',
'user_name_attribute',
array(
'required' => true,
'label' => t('LDAP User Name Attribute'),
'helptext' => t('The attribute name used for storing the user name on the ldap server'),
'value' => 'uid'
)
),
$this->createElement(
'hidden',
'backend',
array(
'required' => true,
'value' => 'ldap'
)
)
);
}
/**
* Return the ldap authentication backend configuration for this form
*
* @return array
*
* @see BaseBackendForm::getConfig()
*/
public function getConfig()
{
$prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_';
$section = $this->getValue($prefix . 'name');
$cfg = array(
'backend' => 'ldap',
'resource' => $this->getValue($prefix . 'resource'),
'user_class' => $this->getValue($prefix . 'user_class'),
'user_name_attribute' => $this->getValue($prefix . 'user_name_attribute')
);
return array($section => $cfg);
}
/**
* Validate the current configuration by creating a backend and requesting the user count
* Validate the current configuration by connecting to a backend and requesting the user count
*
* @return bool Whether validation succeeded or not
*
* @see BaseBackendForm::isValidAuthenticationBacken
* @see BaseBackendForm::isValidAuthenticationBacken()
*/
public function isValidAuthenticationBackend()
{
if (! ResourceFactory::ldapAvailable()) {
/*
* It should be possible to run icingaweb without the php ldap extension, when
* no ldap backends are needed. When the user tries to create an ldap backend
* without ldap installed we need to show him an error.
*/
if (false === ResourceFactory::ldapAvailable()) {
// It should be possible to run icingaweb without the php ldap extension. When the user
// tries to create an ldap backend without ldap being installed we display an error.
$this->addErrorMessage(t('Using ldap is not possible, the php extension "ldap" is not installed.'));
return false;
}
try {
$cfg = $this->getConfig();
$backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name';
$backendConfig = new Zend_Config($cfg[$this->getValue($backendName)]);
$backend = ResourceFactory::createResource(ResourceFactory::getResourceConfig($backendConfig->resource));
$backend = ResourceFactory::createResource(
ResourceFactory::getResourceConfig($this->getValue('resource'))
);
$testConn = new LdapUserBackend(
$backend,
$backendConfig->user_class,
$backendConfig->user_name_attribute
$this->getValue('user_class'),
$this->getValue('user_name_attribute')
);
$testConn->assertAuthenticationPossible();
/*
if ($testConn->count() === 0) {
throw new Exception('No Users Found On Directory Server');
}
*/
} catch (Exception $exc) {
$this->addErrorMessage(
t('Connection Validation Failed: ' . $exc->getMessage())
);
$this->addErrorMessage(sprintf(t('Connection validation failed: %s'), $exc->getMessage()));
return false;
}

@ -1,233 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Authentication;
use \Zend_Config;
use Icinga\Web\Form;
/**
* Form for modifying the authentication provider order
*/
class ReorderForm extends Form
{
/**
* The name of the current backend which will get action buttons for up and down movement
*
* @var string
*/
protected $backend;
/**
* The current ordering of all backends, required to determine possible changes
*
* @var array
*/
protected $currentOrder = array();
/**
* Set an array with the current order of all backends
*
* @param array $order An array containing backend names in the order
* they are defined in the authentication.ini
*/
public function setCurrentOrder(array $order)
{
$this->currentOrder = $order;
}
/**
* Set the name of the authentication backend for which to create the form
*
* @param string $backend The name of the authentication backend
*/
public function setBackendName($backend)
{
$this->backend = $backend;
}
/**
* Return the name of the currently set backend as it will appear in the form
*
* @return string The name of the backend
*/
public function getBackendName()
{
return $this->filterName($this->backend);
}
/**
* Create this form
*
* @see Form::create
*/
public function create()
{
if ($this->moveElementUp($this->backend, $this->currentOrder) !== $this->currentOrder) {
$upForm = new Form();
$upForm->addElement(
'hidden',
'form_backend_order',
array(
'required' => true,
'value' => join(',', $this->moveElementUp($this->backend, $this->currentOrder))
)
);
$upForm->addElement(
'button',
'btn_' . $this->getBackendName() . '_reorder_up',
array(
'type' => 'submit',
'escape' => false,
'value' => 'btn_' . $this->getBackendName() . '_reorder_up',
'name' => 'btn_' . $this->getBackendName() . '_reorder_up',
'label' => $this->getView()->icon('up.png', t('Move up in authentication order'))
)
);
$this->addSubForm($upForm, 'btn_reorder_up');
}
if ($this->moveElementDown($this->backend, $this->currentOrder) !== $this->currentOrder) {
$downForm = new Form();
$downForm->addElement(
'hidden',
'form_backend_order',
array(
'required' => true,
'value' => join(',', $this->moveElementDown($this->backend, $this->currentOrder))
)
);
$downForm->addElement(
'button',
'btn_' . $this->getBackendName() . '_reorder_down',
array(
'type' => 'submit',
'escape' => false,
'value' => 'btn_' . $this->getBackendName() . '_reorder_down',
'name' => 'btn_' . $this->getBackendName() . '_reorder_down',
'label' => $this->getView()->icon('down.png', t('Move down in authentication order'))
)
);
$this->addSubForm($downForm, 'btn_reorder_down');
}
}
/**
* Return the flattened result of $this->getValues
*
* @return array The currently set values
*
* @see Form::getValues()
*/
protected function getFlattenedValues()
{
$result = array();
foreach (parent::getValues() as $key => $value) {
if (is_array($value)) {
$result += $value;
} else {
$result[$key] = $value;
}
}
return $result;
}
/**
* Determine whether this form is submitted by testing the submit buttons of both subforms
*
* @return bool Whether the form has been submitted or not
*/
public function isSubmitted()
{
$checkData = $this->getRequest()->getParams();
return isset($checkData['btn_' . $this->getBackendName() . '_reorder_up']) ||
isset($checkData['btn_' . $this->getBackendName() . '_reorder_down']);
}
/**
* Return the reordered configuration after a reorder button has been submitted
*
* @param Zend_Config $config The configuration to reorder
*
* @return array An array containing the reordered configuration
*/
public function getReorderedConfig(Zend_Config $config)
{
$originalConfig = $config->toArray();
$newOrder = $this->getFlattenedValues();
$order = explode(',', $newOrder['form_backend_order']);
$reordered = array();
foreach ($order as $key) {
if (isset($originalConfig[$key])) {
$reordered[$key] = $originalConfig[$key];
}
}
return $reordered;
}
/**
* Static helper for moving an element in an array one slot up, if possible
*
* Example:
*
* <pre>
* $array = array('first', 'second', 'third');
* moveElementUp('third', $array); // returns ['first', 'third', 'second']
* </pre>
*
* @param string $key The key to bubble up one slot
* @param array $array The array to work with
*
* @return array The modified array
*/
protected static function moveElementUp($key, array $array)
{
for ($i = 0; $i < count($array) - 1; $i++) {
if ($array[$i + 1] === $key) {
$swap = $array[$i];
$array[$i] = $array[$i + 1];
$array[$i + 1] = $swap;
return $array;
}
}
return $array;
}
/**
* Static helper for moving an element in an array one slot down, if possible
*
* Example:
*
* <pre>
* $array = array('first', 'second', 'third');
* moveElementDown('first', $array); // returns ['second', 'first', 'third']
* </pre>
*
* @param string $key The key to bubble up one slot
* @param array $array The array to work with
*
* @return array The modified array
*/
protected static function moveElementDown($key, array $array)
{
for ($i = 0; $i < count($array) - 1; $i++) {
if ($array[$i] === $key) {
$swap = $array[$i + 1];
$array[$i + 1] = $array[$i];
$array[$i] = $swap;
return $array;
}
}
return $array;
}
}

@ -12,58 +12,11 @@ use Icinga\Web\Form;
class ConfirmRemovalForm extends Form
{
/**
* The value of the target to remove
*
* @var string
* Initalize this form
*/
private $removeTarget;
/**
* The name of the target parameter to remove
*
* @var string
*/
private $targetName;
/**
* Set the remove target in this field to be a hidden field with $name and value $target
*
* @param string $name The name to be set in the hidden field
* @param string $target The value to be set in the hidden field
*/
public function setRemoveTarget($name, $target)
{
$this->targetName = $name;
$this->removeTarget = $target;
}
/**
* Create the confirmation form
*
* @see Form::create()
*/
public function create()
public function init()
{
$this->setName('form_confirm_removal');
$this->addElement(
'hidden',
$this->targetName,
array(
'value' => $this->removeTarget,
'required' => true
)
);
$this->addElement(
'button',
'btn_submit',
array(
'type' => 'submit',
'escape' => false,
'value' => '1',
'class' => 'btn btn-cta btn-common',
'label' => '<i class="icinga-icon-remove"></i> Confirm Removal'
)
);
$this->setSubmitLabel(t('Confirm Removal'));
}
}

@ -4,15 +4,13 @@
namespace Icinga\Form\Config;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Data\ResourceFactory;
use DateTimeZone;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Util\Translator;
use Icinga\Application\Icinga;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Validator\WritablePathValidator;
use Icinga\Web\Form\Decorator\ConditionalHidden;
use DateTimeZone;
use Zend_Form_Element_Select;
use Zend_Config;
/**
* Configuration form for general, application-wide settings
@ -20,251 +18,295 @@ use Zend_Config;
class GeneralForm extends Form
{
/**
* The base directory of the icingaweb configuration
*
* @var string
* Initialize this configuration form
*/
private $configDir = null;
/**
* The resources to use instead of the factory provided ones (use for testing)
*
* @var null
*/
private $resources;
/**
* Set a specific configuration directory to use for configuration specific default paths
*
* @param string $dir
*/
public function setConfigDir($dir)
public function init()
{
$this->configDir = $dir;
$this->setName('form_config_general');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* Return the config path set for this form or the application wide config path if none is set
*
* @return string
*
* @see IcingaConfig::configDir
* @see Form::createElements()
*/
public function getConfigDir()
public function createElements(array $formData)
{
return $this->configDir === null ? IcingaConfig::$configDir : $this->configDir;
$elements = array(
$this->getLanguageSelection(),
$this->getTimezoneSelection(),
$this->getModulePathInput()
);
return array_merge(
$elements,
$this->getPreferencesElements($formData),
$this->getLoggingElements($formData)
);
}
/**
* Set an alternative array of resources that should be used instead of the DBFactory resource set
* (used for testing)
* Populate this form with the given configuration
*
* @param array $resources The resources to use for populating the db selection field
*/
public function setResources(array $resources)
{
$this->resources = $resources;
}
/**
* Return content of the resources.ini or previously set resources for displaying in the database selection field
* @param Zend_Config $config The configuration to populate this form with
*
* @return array
* @return self
*/
public function getResources()
public function setConfiguration(Zend_Config $config)
{
if ($this->resources === null) {
return ResourceFactory::getResourceConfigs()->toArray();
} else {
return $this->resources;
$defaults = array();
foreach ($config as $section => $properties) {
foreach ($properties as $name => $value) {
$defaults[$section . '_' . $name] = $value;
}
}
$this->populate($defaults);
return $this;
}
/**
* Add a select field for setting the default language
* Return the configured configuration values
*
* @return Zend_Config
*/
public function getConfiguration()
{
$config = array();
$values = $this->getValues();
foreach ($values as $sectionAndPropertyName => $value) {
list($section, $property) = explode('_', $sectionAndPropertyName);
$config[$section][$property] = $value;
}
return new Zend_Config($config);
}
/**
* Return a select field for setting the default language
*
* Possible values are determined by Translator::getAvailableLocaleCodes.
*
* @param Zend_Config $cfg The "global" section of the config.ini
* @return Zend_Form_Element
*/
private function addLanguageSelection(Zend_Config $cfg)
protected function getLanguageSelection()
{
$languages = array();
foreach (Translator::getAvailableLocaleCodes() as $language) {
$languages[$language] = $language;
}
$this->addElement(
return $this->createElement(
'select',
'language',
'global_language',
array(
'label' => t('Default Language'),
'required' => true,
'multiOptions' => $languages,
'helptext' => t(
'Select the language to use by default. Can be overwritten by a user in his preferences.'
),
'value' => $cfg->get('language', Translator::DEFAULT_LOCALE)
)
)
);
}
/**
* Add a select field for setting the default timezone.
* Return a select field for setting the default timezone
*
* Possible values are determined by DateTimeZone::listIdentifiers
* Possible values are determined by DateTimeZone::listIdentifiers.
*
* @param Zend_Config $cfg The "global" section of the config.ini
* @return Zend_Form_Element
*/
private function addTimezoneSelection(Zend_Config $cfg)
protected function getTimezoneSelection()
{
$tzList = array();
foreach (DateTimeZone::listIdentifiers() as $tz) {
$tzList[$tz] = $tz;
}
$helptext = 'Select the timezone to be used as the default. User\'s can set their own timezone if'
. ' they like to, but this is the timezone to be used as the default setting .';
$this->addElement(
'select',
'timezone',
'global_timezone',
array(
'label' => 'Default Application Timezone',
'required' => true,
'multiOptions' => $tzList,
'helptext' => $helptext,
'value' => $cfg->get('timezone', date_default_timezone_get())
'label' => t('Default Application Timezone'),
'required' => true,
'multiOptions' => $tzList,
'helptext' => t(
'Select the timezone to be used as the default. User\'s can set their own timezone if'
. ' they like to, but this is the timezone to be used as the default setting .'
),
'value' => date_default_timezone_get()
)
);
}
/**
* Add configuration settings for module paths
*
* @param Zend_Config $cfg The "global" section of the config.ini
* Return a input field for setting the module path
*/
private function addModuleSettings(Zend_Config $cfg)
protected function getModulePathInput()
{
$this->addElement(
'text',
'module_path',
'global_modulePath',
array(
'label' => 'Module Path',
'label' => t('Module Path'),
'required' => true,
'helptext' => 'Contains the directories that will be searched for available modules, separated by ' .
' colons. Modules that don\'t exist in these directories can still be symlinked in the module ' .
' folder, but won\'t show up in the list of disabled modules.',
'value' => $cfg->get('modulePath', realpath(ICINGAWEB_APPDIR . '/../modules'))
'helptext' => t(
'Contains the directories that will be searched for available modules, separated by '
. 'colons. Modules that don\'t exist in these directories can still be symlinked in '
. 'the module folder, but won\'t show up in the list of disabled modules.'
),
'value' => realpath(ICINGAWEB_APPDIR . '/../modules')
)
);
}
/**
* Add form elements for setting the user preference storage backend
* Return form elements for setting the user preference storage backend
*
* @param Zend_Config $cfg The Zend_config object of preference section
* @param array $formData The data sent by the user
*/
public function addUserPreferencesDialog(Zend_Config $cfg)
protected function getPreferencesElements(array $formData)
{
$backend = $cfg->get('type', 'ini');
if ($this->getRequest()->get('preferences_type', null) !== null) {
$backend = $this->getRequest()->get('preferences_type');
}
$this->addElement(
'select',
'preferences_type',
array(
'label' => 'User Preference Storage Type',
'required' => true,
'value' => $backend,
'multiOptions' => array(
'ini' => 'File System (INI Files)',
'db' => 'Database',
'null' => 'Don\'t Store Preferences'
$elements = array(
$this->createElement(
'select',
'preferences_type',
array(
'required' => true,
'class' => 'autosubmit',
'label' => t('User Preference Storage Type'),
'multiOptions' => array(
'ini' => t('File System (INI Files)'),
'db' => t('Database'),
'null' => t('Don\'t Store Preferences')
)
)
)
);
$backends = array();
foreach ($this->getResources() as $name => $resource) {
if ($resource['type'] !== 'db') {
continue;
if (isset($formData['preferences_type']) && $formData['preferences_type'] === 'db') {
$backends = array();
foreach (ResourceFactory::getResourceConfigs()->toArray() as $name => $resource) {
if ($resource['type'] === 'db') {
$backends[$name] = $name;
}
}
$backends[$name] = $name;
$elements[] = $this->createElement(
'select',
'preferences_resource',
array(
'required' => true,
'multiOptions' => $backends,
'label' => t('Database Connection')
)
);
}
$txtPreferencesDbResource = new Zend_Form_Element_Select(
array(
'name' => 'preferences_db_resource',
'label' => 'Database Connection',
'required' => $backend === 'db',
'condition' => $backend === 'db',
'value' => $cfg->get('resource'),
'multiOptions' => $backends
)
);
$validator = new WritablePathValidator();
$validator->setRequireExistence();
$this->addElement($txtPreferencesDbResource);
$txtPreferencesDbResource->addDecorator(new ConditionalHidden());
$this->enableAutoSubmit(
array(
'preferences_type'
)
);
return $elements;
}
/**
* Create the general form, using the provided configuration
* Return form elements to setup the application's logging
*
* @see Form::create()
* @param array $formData The data sent by the user
*
* @return array
*/
public function create()
protected function getLoggingElements(array $formData)
{
$config = $this->getConfiguration();
$global = $config->global;
if ($global === null) {
$global = new Zend_Config(array());
}
$preferences = $config->preferences;
if ($preferences === null) {
$preferences = new Zend_Config(array());
}
$this->setName('form_config_general');
$this->addLanguageSelection($global);
$this->addTimezoneSelection($global);
$this->addModuleSettings($global);
$this->addUserPreferencesDialog($preferences);
$elements = array();
$this->setSubmitLabel('Save Changes');
$elements[] = $this->createElement(
'select',
'logging_level',
array(
'required' => true,
'label' => t('Logging Level'),
'helptext' => t('The maximum loglevel to emit.'),
'multiOptions' => array(
0 => t('None'),
1 => t('Error'),
2 => t('Warning'),
3 => t('Information'),
4 => t('Debug')
)
)
);
$elements[] = $this->createElement(
'select',
'logging_type',
array(
'required' => true,
'class' => 'autosubmit',
'label' => t('Logging Type'),
'helptext' => t('The type of logging to utilize.'),
'multiOptions' => array(
'syslog' => 'Syslog',
'file' => t('File')
)
)
);
if (false === isset($formData['logging_type']) || $formData['logging_type'] === 'syslog') {
$elements[] = $this->createElement(
'text',
'logging_application',
array(
'required' => true,
'label' => t('Application Prefix'),
'helptext' => t('The name of the application by which to prefix syslog messages.'),
'value' => 'icingaweb',
'validators' => array(
array(
'Regex',
false,
array(
'pattern' => '/^[^\W]+$/',
'messages' => array(
'regexNotMatch' => 'The application prefix cannot contain any whitespaces.'
)
)
)
)
)
);
$elements[] = $this->createElement(
'select',
'logging_facility',
array(
'required' => true,
'label' => t('Facility'),
'helptext' => t('The Syslog facility to utilize.'),
'multiOptions' => array(
'LOG_USER' => 'LOG_USER'
)
)
);
} elseif ($formData['logging_type'] === 'file') {
$elements[] = $this->createElement(
'text',
'logging_target',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('The logfile to write messages to.'),
'value' => $this->getDefaultLogDir(),
'validators' => array(new WritablePathValidator())
)
);
}
return $elements;
}
/**
* Return an Zend_Config object containing the configuration set in this form
* Return the default logging directory for type "file"
*
* @return Zend_Config
* @return string
*/
public function getConfig()
protected function getDefaultLogDir()
{
$config = $this->getConfiguration();
if ($config->global === null) {
$config->global = new Zend_Config(array(), true);
}
if ($config->preferences === null) {
$config->preferences = new Zend_Config(array(), true);
}
$values = $this->getValues();
$cfg = clone $config;
$cfg->global->language = $values['language'];
$cfg->global->timezone = $values['timezone'];
$cfg->global->modulePath = $values['module_path'];
$cfg->preferences->type = $values['preferences_type'];
if ($cfg->preferences->type === 'db') {
$cfg->preferences->resource = $values['preferences_db_resource'];
}
return $cfg;
return realpath(Icinga::app()->getApplicationDir('../var/log/icingaweb.log'));
}
}

@ -1,178 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config;
use \Zend_Config;
use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Web\Form\Validator\WritablePathValidator;
/**
* Form class for setting the application wide logging configuration
*/
class LoggingForm extends Form
{
/**
* Return the default logging directory for type "file"
*
* @return string
*/
protected function getDefaultLogDir()
{
return realpath(Icinga::app()->getApplicationDir() . '/../var/log/icingaweb.log');
}
/**
* Create this logging configuration form
*
* @see Form::create()
*/
public function create()
{
$this->setName('form_config_logging');
$config = $this->getConfiguration();
if (($loggingConfig = $config->logging) === null) {
$loggingConfig = new Zend_Config(array());
}
$this->addElement(
'checkbox',
'logging_enable',
array(
'required' => true,
'label' => t('Logging Enabled'),
'helptext' => t('Check this to enable logging.'),
'value' => $loggingConfig->enable ? 1 : 0
)
);
$this->addElement(
'select',
'logging_level',
array(
'required' => true,
'label' => t('Logging Level'),
'helptext' => t('The maximum loglevel to emit.'),
'value' => intval($loggingConfig->get('level', 0)),
'multiOptions' => array(
0 => t('Error'),
1 => t('Warning'),
2 => t('Information'),
3 => t('Debug')
)
)
);
$this->addElement(
'select',
'logging_type',
array(
'required' => true,
'label' => t('Logging Type'),
'helptext' => t('The type of logging to utilize.'),
'value' => $loggingConfig->get('type', 'file'),
'multiOptions' => array(
'file' => t('File'),
'syslog' => 'Syslog'
)
)
);
$this->enableAutoSubmit(array('logging_type'));
switch ($this->getRequest()->getParam('logging_type', $loggingConfig->get('type', 'file')))
{
case 'syslog':
$this->addElement(
'text',
'logging_application',
array(
'required' => true,
'label' => t('Application Prefix'),
'helptext' => t('The name of the application by which to prefix syslog messages.'),
'value' => $loggingConfig->get('application', 'icingaweb'),
'validators' => array(
array(
'Regex',
false,
array(
'pattern' => '/^[^\W]+$/',
'messages' => array(
'regexNotMatch' => 'The application prefix cannot contain any whitespaces.'
)
)
)
)
)
);
$this->addElement(
'select',
'logging_facility',
array(
'required' => true,
'label' => t('Facility'),
'helptext' => t('The Syslog facility to utilize.'),
'value' => $loggingConfig->get('facility', 'LOG_USER'),
'multiOptions' => array(
'LOG_USER' => 'LOG_USER'
)
)
);
break;
case 'file':
default:
$this->addElement(
'text',
'logging_target',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('The logfile to write messages to.'),
'value' => $loggingConfig->target ? $loggingConfig->target : $this->getDefaultLogDir(),
'validators' => array(new WritablePathValidator())
)
);
}
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
}
public function isValid($data) {
foreach ($this->getElements() as $key => $element) {
// Initialize all empty elements with their default values.
if (!isset($data[$key])) {
$data[$key] = $element->getValue();
}
}
return parent::isValid($data);
}
/**
* Return a Zend_Config object containing the state defined in this form
*
* @return Zend_Config The config defined in this form
*/
public function getConfig()
{
$values = $this->getValues();
$cfg = $this->getConfiguration()->toArray();
$cfg['logging']['enable'] = $values['logging_enable'] == 1;
$cfg['logging']['level'] = $values['logging_level'];
switch ($values['logging_type'])
{
case 'file':
$cfg['logging']['type'] = 'file';
$cfg['logging']['target'] = $values['logging_target'];
break;
case 'syslog':
$cfg['logging']['type'] = 'syslog';
$cfg['logging']['application'] = $values['logging_application'];
$cfg['logging']['facility'] = $values['logging_facility'];
break;
}
return new Zend_Config($cfg);
}
}

@ -6,350 +6,47 @@ namespace Icinga\Form\Config;
use Exception;
use Zend_Config;
use Zend_Form_Element_Checkbox;
use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Element\Number;
use Icinga\Web\Form\Decorator\HelpText;
use Icinga\Web\Form\Decorator\ElementWrapper;
class ResourceForm extends Form
{
/**
* The resource
*
* @var Zend_Config
* Initialize this form
*/
protected $resource;
/**
* The (new) name of the resource
*
* @var string
*/
protected $name;
/**
* The old name of the resource
*
* @var string
*/
protected $oldName;
/**
* Set the current resource name
*
* @param string $name The name to set
*/
public function setName($name)
public function init()
{
$this->name = $name;
$this->setName('form_config_resource');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* Get the current resource name
*
* @return null|string
* @see Form::createElemeents()
*/
public function getName()
public function createElements(array $formData)
{
$name = $this->getValue('resource_all_name');
if (!$name) {
return $this->name;
}
return $name;
}
/**
* Set the original name of the resource
*
* @param string $name The name to set
*/
public function setOldName($name)
{
$this->oldName = $name;
}
/**
* Get the resource name that was initially set
*
* @return null|string
*/
public function getOldName()
{
$oldName = $this->getValue('resource_all_name_old');
if (!$oldName) {
return $this->oldName;
}
return $oldName;
}
/**
* Set the resource configuration to edit.
*
* @param Zend_Config $resource The config to set
*/
public function setResource(Zend_Config $resource)
{
$this->resource = $resource;
}
/**
* Get the current resource configuration.
*
* @return Zend_Config
*/
public function getResource()
{
if (!isset($this->resource)) {
$this->resource = new Zend_Config(array('type' => 'db'));
}
return $this->resource;
}
protected function addDbForm()
{
$this->addElement(
'select',
'resource_db_db',
array(
'required' => true,
'label' => t('Database Type'),
'helptext' => t('The type of SQL database you want to create.'),
'value' => $this->getResource()->get('db', 'mysql'),
'multiOptions' => array(
'mysql' => 'MySQL',
'pgsql' => 'PostgreSQL'
//'oracle' => 'Oracle'
)
)
);
$this->addElement(
$elements = array();
$elements[] = $this->createElement(
'text',
'resource_db_host',
array (
'required' => true,
'label' => t('Host'),
'helptext' => t('The hostname of the database.'),
'value' => $this->getResource()->get('host', 'localhost')
)
);
$this->addElement(
new Number(
array(
'name' => 'resource_db_port',
'required' => true,
'label' => t('Port'),
'helptext' => t('The port to use.'),
'value' => $this->getResource()->get('port', 3306)
)
)
);
$this->addElement(
'text',
'resource_db_dbname',
array(
'required' => true,
'label' => t('Database Name'),
'helptext' => t('The name of the database to use'),
'value' => $this->getResource()->get('dbname', '')
)
);
$this->addElement(
'text',
'resource_db_username',
array (
'required' => true,
'label' => t('Username'),
'helptext' => t('The user name to use for authentication.'),
'value' => $this->getResource()->get('username', '')
)
);
$this->addElement(
'password',
'resource_db_password',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Password'),
'helptext' => t('The password to use for authentication'),
'value' => $this->getResource()->get('password', '')
)
);
}
protected function addStatusdatForm()
{
$this->addElement(
'text',
'resource_statusdat_status_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga status.dat file'),
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/status.dat')
)
);
$this->addElement(
'text',
'resource_statusdat_object_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga objects.cache file'),
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/objects.cache')
)
);
}
protected function addLivestatusForm()
{
$this->addElement(
'text',
'resource_livestatus_socket',
array(
'required' => true,
'label' => t('Socket'),
'helptext' => t('The path to your livestatus socket used for querying monitoring data'),
'value' => $this->getResource()->get('socket', '/usr/local/icinga/var/rw/livestatus')
)
);
}
protected function addLdapForm()
{
$this->addElement(
'text',
'resource_ldap_hostname',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Host'),
'helptext' => t('The hostname or address of the LDAP server to use for authentication'),
'value' => $this->getResource()->get('hostname', 'localhost')
)
);
$this->addElement(
'text',
'resource_ldap_root_dn',
array(
'required' => true,
'label' => t('Root DN'),
'helptext' => t('The path where users can be found on the ldap server'),
'value' => $this->getResource()->get('root_dn', 'ou=people,dc=icinga,dc=org')
)
);
$this->addElement(
'text',
'resource_ldap_bind_dn',
array(
'required' => true,
'label' => t('Bind DN'),
'helptext' => t('The user dn to use for querying the ldap server'),
'value' => $this->getResource()->get('bind_dn', 'cn=admin,cn=config')
)
);
$this->addElement(
'password',
'resource_ldap_bind_pw',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Bind Password'),
'helptext' => t('The password to use for querying the ldap server'),
'value' => $this->getResource()->get('bind_pw', '')
)
);
}
protected function addFileForm()
{
$this->addElement(
'text',
'resource_file_filename',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('The filename to fetch information from'),
'value' => $this->getResource()->get('filename', '')
)
);
$this->addElement(
'text',
'resource_file_fields',
array(
'required' => true,
'label' => t('Pattern'),
'helptext' => t('The regular expression by which to identify columns'),
'value' => $this->getResource()->get('fields', '')
)
);
}
protected function addNameFields()
{
$this->addElement(
'text',
'resource_all_name',
'name',
array(
'required' => true,
'label' => t('Resource Name'),
'helptext' => t('The unique name of this resource'),
'value' => $this->getName()
'helptext' => t('The unique name of this resource')
)
);
$this->addElement(
'hidden',
'resource_all_name_old',
array(
'value' => $this->getOldName()
)
);
}
/**
* Add checkbox at the beginning of the form which allows to skip connection validation
*/
protected function addForceCreationCheckbox()
{
$checkbox = new Zend_Form_Element_Checkbox(
array(
'order' => 0,
'name' => 'resource_force_creation',
'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation')
)
);
$checkbox->addDecorator(new HelpText());
$this->addElement($checkbox);
}
/**
* Add a select box for choosing the type to use for this backend
*/
protected function addTypeSelectionBox()
{
$this->addElement(
$elements[] = $this->createElement(
'select',
'resource_type',
'type',
array(
'required' => true,
'class' => 'autosubmit',
'label' => t('Resource Type'),
'helptext' => t('The type of resource'),
'value' => $this->getResource()->type,
'multiOptions' => array(
'db' => t('SQL Database'),
'ldap' => 'LDAP',
@ -359,60 +56,76 @@ class ResourceForm extends Form
)
)
);
$this->enableAutoSubmit(array('resource_type'));
if (isset($formData['force_creation']) && $formData['force_creation']) {
// In case the resource name already exists and the checkbox was displayed before
$elements[] = $this->getForceCreationCheckbox();
}
if (false === isset($formData['type']) || $formData['type'] === 'db') {
return array_merge($elements, $this->getDbElements());
} elseif ($formData['type'] === 'statusdat') {
return array_merge($elements, $this->getStatusdatElements());
} elseif ($formData['type'] === 'livestatus') {
return array_merge($elements, $this->getLivestatusElements());
} elseif ($formData['type'] === 'ldap') {
return array_merge($elements, $this->getLdapElements());
} elseif ($formData['type'] === 'file') {
return array_merge($elements, $this->getFileElements());
}
}
/**
* Validate this form with the Zend validation mechanism and perform a validation of the connection
* Return whether the given values are complete/valid and check whether it is possible to connect to the resource
*
* If validation fails, the 'resource_force_creation' checkbox is prepended to the form to allow users to
* skip the connection validation
* If connection validation fails, a checkbox is prepended to the form to allow users to skip it.
*
* @param array $data The form input to validate
* @param array $data The data to validate
*
* @return bool True when validation succeeded, false if not
* @return bool Whether the validation succeeded or not
*/
public function isValid($data)
{
if (!parent::isValid($data)) {
if (false === parent::isValid($data)) {
return false;
}
if (isset($data['resource_force_creation']) && $data['resource_force_creation']) {
return true;
}
if (!$this->isValidResource()) {
$this->addForceCreationCheckbox();
if (
(false === isset($data['force_creation']) || false == $data['force_creation'])
&& false === $this->isValidResource()
) {
$this->addElement($this->getForceCreationCheckbox());
return false;
}
return true;
}
/**
* Test if the changed resource is a valid resource, by instantiating it and
* checking if a connection is possible
* Return whether a connection can be established with the current resource configuration values
*
* @return bool True when a connection to the resource is possible
* @return bool Whether the connection validation was successful or not
*/
public function isValidResource()
{
$config = $this->getConfig();
list($name, $config) = $this->getResourceConfig();
try {
switch ($config->type) {
switch ($config['type']) {
case 'db':
/*
* It should be possible to run icingaweb without the pgsql or mysql extension or Zend-Pdo-Classes,
* in case they aren't actually used. When the user tries to create a resource that depends on an
* uninstalled extension, an error should be displayed.
*/
if ($config->db === 'mysql' && !ResourceFactory::mysqlAvailable()) {
if ($config['db'] === 'mysql' && false === ResourceFactory::mysqlAvailable()) {
$this->addErrorMessage(
t('You need to install the php extension "mysql" and the ' .
'Zend_Pdo_Mysql classes to use MySQL database resources.')
);
return false;
}
if ($config->db === 'pgsql' && !ResourceFactory::pgsqlAvailable()) {
if ($config['db'] === 'pgsql' && false === ResourceFactory::pgsqlAvailable()) {
$this->addErrorMessage(
t('You need to install the php extension "pgsql" and the ' .
'Zend_Pdo_Pgsql classes to use PostgreSQL database resources.')
@ -420,30 +133,31 @@ class ResourceForm extends Form
return false;
}
$resource = ResourceFactory::createResource($config);
$resource = ResourceFactory::createResource(new Zend_Config($config));
$resource->getConnection()->getConnection();
break;
case 'statusdat':
if (!file_exists($config->object_file) || !file_exists($config->status_file)) {
if (
false === file_exists($config['object_file'])
|| false === file_exists($config['status_file'])
) {
$this->addErrorMessage(
t('Connectivity validation failed, the provided file does not exist.')
t('Connectivity validation failed. At least one of the provided files does not exist.')
);
return false;
}
break;
case 'livestatus':
$resource = ResourceFactory::createResource($config);
$resource = ResourceFactory::createResource(new Zend_Config($config));
$resource->connect()->disconnect();
break;
case 'ldap':
$resource = ResourceFactory::createResource($config);
$resource = ResourceFactory::createResource(new Zend_Config($config));
$resource->connect();
break;
case 'file':
if (!file_exists($config->filename)) {
$this->addErrorMessage(
t('Connectivity validation failed, the provided file does not exist.')
);
if (false === file_exists($config['filename'])) {
$this->addErrorMessage(t('Connectivity validation failed. The provided file does not exist.'));
return false;
}
break;
@ -456,51 +170,274 @@ class ResourceForm extends Form
return true;
}
public function create()
/**
* Return the resource configuration values and its name
*
* The first value is the name and the second one the values as array.
*
* @return array
*/
public function getResourceConfig()
{
$this->addNameFields();
$this->addTypeSelectionBox();
switch ($this->getRequest()->getParam('resource_type', $this->getResource()->type)) {
case 'db':
$this->addDbForm();
break;
case 'statusdat':
$this->addStatusdatForm();
break;
case 'livestatus':
$this->addLivestatusForm();
break;
case 'ldap':
$this->addLdapForm();
break;
case 'file':
$this->addFileForm();
break;
}
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
$values = $this->getValues();
$name = $values['name'];
unset($values['name']);
return array($name, $values);
}
/**
* Return a configuration containing the backend settings entered in this form
* Populate the form with the given configuration values
*
* @return Zend_Config The updated configuration for this backend
* @param string $name The name of the resource
* @param array $config The configuration values
*/
public function getConfig()
public function setResourceConfig($name, array $config)
{
$values = $this->getValues();
$config['name'] = $name;
$this->populate($config);
}
$result = array('type' => $values['resource_type']);
foreach ($values as $key => $value) {
if ($key !== 'resource_type' && $key !== 'resource_all_name' && $key !== 'resource_all_name_old') {
$configKey = explode('_', $key, 3);
if (count($configKey) === 3) {
$result[$configKey[2]] = $value;
}
}
}
/**
* Return a checkbox to be displayed at the beginning of the form
* which allows the user to skip the connection validation
*
* @return Zend_Form_Element
*/
protected function getForceCreationCheckbox()
{
return $this->createElement(
'checkbox',
'force_creation',
array(
'order' => 0,
'ignore' => true,
'label' => t('Force Changes'),
'helptext' => t('Check this box to enforce changes without connectivity validation')
)
);
}
return new Zend_Config($result);
/**
* Return all required elements to define a resource of type "db"
*
* @return array
*/
protected function getDbElements()
{
return array(
$this->createElement(
'select',
'db',
array(
'required' => true,
'label' => t('Database Type'),
'helptext' => t('The type of SQL database'),
'multiOptions' => array(
'mysql' => 'MySQL',
'pgsql' => 'PostgreSQL'
//'oracle' => 'Oracle'
)
)
),
$this->createElement(
'text',
'host',
array (
'required' => true,
'label' => t('Host'),
'helptext' => t('The hostname of the database'),
'value' => 'localhost'
)
),
new Number(
array(
'required' => true,
'name' => 'port',
'label' => t('Port'),
'helptext' => t('The port to use'),
'value' => 3306,
'decorators' => array( // The order is important!
'ViewHelper',
'Errors',
new ElementWrapper(),
new HelpText()
)
)
),
$this->createElement(
'text',
'dbname',
array(
'required' => true,
'label' => t('Database Name'),
'helptext' => t('The name of the database to use')
)
),
$this->createElement(
'text',
'username',
array (
'required' => true,
'label' => t('Username'),
'helptext' => t('The user name to use for authentication')
)
),
$this->createElement(
'password',
'password',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Password'),
'helptext' => t('The password to use for authentication')
)
)
);
}
/**
* Return all required elements to define a resource of type "statusdat"
*
* @return array
*/
protected function getStatusdatElements()
{
return array(
$this->createElement(
'text',
'status_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga status.dat file'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/status.dat')
)
),
$this->createElement(
'text',
'object_file',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('Location of your icinga objects.cache file'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/objects.cache')
)
)
);
}
/**
* Return all required elements to define a resource of type "livestatus"
*
* @return array
*/
protected function getLivestatusElements()
{
return array(
$this->createElement(
'text',
'socket',
array(
'required' => true,
'label' => t('Socket'),
'helptext' => t('The path to your livestatus socket used for querying monitoring data'),
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
)
)
);
}
/**
* Return all required elements to define a resource of type "ldap"
*
* @return array
*/
protected function getLdapElements()
{
return array(
$this->createElement(
'text',
'hostname',
array(
'required' => true,
'allowEmpty' => false,
'label' => t('Host'),
'helptext' => t('The hostname or address of the LDAP server to use for authentication'),
'value' => 'localhost'
)
),
new Number(
array(
'required' => true,
'name' => 'port',
'label' => t('Port'),
'helptext' => t('The port of the LDAP server to use for authentication'),
'value' => 389,
'decorators' => array( // The order is important!
'ViewHelper',
'Errors',
new ElementWrapper(),
new HelpText()
)
)
),
$this->createElement(
'text',
'root_dn',
array(
'required' => true,
'label' => t('Root DN'),
'helptext' => t('The path where users can be found on the ldap server')
)
),
$this->createElement(
'text',
'bind_dn',
array(
'required' => true,
'label' => t('Bind DN'),
'helptext' => t('The user dn to use for querying the ldap server')
)
),
$this->createElement(
'password',
'bind_pw',
array(
'required' => true,
'renderPassword' => true,
'label' => t('Bind Password'),
'helptext' => t('The password to use for querying the ldap server')
)
)
);
}
/**
* Return all required elements to define a resource of type "file"
*
* @return array
*/
protected function getFileElements()
{
return array(
$this->createElement(
'text',
'filename',
array(
'required' => true,
'label' => t('Filepath'),
'helptext' => t('The filename to fetch information from')
)
),
$this->createElement(
'text',
'fields',
array(
'required' => true,
'label' => t('Pattern'),
'helptext' => t('The regular expression by which to identify columns')
)
)
);
}
}

@ -5,12 +5,8 @@
namespace Icinga\Form\Dashboard;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Form;
use Icinga\Web\Widget\Dashboard;
use Zend_Form_Element_Text;
use Zend_Form_Element_Submit;
use Zend_Form_Element_Hidden;
use Zend_Form_Element_Select;
use Icinga\Web\Form;
/**
* Form to add an url a dashboard pane
@ -18,124 +14,106 @@ use Zend_Form_Element_Select;
class AddUrlForm extends Form
{
/**
* Add a selection box for different panes to the form
*
* @param Dashboard $dashboard The dashboard to retrieve the panes from
* Initialize this form
*/
private function addPaneSelectionBox(Dashboard $dashboard)
public function init()
{
$selectPane = new Zend_Form_Element_Select(
'pane',
array(
'label' => 'Dashboard',
'required' => true,
'style' => 'display:inline-block;',
'multiOptions' => $dashboard->getPaneKeyTitleArray()
)
);
$newDashboardBtn = new Zend_Form_Element_Submit(
'create_new_pane',
array(
'label' => 'Create A New Pane',
'required' => false,
'class' => 'btn btn-default',
'style' => 'display:inline-block'
)
);
$newDashboardBtn->removeDecorator('DtDdWrapper');
$selectPane->removeDecorator('DtDdWrapper');
$selectPane->removeDecorator('htmlTag');
$this->addElement($selectPane);
$this->addElement($newDashboardBtn);
$this->enableAutoSubmit(array('create_new_pane'));
$this->setName('form_dashboard_addurl');
$this->setSubmitLabel(t('Add To Dashboard'));
}
/**
* Add a textfield for creating a new pane to this form
* @see Form::createElements()
*/
private function addNewPaneTextField($showExistingButton = true)
public function createElements(array $formData)
{
$txtCreatePane = new Zend_Form_Element_Text(
'pane',
array(
'label' => 'New Dashboard Title',
'required' => true,
'style' => 'display:inline-block'
$elements = array(
$this->createElement(
'text',
'url',
array(
'required' => true,
'label' => t('Url'),
'helptext' => t('The url being loaded in the dashlet')
)
)
);
// Marks this field as a new pane (and prevents the checkbox being displayed when validation errors occur)
$markAsNewPane = new Zend_Form_Element_Hidden(
'create_new_pane',
array(
'required' => true,
'value' => 1
)
);
$cancelDashboardBtn = new Zend_Form_Element_Submit(
'use_existing_dashboard',
array(
'class' => 'btn',
'escape' => false,
'label' => 'Use An Existing Dashboard',
'required' => false
)
);
$cancelDashboardBtn->removeDecorator('DtDdWrapper');
$txtCreatePane->removeDecorator('DtDdWrapper');
$txtCreatePane->removeDecorator('htmlTag');
$this->addElement($txtCreatePane);
if ($showExistingButton) {
$this->addElement($cancelDashboardBtn);
}
$this->addElement($markAsNewPane);
}
/**
* Add elements to this form (used by extending classes)
*/
protected function create()
{
$dashboard = new Dashboard();
$this->setName('form_dashboard_add');
$dashboard->readConfig(IcingaConfig::app('dashboard/dashboard'));
$this->addElement(
'text',
'url',
array(
'label' => 'Url',
'required' => true,
'value' => htmlspecialchars_decode($this->getRequest()->getParam('url', ''))
)
);
$elems = $dashboard->getPaneKeyTitleArray();
if (empty($elems) || // show textfield instead of combobox when no pane is available
($this->getRequest()->getPost('create_new_pane', '0') && // or when a new pane should be created (+ button)
!$this->getRequest()->getPost('use_existing_dashboard', '0')) // and the user didn't click the 'use
// existing' button
$paneSelectionValues = $this->getDashboardPaneSelectionValues();
if (empty($paneSelectionValues) ||
((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false) &&
(false === isset($formData['use_existing_dashboard']) || $formData['use_existing_dashboard'] != true))
) {
$this->addNewPaneTextField(!empty($elems));
$elements[] = $this->createElement(
'text',
'pane',
array(
'required' => true,
'label' => t("The New Pane's Title"),
'style' => 'display: inline-block'
)
);
$elements[] = $this->createElement( // Prevent the button from being displayed again on validation errors
'hidden',
'create_new_pane',
array(
'value' => 1
)
);
if (false === empty($paneSelectionValues)) {
$elements[] = $this->createElement(
'submit',
'use_existing_dashboard',
array(
'ignore' => true,
'label' => t('Use An Existing Pane'),
'style' => 'display: inline-block'
)
);
}
} else {
$this->addPaneSelectionBox($dashboard);
$elements[] = $this->createElement(
'select',
'pane',
array(
'required' => true,
'label' => t('Pane'),
'style' => 'display: inline-block;',
'multiOptions' => $paneSelectionValues
)
);
$elements[] = $this->createElement(
'submit',
'create_new_pane',
array(
'ignore' => true,
'label' => t('Create A New Pane'),
'style' => 'display: inline-block'
)
);
}
$this->addElement(
$elements[] = $this->createElement(
'text',
'component',
array(
'label' => 'Title',
'required' => true,
'required' => true,
'label' => t('Title'),
'helptext' => t('The title for the dashlet')
)
);
$this->setSubmitLabel("Add To Dashboard");
return $elements;
}
/**
* Return the names and titles of the available dashboard panes as key-value array
*
* @return array
*/
protected function getDashboardPaneSelectionValues()
{
$dashboard = new Dashboard();
$dashboard->readConfig(IcingaConfig::app('dashboard/dashboard'));
return $dashboard->getPaneKeyTitleArray();
}
}

@ -1,65 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Install;
use Zend_Config;
use Icinga\Web\Wizard\Page;
use Icinga\Form\Config\LoggingForm;
class LoggingPage extends Page
{
/**
* The logging form
*
* @var LoggingForm
*/
protected $loggingForm;
/**
* Initialize this LoggingPage
*/
public function init()
{
$this->setName('logging');
}
/**
* Create and return the logging form
*
* @return LoggingForm
*/
protected function createForm()
{
if ($this->loggingForm === null) {
$this->loggingForm = new LoggingForm();
$this->loggingForm->hideButtons();
$this->loggingForm->setTokenDisabled();
$this->loggingForm->setRequest($this->getRequest());
$this->loggingForm->setConfiguration($this->getConfiguration());
}
return $this->loggingForm;
}
/**
* Create this wizard page
*/
protected function create()
{
$loggingForm = $this->createForm();
$loggingForm->buildForm(); // Needs to get called manually as it's nothing that Zend knows about
$this->addSubForm($loggingForm, $loggingForm->getName());
}
/**
* Return a config containing all values provided by the user
*
* @return Zend_Config
*/
public function getConfig()
{
return $this->createForm()->getConfig();
}
}

@ -4,147 +4,168 @@
namespace Icinga\Form\Preference;
use \DateTimeZone;
use \Zend_Config;
use \Zend_Form_Element_Text;
use \Zend_Form_Element_Select;
use \Zend_View_Helper_DateFormat;
use \Icinga\Web\Form;
use \Icinga\Web\Form\Validator\TimeFormatValidator;
use \Icinga\Web\Form\Validator\DateFormatValidator;
use \Icinga\Util\Translator;
use DateTimeZone;
use Icinga\Web\Form;
use Icinga\Util\Translator;
use Icinga\User\Preferences;
/**
* General user preferences
*/
class GeneralForm extends Form
{
/**
* Initialize this preferences config form
*/
public function init()
{
$this->setName('form_config_preferences');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* Add a select field for setting the user's language
*
* Possible values are determined by Translator::getAvailableLocaleCodes.
* Also, a 'use default format' checkbox is added in order to allow a user to discard his overwritten setting
* Also, a 'use browser language' checkbox is added in order to allow a user to discard his setting
*
* @param Zend_Config $cfg The "global" section of the config.ini to be used as default value
* @param array $formData The data sent by the user
*/
private function addLanguageSelection(Zend_Config $cfg)
protected function getLanguageElements(array $formData)
{
$languages = array();
foreach (Translator::getAvailableLocaleCodes() as $language) {
$languages[$language] = $language;
}
$prefs = $this->getUserPreferences();
$useDefaultLanguage = $this->getRequest()->getParam('default_language', !$prefs->has('app.language'));
$this->addElement(
'checkbox',
'default_language',
array(
'label' => t('Use Default Language'),
'value' => $useDefaultLanguage,
'required' => true
)
);
$useBrowserLanguage = isset($formData['browser_language']) ? $formData['browser_language'] == 1 : true;
$selectOptions = array(
'label' => t('Your Current Language'),
'required' => !$useDefaultLanguage,
'required' => false === $useBrowserLanguage,
'multiOptions' => $languages,
'helptext' => t('Use the following language to display texts and messages'),
'value' => $prefs->get('app.language', $cfg->get('language', Translator::DEFAULT_LOCALE))
'value' => substr(setlocale(LC_ALL, 0), 0, 5)
);
if ($useDefaultLanguage) {
if ($useBrowserLanguage) {
$selectOptions['disabled'] = 'disabled';
}
$this->addElement('select', 'language', $selectOptions);
$this->enableAutoSubmit(array('default_language'));
return array(
$this->createElement(
'checkbox',
'browser_language',
array(
'required' => true,
'class' => 'autosubmit',
'label' => t('Use your browser\'s language suggestions'),
'value' => $useBrowserLanguage
)
),
$this->createElement('select', 'language', $selectOptions)
);
}
/**
* Add a select field for setting the user's timezone.
* Add a select field for setting the user's timezone
*
* Possible values are determined by DateTimeZone::listIdentifiers
* Also, a 'use default format' checkbox is added in order to allow a user to discard his overwritten setting
* Possible values are determined by DateTimeZone::listIdentifiers.
* Also, a 'use local timezone' checkbox is added in order to allow a user to discard his overwritten setting
*
* @param Zend_Config $cfg The "global" section of the config.ini to be used as default value
* @param array $formData The data sent by the user
*/
private function addTimezoneSelection(Zend_Config $cfg)
protected function getTimezoneElements(array $formData)
{
$tzList = array();
foreach (DateTimeZone::listIdentifiers() as $tz) {
$tzList[$tz] = $tz;
}
$helptext = 'Use the following timezone for dates and times';
$prefs = $this->getUserPreferences();
$useGlobalTimezone = $this->getRequest()->getParam('default_timezone', !$prefs->has('app.timezone'));
$selectTimezone = new Zend_Form_Element_Select(
array(
'name' => 'timezone',
'label' => 'Your Current Timezone',
'required' => !$useGlobalTimezone,
'multiOptions' => $tzList,
'helptext' => $helptext,
'value' => $prefs->get('app.timezone', $cfg->get('timezone', date_default_timezone_get()))
)
$useLocalTimezone = isset($formData['local_timezone']) ? $formData['local_timezone'] == 1 : true;
$selectOptions = array(
'label' => 'Your Current Timezone',
'required' => false === $useLocalTimezone,
'multiOptions' => $tzList,
'helptext' => t('Use the following timezone for dates and times'),
'value' => date_default_timezone_get()
);
$this->addElement(
'checkbox',
'default_timezone',
array(
'label' => 'Use Default Timezone',
'value' => $useGlobalTimezone,
'required' => true
)
);
if ($useGlobalTimezone) {
$selectTimezone->setAttrib('disabled', 1);
if ($useLocalTimezone) {
$selectOptions['disabled'] = 'disabled';
}
$this->addElement($selectTimezone);
$this->enableAutoSubmit(array('default_timezone'));
return array(
$this->createElement(
'checkbox',
'local_timezone',
array(
'required' => true,
'class' => 'autosubmit',
'label' => t('Use your local timezone'),
'value' => $useLocalTimezone,
)
),
$this->createElement('select', 'timezone', $selectOptions)
);
}
/**
* Create the general form, using the global configuration as fallback values for preferences
*
* @see Form::create()
* @see Form::createElements()
*/
public function create()
public function createElements(array $formData)
{
$this->setName('form_preference_set');
$config = $this->getConfiguration();
$global = $config->global;
if ($global === null) {
$global = new Zend_Config(array());
}
$this->addLanguageSelection($global);
$this->addTimezoneSelection($global);
$this->setSubmitLabel('Save Changes');
$this->addElement(
$elements = array_merge($this->getLanguageElements($formData), $this->getTimezoneElements($formData));
$elements[] = $this->createElement(
'checkbox',
'show_benchmark',
array(
'label' => 'Use benchmark',
'value' => $this->getUserPreferences()->get('app.show_benchmark')
'label' => t('Use benchmark')
)
);
return $elements;
}
/**
* Return an array containing the preferences set in this form
* Populate the form with the given preferences
*
* @return array
* @param Preferences $preferences The preferences to populate the form with
*
* @return self
*/
public function setPreferences(Preferences $preferences)
{
$defaults = array(
'browser_language' => $preferences->get('app.language') === null,
'local_timezone' => $preferences->get('app.timezone') === null
);
if ($preferences->get('app.language') !== null) {
$defaults['language'] = $preferences->get('app.language');
}
if ($preferences->get('app.timezone') !== null) {
$defaults['timezone'] = $preferences->get('app.timezone');
}
if ($preferences->get('app.show_benchmark')) {
$defaults['show_benchmark'] = $preferences->get('app.show_benchmark');
}
$this->setDefaults($defaults);
return $this;
}
/**
* Return the configured preferences
*
* @return Preferences
*/
public function getPreferences()
{
$values = $this->getValues();
return array(
'app.language' => $values['default_language'] ? null : $values['language'],
'app.timezone' => $values['default_timezone'] ? null : $values['timezone'],
'app.show_benchmark' => $values['show_benchmark'] === '1' ? true : false
return new Preferences(
array(
'app.language' => $values['browser_language'] ? null : $values['language'],
'app.timezone' => $values['local_timezone'] ? null : $values['timezone'],
'app.show_benchmark' => $values['show_benchmark'] ? $values['show_benchmark'] : null
)
);
}
}

@ -1,45 +1,57 @@
<div class="controls">
<?= $this->tabs ?>
<?= $tabs; ?>
</div>
<div class="content" data-base-target="_next">
<?php
if (isset($this->messageBox)) {
// TODO: Get rid of such boxes -> notifications?
echo $this->messageBox->render();
}
?>
<p>
<a href="<?= $this->href('/config/createAuthenticationBackend', array('type' => 'ldap')) ?>"><?= $this->icon('create.png'); ?> Create A New LDAP Authentication Backend</a>
<br />
<a href="<?= $this->href('/config/createAuthenticationBackend', array('type' => 'db')) ?>"><?= $this->icon('create.png'); ?> Create A New DB Authentication Backend</a>
</p>
<table class="action">
<thead>
<th>Resource</th>
<th style="width: 5em">Remove</th>
<th style="width: 5em">Order</th>
</thead>
<tbody>
<?php foreach ($this->backends as $backend): ?>
<tr>
<td class="action">
<a href="<?= $this->href('config/editAuthenticationBackend', array('auth_backend' => $backend->name)) ?>">
<?= $this->icon('edit.png') ?> <?= $this->escape($backend->name); ?>
</a>
</td>
<td>
<a href="<?= $this->href('config/removeAuthenticationBackend', array('auth_backend' => $backend->name)) ?>">
<?= $this->icon('remove.png', 'Remove') ?>
</a>
</td>
<td>
<?= $backend->reorderForm; ?>
</td>
</tr>
<?php endforeach; ?>
</table>
<?= $messageBox; ?>
<p>
<a href="<?= $this->href('/config/createAuthenticationBackend', array('type' => 'ldap')); ?>">
<?= $this->icon('create.png'); ?><?= $this->translate('Create A New LDAP Authentication Backend'); ?>
</a>
<br>
<a href="<?= $this->href('/config/createAuthenticationBackend', array('type' => 'db')); ?>">
<?= $this->icon('create.png'); ?><?= $this->translate('Create A New DB Authentication Backend'); ?>
</a>
<br>
<a href="<?= $this->href('/config/createAuthenticationBackend', array('type' => 'autologin')); ?>">
<?= $this->icon('create.png'); ?><?= $this->translate('Create A New Autologin Authentication Backend'); ?>
</a>
</p>
<form id="<?= $form->getName(); ?>" name="<?= $form->getName(); ?>" enctype="<?= $form->getEncType(); ?>" method="<?= $form->getMethod(); ?>">
<?= $form->getElement($form->getTokenElementName()); ?>
<table class="action">
<thead>
<th>Backend</th>
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
<th style="width: 5em"><?= $this->translate('Order'); ?></th>
</thead>
<tbody>
<?php for ($i = 0; $i < count($backendNames); $i++): ?>
<tr>
<td class="action">
<a href="<?= $this->href('config/editAuthenticationBackend', array('auth_backend' => $backendNames[$i])); ?>">
<?= $this->icon('edit.png'); ?> <?= $this->escape($backendNames[$i]); ?>
</a>
</td>
<td>
<a href="<?= $this->href('config/removeAuthenticationBackend', array('auth_backend' => $backendNames[$i])); ?>">
<?= $this->icon('remove.png', $this->translate('Remove')); ?>
</a>
</td>
<td>
<?php if ($i > 0): ?>
<button type="submit" name="<?= $backendNames[$i]; ?>" value="<?= $i - 1; ?>">
<?= $this->icon('up.png', $this->translate('Move up in authentication order')); ?>
</button>
<?php endif; ?>
<?php if ($i + 1 < count($backendNames)): ?>
<button type="submit" name="<?= $backendNames[$i]; ?>" value="<?= $i + 1; ?>">
<?= $this->icon('down.png', $this->translate('Move down in authentication order')); ?>
</button>
<?php endif; ?>
</td>
</tr>
<?php endfor; ?>
</tbody>
</table>
</form>
</div>

@ -1,18 +1,8 @@
<h4>
<i class="icinga-icon-edit"></i>
Edit Backend "<?= $this->escape($this->name); ?>"
<?php printf(
$this->translate('Edit Backend "%s"'),
$this->escape($this->name)
); ?>
</h4>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<?php if ($this->form->getErrorMessages()): ?>
<div>
<?php foreach ($this->form->getErrorMessages() as $error): ?>
<?= $this->escape($error); ?><br/>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?= $this->form ?>
<?= $messageBox; ?>
<?= $this->form; ?>

@ -1,10 +1,8 @@
<h4>
<i class="icinga-icon-remove"></i>
Remove Backend "<?= $this->escape($this->name); ?>"
<?php printf(
$this->translate('Remove Backend "%s"'),
$this->escape($name)
); ?>
</h4>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<?= $this->form ?>
<?= $messageBox ?>
<?= $form ?>

@ -1,30 +1,33 @@
<div class="controls">
<?= $this->tabs ?>
<?= $tabs; ?>
</div>
<div class="content" data-base-target="_next">
<?php
if (isset($this->messageBox)) {
// TODO: Get rid of messageBoxes in favour of notifications
echo $this->messageBox->render();
}
?>
<p><a href="<?= $this->href('/config/createresource') ?>"><?= $this->icon('create.png'); ?> Create A New Resource</a></p>
<table class="action">
<thead>
<th>Resource</th>
<th style="width: 5em">Remove</th>
</thead>
<tbody>
<?= $messageBox; ?>
<p>
<a href="<?= $this->href('/config/createresource') ?>">
<?= $this->icon('create.png'); ?> <?= $this->translate('Create a new resource'); ?>
</a>
</p>
<table class="action">
<thead>
<th><?= $this->translate('Resource'); ?></th>
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
</thead>
<tbody>
<?php foreach ($this->resources as $name => $resource): ?>
<tr>
<td><a href="<?= $this->href('config/editresource', array('resource' => $name)) ?>"><?= $this->icon('edit.png') ?> <?= $this->escape($name); ?></td>
<td style="text-align: center"><a href="<?= $this->href('config/removeresource', array('resource' => $name)) ?>"><?= $this->icon('remove.png'); ?></a></td>
</tr>
<tr>
<td>
<a href="<?= $this->href('config/editresource', array('resource' => $name)) ?>">
<?= $this->icon('edit.png') ?> <?= $this->escape($name); ?>
</a>
</td>
<td style="text-align: center">
<a href="<?= $this->href('config/removeresource', array('resource' => $name)) ?>">
<?= $this->icon('remove.png'); ?>
</a>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
</tbody>
</table>
</div>

@ -1,14 +1,4 @@
<h4>
<i class="icinga-icon-create"></i>
Create New Resource
</h4>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<p>
Resources are entities that provide data to Icingaweb.
</p>
<?= $this->form ?>
<?= $messageBox; ?>
<h4><?= $this->translate('Create a new resource'); ?></h4>
<p><?= $this->translate('Resources are entities that provide data to Icingaweb.'); ?></p>
<?= $form; ?>

@ -1,18 +1,3 @@
<h4>
<i class="icinga-icon-edit"></i>
Edit Resource "<?= $this->escape($this->name); ?>"
</h4>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<?php if ($this->form->getErrorMessages()): ?>
<div>
<?php foreach ($this->form->getErrorMessages() as $error): ?>
<?= $this->escape($error); ?><br/>
<?php endforeach; ?>
</div>
<?php endif ?>
<?= $this->form ?>
<h4><?= $this->translate('Edit Existing Resource'); ?></h4>
<?= $messageBox; ?>
<?= $form; ?>

@ -1,10 +1,3 @@
<h4>
<i class="icinga-icon-remove"></i>
Remove Resource "<?= $this->escape($this->name); ?>"
</h4>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<?= $this->form ?>
<h4><?= $this->translate('Remove Existing Resource'); ?></h4>
<?= $messageBox; ?>
<?= $form; ?>

@ -6,6 +6,7 @@ namespace Icinga\Logger;
use Exception;
use Zend_Config;
use LogicException;
use Icinga\Exception\ConfigurationError;
/**
@ -37,10 +38,11 @@ class Logger
/**
* The supported severities
*/
public static $ERROR = 0;
public static $WARNING = 1;
public static $INFO = 2;
public static $DEBUG = 3;
public static $NONE = 0;
public static $ERROR = 1;
public static $WARNING = 2;
public static $INFO = 3;
public static $DEBUG = 4;
/**
* Create a new logger object
@ -93,9 +95,15 @@ class Logger
*
* @param string $message The message to write
* @param int $severity The severity to use
*
* @throws LogicException In case $severity equals self::$NONE
*/
public function log($message, $severity)
{
if ($severity === static::$NONE) {
throw new LogicException("`None' (0) is not a valid severity to log messages");
}
if ($this->writer !== null && $this->verbosity >= $severity) {
$this->writer->log($severity, $message);
}

@ -315,14 +315,7 @@ namespace Icinga\Test {
public function createForm($formClass, array $requestData = array())
{
$form = new $formClass;
// If the form has CSRF protection enabled, add the token to the request data, else all calls to
// isSubmittedAndValid will fail
$form->setSessionId('1234');
$form->initCsrfToken();
$token = $form->getValue($form->getTokenElementName());
if ($token !== null) {
$requestData[$form->getTokenElementName()] = $token;
}
$form->setTokenDisabled(); // Disable CSRF protection else all calls to isSubmittedAndValid will fail
$request = $this->getRequest();
$request->setMethod('POST');
$request->setPost($requestData);

@ -47,6 +47,20 @@ class BaseConfigController extends ActionController
Session::getSession()->write();
}
/**
* Send a message with the logging level Zend_Log::WARN to the current user and
* commit the changes to the underlying session.
*
* @param $msg The message content
*/
protected function addWarningMessage($msg)
{
AuthenticationManager::getInstance()->getUser()->addMessage(
new Message($msg, Zend_Log::WARN)
);
Session::getSession()->write();
}
/*
* Return an array of tabs provided by this configuration controller.
*

@ -4,19 +4,12 @@
namespace Icinga\Web;
use Zend_Controller_Request_Abstract;
use Zend_Form;
use Zend_Config;
use Zend_Form_Element_Submit;
use Zend_Form_Element_Reset;
use Zend_View_Interface;
use Icinga\Web\Session;
use Icinga\Web\Form\Element\Note;
use Icinga\Exception\ProgrammingError;
use Icinga\Application\Icinga;
use Icinga\Web\Form\Decorator\HelpText;
use Icinga\Web\Form\Decorator\BootstrapForm;
use Icinga\Web\Form\InvalidCSRFTokenException;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Form\Decorator\ElementWrapper;
use Icinga\Web\Form\Element\CsrfCounterMeasure;
/**
* Base class for forms providing CSRF protection, confirmation logic and auto submission
@ -24,27 +17,32 @@ use Icinga\Application\Config as IcingaConfig;
class Form extends Zend_Form
{
/**
* The form's request object
* Whether this form has been created
*
* @var Zend_Controller_Request_Abstract
* @var bool
*/
protected $request;
protected $created = false;
/**
* Main configuration
* Label to use for the standard submit button
*
* Used as fallback if user preferences are not available.
*
* @var IcingaConfig
* @var string
*/
protected $config;
protected $submitLabel;
/**
* The preference object to use instead of the one from the user (used for testing)
* The url to redirect to upon success
*
* @var Zend_Config
* @var string|Url
*/
protected $preferences;
protected $redirectUrl;
/**
* The view script to use when rendering this form
*
* @var string
*/
protected $viewScript;
/**
* Whether this form should NOT add random generated "challenge" tokens that are associated with the user's current
@ -56,83 +54,129 @@ class Form extends Zend_Form
protected $tokenDisabled = false;
/**
* Name of the CSRF token element (used to create non-colliding hashes)
* Name of the CSRF token element
*
* @var string
*/
protected $tokenElementName = 'CSRFToken';
/**
* Flag to indicate that form is already build
* Set the label to use for the standard submit button
*
* @var bool
* @param string $label The label to use for the submit button
*
* @return self
*/
protected $created = false;
public function setSubmitLabel($label)
{
$this->submitLabel = $label;
return $this;
}
/**
* Session id used for CSRF token generation
*
* @var string
*/
protected $sessionId;
/**
* Label for submit button
*
* If omitted, no button will be shown
*
* @var string
*/
protected $submitLabel;
/**
* Label for cancel button
*
* If omitted, no button will be shown
*
* @var string
*/
protected $cancelLabel;
/**
* Last used note-id
*
* Helper to generate unique names for note elements
*
* @var int
*/
protected $last_note_id = 0;
/**
* Getter for the session ID
*
* If the ID has never been set, the ID from session_id() is returned
* Return the label being used for the standard submit button
*
* @return string
*/
public function getSessionId()
public function getSubmitLabel()
{
if (!$this->sessionId) {
$this->sessionId = Session::getSession()->getId();
return $this->submitLabel;
}
/**
* Set the url to redirect to upon success
*
* @param string|Url $url The url to redirect to
*
* @return self
*/
public function setRedirectUrl($url)
{
$this->redirectUrl = $url;
return $this;
}
/**
* Return the url to redirect to upon success
*
* @return string|Url
*/
public function getRedirectUrl()
{
if ($this->redirectUrl === null) {
// Be sure to remove all form dependent params because we do not want to submit it again
$this->redirectUrl = Url::fromRequest()->without(array_keys($this->getElements()));
}
return $this->sessionId;
return $this->redirectUrl;
}
/**
* Setter for the session ID
* Set the view script to use when rendering this form
*
* This method should be used for testing purposes only
* @param string $viewScript The view script to use
*
* @param string $sessionId
* @return self
*/
public function setSessionId($sessionId)
public function setViewScript($viewScript)
{
$this->sessionId = $sessionId;
$this->viewScript = $viewScript;
return $this;
}
/**
* Return the HTML element name of the CSRF token field
* Return the view script being used when rendering this form
*
* @return string
*/
public function getViewScript()
{
return $this->viewScript;
}
/**
* Disable CSRF counter measure and remove its field if already added
*
* @param bool $disabled Set true in order to disable CSRF protection for this form, otherwise false
*
* @return self
*/
public function setTokenDisabled($disabled = true)
{
$this->tokenDisabled = (bool) $disabled;
if ($disabled && $this->getElement($this->tokenElementName) !== null) {
$this->removeElement($this->tokenElementName);
}
return $this;
}
/**
* Return whether CSRF counter measures are disabled for this form
*
* @return bool
*/
public function getTokenDisabled()
{
return $this->tokenDisabled;
}
/**
* Set the name to use for the CSRF element
*
* @param string $name The name to set
*
* @return self
*/
public function setTokenElementName($name)
{
$this->tokenElementName = $name;
return $this;
}
/**
* Return the name of the CSRF element
*
* @return string
*/
@ -142,427 +186,284 @@ class Form extends Zend_Form
}
/**
* Render the form to HTML
* Create this form
*
* @param Zend_View_Interface $view
*
* @return string
*/
public function render(Zend_View_Interface $view = null)
{
// Elements must be there to render the form
$this->buildForm();
return parent::render($view);
}
/**
* Add elements to this form (used by extending classes)
*/
protected function create()
{
}
/**
* Method called before validation
*/
protected function preValidation(array $data)
{
}
/**
* Setter for the request
*
* @param Zend_Controller_Request_Abstract $request
*/
public function setRequest(Zend_Controller_Request_Abstract $request)
{
$this->request = $request;
}
/**
* Getter for the request
*
* @return Zend_Controller_Request_Abstract
*/
public function getRequest()
{
return $this->request;
}
/**
* Set the configuration to be used for this form when no preferences are set yet
*
* @param IcingaConfig $cfg
* @param array $formData The data sent by the user
*
* @return self
*/
public function setConfiguration($cfg)
public function create(array $formData = array())
{
$this->config = $cfg;
return $this;
}
if (false === $this->created) {
$this->addElements($this->createElements($formData));
$this->addFormIdentification()
->addCsrfCounterMeasure()
->addSubmitButton();
/**
* Get the main configuration
*
* Returns the set configuration or an empty default one.
*
* @return Zend_Config
*/
public function getConfiguration()
{
if ($this->config === null) {
$this->config = new Zend_Config(array(), true);
}
return $this->config;
}
/**
* Set preferences to be used instead of the one from the user object (used for testing)
*
* @param Zend_Config $prefs
*/
public function setUserPreferences($prefs)
{
$this->preferences = $prefs;
}
/**
* Return the preferences of the user or the overwritten ones
*
* @return Zend_Config
*/
public function getUserPreferences()
{
if ($this->preferences) {
return $this->preferences;
}
return $this->getRequest()->getUser()->getPreferences();
}
/**
* Create the form if not done already
*
* Adds all elements to the form
*/
public function buildForm()
{
if ($this->created === false) {
$this->initCsrfToken();
$this->create();
if ($this->submitLabel) {
$this->addSubmitButton();
}
if ($this->cancelLabel) {
$this->addCancelButton();
}
// Empty action if not safe
if (!$this->getAction() && $this->getRequest()) {
$this->setAction($this->getRequest()->getRequestUri());
if ($this->getAction() === '') {
// We MUST set an action as JS gets confused otherwise, if
// this form is being displayed in an additional column
$this->setAction(Url::fromRequest()->getUrlWithout(array_keys($this->getElements())));
}
$this->created = true;
}
return $this;
}
/**
* Setter for the cancel label
* Create and return the elements to add to this form
*
* @param string $cancelLabel
*/
public function setCancelLabel($cancelLabel)
{
$this->cancelLabel = $cancelLabel;
}
/**
* Add cancel button to form
*/
protected function addCancelButton()
{
$this->addElement(
new Zend_Form_Element_Reset(
array(
'name' => 'btn_reset',
'label' => $this->cancelLabel,
'class' => 'btn pull-right'
)
)
);
}
/**
* Setter for the submit label
* Intended to be implemented by concrete form classes.
*
* @param string $submitLabel
*/
public function setSubmitLabel($submitLabel)
{
$this->submitLabel = $submitLabel;
}
/**
* Add submit button to form
*/
protected function addSubmitButton()
{
$this->addElement(
new Zend_Form_Element_Submit(
array(
'name' => 'btn_submit',
'label' => $this->submitLabel
)
)
);
}
/**
* Add message to form
*
* @param string $message The message to be displayed
* @param int $headingType Whether it should be displayed as heading (1-6) or not (null)
*/
public function addNote($message, $headingType = null)
{
$this->addElement(
new Note(
array(
'escape' => $headingType === null ? false : true,
'name' => sprintf('note_%s', $this->last_note_id++),
'value' => $headingType === null ? $message : sprintf(
'<h%1$s>%2$s</h%1$s>',
$headingType,
$message
)
)
)
);
}
/**
* Enable automatic form submission on the given elements
*
* Enables automatic submission of this form once the user edits specific elements
*
* @param array $triggerElements The element names which should auto-submit the form
*
* @throws ProgrammingError When an element is found which does not yet exist
*/
public function enableAutoSubmit($triggerElements)
{
foreach ($triggerElements as $elementName) {
$element = $this->getElement($elementName);
if ($element !== null) {
$class = $element->getAttrib('class');
if ($class === null) {
$class = 'autosubmit';
} else {
$class .= ' autosubmit';
}
$element->setAttrib('class', $class);
} else {
throw new ProgrammingError(
'You need to add the element "%s" to the form before automatic submission can be enabled!',
$elementName
);
}
}
}
/**
* Check whether the form was submitted with a valid request
*
* Ensures that the current request method is POST, that the form was manually submitted and that the data provided
* in the request is valid and gets repopulated in case its invalid.
*
* @return bool True when the form is submitted and valid, otherwise false
*/
public function isSubmittedAndValid()
{
if ($this->getRequest()->isPost() === false) {
return false;
}
$this->buildForm();
$checkData = $this->getRequest()->getParams();
$this->assertValidCsrfToken($checkData);
if ($this->isSubmitted()) {
// perform full validation if submitted
$this->preValidation($checkData);
return $this->isValid($checkData);
} else {
// only populate if not submitted
$this->populate($checkData);
$this->setAttrib('data-icinga-form-modified', 'true');
return false;
}
}
/**
* Check whether this form has been submitted
*
* Per default, this checks whether the button set with the 'setSubmitLabel' method
* is being submitted. For custom submission logic, this method must be overwritten
*
* @return bool True when the form is marked as submitted, otherwise false
*/
public function isSubmitted()
{
// TODO: There are some missunderstandings and missconceptions to be
// found in this class. If populate() etc would have been used as
// designed this function would read as simple as:
// return $this->getElement('btn_submit')->isChecked();
if ($this->submitLabel) {
$checkData = $this->getRequest()->getParams();
return isset($checkData['btn_submit']) && $checkData['btn_submit'];
}
return true;
}
/**
* Disable CSRF counter measure and remove its field if already added
*
* This method should be used for testing purposes only
*
* @param bool $disabled Set true in order to disable CSRF tokens in
* this form (default: true), otherwise false
*/
public function setTokenDisabled($disabled = true)
{
$this->tokenDisabled = (boolean) $disabled;
if ($disabled === true) {
$this->removeElement($this->tokenElementName);
}
}
/**
* Add CSRF counter measure field to form
*/
public function initCsrfToken()
{
if (!$this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
$this->addElement(
'hidden',
$this->tokenElementName,
array(
'value' => $this->generateCsrfTokenAsString()
)
);
}
}
/**
* Test the submitted data for a correct CSRF token
*
* @param array $checkData The POST data send by the user
*
* @throws InvalidCSRFTokenException When CSRF Validation fails
*/
public function assertValidCsrfToken(array $checkData)
{
if (!$this->tokenDisabled) {
if (!isset($checkData[$this->tokenElementName])
|| !$this->hasValidCsrfToken($checkData[$this->tokenElementName])
) {
throw new InvalidCSRFTokenException();
}
}
}
/**
* Check whether the form's CSRF token-field has a valid value
*
* @param string $elementValue Value from the form element
*
* @return bool
*/
protected function hasValidCsrfToken($elementValue)
{
if ($this->getElement($this->tokenElementName) === null || strpos($elementValue, '|') === false) {
return false;
}
list($seed, $token) = explode('|', $elementValue);
if (!is_numeric($seed)) {
return false;
}
return $token === hash('sha256', $this->getSessionId() . $seed);
}
/**
* Generate a new (seed, token) pair
* @param array $formData The data sent by the user
*
* @return array
*/
public function generateCsrfToken()
public function createElements(array $formData)
{
$seed = mt_rand();
$hash = hash('sha256', $this->getSessionId() . $seed);
return array($seed, $hash);
return array();
}
/**
* Return the string representation of the CSRF seed/token pair
* Perform actions after this form was submitted using a valid request
*
* @return string
* Intended to be implemented by concrete form classes. The base implementation returns always FALSE.
*
* @param Request $request The valid request used to process this form
*
* @return bool Whether any redirection should take place
*/
public function generateCsrfTokenAsString()
public function onSuccess(Request $request)
{
list ($seed, $token) = $this->generateCsrfToken($this->getSessionId());
return sprintf('%s|%s', $seed, $token);
return false;
}
/**
* Add a new element
* Perform actions when no form dependent data was sent
*
* Additionally, all DtDd tags will be removed and the Bootstrap compatible
* BootstrapForm decorator will be added to the elements
* Intended to be implemented by concrete form classes.
*
* @param string|Zend_Form_Element $element String element type, or an object of type Zend_Form_Element
* @param string $name The name of the element to add if $element is a string
* @param array $options The settings for the element if $element is a string
* @param Request $request The current request
*/
public function onShow(Request $request)
{
}
/**
* Add a submit button to this form
*
* Uses the label previously set with Form::setSubmitLabel(). Overwrite this
* method in order to add multiple submit buttons or one with a custom name.
*
* @return self
* @see Zend_Form::addElement()
*/
public function addElement($element, $name = null, $options = null)
public function addSubmitButton()
{
parent::addElement($element, $name, $options);
$el = $name !== null ? $this->getElement($name) : $element;
if ($this->submitLabel !== null) {
$this->addElement(
'submit',
'btn_submit',
array(
'ignore' => true,
'label' => $this->submitLabel
)
);
}
return $this;
}
/**
* Create a new element
*
* Additionally, all structural form element decorators by Zend are replaced with our own ones.
*
* @param string $type String element type
* @param string $name The name of the element to add
* @param array $options The options for the element
*
* @return Zend_Form_Element
*
* @see Zend_Form::createElement()
*/
public function createElement($type, $name, $options = null)
{
$el = parent::createElement($type, $name, $options);
if ($el) {
if (strpos(strtolower(get_class($el)), 'hidden') !== false) {
// Do not add structural elements to invisible elements which produces ugly views
$el->setDecorators(array('ViewHelper'));
} else {
$el->removeDecorator('HtmlTag');
$el->removeDecorator('Label');
$el->removeDecorator('DtDdWrapper');
$el->addDecorator(new BootstrapForm());
$el->addDecorator(new ElementWrapper());
$el->addDecorator(new HelpText());
}
}
return $el;
}
/**
* Add a field with a unique and form specific ID
*
* @return self
*/
public function addFormIdentification()
{
$this->addElement(
'hidden',
'form_uid',
array(
'ignore' => true,
'value' => $this->getName()
)
);
return $this;
}
/**
* Add CSRF counter measure field to this form
*
* @return self
*/
public function addCsrfCounterMeasure()
{
if (false === $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
$element = new CsrfCounterMeasure($this->tokenElementName);
$element->setDecorators(array('ViewHelper'));
$this->addElement($element);
}
return $this;
}
/**
* Populate the elements with the given values
*
* @param array $defaults The values to populate the elements with
*/
public function setDefaults(array $defaults)
{
$this->create($defaults);
return parent::setDefaults($defaults);
}
/**
* Process the given request using this form
*
* Redirects to the url set with setRedirectUrl() upon success. See onSuccess()
* and onShow() wherewith you can customize the processing logic.
*
* @param Request $request The request to be processed
*
* @return Request The request supposed to be processed
*/
public function handleRequest(Request $request = null)
{
if ($request === null) {
$request = $this->getRequest();
}
$formData = $this->getRequestData($request);
if ($this->wasSent($formData)) {
$this->populate($formData); // Necessary to get isSubmitted() to work
if ($this->isSubmitted() || ! $this->getSubmitLabel()) {
if ($this->isValid($formData) && $this->onSuccess($request)) {
$this->getResponse()->redirectAndExit($this->getRedirectUrl());
}
} else {
// The form can't be processed but we want to show validation errors though
$this->isValidPartial($formData);
}
} else {
$this->onShow($request);
}
return $request;
}
/**
* Return whether the submit button of this form was pressed
*
* When overwriting Form::addSubmitButton() be sure to overwrite this method as well.
*
* @return bool True in case it was pressed, False otherwise or no submit label was set
*/
public function isSubmitted()
{
if ($this->submitLabel !== null) {
return $this->getElement('btn_submit')->isChecked();
}
return false;
}
/**
* Return whether the data sent by the user refers to this form
*
* Ensures that the correct form gets processed in case there are multiple forms
* with equal submit button names being posted against the same route.
*
* @param array $formData The data sent by the user
*
* @return bool Whether the given data refers to this form
*/
public function wasSent(array $formData)
{
return isset($formData['form_uid']) && $formData['form_uid'] === $this->getName();
}
/**
* Return whether the given values (possibly incomplete) are valid
*
* Unlike Zend_Form::isValid() this will not set NULL as value for
* an element that is not present in the given data.
*
* @param array $formData The data to validate
*
* @return bool
*/
public function isValidPartial(array $formData)
{
$this->create($formData);
return parent::isValidPartial($formData);
}
/**
* Return whether the given values are valid
*
* @param array $formData The data to validate
*
* @return bool
*/
public function isValid($formData)
{
$this->create($formData);
return parent::isValid($formData);
}
/**
* Remove all elements of this form
*
* @return self
*/
public function clearElements()
{
$this->created = false;
return parent::clearElements();
}
/**
* Load the default decorators
*
* Overwrites Zend_Form::loadDefaultDecorators to avoid having the HtmlTag-Decorator added
* Overwrites Zend_Form::loadDefaultDecorators to avoid having
* the HtmlTag-Decorator added and to provide viewscript usage
*
* @return self
*/
@ -574,11 +475,83 @@ class Form extends Zend_Form
$decorators = $this->getDecorators();
if (empty($decorators)) {
$this->addDecorator('FormElements')
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
->addDecorator('Form');
if ($this->viewScript) {
$this->addDecorator('ViewScript', array(
'viewScript' => $this->viewScript,
'form' => $this
));
} else {
$this->addDecorator('FormElements')
//->addDecorator('HtmlTag', array('tag' => 'dl', 'class' => 'zend_form'))
->addDecorator('Form');
}
}
return $this;
}
/**
* Return the name of this form
*
* @return string
*/
public function getName()
{
$name = parent::getName();
if (! $name) {
$name = get_class($this);
$this->setName($name);
}
return $name;
}
/**
* Return the request data based on this form's request method
*
* @param Request $request The request to fetch the data from
*
* @return array
*/
public function getRequestData(Request $request)
{
if (strtolower($request->getMethod()) === $this->getMethod()) {
return $request->{'get' . ($request->isPost() ? 'Post' : 'Query')}();
}
return array();
}
/**
* Return the current request
*
* @return Request
*/
public function getRequest()
{
return Icinga::app()->getFrontController()->getRequest();
}
/**
* Return the current Response
*
* @return Response
*/
public function getResponse()
{
return Icinga::app()->getFrontController()->getResponse();
}
/**
* Render this form
*
* @param Zend_View_Interface $view The view context to use
*
* @return string
*/
public function render(Zend_View_Interface $view = null)
{
$this->create();
return parent::render($view);
}
}

@ -7,23 +7,21 @@ namespace Icinga\Web\Form\Decorator;
use Zend_Form_Decorator_Abstract;
/**
* Decorator that styles forms in the DOM Bootstrap wants for it's forms
* Decorator that wraps form elements with their labels to allow easier styling
*
* This component replaces the dt/dd wrapping of elements with the approach used by bootstrap.
*
* Labels are drawn for all elements, except hidden, button and submit elements. If you want a
* placeholder for this elements, set the 'addLabelPlaceholder' property. This can be useful in
* cases where you want to put inputs with and inputs without labels on the same line and don't
* want buttons to 'jump'
* Labels are drawn for all elements, except hidden, button and submit elements. If you want a
* placeholder for these elements, set the 'addLabelPlaceholder' property. This can be useful in
* cases where you want to put inputs with and inputs without labels on the same line and don't
* want buttons to 'jump'
*/
class BootstrapForm extends Zend_Form_Decorator_Abstract
class ElementWrapper extends Zend_Form_Decorator_Abstract
{
/**
* An array of elements that won't get a <label> dom added per default
*
* @var array
*/
private static $noLabel = array(
protected static $noLabel = array(
'Zend_Form_Element_Hidden',
'Zend_Form_Element_Button',
'Zend_Form_Element_Submit'
@ -32,18 +30,19 @@ class BootstrapForm extends Zend_Form_Decorator_Abstract
/**
* Return the DOM for the element label
*
* @param String $elementName The name of the element
* @param String $elementName The name of the element
*
* @return String The DOM for the form element's label
*/
public function getLabel($elementName)
{
$label = $this->getElement()->getLabel();
if (!$label) {
if (! $label) {
$label = '&nbsp;';
}
if (in_array($this->getElement()->getType(), self::$noLabel)
&& !$this->getElement()->getAttrib('addLabelPlaceholder', false)) {
&& false === $this->getElement()->getAttrib('addLabelPlaceholder', false)) {
$label = '';
} else {
if (in_array($this->getElement()->getType(), self::$noLabel)) {
@ -51,30 +50,21 @@ class BootstrapForm extends Zend_Form_Decorator_Abstract
}
$label = '<label for="' . $elementName . '">' . $label . '</label>';
}
return $label;
}
/**
* Render this element
*
* Renders as the following:
* <div class="form-group">
* $dtLabel
* $dtElement
* </div>
* @param String $content The content of the form element
*
* @param String $content The content of the form element
*
* @return String The decorated form element
* @return String The decorated form element
*/
public function render($content)
{
$el = $this->getElement();
$elementName = $el->getName();
$elementName = $this->getElement()->getName();
$label = $this->getLabel($elementName);
return '<div class="form-group" id="' . $elementName . '-element">'
. $label
. $content
. '</div>';
return '<div class="form-element" id="' . $elementName . '-element">' . $label . $content . '</div>';
}
}

@ -0,0 +1,87 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web\Form\Element;
use Zend_Form_Element_Xhtml;
use Icinga\Web\Session;
use Icinga\Web\Form\InvalidCSRFTokenException;
/**
* CSRF counter measure element
*
* You must not set a value to successfully use this element, just give it a name and you're good to go.
*/
class CsrfCounterMeasure extends Zend_Form_Element_Xhtml
{
/**
* Default form view helper to use for rendering
*
* @var string
*/
public $helper = 'formHidden';
/**
* Initialize this form element
*/
public function init()
{
$this->setRequired(true); // Not requiring this element would not make any sense
$this->setIgnore(true); // We do not want this element's value being retrieved by Form::getValues()
$this->setValue($this->generateCsrfToken());
}
/**
* Check whether $value is a valid CSRF token
*
* @param string $value The value to check
* @param mixed $context Context to use
*
* @return bool True, in case the CSRF token is valid
*
* @throws InvalidCSRFTokenException In case the CSRF token is not valid
*/
public function isValid($value, $context = null)
{
if (parent::isValid($value, $context) && $this->isValidCsrfToken($value)) {
return true;
}
throw new InvalidCSRFTokenException();
}
/**
* Check whether the given value is a valid CSRF token for the current session
*
* @param string $token The CSRF token
*
* @return bool
*/
protected function isValidCsrfToken($token)
{
if (strpos($token, '|') === false) {
return false;
}
list($seed, $hash) = explode('|', $token);
if (false === is_numeric($seed)) {
return false;
}
return $hash === hash('sha256', Session::getSession()->getId() . $seed);
}
/**
* Generate a new (seed, token) pair
*
* @return string
*/
protected function generateCsrfToken()
{
$seed = mt_rand();
$hash = hash('sha256', Session::getSession()->getId() . $seed);
return sprintf('%s|%s', $seed, $hash);
}
}

@ -6,6 +6,7 @@ namespace Icinga\Web\Widget;
use Zend_Log;
use Zend_Form;
use Zend_View_Abstract;
use Icinga\User;
use Icinga\User\Message;
use Icinga\Web\Session;

@ -132,7 +132,6 @@ class SortBox extends AbstractWidget
$sort = $form->getElement('sort')->setDecorators(array('ViewHelper'));
$dir = $form->getElement('dir')->setDecorators(array('ViewHelper'));
if ($this->request) {
$form->setAction($this->request->getRequestUri());
$form->populate($this->request->getParams());
}
return $form;

@ -2,15 +2,8 @@
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Application\Icinga;
use Icinga\Application\Config;
use Icinga\Logger\Logger;
use Icinga\Web\Form;
use Icinga\Module\Monitoring\Controller;
use Icinga\Chart\SVGRenderer;
use Icinga\Chart\GridChart;
use Icinga\Chart\Palette;
use Icinga\Chart\Axis;
use Icinga\Chart\PieChart;
use Icinga\Chart\Unit\StaticAxis;
@ -140,7 +133,7 @@ class Monitoring_ChartController extends Controller
}
$this->view->chart = new GridChart();
$this->view->chart->setAxisLabel('', t('Services'))
->setXAxis(new \Icinga\Chart\Unit\StaticAxis())
->setXAxis(new StaticAxis())
->setAxisMin(null, 0);
$this->view->chart->drawBars(

@ -3,19 +3,14 @@
// {{{ICINGA_LICENSE_HEADER}}}
use \Exception;
use \Zend_Config;
use Icinga\Config\PreservingIniWriter;
use Icinga\Web\Controller\ModuleActionController;
use Icinga\Web\Notification;
use Icinga\Web\Url;
use Icinga\Module\Monitoring\Form\Config\ConfirmRemovalForm;
use Icinga\Module\Monitoring\Form\Config\Backend\EditBackendForm;
use Icinga\Module\Monitoring\Form\Config\Backend\CreateBackendForm;
use Icinga\Module\Monitoring\Form\Config\Instance\EditInstanceForm;
use Icinga\Module\Monitoring\Form\Config\Instance\CreateInstanceForm;
use Icinga\Form\Config\ConfirmRemovalForm;
use Icinga\Module\Monitoring\Form\Config\BackendForm;
use Icinga\Module\Monitoring\Form\Config\InstanceForm;
use Icinga\Module\Monitoring\Form\Config\SecurityForm;
use Icinga\Exception\NotReadableError;
/**
@ -23,7 +18,6 @@ use Icinga\Exception\NotReadableError;
*/
class Monitoring_ConfigController extends ModuleActionController
{
/**
* Display a list of available backends and instances
*/
@ -49,52 +43,63 @@ class Monitoring_ConfigController extends ModuleActionController
*/
public function editbackendAction()
{
// Fetch the backend to be edited
$backend = $this->getParam('backend');
if (!$this->isExistingBackend($backend)) {
$this->view->error = 'Unknown backend ' . $backend;
return;
$backendsConfig = $this->Config('backends')->toArray();
if (false === array_key_exists($backend, $backendsConfig)) {
// TODO: Should behave as in the app's config controller (Specific redirect to an error action)
Notification::error(sprintf($this->translate('Cannot edit "%s". Backend not found.'), $backend));
$this->redirectNow('monitoring/config');
}
$backendForm = new EditBackendForm();
$backendForm->setRequest($this->getRequest());
$backendForm->setBackendConfiguration($this->Config('backends')->get($backend));
if ($backendForm->isSubmittedAndValid()) {
$newConfig = $backendForm->getConfig();
$config = $this->Config('backends');
$config->$backend = $newConfig;
if ($this->writeConfiguration($config, 'backends')) {
Notification::success('Backend ' . $backend . ' Modified.');
$form = new BackendForm();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
list($newName, $config) = $form->getBackendConfig();
if ($newName !== $backend) {
// Backend name has changed
unset($backendsConfig[$backend]); // We can safely use unset as all values are part of the form
}
$backendsConfig[$newName] = $config;
if ($this->writeConfiguration($backendsConfig, 'backends')) {
Notification::success(sprintf($this->translate('Backend "%s" successfully modified.'), $backend));
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
return;
}
}
} else {
$form->setBackendConfig($backend, $backendsConfig[$backend]);
}
$this->view->form = $form;
}
/**
* Display a form to create a new backend
*/
public function createbackendAction()
{
$form = new BackendForm();
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
list($name, $config) = $form->getBackendConfig();
$backendsConfig = $this->Config('backends')->toArray();
$backendsConfig[$name] = $config;
if ($this->writeConfiguration($backendsConfig, 'backends')) {
Notification::success(sprintf($this->translate('Backend "%s" created successfully.'), $name));
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
return;
}
}
$this->view->name = $backend;
$this->view->form = $backendForm;
}
/**
* Display a form to create a new backends
*/
public function createbackendAction()
{
$form = new CreateBackendForm();
$form->setRequest($this->getRequest());
if ($form->isSubmittedAndValid()) {
$configArray = $this->Config('backends')->toArray();
$configArray[$form->getBackendName()] = $form->getConfig();
if ($this->writeConfiguration(new Zend_Config($configArray), 'backends')) {
Notification::success('Backend Creation Succeeded');
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
}
return;
}
$this->view->form = $form;
$this->render('editbackend');
}
/**
@ -103,57 +108,53 @@ class Monitoring_ConfigController extends ModuleActionController
public function removebackendAction()
{
$backend = $this->getParam('backend');
if (!$this->isExistingBackend($backend)) {
$this->view->error = 'Unknown backend ' . $backend;
return;
$backendsConfig = $this->Config('backends')->toArray();
if (false === array_key_exists($backend, $backendsConfig)) {
// TODO: Should behave as in the app's config controller (Specific redirect to an error action)
Notification::error(sprintf($this->translate('Cannot remove "%s". Backend not found.'), $backend));
$this->redirectNow('monitoring/config');
}
$form = new ConfirmRemovalForm();
$form->setRequest($this->getRequest());
$form->setRemoveTarget('backend', $backend);
if ($form->isSubmittedAndValid()) {
$configArray = $this->Config('backends')->toArray();
unset($configArray[$backend]);
if ($this->writeConfiguration(new Zend_Config($configArray), 'backends')) {
Notification::success('Backend "' . $backend . '" Removed');
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
unset($backendsConfig[$backend]);
if ($this->writeConfiguration($backendsConfig, 'backends')) {
Notification::success(sprintf($this->translate('Backend "%s" successfully removed.'), $backend));
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
return;
}
return;
}
$this->view->form = $form;
$this->view->name = $backend;
}
/**
* Display a form to remove the instance identified by the 'instance' parameter
* Display a confirmation form to remove the instance identified by the 'instance' parameter
*/
public function removeinstanceAction()
{
$instance = $this->getParam('instance');
if (!$this->isExistingInstance($instance)) {
$this->view->error = 'Unknown instance ' . $instance;
return;
$instancesConfig = $this->Config('instances')->toArray();
if (false === array_key_exists($instance, $instancesConfig)) {
// TODO: Should behave as in the app's config controller (Specific redirect to an error action)
Notification::error(sprintf($this->translate('Cannot remove "%s". Instance not found.'), $instance));
$this->redirectNow('monitoring/config');
}
$form = new ConfirmRemovalForm();
$form->setRequest($this->getRequest());
$form->setRemoveTarget('instance', $instance);
if ($form->isSubmittedAndValid()) {
$configArray = $this->Config('instances')->toArray();
unset($configArray[$instance]);
if ($this->writeConfiguration(new Zend_Config($configArray), 'instances')) {
Notification::success('Instance "' . $instance . '" Removed');
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
unset($instancesConfig[$instance]);
if ($this->writeConfiguration($instancesConfig, 'instances')) {
Notification::success(sprintf($this->translate('Instance "%s" successfully removed.'), $instance));
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
return;
}
return;
}
$this->view->form = $form;
@ -166,24 +167,36 @@ class Monitoring_ConfigController extends ModuleActionController
public function editinstanceAction()
{
$instance = $this->getParam('instance');
if (!$this->isExistingInstance($instance)) {
$this->view->error = 'Unknown instance ' . htmlentities($instance);
return;
$instancesConfig = $this->Config('instances')->toArray();
if (false === array_key_exists($instance, $instancesConfig)) {
// TODO: Should behave as in the app's config controller (Specific redirect to an error action)
Notification::error(sprintf($this->translate('Cannot edit "%s". Instance not found.'), $instance));
$this->redirectNow('monitoring/config');
}
$form = new EditInstanceForm();
$form->setInstanceConfiguration($this->Config('instances')->get($instance));
$form->setRequest($this->getRequest());
if ($form->isSubmittedAndValid()) {
$instanceConfig = $this->Config('instances')->toArray();
$instanceConfig[$instance] = $form->getConfig();
if ($this->writeConfiguration(new Zend_Config($instanceConfig), 'instances')) {
Notification::success('Instance Modified');
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
return;
$form = new InstanceForm();
$request = $this->getRequest();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
list($newName, $config) = $form->getInstanceConfig();
if ($newName !== $instance) {
unset($instancesConfig[$instance]); // We can safely use unset as all values are part of the form
}
$instancesConfig[$newName] = $config;
if ($this->writeConfiguration($instancesConfig, 'instances')) {
Notification::success(sprintf($this->translate('Instance "%s" successfully modified.'), $instance));
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
return;
}
}
} else {
$form->setInstanceConfig($instance, $instancesConfig[$instance]);
}
$this->view->form = $form;
}
@ -192,33 +205,37 @@ class Monitoring_ConfigController extends ModuleActionController
*/
public function createinstanceAction()
{
$form = new CreateInstanceForm();
$form->setRequest($this->getRequest());
if ($form->isSubmittedAndValid()) {
$instanceConfig = $this->Config('instances');
if ($instanceConfig === null) {
$instanceConfig = array();
} else {
$instanceConfig = $instanceConfig->toArray();
}
$instanceConfig[$form->getInstanceName()] = $form->getConfig()->toArray();
if ($this->writeConfiguration(new Zend_Config($instanceConfig), 'instances')) {
Notification::success('Instance Creation Succeeded');
$form = new InstanceForm();
$request = $this->getRequest();
if ($request->isPost() && $form->isValid($request->getPost())) {
list($name, $config) = $form->getInstanceConfig();
$instancesConfig = $this->Config('instances')->toArray();
$instancesConfig[$name] = $config;
if ($this->writeConfiguration($instancesConfig, 'instances')) {
Notification::success(sprintf($this->translate('Instance "%s" created successfully.'), $name));
$this->redirectNow('monitoring/config');
} else {
$this->render('show-configuration');
return;
}
return;
}
$this->view->form = $form;
$this->render('editinstance');
}
/**
* Display a form to remove the instance identified by the 'instance' parameter
* Write configuration to an ini file
*
* @param Zend_Config $config The configuration to write
* @param string $file The config file to write to
*
* @return bool Whether the configuration was written or not
*/
private function writeConfiguration($config, $file = null)
protected function writeConfiguration($config, $file = null)
{
if (is_array($config)) {
$config = new Zend_Config($config);
}
$target = $this->Config($file)->getConfigFile();
$writer = new PreservingIniWriter(array('filename' => $target, 'config' => $config));
@ -235,49 +252,30 @@ class Monitoring_ConfigController extends ModuleActionController
}
/**
* Return true if the backend exists in the current configuration
*
* @param string $backend The name of the backend to check for existence
*
* @return bool True if the backend name exists, otherwise false
* Display a form to adjust security relevant settings
*/
private function isExistingBackend($backend)
{
$backendCfg = $this->Config('backends');
return $backend && $backendCfg->get($backend);
}
/**
* Return true if the instance exists in the current configuration
*
* @param string $instance The name of the instance to check for existence
*
* @return bool True if the instance name exists, otherwise false
*/
private function isExistingInstance($instance)
{
$instanceCfg = $this->Config('instances');
return $instanceCfg && $instanceCfg->get($instance);
}
public function securityAction()
{
$this->view->tabs = $this->Module()->getConfigTabs()->activate('security');
$form = new SecurityForm();
$form->setConfiguration($this->Config()->get('security'));
$form->setRequest($this->getRequest());
if ($form->isSubmittedAndValid()) {
$config = $this->Config()->toArray();
$config['security'] = $form->getConfig();
if ($this->writeConfiguration(new Zend_Config($config))) {
Notification::success('Configuration modified successfully');
$this->redirectNow('monitoring/config/security');
} else {
$this->render('show-configuration');
return;
$request = $this->getRequest();
$config = $this->Config()->toArray();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
$config['security'] = $form->getValues();
if ($this->writeConfiguration(new Zend_Config($config))) {
Notification::success('Configuration modified successfully');
$this->redirectNow('monitoring/config/security');
} else {
$this->render('show-configuration');
return;
}
}
} elseif (isset($config['security'])) {
$form->populate($config['security']);
}
$this->view->form = $form;
}
}

@ -2,10 +2,7 @@
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Form;
use Icinga\Module\Monitoring\Controller;
use Icinga\Module\Monitoring\Backend;
use Icinga\Data\SimpleQuery;
use Icinga\Web\Widget\Chart\InlinePie;
use Icinga\Module\Monitoring\Form\Command\MultiCommandFlagForm;
use Icinga\Web\Widget;

@ -1,45 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Form\Config\Backend;
use \Zend_Config;
/**
* Extended EditBackendForm for creating new Backends
*
* @see EditBackendForm
*/
class CreateBackendForm extends EditBackendForm
{
/**
* Create this form
*
* @see EditBackendForm::create()
*/
public function create()
{
$this->setBackendConfiguration(new Zend_Config(array('type' => 'ido')));
$this->addElement(
'text',
'backend_name',
array(
'label' => 'Backend Name',
'required' => true,
'helptext' => 'This will be the identifier of this backend'
)
);
parent::create();
}
/**
* Return the name of the backend that is to be created
*
* @return string The name of the backend as entered in the form
*/
public function getBackendName()
{
return $this->getValue('backend_name');
}
}

@ -1,148 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Form\Config\Backend;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Data\ResourceFactory;
/**
* Form for modifying a monitoring backend
*/
class EditBackendForm extends Form
{
/**
* Database resources to use instead of the one's from ResourceFactory (used for testing)
*
* @var array
*/
protected $resources;
/**
* The Backend configuration to use for populating the form
*
* @var Zend_Config
*/
protected $backend;
/**
* Set the configuration to be used for initial population of the form
*
* @param Zend_Form $config
*/
public function setBackendConfiguration($config)
{
$this->backend = $config;
}
/**
* Set a custom array of resources to be used in this form instead of the ones from ResourceFactory
* (used for testing)
*/
public function setResources($resources)
{
$this->resources = $resources;
}
/**
* Return content of the resources.ini or previously set resources for displaying in the database selection field
*
* @return array
*/
public function getResources()
{
if ($this->resources === null) {
return ResourceFactory::getResourceConfigs()->toArray();
} else {
return $this->resources;
}
}
/**
* Return a list of all resources of the given type ready to be used as content for a select input
*
* @param string $type The type of resources to return
*
* @return array
*/
protected function getResourcesByType($type)
{
$backends = array();
foreach ($this->getResources() as $name => $resource) {
if ($resource['type'] === $type) {
$backends[$name] = $name;
}
}
return $backends;
}
/**
* Create this form
*
* @see Icinga\Web\Form::create()
*/
public function create()
{
$backendType = $this->getRequest()->getParam('backend_type', $this->backend->type);
$this->addElement(
'select',
'backend_type',
array(
'label' => 'Backend Type',
'value' => $this->backend->type,
'required' => true,
'helptext' => 'The data source used for retrieving monitoring information',
'multiOptions' => array(
'ido' => 'IDO Backend',
'statusdat' => 'Status.dat',
'livestatus' => 'Livestatus'
)
)
);
$this->addElement(
'select',
'backend_resource',
array(
'label' => 'Resource',
'value' => $this->backend->resource,
'required' => true,
'multiOptions' => $this->getResourcesByType($backendType === 'ido' ? 'db' : $backendType),
'helptext' => 'The resource to use'
)
);
$this->addElement(
'checkbox',
'backend_disable',
array(
'label' => 'Disable This Backend',
'required' => true,
'value' => $this->backend->disabled
)
);
$this->enableAutoSubmit(array('backend_type'));
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
}
/**
* Return a configuration containing the backend settings entered in this form
*
* @return Zend_Config The updated configuration for this backend
*/
public function getConfig()
{
$values = $this->getValues();
return new Zend_Config(
array(
'type' => $values['backend_type'],
'disabled' => $values['backend_disable'],
'resource' => $values['backend_resource']
)
);
}
}

@ -0,0 +1,125 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Form\Config;
use Icinga\Web\Form;
use Icinga\Data\ResourceFactory;
/**
* Form for modifying a monitoring backend
*/
class BackendForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_monitoring_backends');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
return array(
$this->createElement(
'text',
'name',
array(
'required' => true,
'label' => t('Backend Name'),
'helptext' => t('The identifier of this backend')
)
),
$this->createElement(
'select',
'type',
array(
'required' => true,
'class' => 'autosubmit',
'label' => t('Backend Type'),
'helptext' => t('The data source used for retrieving monitoring information'),
'multiOptions' => array(
'ido' => 'IDO Backend',
'statusdat' => 'Status.dat',
'livestatus' => 'Livestatus'
)
)
),
$this->createElement(
'select',
'resource',
array(
'required' => true,
'label' => t('Resource'),
'helptext' => t('The resource to use'),
'multiOptions' => $this->getResourcesByType(
false === isset($formData['type']) || $formData['type'] === 'ido' ? 'db' : $formData['type']
)
)
),
$this->createElement(
'checkbox',
'disabled',
array(
'required' => true,
'label' => t('Disable This Backend')
)
)
);
}
/**
* Return the backend configuration values and its name
*
* The first value is the name and the second one the values as array.
*
* @return array
*/
public function getBackendConfig()
{
$values = $this->getValues();
$name = $values['name'];
if ($values['disabled'] == '0') {
unset($values['disabled']);
}
unset($values['name']);
return array($name, $values);
}
/**
* Populate the form with the given configuration values
*
* @param string $name The name of the backend
* @param array $config The configuration values
*/
public function setBackendConfig($name, array $config)
{
$config['name'] = $name;
$this->populate($config);
}
/**
* Return a list of all resources of the given type ready to be used as content for a select input
*
* @param string $type The type of resources to return
*
* @return array
*/
protected function getResourcesByType($type)
{
$backends = array();
foreach (array_keys(ResourceFactory::getResourceConfigs($type)->toArray()) as $name) {
$backends[$name] = $name;
}
return $backends;
}
}

@ -1,68 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Form\Config;
use Icinga\Web\Form;
/**
* Form for confirming removal of an object
*/
class ConfirmRemovalForm extends Form
{
/**
* The value of the target to remove
*
* @var string
*/
private $removeTarget;
/**
* The name of the target parameter to remove
*
* @var string
*/
private $targetName;
/**
* Set the remove target in this field to be a hidden field with $name and value $target
*
* @param string $name The name to be set in the hidden field
* @param string $target The value to be set in the hidden field
*/
public function setRemoveTarget($name, $target)
{
$this->targetName = $name;
$this->removeTarget = $target;
}
/**
* Create the confirmation form
*
* @see Form::create()
*/
public function create()
{
$this->addElement(
'hidden',
$this->targetName,
array(
'value' => $this->removeTarget,
'required' => true
)
);
$this->addElement(
'button',
'btn_submit',
array(
'type' => 'submit',
'escape' => false,
'value' => '1',
'class' => 'btn btn-cta btn-common',
'label' => $this->getView()->icon('remove.png') . ' Confirm Removal'
)
);
}
}

@ -1,46 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Form\Config\Instance;
use \Icinga\Web\Form;
use \Zend_Config;
/**
* Form for creating new instances
*
* @see EditInstanceForm
*/
class CreateInstanceForm extends EditInstanceForm
{
/**
* Create the form elements
*
* @see EditInstanceForm::create()
*/
public function create()
{
$this->setInstanceConfiguration(new Zend_Config(array()));
$this->addElement(
'text',
'instance_name',
array(
'label' => 'Instance Name',
'helptext' => 'Please enter the name for the instance to create'
)
);
parent::create();
}
/**
* Return the name of the instance to be created
*
* @return string The name of the instance as entered in the form
*/
public function getInstanceName()
{
return $this->getValue('instance_name');
}
}

@ -1,148 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Form\Config\Instance;
use \Zend_Config;
use \Icinga\Web\Form;
/**
* Form for editing existing instances
*/
class EditInstanceForm extends Form
{
/**
* The instance to edit
*
* @var Zend_Config
*/
private $instance;
/**
* The type of the instance
*
* 'local' when no host is given, otherwise 'remote'
*
* @var string
*/
private $instanceType = 'local';
/**
* Set instance configuration to be used for initial form population
*
* @param Zend_Config $config
*/
public function setInstanceConfiguration($config)
{
$this->instance = $config;
if (isset($this->instance->host)) {
$this->instanceType = 'remote';
}
}
/**
* Add a form field for selecting the command pipe type (local or remote)
*/
private function addTypeSelection()
{
$this->addElement(
'select',
'instance_type',
array(
'value' => $this->instanceType,
'multiOptions' => array(
'local' => 'Local Command Pipe',
'remote' => 'Remote Command Pipe'
)
)
);
$this->enableAutoSubmit(array('instance_type'));
}
/**
* Add form elements for remote instance
*/
private function addRemoteInstanceForm()
{
$this->addNote('When configuring a remote host, you need to setup passwordless key authentication');
$this->addElement(
'text',
'instance_remote_host',
array(
'label' => 'Remote Host',
'required' => true,
'value' => $this->instance->host,
'helptext' => 'Enter the hostname or address of the machine on which the icinga instance is running'
)
);
$this->addElement(
'text',
'instance_remote_port',
array(
'label' => 'Remote SSH Port',
'required' => true,
'value' => $this->instance->get('port', 22),
'helptext' => 'Enter the ssh port to use for connecting to the remote icigna instance'
)
);
$this->addElement(
'text',
'instance_remote_user',
array(
'label' => 'Remote SSH User',
'value' => $this->instance->user,
'helptext' => 'Enter the username to use for connecting '
. 'to the remote machine or leave blank for default'
)
);
}
/**
* Create this form
*
* @see Icinga\Web\Form::create
*/
public function create()
{
$this->addTypeSelection();
if ($this->getRequest()->getParam('instance_type', $this->instanceType) === 'remote') {
$this->addRemoteInstanceForm();
}
$this->addElement(
'text',
'instance_path',
array(
'label' => 'Remote Pipe Filepath',
'required' => true,
'value' => $this->instance->get('path', '/usr/local/icinga/var/rw/icinga.cmd'),
'helptext' => 'The file path where the icinga commandpipe can be found'
)
);
$this->setSubmitLabel('{{SAVE_ICON}} Save');
}
/**
* Return the configuration set by this form
*
* @return Zend_Config The configuration set in this form
*/
public function getConfig()
{
$values = $this->getValues();
$config = array(
'path' => $values['instance_path']
);
if ($values['instance_type'] === 'remote') {
$config['host'] = $values['instance_remote_host'];
$config['port'] = $values['instance_remote_port'];
if (isset($values['instance_remote_user']) && $values['instance_remote_user'] != '') {
$config['user'] = $values['instance_remote_user'];
}
}
return new Zend_Config($config);
}
}

@ -0,0 +1,156 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Form\Config;
use Icinga\Web\Form;
use Icinga\Web\Form\Element\Number;
use Icinga\Web\Form\Decorator\HelpText;
use Icinga\Web\Form\Decorator\ElementWrapper;
/**
* Form for modifying/creating monitoring instances
*/
class InstanceForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_monitoring_instances');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
$elements = array(
$this->createElement(
'text',
'name',
array(
'required' => true,
'label' => t('Instance Name')
)
),
$this->createElement(
'select',
'type',
array(
'required' => true,
'ignore' => true,
'label' => t('Instance Type'),
'class' => 'autosubmit',
'helptext' => t(
'When configuring a remote host, you need to setup passwordless key authentication'
),
'multiOptions' => array(
'local' => t('Local Command Pipe'),
'remote' => t('Remote Command Pipe')
)
)
)
);
if (isset($formData['type']) && $formData['type'] === 'remote') {
$elements[] = $this->createElement(
'text',
'host',
array(
'required' => true,
'label' => t('Remote Host'),
'helptext' => t(
'Enter the hostname or address of the machine on which the icinga instance is running'
)
)
);
$elements[] = new Number(
array(
'required' => true,
'name' => 'port',
'label' => t('Remote SSH Port'),
'helptext' => t('Enter the ssh port to use for connecting to the remote icinga instance'),
'value' => 22,
'decorators' => array( // The order is important!
'ViewHelper',
'Errors',
new ElementWrapper(),
new HelpText()
)
)
);
$elements[] = $this->createElement(
'text',
'user',
array(
'required' => true,
'label' => t('Remote SSH User'),
'helptext' => t(
'Enter the username to use for connecting to the remote machine or leave blank for default'
)
)
);
} else {
// TODO(5967,5525): Without this element, switching the type to "local" causes
// the form to be processed as it's complete in that case.
$elements[] = $this->createElement(
'hidden',
'hitchhiker',
array(
'required' => true,
'ignore' => true,
'value' => 'Arthur'
)
);
}
$elements[] = $this->createElement(
'text',
'path',
array(
'required' => true,
'label' => t('Pipe Filepath'),
'value' => '/usr/local/icinga/var/rw/icinga.cmd',
'helptext' => t('The file path where the icinga commandpipe can be found')
)
);
return $elements;
}
/**
* Return the instance configuration values and its name
*
* The first value is the name and the second one the values as array.
*
* @return array
*/
public function getInstanceConfig()
{
$values = $this->getValues();
$name = $values['name'];
unset($values['name']);
return array($name, $values);
}
/**
* Populate the form with the given configuration values
*
* @param string $name The name of the instance
* @param array $config The configuration values
*/
public function setInstanceConfig($name, array $config)
{
$config['name'] = $name;
if (isset($config['host'])) {
// Necessary as we have no config directive for setting the instance's type
$config['type'] = 'remote';
}
$this->populate($config);
}
}

@ -4,57 +4,39 @@
namespace Icinga\Module\Monitoring\Form\Config;
use Zend_Config;
use Icinga\Web\Form;
/**
* Form for modifying security relevant settings
*/
class SecurityForm extends Form
{
/**
* The configuration to use for populating the form
* Initialize this form
*/
protected $config;
public function init()
{
$this->setName('form_config_monitoring_security');
$this->setSubmitLabel(t('Save Changes'));
}
/**
* Create this form
*
* @see Icinga\Web\Form::create
* @see Form::createElements()
*/
public function create()
public function createElements(array $formData)
{
$default = '*pw*,*pass*,community';
$this->addElement(
'text',
'protected_customvars',
array(
'label' => 'Protected Custom Variables',
'required' => true,
'value' => $this->config ? $this->config->get('protected_customvars', $default) : $default,
'helptext' => 'Comma separated case insensitive list of protected custom variables.'
. ' Use * as a placeholder for zero or more wildcard characters.'
. ' Existance of those custom variables will be shown, but their values will be masked.'
return array(
$this->createElement(
'text',
'protected_customvars',
array(
'label' => 'Protected Custom Variables',
'required' => true,
'helptext' => 'Comma separated case insensitive list of protected custom variables.'
. ' Use * as a placeholder for zero or more wildcard characters.'
. ' Existance of those custom variables will be shown, but their values will be masked.'
)
)
);
$this->setSubmitLabel('Save');
}
/**
* Set the configuration to be used for initial population of the form
*/
public function setConfiguration($config)
{
$this->config = $config;
}
/**
* Return the configuration set by this form
*
* @return Zend_Config The configuration set in this form
*/
public function getConfig()
{
$values = $this->getValues();
return new Zend_Config(array(
'protected_customvars' => $values['protected_customvars']
));
}
}

@ -0,0 +1,2 @@
<h4><?= $this->translate('Add New Backend'); ?></h4>
<?= $form; ?>

@ -0,0 +1,2 @@
<h4><?= $this->translate('Add New Instance'); ?></h4>
<?= $form; ?>

@ -1,13 +1,2 @@
<?php if ($this->name): ?>
<h4><i> <i class="icinga-icon-edit"></i> Edit Backend "<?= $this->escape($this->name) ?>"</h4>
<?php else: ?>
<h4> <i class="icinga-icon-create"></i> Create New Backend</h4>
<?php endif; ?>
<?php if ($this->error): ?>
<div class="alert alert-danger">
<?= $this->escape($this->error); ?>
</div>
<?php endif; ?>
<?= $this->form; ?>
<h4><?= $this->translate('Edit Existing Backend'); ?></h4>
<?= $form; ?>

@ -1,14 +1,2 @@
<?php if (isset($this->name)): ?>
<h4><i class="icinga-icon-edit"></i> } Edit Instance Configuration for "<?= $this->escape($this->name) ?>"</h4>
<?php else: ?>
<h4><i class="icinga-icon-create"></i> Configure New Icinga Instance</h4>
<?php endif; ?>
<?php if ($this->error): ?>
<div class="alert alert-danger">
<?= $this->escape($this->error); ?>
</div>
<?php endif; ?>
<?= $this->form; ?>
<h4><?= $this->translate('Edit Existing Instance'); ?></h4>
<?= $form; ?>

@ -1,8 +1,2 @@
<h4><i class="icinga-icon-remove"></i> Remove Backend "<?= $this->escape($this->name) ?>"</h4>
<p>
Are you sure you want to remove the backend <?= $this->escape($this->name) ?>?
</p>
<?= $this->form; ?>
<h4><?= $this->translate('Remove Existing Backend'); ?></h4>
<?= $form; ?>

@ -1,13 +1,4 @@
<h4><i class="icinga-icon-remove"></i> Remove Instance "<?= $this->escape($this->name) ?>"</h4>
<p>
Are you sure you want to remove the instance <?= $this->escape($this->name) ?>?
</p>
<p>
<i class="icinga-icon-warning"></i> If you have still any environments or views refering to this instance, you won't be able to send commands anymore
after deletion.
</p>
<?= $this->form; ?>
<h4><?= $this->translate('Remove Existing Instance'); ?></h4>
<p>Are you sure you want to remove the instance <?= $this->escape($name); ?>?</p>
<p><i class="icinga-icon-warning"></i> If you have still any environments or views referring to this instance, you won't be able to send commands anymore after deletion.</p>
<?= $form; ?>

@ -97,7 +97,6 @@ class TimelineIntervalBox extends AbstractWidget
);
if ($this->request) {
$form->setAction($this->request->getRequestUri());
$form->populate($this->request->getParams());
}

@ -17,11 +17,7 @@ td.configTable {
min-width: 300px;
}
div.config-form-group {
float: right;
}
.form-group {
.form-element {
margin-bottom: 1em;
}