Merge branch 'bugfix/frontend-tests-4491'

fixes #4602
fixes #4605
fixes #4606
fixes #4642
fixes #4643
fixes #4546
fixes #4640
fixes #4491
fixes #4657
This commit is contained in:
Johannes Meyer 2013-08-29 13:32:33 +02:00
commit 772d27bb89
75 changed files with 1727 additions and 1404 deletions

4
.gitignore vendored
View File

@ -4,6 +4,7 @@
!.gitignore
!.vagrant-puppet
!public/.htaccess
!public/.htaccess.in
!.gitkeep
build/
@ -30,3 +31,6 @@ config/enabledModules/
# User preferences
config/preferences/*.ini
# Application logfiles
var/log/*.log

View File

@ -42,7 +42,7 @@ user { 'icinga':
}
user { 'apache':
groups => 'icinga-cmd',
groups => ['icinga-cmd', 'vagrant'],
require => [ Class['apache'], Group['icinga-cmd'] ]
}
@ -471,13 +471,13 @@ exec { 'create-pgsql-icingaweb-db':
exec { 'populate-icingaweb-mysql-db-accounts':
unless => 'mysql -uicingaweb -picinga icingaweb -e "SELECT * FROM account;" &> /dev/null',
command => 'mysql -uicingaweb -picinga icingaweb < /vagrant/etc/schema/users.mysql.sql',
command => 'mysql -uicingaweb -picinga icingaweb < /vagrant/etc/schema/accounts.mysql.sql',
require => [ Exec['create-mysql-icingaweb-db'] ]
}
exec { 'populate-icingweba-pgsql-db-accounts':
unless => 'psql -U icingaweb -d icingaweb -c "SELECT * FROM account;" &> /dev/null',
command => 'sudo -u postgres psql -U icingaweb -d icingaweb -f /vagrant/etc/schema/users.pgsql.sql',
command => 'sudo -u postgres psql -U icingaweb -d icingaweb -f /vagrant/etc/schema/accounts.pgsql.sql',
require => [ Exec['create-pgsql-icingaweb-db'] ]
}

View File

@ -7,7 +7,7 @@ INSTALL_OPTS=@INSTALL_OPTS@
INSTALL_OPTS_WEB=@INSTALL_OPTS_WEB@
default:
@echo "Icinga2Web make targets: "
@echo "IcingaWeb make targets: "
@printf "%b" " -install:\t\t\tInstall the application and overwrite configs\n"
@printf "%b" " -update:\t\t\tInstall the application without touching the configs\n"
@printf "%b" " -install-apache-config:\tInstall the apache configuration\n"
@ -15,7 +15,7 @@ default:
#
# Installs the whole application w\o httpd configurations
#
install: install-static-files install-runtime-dirs
install: install-static-files install-runtime-dirs ensure-writable-folders
update: install-application
#
@ -26,8 +26,8 @@ clean:
if [ -f ./Makefile ];then \
rm ./Makefile; \
fi; \
if [ -f ./etc/apache/icinga2web.conf ];then \
rm ./etc/apache/icinga2web.conf; \
if [ -f ./etc/apache/icingaweb.conf ];then \
rm ./etc/apache/icingaweb.conf; \
fi;
#
@ -51,12 +51,12 @@ install-tests: copy-folder-tests
# Install configurations for apache2
#
install-apache-config:
$(INSTALL) -m 644 $(INSTALL_OPTS) "./etc/apache/icinga2web.conf" $(WWW_CONF_PATH)/icinga2web.conf;
$(INSTALL) -m 644 $(INSTALL_OPTS) "./etc/apache/icingaweb.conf" $(WWW_CONF_PATH)/icingaweb.conf;
#
# Installs the php files to the prefix
#
install-application: copy-web-files-application copy-web-files-library
install-application: copy-web-files-application copy-web-files-library
#
# Rule for coying folders and containing files (arbitary types), hidden files are excluded
@ -76,6 +76,12 @@ copy-folder-%:
done
ensure-writable-folders:
$(INSTALL) -m 775 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/var/
$(INSTALL) -m 775 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/var/log
chmod -R 775 $(DESTDIR)$(prefix)/config
#
# Rule for copying only php, *html, js and ini files. Hidden files are ignored
#
@ -84,14 +90,17 @@ copy-web-files-%:
@dirs=`find ./$* -mindepth 1 -type d `;\
for dir in $$dirs; do \
$(INSTALL) -m 755 $(INSTALL_OPTS) -d $(DESTDIR)$(prefix)/"$$dir"; \
$(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/"$$dir"; \
done;
@files=`find ./$* -mindepth 1 -type f \
-name "*.php" -or -name "*.ini" -or -name "*.*html" -or -name "*.js" \
-name "*.php" -or -name "*.ini" -or -name "*.*html" \
-or -name "*.js" -or -name "*.css" -or -name "*.less" \
-or -name "*.otf" -or -name "*.ttf" -or -name "*.otf" \
-or -name "*.svg" -or -name "*.woff" \
-and ! -name ".*"`; \
for file in $$files; do \
$(INSTALL) -m 644 $(INSTALL_OPTS) "$$file" $(DESTDIR)$(prefix)/"$$file"; \
$(INSTALL) -m 644 $(INSTALL_OPTS_WEB) "$$file" $(DESTDIR)$(prefix)/"$$file"; \
done

View File

@ -63,7 +63,7 @@ class AuthenticationController extends ActionController
$credentials = new Credentials();
$this->view->form = new LoginForm();
$this->view->form->setRequest($this->_request);
$this->view->title = "Icinga Web Login";
try {
$auth = AuthManager::getInstance(null, array(
'writeSession' => $this->modifiesSession

View File

@ -24,8 +24,6 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
use \Icinga\Application\Benchmark;
use \Icinga\Authentication\Manager;
use \Icinga\Web\Controller\BaseConfigController;
use \Icinga\Web\Widget\Tab;
use \Icinga\Web\Url;
@ -33,10 +31,11 @@ use \Icinga\Web\Hook\Configuration\ConfigurationTabBuilder;
use \Icinga\Application\Icinga;
use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Form\Config\GeneralForm;
use \Icinga\Form\Config\AuthenticationForm;
use \Icinga\Form\Config\Authentication\ReorderForm;
use \Icinga\Form\Config\Authentication\LdapBackendForm;
use \Icinga\Form\Config\Authentication\DbBackendForm;
use \Icinga\Form\Config\LoggingForm;
use \Icinga\Form\Config\ConfirmRemovalForm;
use \Icinga\Config\PreservingIniWriter;
/**
@ -44,6 +43,7 @@ use \Icinga\Config\PreservingIniWriter;
*/
class ConfigController extends BaseConfigController
{
/**
* Create tabs for this configuration controller
*
@ -97,9 +97,11 @@ class ConfigController extends BaseConfigController
$form->setRequest($this->_request);
if ($form->isSubmittedAndValid()) {
if (!$this->writeConfigFile($form->getConfig(), 'config')) {
return false;
return;
}
$this->redirectNow('/config');
$this->view->successMessage = "Config Sucessfully Updated";
$form->setConfiguration(IcingaConfig::app(), true);
}
$this->view->form = $form;
}
@ -114,11 +116,11 @@ class ConfigController extends BaseConfigController
$form->setConfiguration(IcingaConfig::app());
$form->setRequest($this->_request);
if ($form->isSubmittedAndValid()) {
$config = $form->getConfig();
if (!$this->writeConfigFile($form->getConfig(), 'config')) {
return;
}
$this->redirectNow('/config/logging');
$this->view->successMessage = "Config Sucessfully Updated";
$form->setConfiguration(IcingaConfig::app(), true);
}
$this->view->form = $form;
}
@ -139,10 +141,12 @@ class ConfigController extends BaseConfigController
*/
public function moduleenableAction()
{
$module = $this->_getParam('name');
$manager = Icinga::app()->getModuleManager();
$manager->enableModule($this->_getParam('name'));
$manager->loadModule($this->_getParam('name'));
$this->redirectNow('config/moduleoverview?_render=body');
$manager->enableModule($module);
$manager->loadModule($module);
$this->view->successMessage = 'Module "' . $module . '" enabled';
$this->moduleoverviewAction();
}
/**
@ -150,32 +154,78 @@ class ConfigController extends BaseConfigController
*/
public function moduledisableAction()
{
$module = $this->_getParam('name');
$manager = Icinga::app()->getModuleManager();
$manager->disableModule($this->_getParam('name'));
$this->redirectNow('config/moduleoverview?_render=body');
$manager->disableModule($module);
$this->view->successMessage = 'Module "' . $module . '" disabled';
$this->moduleoverviewAction();
}
/**
* Action for creating a new authentication backend
*/
public function authenticationAction()
public function authenticationAction($showOnly = false)
{
$form = new AuthenticationForm();
$config = IcingaConfig::app('authentication');
$form->setConfiguration($config);
$form->setRequest($this->_request);
$config = IcingaConfig::app('authentication', true);
$order = array_keys($config->toArray());
$this->view->backends = array();
foreach ($config as $backend=>$backendConfig) {
$form = new ReorderForm();
$form->setName('form_reorder_backend_' . $backend);
$form->setAuthenticationBackend($backend);
$form->setCurrentOrder($order);
$form->setRequest($this->_request);
if (!$showOnly && $form->isSubmittedAndValid()) {
if ($this->writeAuthenticationFile($form->getReorderedConfig($config))) {
$this->view->successMessage = 'Authentication Order Updated';
$this->authenticationAction(true);
}
return;
}
$this->view->backends[] = (object) array(
'name' => $backend,
'reorderForm' => $form
);
}
$this->render('authentication');
}
/**
* Action for removing a backend from the authentication list.
*
* Redirects to the overview after removal is finished
*/
public function removeauthenticationbackendAction()
{
$configArray = IcingaConfig::app('authentication', true)->toArray();
$authBackend = $this->getParam('auth_backend');
if (!isset($configArray[$authBackend])) {
$this->view->errorMessage = 'Can\'t perform removal: Unknown Authentication Backend Provided';
$this->authenticationAction(true);
return;
}
$form = new ConfirmRemovalForm();
$form->setRequest($this->getRequest());
$form->setRemoveTarget('auth_backend', $authBackend);
if ($form->isSubmittedAndValid()) {
$modifiedConfig = $form->getConfig();
if (empty($modifiedConfig)) {
$form->addError('You need at least one authentication backend.');
} else if (!$this->writeAuthenticationFile($modifiedConfig)) {
return;
} else {
$this->redirectNow('/config/authentication');
unset($configArray[$authBackend]);
if ($this->writeAuthenticationFile($configArray)) {
$this->view->successMessage = 'Authentication Backend "' . $authBackend . '" Removed';
$this->authenticationAction(true);
}
return;
}
$this->view->form = $form;
$this->view->name = $authBackend;
$this->render('authentication/remove');
}
/**
@ -188,18 +238,78 @@ class ConfigController extends BaseConfigController
} 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 ($form->getConfig() as $backendName => $settings) {
if (isset($backendCfg[$backendName])) {
$this->view->errorMessage = 'Backend name already exists';
$this->view->form = $form;
$this->render('authentication/create');
return;
}
$backendCfg[$backendName] = $settings;
}
if ($this->writeAuthenticationFile($backendCfg)) {
// redirect to overview with success message
$this->view->successMessage = 'Backend Modification Written';
$this->authenticationAction(true);
}
return;
}
$this->view->form = $form;
$this->render('authentication/create');
}
/**
* Form for editing backends
*
* Mostly the same like the createAuthenticationBackendAction, but with additional checks for backend existence
* and form population
*/
public function editauthenticationbackendAction()
{
$configArray = IcingaConfig::app('authentication', true)->toArray();
$authBackend = $this->getParam('auth_backend');
if (!isset($configArray[$authBackend])) {
$this->view->errorMessage = 'Can\'t edit: Unknown Authentication Backend Provided';
$this->authenticationAction(true);
return;
}
if ($configArray[$authBackend]['backend'] === 'ldap') {
$form = new LdapBackendForm();
} else {
$form = new DbBackendForm();
}
$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
if ($backendName != $authBackend) {
unset($backendCfg[$authBackend]);
}
}
if (!$this->writeAuthenticationFile($backendCfg)) {
return;
if ($this->writeAuthenticationFile($backendCfg)) {
// redirect to overview with success message
$this->view->successMessage = 'Backend "' . $authBackend . '" created';
$this->authenticationAction(true);
}
$this->redirectNow('/config/authentication');
return;
}
$this->view->name = $authBackend;
$this->view->form = $form;
$this->render('authentication/modify');
}

View File

@ -90,7 +90,7 @@ class PreferenceController extends BasePreferenceController
}
try {
$userPreferences->commit();
$this->view->success = true;
$this->view->successMessage = "Preferences Updated Successfully";
// recreate form to show new values
$form = new GeneralForm();

View File

@ -43,6 +43,7 @@ class LoginForm extends Form
*/
protected function create()
{
$this->setName('form_login');
$this->addElement(
'text',
'username',

View File

@ -30,9 +30,7 @@
namespace Icinga\Form\Config\Authentication;
use \Zend_Config;
use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Application\Icinga;
use \Icinga\Application\Logger;
use \Icinga\Web\Form\Decorator\HelpText;
use \Icinga\Application\DbAdapterFactory;
use \Icinga\Web\Form;
@ -129,6 +127,48 @@ abstract class BaseBackendForm extends Form
}
}
/**
* Add checkbox at the beginning of the form which allows to skip logic connection validation
*/
private function addForceCreationCheckbox()
{
$checkbox = new \Zend_Form_Element_Checkbox(
array(
'name' => 'backend_force_creation',
'label' => 'Force Changes',
'helptext' => '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 True when validation succeeded, false if not
*/
public function isValid($data)
{
if (!parent::isValid($data)) {
return false;
}
if ($this->getRequest()->getPost('backend_force_creation')) {
return true;
}
if (!$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
@ -136,4 +176,14 @@ abstract class BaseBackendForm extends Form
* @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.
*
* @return bool True when validation succeeded, otherwise false
*/
abstract public function isValidAuthenticationBackend();
}

View File

@ -29,12 +29,8 @@
namespace Icinga\Form\Config\Authentication;
use \Zend_Config;
use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Application\Icinga;
use \Icinga\Application\Logger;
use \Icinga\Authentication\Backend\DbUserBackend;
use \Icinga\Application\DbAdapterFactory;
use \Icinga\Web\Form;
/**
* Form class for adding/modifying database authentication backends
@ -66,6 +62,7 @@ class DbBackendForm extends BaseBackendForm
*/
public function create()
{
$this->setName('form_modify_backend');
$name = $this->filterName($this->getBackendName());
$this->addElement(
@ -118,4 +115,32 @@ class DbBackendForm extends BaseBackendForm
$section => $cfg
);
}
/**
* Validate the current configuration by creating a backend and requesting the user count
*
* @return bool True when the backend is valid, false otherwise
* @see BaseBackendForm::isValidAuthenticationBackend
*/
public function isValidAuthenticationBackend()
{
try {
$name = $this->getBackendName();
$db = DbAdapterFactory::getDbAdapter(
$this->getValue('backend_' . $this->filterName($name) . '_' . 'resource')
);
$dbBackend = new DbUserBackend($db);
if ($dbBackend->getUserCount() < 1) {
$this->addErrorMessage("No users found under the specified database backend");
return false;
}
} catch (\Exception $e) {
$this->addErrorMessage("Using the specified backend failed: " . $e->getMessage());
return false;
} catch (\Zend_Db_Statement_Exception $e) {
$this->addErrorMessage("Using the specified backend failed: " . $e->getMessage());
return false;
}
return true;
}
}

View File

@ -28,11 +28,9 @@
namespace Icinga\Form\Config\Authentication;
use \Icinga\Authentication\Backend\LdapUserBackend;
use \Exception;
use \Zend_Config;
use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Application\Icinga;
use \Icinga\Application\Logger;
use \Icinga\Application\DbAdapterFactory;
use \Icinga\Web\Form;
/**
@ -47,6 +45,7 @@ class LdapBackendForm extends BaseBackendForm
*/
public function create()
{
$this->setName('form_modify_backend');
$name = $this->filterName($this->getBackendName());
$backend = $this->getBackend();
@ -133,6 +132,7 @@ class LdapBackendForm extends BaseBackendForm
$this->setSubmitLabel('{{SAVE_ICON}} Save Backend');
}
/**
* Return the ldap authentication backend configuration for this form
*
@ -160,4 +160,33 @@ class LdapBackendForm extends BaseBackendForm
$section => $cfg
);
}
/**
* Validate the current configuration by creating a backend and requesting the user count
*
* @return bool True when the backend is valid, false otherwise
* @see BaseBackendForm::isValidAuthenticationBacken
*/
public function isValidAuthenticationBackend()
{
try {
$cfg = $this->getConfig();
$backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name';
$testConn = new LdapUserBackend(
new Zend_Config($cfg[$this->getValue($backendName)])
);
if ($testConn->getUserCount() === 0) {
throw new Exception('No Users Found On Directory Server');
}
} catch (Exception $exc) {
$this->addErrorMessage(
'Connection Validation Failed:'.
$exc->getMessage()
);
return false;
}
return true;
}
}

View File

@ -0,0 +1,262 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config\Authentication;
use \Zend_Config;
use \Icinga\Web\Form;
use \Icinga\Web\Url;
/**
* 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
*/
private $backend = null;
/**
* The current ordering of all backends, required to determine possible changes
*
* @var array
*/
private $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 setAuthenticationBackend($backend)
{
$this->backend = $backend;
}
/**
* Return the name of the currently set backend as it will appear in the forms
*
* This calls the Zend Filtername function in order to filter specific chars
*
* @return string The filtered name of the backend
* @see Form::filterName()
*/
public function getBackendName()
{
return $this->filterName($this->backend);
}
/**
* Create this form.
*
* Note: The form action will be set here to the authentication overview
*
* @see Form::create
*/
public function create()
{
$this->upForm = new Form();
$this->downForm = new Form();
if ($this->moveElementUp($this->backend, $this->currentOrder) !== $this->currentOrder) {
$this->upForm->addElement(
'hidden',
'form_backend_order',
array(
'required' => true,
'value' => join(',', $this->moveElementUp($this->backend, $this->currentOrder))
)
);
$this->upForm->addElement(
'submit',
'btn_' . $this->getBackendName() . '_reorder_up',
array(
'name' => 'btn_' . $this->getBackendName() . '_reorder_up',
'label' => '{{ICON_UP}} Move up in authentication order',
)
);
}
if ($this->moveElementDown($this->backend, $this->currentOrder) !== $this->currentOrder) {
$this->downForm->addElement(
'hidden',
'form_backend_order',
array(
'required' => true,
'value' => join(',', $this->moveElementDown($this->backend, $this->currentOrder))
)
);
$this->downForm->addElement(
'submit',
'btn_' . $this->getBackendName() . '_reorder_down',
array(
'name' => 'btn_' . $this->getBackendName() . '_reorder_down',
'label' => '{{ICON_UP}} Move down in authentication order',
)
);
}
$this->setAction(Url::fromPath("config/authentication", array())->getAbsoluteUrl());
}
/**
* Return the result of $this->getValues but flatten the result
*
* The result will be a key=>value array without subarrays
*
* @param bool $supressArrayNotation passed to getValues
*
* @return array The currently set values
* @see Form::getValues()
*/
public function getFlattenedValues($supressArrayNotation = false)
{
$values = parent::getValues($supressArrayNotation);
$result = array();
foreach ($values 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 True when the form is submitted, otherwise false
*/
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 submited
*
* @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();
$reordered = array();
$newOrder = $this->getFlattenedValues();
$order = explode(',', $newOrder['form_backend_order']);
foreach ($order as $key) {
if (!isset($originalConfig[$key])) {
continue;
}
$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
*/
private static function moveElementUp($key, array $array)
{
$swap = null;
for ($i=0; $i<count($array)-1; $i++) {
if ($array[$i+1] !== $key) {
continue;
}
$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 up, 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
*/
private static function moveElementDown($key, array $array)
{
$swap = null;
for ($i=0; $i<count($array)-1; $i++) {
if ($array[$i] !== $key) {
continue;
}
$swap = $array[$i+1];
$array[$i+1] = $array[$i];
$array[$i] = $swap;
return $array;
}
return $array;
}
}

View File

@ -1,385 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Config;
use \Zend_Config;
use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Application\Logger;
use \Icinga\Web\Form;
use \Icinga\Web\Form\Decorator\ConditionalHidden;
/**
* Form for modifying the authentication provider and order.
*
* This is a composite form from one or more forms under the Authentication folder
*/
class AuthenticationForm extends Form
{
/**
* The configuration to use for populating this form
*
* @var IcingaConfig
*/
private $config = null;
/**
* The resources to use instead of the factory provided ones (use for testing)
*
* @var null
*/
private $resources = null;
/**
* An array containing all provider subforms currently displayed
*
* @var array
*/
private $backendForms = array();
/**
* Set an alternative array of resources that should be used instead of the DBFactory resource set
* (used for testing)
*
* @param array $resources The resources to use for populating the db selection field
*/
public function setResources(array $resources)
{
$this->resources = $resources;
}
/**
* Set the configuration to be used for this form
*
* @param IcingaConfig $cfg
*/
public function setConfiguration($cfg)
{
$this->config = $cfg;
}
/**
* Add a hint to remove the backend identified by $name
*
* The button will have the name "backend_$name_remove"
*
* @param string $name The backend to add this button for
*
* @return string The id of the added button
*/
private function addRemoveHint($name)
{
$this->addElement(
'checkbox',
'backend_' . $name . '_remove',
array(
'name' => 'backend_' . $name . '_remove',
'label' => 'Remove this authentication provider',
'value' => $name,
'checked' => $this->isMarkedForDeletion($name)
)
);
$this->enableAutoSubmit(array('backend_' . $name . '_remove'));
return 'backend_' . $name . '_remove';
}
/**
* Add the form for the provider identified by $name, with the configuration $backend
*
* Supported backends are backends with a form found under \Icinga\Form\Config\Authentication.
* The backend name ist the (uppercase first) prefix with 'BackendForm' as the suffix.
*
* Originally it was intended to add the provider as a subform. As this didn't really work with
* the Zend validation logic (maybe our own validation logic breaks it), we now create the form, but add
* all elements to this form explicitly.
*
* @param string $name The name of the backend to add
* @param Zend_Config $backend The configuration of the backend
*/
private function addProviderForm($name, $backend)
{
$type = ucfirst(strtolower($backend->get('backend')));
$formClass = '\Icinga\Form\Config\Authentication\\' . $type . 'BackendForm';
if (!class_exists($formClass)) {
Logger::error('Unsupported backend found in authentication configuration: ' . $backend->get('backend'));
return;
}
$form = new $formClass();
$form->setBackendName($name);
$form->setBackend($backend);
if ($this->resources) {
$form->setResources($this->resources);
}
// It would be nice to directly set the form via
// this->setForm, but Zend doesn't handle form validation
// properly if doing so.
$form->create();
foreach ($form->getElements() as $elName => $element) {
if ($elName === 'backend_' . $this->filterName($name) . '_name') {
continue;
}
$this->addElement($element, $elName);
}
$this->backendForms[] = $form;
}
/**
* Add the buttons for modifying authentication priorities
*
* @param string $name The name of the backend to add the buttons for
* @param array $order The current order which will be used to determine the changed order
*
* @return array An array containing the newly added form element ids as strings
*/
public function addPriorityButtons($name, $order = array())
{
$formEls = array();
$priorities = array(
'up' => join(',', self::moveElementUp($name, $order)),
'down' => join(',', self::moveElementDown($name, $order))
);
if ($priorities['up'] != join(',', $order)) {
$this->addElement(
'button',
'priority' . $name . '_up',
array(
'name' => 'priority',
'label' => 'Move up in authentication order',
'value' => $priorities['up'],
'type' => 'submit'
)
);
$formEls[] = 'priority' . $name . '_up';
}
if ($priorities['down'] != join(',', $order)) {
$this->addElement(
'button',
'priority' . $name . '_down',
array(
'name' => 'priority',
'label' => 'Move down in authentication order',
'value' => $priorities['down'],
'type' => 'submit'
)
);
$formEls[] = 'priority' . $name . '_down';
}
return $formEls;
}
/**
* Overwrite for Zend_Form::populate in order to preserve the modified priority of the backends
*
* @param array $values The values to populate the form with
*
* @return self
*
* @see Zend_Form::populate()
*/
public function populate(array $values)
{
$last_priority = $this->getValue('current_priority');
parent::populate($values);
$this->getElement('current_priority')->setValue($last_priority);
return $this;
}
/**
* Return an array containing all authentication providers in the order they should be used
*
* @return array An array containing the identifiers (section names) of the authentication backend in
* the order they should be persisted
*/
private function getAuthenticationOrder()
{
$request = $this->getRequest();
$order = $request->getParam(
'priority',
$request->getParam('current_priority', null)
);
if ($order === null) {
$order = array_keys($this->config->toArray());
} else {
$order = explode(',', $order);
}
return $order;
}
/**
* Return true if the backend should be deleted when the changes are persisted
*
* @param string $backendName The name of the backend to check for being in a 'delete' state
*
* @return bool Whether this backend will be deleted on save
*/
private function isMarkedForDeletion($backendName)
{
return intval($this->getRequest()->getParam('backend_' . $backendName . '_remove', 0)) === 1;
}
/**
* Add persistent values to the form in hidden fields
*
* Currently this adds the 'current_priority' field to persist priority modifications. This prevents changes in the
* authentication order to be lost as soon as other changes are submitted (like marking a backend for deletion)
*/
private function addPersistentState()
{
$this->addElement(
'hidden',
'current_priority',
array(
'name' => 'current_priority',
'value' => join(',', $this->getAuthenticationOrder())
)
);
}
/**
* Create the authentication provider configuration form
*
* @see IcingaForm::create()
*/
public function create()
{
$order = $this->getAuthenticationOrder();
foreach ($order as $name) {
$this->addNote('Backend ' . $name, 4);
$this->addRemoveHint($this->filterName($name));
$backend = $this->config->get($name, null);
if ($backend === null) {
continue;
}
if (!$this->isMarkedForDeletion($this->filterName($name))) {
$this->addProviderForm($name, $backend);
$this->addPriorityButtons($name, $order);
}
}
$this->addPersistentState();
$this->enableConditionalDecorator();
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
}
/**
* Return the configuration state defined by this form
*
* @return array
*/
public function getConfig()
{
$result = array();
foreach ($this->backendForms as $name) {
$name->populate($this->getRequest()->getParams());
$result += $name->getConfig();
}
return $result;
}
/**
* Enable the "ConditionalHidden" Decorator for all elements in this form
*
* @see ConditionalHidden
*/
private function enableConditionalDecorator()
{
foreach ($this->getElements() as $element) {
$element->addDecorator(new ConditionalHidden());
}
}
/**
* 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
*/
private static function moveElementUp($key, array $array)
{
$swap = null;
for ($i=0; $i<count($array)-1; $i++) {
if ($array[$i+1] !== $key) {
continue;
}
$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 up, 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
*/
private static function moveElementDown($key, array $array)
{
$swap = null;
for ($i=0; $i<count($array)-1; $i++) {
if ($array[$i] !== $key) {
continue;
}
$swap = $array[$i+1];
$array[$i+1] = $array[$i];
$array[$i] = $swap;
return $array;
}
return $array;
}
}

View File

@ -0,0 +1,83 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\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->setName('form_confirm_removal');
$this->addElement(
'hidden',
$this->targetName,
array(
'value' => $this->removeTarget,
'required' => true
)
);
$this->setSubmitLabel('{{REMOVE_ICON}} Confirm Removal');
}
}

View File

@ -33,7 +33,6 @@ use \Zend_Config;
use \Zend_Form_Element_Text;
use \Zend_Form_Element_Select;
use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Application\Icinga;
use \Icinga\Application\DbAdapterFactory;
use \Icinga\Web\Form;
use \Icinga\Web\Form\Validator\WritablePathValidator;
@ -322,7 +321,7 @@ class GeneralForm extends Form
if ($preferences === null) {
$preferences = new Zend_Config(array());
}
$this->setName('form_config_general');
$this->addDevelopmentCheckbox($global);
$this->addTimezoneSelection($global);
$this->addModuleSettings($global);

View File

@ -122,6 +122,7 @@ class LoggingForm extends Form
*/
public function create()
{
$this->setName('form_config_logging');
if ($this->config === null) {
$this->config = new Zend_Config(array());
}

View File

@ -129,7 +129,7 @@ class AddUrlForm extends Form
protected function create()
{
$dashboard = new Dashboard();
$this->setName('form_dashboard_add');
$dashboard->readConfig(IcingaConfig::app('dashboard/dashboard'));
$this->addElement(
'text',
@ -144,7 +144,8 @@ class AddUrlForm extends Form
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
!$this->getRequest()->getPost('use_existing_dashboard', '0')) // and the user didn't click the 'use
// existing' button
) {
$this->addNewPaneTextField();
} else {

View File

@ -34,7 +34,6 @@ use \Zend_Form_Element_Text;
use \Zend_Form_Element_Select;
use \Icinga\Application\Config as IcingaConfig;
use \Icinga\Application\Icinga;
use \Icinga\Application\DbAdapterFactory;
use \Icinga\User\Preferences;
use \Icinga\Web\Form;
use \Icinga\Web\Form\Validator\TimeFormatValidator;
@ -215,6 +214,7 @@ class GeneralForm extends Form
if ($this->config === null) {
$this->config = new Zend_Config(array());
}
$this->setName('form_preference_set');
$global = $this->config->global;
if ($global === null) {
$global = new Zend_Config(array());

View File

@ -11,7 +11,7 @@
<meta charset="utf-8">
<meta content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<title><?= $this->title ? $this->title : 'Icinga Web'; ?></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

View File

@ -13,17 +13,19 @@
<!-- </form>-->
<!-- </li>-->
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<?= $this->escape($this->auth()->getUser()->getUsername()); ?>
<a href="#" class="dropdown-toggle" data-toggle="dropdown" id="icinga_app_nav_useraction">
<span id="icinga_app_nav_username">
<?= $this->escape($this->auth()->getUser()->getUsername()); ?>
</span>
<i>{{USER_ICON}}</i>
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li>
<li id="icinga_app_nav_preferences">
<a href="<?= $this->href('/preference'); ?>"><?= $this->translate('Preferences'); ?> </a>
</li>
<li>
<a href="<?= $this->href('/authentication/logout'); ?>"><?= $this->translate('Logout'); ?></a>
<li id="icinga_app_nav_logout">
<a href="<?= $this->href('/authentication/logout'); ?>" title="Logout"><?= $this->translate('Logout'); ?></a>
</li>
</ul>
</li>

View File

@ -1,35 +1,56 @@
<?php
use Icinga\Web\Url;
$createLdapBackend = Url::fromPath(
'/config/createAuthenticationBackend',
array('type' => 'ldap')
)->getAbsoluteUrl();
$createDbBackend = Url::fromPath(
'/config/createAuthenticationBackend',
array('type' => 'db')
)->getAbsoluteUrl();
$createLdapBackend = $this->href('/config/createAuthenticationBackend', array('type' => 'ldap'));
$createDbBackend = $this->href('/config/createAuthenticationBackend', array('type' => 'db'));
?>
<?= $this->tabs->render($this); ?>
<?php
$errors = $this->form->getErrorMessages();
if (!empty($errors)):
?>
<div class="alert alert-danger">
<h4>{{ERROR_ICON}} There are errors in your configuration:</h4>
<br/>
<ul>
<?php foreach($errors as $error): ?>
<li><?= $error ?></li>
<?php endforeach;?>
</ul>
</div>
<?php if ($this->errorMessage): ?>
<div class="alert alert-danger">
<i>{{ERROR_ICON}}</i>
<strong><?= $this->escape($this->errorMessage); ?></strong>
</div>
<?php endif; ?>
<div>
<a href="<?= $createLdapBackend ?>">{{CREATE_ICON}} Create A New LDAP Authentication Backend</a><br/>
<a href="<?= $createDbBackend ?>">{{CREATE_ICON}} Create A New DB Authentication Backend</a>
<?php if ($this->successMessage): ?>
<div class="alert alert-success">
<i>{{OK_ICON}}</i>
<strong><?= $this->escape($this->successMessage); ?></strong>
</div>
<?= $this->form ?>
<?php endif; ?>
<div class="panel panel-default">
<div class="panel-heading panel-title">
Create Authentication Provider
</div>
<div class="panel-body">
<a href="<?= $createLdapBackend ?>">{{CREATE_ICON}} Create A New LDAP Authentication Backend</a><br/>
<a href="<?= $createDbBackend ?>">{{CREATE_ICON}} Create A New DB Authentication Backend</a>
</div>
</div>
<?php foreach ($this->backends as $backend): ?>
<div class="panel panel-default">
<div class="panel-heading panel-title">
Backend <?= $this->escape($backend->name); ?>
<br/>
<?= $backend->reorderForm; ?>
</div>
<div class="panel-body">
<a href="<?= $this->href('config/editAuthenticationBackend', array('auth_backend' => $backend->name));?>">
{{EDIT_ICON}} Edit This Authentication Provider
</a>
<br/>
<?php if (count($this->backends) > 1): ?>
<a href="<?= $this->href('config/removeAuthenticationBackend', array('auth_backend' => $backend->name));?>">
{{REMOVE_ICON}} Remove This Authentication Provider
</a>
<br/>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>

View File

@ -0,0 +1,15 @@
<?= $this->tabs->render($this); ?>
<h4>{{CREATE_ICON}} Create New Authentication Backend</h4>
<?php if ($this->errorMessage): ?>
<div class="alert alert-danger">
<?= $this->escape($this->errorMessage); ?>
</div>
<?php endif; ?>
<p>
Create a new backend for authenticating your users. This backend will be added at the end of your authentication order.
</p>
<?= $this->form ?>

View File

@ -1,4 +1,14 @@
<?= $this->tabs->render($this); ?>
<h4>{{CREATE_ICON}} Create New Backend</h4>
<h4>{{CREATE_ICON}} Edit Backend "<?= $this->escape($this->name); ?>"</h4>
<?php if ($this->errorMessage || $this->form->getErrorMessages()): ?>
<div class="alert alert-danger">
<?= $this->escape($this->errorMessage); ?>
<?php foreach ($this->form->getErrorMessages() as $error): ?>
<?= $this->escape($error); ?><br/>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?= $this->form ?>

View File

@ -0,0 +1,4 @@
<?= $this->tabs->render($this); ?>
<h4>{{REMOVE_ICON}} Remove Backend "<?= $this->escape($this->name); ?>"</h4>
<?= $this->form ?>

View File

@ -1,2 +1,10 @@
<?= $this->tabs->render($this); ?>
<?php if ($this->successMessage): ?>
<div class="alert alert-success">
<i>{{OK_ICON}}</i>
<strong><?= $this->escape($this->successMessage); ?></strong>
</div>
<?php endif; ?>
<?= $this->form ?>

View File

@ -2,6 +2,13 @@
<?php $errors = $this->form->getErrorMessages(); ?>
<?php if ($this->successMessage): ?>
<div class="alert alert-success">
<i>{{OK_ICON}}</i>
<strong><?= $this->escape($this->successMessage); ?></strong>
</div>
<?php endif; ?>
<?php if (!empty($errors)) : ?>
<div class="alert alert-danger">
<h4>Errors occured when trying to save the project.</h4>

View File

@ -8,6 +8,14 @@ $modules = $this->modules->paginate();
<?= $this->tabs->render($this); ?>
<h3>Installed Modules</h3>
<?php if ($this->successMessage): ?>
<div class="alert alert-success">
<i>{{OK_ICON}}</i>
<strong><?= $this->escape($this->successMessage); ?></strong>
</div>
<?php endif; ?>
<?= $this->paginationControl($modules, null, null, array(
'preserve' => $this->preserve
));

View File

@ -1,8 +1,8 @@
<?= $this->tabs->render($this); ?>
<?php if (isset($this->success)) : ?>
<?php if (isset($this->successMessage)) : ?>
<div class="alert alert-success">
<h4>Preferences Updated Successfully</h4>
<h4>{{SUCCESS_ICON}} <?= $this->successMessage ?></h4>
</div>
<?php endif; ?>

49
config/authentication.ini.in Normal file → Executable file
View File

@ -1,24 +1,33 @@
[ldap-authentication]
backend=ldap
hostname=@ldap_host@
port=@ldap_port@
root_dn='@ldap_rootdn@'
bind_dn='@ldap_binddn@'
bind_pw=@ldap_bindpass@
; authentication.ini
;
; Each section listed in this configuration represents a single backend
; that can be used to authenticate users or groups. Each databse backend must refer
; to a resource defined in resources.ini,
;
; The order of entries in this configuration is used to determine the fallback
; priority in case of an error. If the resource referenced in the first
; entry is not reachable, the next lower entry will be used for authentication.
; Please be aware that this behaviour is not valid for the authentication itself.
; The authentication will only be done against the one available resource with the highest
; priority.
@use_ldap_auth@[ldap_authentication]
@use_ldap_auth@backend = "ldap"
@use_ldap_auth@target = "user"
@use_ldap_auth@hostname = "@ldap_host@"
@use_ldap_auth@port = "@ldap_port@"
@use_ldap_auth@root_dn = "@ldap_rootdn@"
@use_ldap_auth@bind_dn = "@ldap_binddn@"
@use_ldap_auth@bind_pw = "@ldap_bindpass@"
; Attributes for ldap user lookup
user.ldap_object_class=@ldap_user_objectclass@
user.ldap_name_attribute=@ldap_attribute_username@
user.password_attribute=@ldap_attribute_password@
group.ldap_object_class=@ldap_group_objectclass@
group.ldap_name_attribute=@ldap_attribute_groupname@
@use_ldap_auth@user_class = "@ldap_user_objectclass@"
@use_ldap_auth@user_name_attribute = "@ldap_attribute_username@"
@use_ldap_auth@user_password_attribute = "@ldap_attribute_password@"
[internal-authentication]
backend=db
type=@internal_db_type@
host=@internal_db_host@
port=@internal_db_port@
database=@internal_db_name@
user=@internal_db_user@
password=@internal_db_pass@
@use_internal_auth@[internal_authentication]
@use_internal_auth@backend = db
@use_internal_auth@target = "user"
@use_internal_auth@resource = "internal_db"

View File

@ -1,36 +1,38 @@
[global]
environment = "development"
timezone = "Europe/Berlin"
indexModule = "monitoring"
indexController = "dashboard"
environment = "development"
timezone = "Europe/Berlin"
indexModule = "monitoring"
indexController = "dashboard"
; The moduleFolder directive is currently not used anywhere but configureable
; via the frontend and this file. With feature #4607 moduleFolder will
; be replaced with a configuration directive for locations of
; installed modules
moduleFolder = "/etc/icinga2-web/enabledModules"
dateFormat = "d/m/Y"
timeFormat = "g:i A"
dateFormat = "d/m/Y"
timeFormat = "g:i A"
[logging]
; General log
enable = "1"
type = "stream"
verbose = "1"
target = "/tmp/icinga2.log"
enable = "1"
type = "stream"
verbose = "1"
target = "{app}/var/log/icinga.log"
; For development and debug purposes: Logs additional (non critical) events to a
; seperate log
debug.enable = "1"
debug.type = "stream"
debug.target = "/tmp/icinga2.debug.log"
debug.enable = "1"
debug.type = "stream"
debug.target = "{app}/var/log/icinga.debug.log"
; Use ini store to store preferences on local disk
[preferences]
type = "ini"
type = "ini"
; Use database to store preference into mysql or postgres
;[preferences]
;type=db
;resource=icingaweb-mysql
configPath = "/vagrant/config/preferences"
configPath = "{app}/config/preferences"

View File

@ -1,18 +1,15 @@
[localdb]
type = ido
resource = "ido"
@ido_enabled@
[locallive]
type = livestatus
socket = @livestatus_socket@
@livestatus_enabled@
[localfile]
type = statusdat
status_file = @statusdat_file@
objects_file = @objects_cache_file@
@statusdat_enabled@
;[localfailsafe]
;enabled=false

View File

@ -3,7 +3,7 @@
; The configuration file *resources.ini* contains data sources that
; can be referenced in other configurations. This allows you to manage
; all connections to SQL databases in one single place, avoiding the need
: to edit several different configuration files, when the connection
; to edit several different configuration files, when the connection
; information of a resource change.
;
; Each section represents a resource, with the section name being the
@ -13,21 +13,13 @@
; be interpreted. Currently only the resource type *db* is available.
[icingaweb-pgsql]
[internal_db]
type = db
db = pgsql ; PostgreSQL
host = localhost
password = icinga
username = icingaweb
dbname = icingaweb
[icingaweb-mysql]
type = db
db = mysql ; MySQL
host = localhost
password = icinga
username = icingaweb
dbname = icingaweb
db = @internal_db_type@
host = @internal_db_host@
password = @internal_db_pass@
username = @internal_db_user@
dbname = @internal_db_name@
[ido]
type = db

144
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for Icinga2Web 1.0.0.
# Generated by GNU Autoconf 2.69 for IcingaWeb 1.0.0.
#
# Report bugs to <info@icinga.org>.
#
@ -578,22 +578,20 @@ MFLAGS=
MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='Icinga2Web'
PACKAGE_TARNAME='icinga2web'
PACKAGE_NAME='IcingaWeb'
PACKAGE_TARNAME='icingaweb'
PACKAGE_VERSION='1.0.0'
PACKAGE_STRING='Icinga2Web 1.0.0'
PACKAGE_STRING='IcingaWeb 1.0.0'
PACKAGE_BUGREPORT='info@icinga.org'
PACKAGE_URL=''
ac_default_prefix=/usr/local/icinga2-web
ac_default_prefix=/usr/local/icingaweb
ac_subst_vars='LTLIBOBJS
LIBOBJS
INSTALL_OPTS_WEB
INSTALL_OPTS
ldap_enabled
ido_enabled
statusdat_enabled
livestatus_enabled
use_internal_auth
use_ldap_auth
icinga_commandpipe
livestatus_socket
objects_cache_file
@ -622,7 +620,7 @@ internal_db_port
internal_db_host
internal_db_name
internal_db_type
icinga2web_config_path
icingaweb_config_path
bin_group
bin_user
www_conf_path
@ -677,7 +675,7 @@ SHELL'
ac_subst_files=''
ac_user_opts='
enable_option_checking
with_icinga2web_config_path
with_icingaweb_config_path
with_web_user
with_web_group
with_web_path
@ -1258,7 +1256,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures Icinga2Web 1.0.0 to adapt to many kinds of systems.
\`configure' configures IcingaWeb 1.0.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1306,7 +1304,7 @@ Fine tuning of the installation directories:
--infodir=DIR info documentation [DATAROOTDIR/info]
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
--mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/icinga2web]
--docdir=DIR documentation root [DATAROOTDIR/doc/icingaweb]
--htmldir=DIR html documentation [DOCDIR]
--dvidir=DIR dvi documentation [DOCDIR]
--pdfdir=DIR pdf documentation [DOCDIR]
@ -1319,18 +1317,18 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of Icinga2Web 1.0.0:";;
short | recursive ) echo "Configuration of IcingaWeb 1.0.0:";;
esac
cat <<\_ACEOF
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-icinga2web-config-path
--with-icingaweb-config-path
Configuration path for icinga
--with-web-user=USER username for web writable files (default www-data)
--with-web-group=GROUP group for web writable files (default www-data)
--with-web-path=PATH web sub path (default /cranberry)
--with-web-path=PATH web sub path (default /icingaweb)
--with-http-configuration-path=PATH
Include folder apache2 (default /etc/apache2/conf.d)
--with-bin-user=USER user for all other files (default root)
@ -1340,7 +1338,7 @@ Optional Packages:
mysql, supported: pgsql, mysql)
--with-internal-db-name=NAME
database name to use for internal database (default
icinga2web)
icingaweb)
--with-internal-db-host=HOST
database host to use for internal database (default
localhost)
@ -1349,10 +1347,10 @@ Optional Packages:
3306 for mysql, 5432 for pgsql)
--with-internal-db-pass=PASS
database pass to use for internal database (default
icinga2web)
icingaweb)
--with-internal-db-user=USER
database user to use for internal database (default
icinga2web)
icingaweb)
--with-internal-authentication
use the internal database for authentication
(default: yes)
@ -1487,7 +1485,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
Icinga2Web configure 1.0.0
IcingaWeb configure 1.0.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1504,7 +1502,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by Icinga2Web $as_me 1.0.0, which was
It was created by IcingaWeb $as_me 1.0.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -1855,7 +1853,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test "x$prefix" = "xNONE" ; then
installDir="/usr/local/icinga2-web"
installDir="/usr/local/icingaweb"
prefix=$installDir
else
installDir=$prefix
@ -2210,11 +2208,11 @@ fi
# Configuration files
#
# Check whether --with-icinga2web_config_path was given.
if test "${with_icinga2web_config_path+set}" = set; then :
withval=$with_icinga2web_config_path; icinga2web_config_path="'$withval'"
# Check whether --with-icingaweb_config_path was given.
if test "${with_icingaweb_config_path+set}" = set; then :
withval=$with_icingaweb_config_path; icingaweb_config_path="'$withval'"
else
icinga2web_config_path="'$prefix/config/'"
icingaweb_config_path="'$prefix/config/'"
fi
@ -2274,7 +2272,7 @@ fi
if test "${with_web_path+set}" = set; then :
withval=$with_web_path; web_path=$withval
else
web_path=/cranberry
web_path=/icingaweb
fi
@ -2346,7 +2344,7 @@ fi
if test "${with_internal_db_name+set}" = set; then :
withval=$with_internal_db_name; internal_db_name=$withval
else
internal_db_name=icinga2web
internal_db_name=icingaweb
fi
@ -2376,7 +2374,7 @@ fi
if test "${with_internal_db_pass+set}" = set; then :
withval=$with_internal_db_pass; internal_db_pass=$withval
else
internal_db_pass=icinga2web
internal_db_pass=icingaweb
fi
@ -2386,7 +2384,7 @@ fi
if test "${with_internal_db_user+set}" = set; then :
withval=$with_internal_db_user; internal_db_user=$withval
else
internal_db_user=icinga2web
internal_db_user=icingaweb
fi
@ -2400,7 +2398,7 @@ fi
if test "${with_internal_authentication+set}" = set; then :
withval=$with_internal_authentication; internal_authentication=yes
else
internal_authentication=def
internal_authentication=yes
fi
@ -2444,7 +2442,7 @@ fi
if test "${with_ldap_binddn+set}" = set; then :
withval=$with_ldap_binddn; ldap_binddn=$withval
else
ldap_binddn="cn=Manager, ou=icinga, ou=org"
ldap_binddn="cn=admin,cn=config"
fi
@ -2454,7 +2452,7 @@ fi
if test "${with_ldap_bindpass+set}" = set; then :
withval=$with_ldap_bindpass; ldap_bindpass=$withval
else
ldap_bindpass="secret"
ldap_bindpass="admin"
fi
@ -2818,7 +2816,6 @@ fi
ido_enabled="disable=1"
statusdat_enabled="disable=1"
livestatus_enabled="disable=1"
ldap_enabled="disable=1"
case $icinga_backend in #(
"ido") :
@ -2831,6 +2828,7 @@ case $icinga_backend in #(
statusdat_enabled="" ;;
esac
use_ldap_auth=";"
if test "x$ldap_authentication" != xno; then :
for x in ldap;do
@ -2844,7 +2842,25 @@ else
fi
done
ldap_enabled=""
use_ldap_auth=""
fi
use_internal_auth=";"
if test "x$internal_authentication" != xno; then :
for x in ldap;do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5
$as_echo_n "checking if php has $x module... " >&6; }
if php -m | $GREP -iq "^$x$" ; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
$as_echo "found" >&6; }
else
as_fn_error $? "not found" "$LINENO" 5
fi
done
use_internal_auth=""
fi
@ -2909,55 +2925,6 @@ fi
# Internal db setup
# ldap setup
# backend setup
# ido backend variables
# status.dat backend
# livestatus backend
# command pipe
# Comment placeholders for toggling backends
# Application and installation
@ -2966,7 +2933,7 @@ fi
#
# Create config files
#
ac_config_files="$ac_config_files Makefile config/authentication.ini config/resources.ini config/modules/monitoring/backends.ini public/index.php"
ac_config_files="$ac_config_files Makefile config/authentication.ini config/resources.ini config/modules/monitoring/backends.ini etc/apache/icingaweb.conf public/.htaccess"
#
@ -3514,7 +3481,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by Icinga2Web $as_me 1.0.0, which was
This file was extended by IcingaWeb $as_me 1.0.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -3567,7 +3534,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
Icinga2Web config.status 1.0.0
IcingaWeb config.status 1.0.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@ -3682,7 +3649,8 @@ do
"config/authentication.ini") CONFIG_FILES="$CONFIG_FILES config/authentication.ini" ;;
"config/resources.ini") CONFIG_FILES="$CONFIG_FILES config/resources.ini" ;;
"config/modules/monitoring/backends.ini") CONFIG_FILES="$CONFIG_FILES config/modules/monitoring/backends.ini" ;;
"public/index.php") CONFIG_FILES="$CONFIG_FILES public/index.php" ;;
"etc/apache/icingaweb.conf") CONFIG_FILES="$CONFIG_FILES etc/apache/icingaweb.conf" ;;
"public/.htaccess") CONFIG_FILES="$CONFIG_FILES public/.htaccess" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac

View File

@ -2,11 +2,11 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.61])
AC_INIT([Icinga2Web], [1.0.0], [info@icinga.org])
AC_PREFIX_DEFAULT(/usr/local/icinga2-web)
AC_INIT([IcingaWeb], [1.0.0], [info@icinga.org])
AC_PREFIX_DEFAULT(/usr/local/icingaweb)
if test "x$prefix" = "xNONE" ; then
installDir="/usr/local/icinga2-web"
installDir="/usr/local/icingaweb"
prefix=$installDir
else
installDir=$prefix
@ -29,10 +29,10 @@ AC_CHECK_PHP_MODULE([sockets json])
#
# Configuration files
#
AC_ARG_WITH([icinga2web_config_path],
AS_HELP_STRING([--with-icinga2web-config-path], [Configuration path for icinga ]),
icinga2web_config_path="'$withval'",
icinga2web_config_path="'$prefix/config/'"
AC_ARG_WITH([icingaweb_config_path],
AS_HELP_STRING([--with-icingaweb-config-path], [Configuration path for icinga ]),
icingaweb_config_path="'$withval'",
icingaweb_config_path="'$prefix/config/'"
)
#
@ -52,9 +52,9 @@ AC_ARG_WITH([web_group],
)
AC_ARG_WITH([web_path],
AS_HELP_STRING([--with-web-path=PATH], [web sub path (default /cranberry)]),
AS_HELP_STRING([--with-web-path=PATH], [web sub path (default /icingaweb)]),
web_path=$withval,
web_path=/cranberry
web_path=/icingaweb
)
AC_ARG_WITH([www_conf_path],
@ -90,9 +90,9 @@ AC_ARG_WITH([internal_db_type],
)
AC_ARG_WITH([internal_db_name],
AS_HELP_STRING([--with-internal-db-name=NAME], [database name to use for internal database (default icinga2web)]),
AS_HELP_STRING([--with-internal-db-name=NAME], [database name to use for internal database (default icingaweb)]),
internal_db_name=$withval,
internal_db_name=icinga2web
internal_db_name=icingaweb
)
AC_ARG_WITH([internal_db_host],
@ -108,15 +108,15 @@ AC_ARG_WITH([internal_db_port],
)
AC_ARG_WITH([internal_db_pass],
AS_HELP_STRING([--with-internal-db-pass=PASS], [database pass to use for internal database (default icinga2web)]),
AS_HELP_STRING([--with-internal-db-pass=PASS], [database pass to use for internal database (default icingaweb)]),
internal_db_pass=$withval,
internal_db_pass=icinga2web
internal_db_pass=icingaweb
)
AC_ARG_WITH([internal_db_user],
AS_HELP_STRING([--with-internal-db-user=USER], [database user to use for internal database (default icinga2web)]),
AS_HELP_STRING([--with-internal-db-user=USER], [database user to use for internal database (default icingaweb)]),
internal_db_user=$withval,
internal_db_user=icinga2web
internal_db_user=icingaweb
)
#
@ -126,7 +126,7 @@ AC_ARG_WITH([internal_db_user],
AC_ARG_WITH([internal_authentication],
AC_HELP_STRING([--with-internal-authentication], [use the internal database for authentication (default: yes)]),
internal_authentication=yes,
internal_authentication=def
internal_authentication=yes
)
AC_ARG_WITH([ldap_authentication],
@ -154,13 +154,13 @@ AC_ARG_WITH([ldap_port],
AC_ARG_WITH([ldap_binddn],
AS_HELP_STRING([--with-ldap-binddn=DN], [dn to use for retrieving user information via ldap (default cn=admin, cn=config)]),
ldap_binddn=$withval,
ldap_binddn=["cn=Manager, ou=icinga, ou=org"]
ldap_binddn=["cn=admin,cn=config"]
)
AC_ARG_WITH([ldap_bindpass],
AS_HELP_STRING([--with-ldap-bindpass=PASS], [password to use for retrieving user information via ldap (default admin)]),
ldap_bindpass=$withval,
ldap_bindpass=["secret"]
ldap_bindpass=["admin"]
)
AC_ARG_WITH([ldap_rootdn],
@ -346,7 +346,6 @@ AS_IF([test "x$ido_db_type" = xpgsql], [
ido_enabled="disable=1"
statusdat_enabled="disable=1"
livestatus_enabled="disable=1"
ldap_enabled="disable=1"
AS_CASE([$icinga_backend],
["ido"], [ido_enabled=""],
@ -354,9 +353,16 @@ AS_CASE([$icinga_backend],
["livestatus"], [livestatus_enabled=""],
[statusdat_enabled=""])
use_ldap_auth=";"
AS_IF([test "x$ldap_authentication" != xno],
AC_CHECK_PHP_MODULE([ldap])
ldap_enabled=""
use_ldap_auth=""
)
use_internal_auth=";"
AS_IF([test "x$internal_authentication" != xno],
AC_CHECK_PHP_MODULE([ldap])
use_internal_auth=""
)
#
@ -371,7 +377,7 @@ AC_SUBST(web_path)
AC_SUBST(www_conf_path)
AC_SUBST(bin_user)
AC_SUBST(bin_group)
AC_SUBST(icinga2web_config_path)
AC_SUBST(icingaweb_config_path)
# Internal db setup
AC_SUBST(internal_db_type)
@ -416,58 +422,9 @@ AC_SUBST(livestatus_socket)
AC_SUBST(icinga_commandpipe)
# Comment placeholders for toggling backends
AC_SUBST(livestatus_enabled)
AC_SUBST(statusdat_enabled)
AC_SUBST(ido_enabled)
AC_SUBST(ldap_enabled)
# Internal db setup
AC_SUBST(internal_db_type)
AC_SUBST(internal_db_name)
AC_SUBST(internal_db_host)
AC_SUBST(internal_db_port)
AC_SUBST(internal_db_user)
AC_SUBST(internal_db_pass)
# ldap setup
AC_SUBST(ldap_host)
AC_SUBST(ldap_port)
AC_SUBST(ldap_rootdn)
AC_SUBST(ldap_binddn)
AC_SUBST(ldap_bindpass)
AC_SUBST(ldap_user_objectclass)
AC_SUBST(ldap_attribute_basedn)
AC_SUBST(ldap_attribute_username)
AC_SUBST(ldap_attribute_password)
AC_SUBST(ldap_group_objectclass)
AC_SUBST(ldap_attribute_groupname)
# backend setup
AC_SUBST(icinga_backend)
# ido backend variables
AC_SUBST(ido_db_type)
AC_SUBST(ido_host)
AC_SUBST(ido_port)
AC_SUBST(ido_database)
AC_SUBST(ido_user)
AC_SUBST(ido_password)
# status.dat backend
AC_SUBST(statusdat_file)
AC_SUBST(objects_cache_file)
# livestatus backend
AC_SUBST(livestatus_socket)
# command pipe
AC_SUBST(icinga_commandpipe)
# Comment placeholders for toggling backends
AC_SUBST(livestatus_enabled)
AC_SUBST(statusdat_enabled)
AC_SUBST(ido_enabled)
AC_SUBST(ldap_enabled)
AC_SUBST(use_ldap_auth)
AC_SUBST(use_internal_auth)
# Application and installation
AC_SUBST(PHP)
@ -482,7 +439,8 @@ AC_CONFIG_FILES([
config/authentication.ini
config/resources.ini
config/modules/monitoring/backends.ini
public/index.php
etc/apache/icingaweb.conf
public/.htaccess
])
#

View File

@ -1,5 +1,7 @@
# Application and Module Configuration
## Basic usage
The \Icinga\Application\Config class is a general purpose service to help you find, load and save
configuration data. It is used both by the Icinga 2 Web modules and the framework itself. With
INI files as source it enables you to store configuration in a familiar format. Icinga 2 Web
@ -22,3 +24,10 @@ keep their main configuration in the INI file called config.ini. Here's some exa
// The following example loads values from the example module's extra.ini:
IcingaConfig::module('example', 'extra')->logging->get('enabled', true);
## Reload from disk
If you want to force reading a configuration from disk (i.e. after you modified it), you can use the $fromDisk flag in
the IcingaConfig::app/IcingaConfig::module call:
IcingaConfig::app('authentication', true)-> ... // read authentication from disk
IcingaConfig::module('example', 'extra', true)->... // read module configuration from disk

View File

@ -8,11 +8,9 @@
If you like to configurea and install icinga2-web from the command line or
if you want to create packages, configure and make is the best choice for installation.
./configure && make install && make install-apache2-config
`
./configure && make install && make install-apache2-config
`
will install the application to the default target (/usr/local/icinga2-web). Also
will install the application to the default target (/usr/local/icinga2-web). Also
an apache configuration entry is added to your apache server, so you should restart
your web server according to your systems configuration.
@ -20,9 +18,9 @@ your web server according to your systems configuration.
If you want to install the application to a different directory, use the --prefix flag in your
configure call:
`
./configure --prefix=/my/target/directory
`
./configure --prefix=/my/target/directory
### Authentication

View File

@ -4,37 +4,55 @@ Frontend tests test your code from the users perspective: By opening a specific
and expecting something to happen. We use [CasperJS](http://casperjs.org/) for frontend testing, which is basically a
headless Webkit browser.
## The current state of frontend testing
**NOTE**: The 1.1.0DEV version does *NOT* work at this time as the api changed. Use the stable 1.0.3 branch instead.
Currently frontend tests are not very advanced: We spawn a small - non php - server on port 12999 to test static files
and javascript behaviour. This will change in the future where we are going to test an installation (or use PHP 5.4
standalone server).
In order to be able to run the frontend tests, you need a running instance of icingaweb. You should make sure that you
don't need this instance after running the tests, as they could change preferences or configuration
## Writing tests
### Test bootstrap
In order to make testing more comfortable, the i2w config provides a few helpers to make testing more straightforward.
In general you start your test by including i2w-config:
### Test bootstrap - icingawebtest.js module
var i2w = require('./i2w-config');
The icingawebtest.js module is required for proper testing, as this module eases casperjs usage. After importing the
module with:
and afterward creating a testenvironment with the getTestEnv() method:
var icingawebtest = require('./icingawebtest');
var casper = i2w.getTestEnv();
You only need two methods for testing:
You can then start the test by calling casper.start with the startpage (the servers root is always frontend/static, where
public is a symlink to the icingaweb public folder).
* *getTestEnv()*: This method returns a modified casperjs test environment. The difference to then normal casperjs object
is that all methods which take a URL are overloaded so you can add a relative URL if you want to (and
normally you don't want to hardcode your test URLs)
Example:
casper.start("http://localhost:12999/generic.html");
var casper = icingawebtest.getTestEnv();
As we use requirejs, this has to be set up for our testcases. i2w provides a setupRequireJs function that does everything for you.
You just have to run this method on your testpage (note that the tested JavaScript is isolated from your test case's JavaScript, if
you want to execute JavaScript you must use the casper.page.evaluate method).
* performLogin(): This calls the login page of your icingaweb instance and tries to login with the supplied credentials
casper.then(function() {
// Setup requirejs
casper.page.evaluate(i2w.setupRequireJs, {icinga: true});
icinga.performLogin();
Login is performed with the credentials from the CASPERJS_USER/CASPERJS_PASS environment (this can be set with the
./runtest --user %user% --pass %pass% arguments). The host, server and port are also represented as
CASPERJS_HOST, CASPERJS_PORT and CASPERJS_PATH environment settings. The default in runtest resembles the version that
works best in the vagrant development environment:
* The default user is 'jdoe'
* The default password is 'password'
* The host and port are localhost:80
* The default path is icinga2-web
### Writing the test code
Most tests will require you to login with the supplied credentials, this can be performed with a simple call
icinga.performLogin();
You can then start the test by calling casper.thenOpen with the page you want to work
casper.thenOpen("/mysite", function() {
// perform tests
});
### Testing

View File

@ -1,30 +0,0 @@
Alias /cranberry /usr/local/i2/public
<Directory "/usr/local/i2/public">
SetEnv APPLICATION_ENV development
DirectoryIndex index.php
Options -MultiViews -Indexes +FollowSymLinks
Options SymLinksIfOwnerMatch
AllowOverride AuthConfig FileInfo
Order allow,deny
Allow from all
RewriteBase /cranberry
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</Directory>
AliasMatch ^/cranberry/static/([a-zA-Z_\-]+) /usr/local/i2/application/modules/$1/public
<DirectoryMatch "usr/local/i2/application/modules/[a-zA-Z_\-]+/public">
SetEnv APPLICATION_ENV development
Options -MultiViews -Indexes +FollowSymLinks
Options SymLinksIfOwnerMatch
AllowOverride AuthConfig FileInfo
Order allow,deny
Allow from all
</DirectoryMatch>

View File

@ -1,20 +0,0 @@
Alias @web_path@ @prefix@/public
<Directory "@prefix@/public">
DirectoryIndex index.php
Options -MultiViews -Indexes +FollowSymLinks
Options SymLinksIfOwnerMatch
AllowOverride AuthConfig FileInfo
Order allow,deny
Allow from all
SetEnv APPLICATION_ENV development
RewriteBase @web_path@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
</Directory>

12
etc/apache/icingaweb.conf.in Executable file
View File

@ -0,0 +1,12 @@
Alias @web_path@ @prefix@/public
<Directory "@prefix@/public">
Options -Indexes
AllowOverride All
Order allow,deny
Allow from all
EnableSendfile Off
</Directory>

View File

@ -28,7 +28,8 @@
namespace Icinga\Application;
use Zend_Config_Ini;
use \Icinga\Exception\ProgrammingError;
use \Zend_Config_Ini;
/**
* Global registry of application and module configuration.
@ -37,24 +38,28 @@ class Config extends Zend_Config_Ini
{
/**
* Configuration directory where ALL (application and module) configuration is located
*
* @var string
*/
public static $configDir;
/**
* The INI file this configuration has been loaded from
*
* @var string
*/
private $configFile;
/**
* Application config instances per file
*
* @var array
*/
protected static $app = array();
/**
* Module config instances per file
*
* @var array
*/
protected static $modules = array();
@ -62,10 +67,10 @@ class Config extends Zend_Config_Ini
/**
* Load configuration from the config file $filename
*
* @param string $filename The filename to parse
* @see Zend_Config_Ini::__construct
*
* @param string $filename
* @throws Exception
* @throws Exception When the file can't be read
*/
public function __construct($filename)
{
@ -83,12 +88,15 @@ class Config extends Zend_Config_Ini
/**
* Retrieve a application config instance
*
* @param string $configname
* @return mixed
* @param string $configname The configuration name (without ini suffix) to read and return
* @param bool $fromDisk When set true, the configuration will be read from the disk, even
* if it already has been read
*
* @return Config The configuration object that has been requested
*/
public static function app($configname = 'config')
public static function app($configname = 'config', $fromDisk = false)
{
if (!isset(self::$app[$configname])) {
if (!isset(self::$app[$configname]) || $fromDisk) {
$filename = self::$configDir . '/' . $configname . '.ini';
self::$app[$configname] = new Config(realpath($filename));
}
@ -98,17 +106,19 @@ class Config extends Zend_Config_Ini
/**
* Retrieve a module config instance
*
* @param string $modulename
* @param string $configname
* @return Config
* @param string $modulename The name of the module to look for configurations
* @param string $configname The configuration name (without ini suffix) to read and return
* @param string $fromDisk Whether to read the configuration from disk
*
* @return Config The configuration object that has been requested
*/
public static function module($modulename, $configname = 'config')
public static function module($modulename, $configname = 'config', $fromDisk = false)
{
if (!isset(self::$modules[$modulename])) {
self::$modules[$modulename] = array();
}
$moduleConfigs = self::$modules[$modulename];
if (!isset($moduleConfigs[$configname])) {
if (!isset($moduleConfigs[$configname]) || $fromDisk) {
$filename = self::$configDir . '/modules/' . $modulename . '/' . $configname . '.ini';
if (file_exists($filename)) {
$moduleConfigs[$configname] = new Config(realpath($filename));
@ -136,10 +146,32 @@ class Config extends Zend_Config_Ini
}
}
public function getConfigFile()
/**
* Return the application wide config file
*
* @return string
*/
public function getConfigFile()
{
return $this->configFile;
}
/**
* Return the input path with resolved path variables
*
* Currently only %app% is considered a path variable and points to the application paths
*
* @param string $path The path to resolve
*
* @return string The resolved path
*/
public static function resolvePath($path)
{
try {
$appDir = realpath(Icinga::app()->getApplicationDir() . '/..');
} catch (ProgrammingError $appNotStarted) {
$appDir = realpath(__DIR__ . '/../../..');
}
return str_replace('{app}', $appDir, $path);
}
}

View File

@ -28,6 +28,7 @@
namespace Icinga\Application;
use Icinga\Protocol\Ldap\Exception;
use \Zend_Config;
use \Zend_Log;
use \Zend_Log_Filter_Priority;
@ -144,7 +145,6 @@ final class Logger
if ($target == self::DEFAULT_LOG_TARGET) {
$type = self::DEFAULT_LOG_TYPE;
}
$this->addWriter($type, $target, Zend_Log::DEBUG);
}
@ -187,11 +187,17 @@ final class Logger
);
return;
}
try {
/** @var Zend_Log_Writer_Abstract $writer */
$target = Config::resolvePath($target);
$writer = new $writerClass($target);
$writer->addFilter(new Zend_Log_Filter_Priority($priority));
// Make sure the permissions for log target file are correct
if ($type === 'Stream' && !file_exists($target)) {
touch($target);
chmod($target, 0664);
}
$this->logger->addWriter($writer);
$this->writers[] = $writer;
} catch (Zend_Log_Exception $e) {

View File

@ -249,7 +249,8 @@ class Web extends ApplicationBootstrap
$preferences->attach($sessionStore);
if ($this->getConfig()->preferences !== null) {
if (is_dir($this->getConfig()->preferences->configPath) === false) {
$path = Config::resolvePath($this->getConfig()->preferences->configPath);
if (is_dir($path) === false) {
Logger::error(
'Path for preferences not found (IniStore, "%s"). Using default one: "%s"',
$this->getConfig()->preferences->configPath,
@ -356,8 +357,6 @@ class Web extends ApplicationBootstrap
$view->setView(new View());
$view->view->addHelperPath($this->getApplicationDir('/views/helpers'));
// TODO: find out how to avoid this additional helper path:
$view->view->addHelperPath($this->getApplicationDir('/views/helpers/layout'));
$view->view->setEncoding('UTF-8');
$view->view->headTitle()->prepend(

View File

@ -29,7 +29,7 @@
namespace Icinga\Authentication\Backend;
use Zend_Db;
use \Zend_Db;
use \Icinga\User;
use \Icinga\Authentication\UserBackend;
use \Icinga\Authentication\Credentials;
@ -81,9 +81,7 @@ class DbUserBackend implements UserBackend
{
$this->db = $database;
/*
* Test if the connection is available
*/
// Test if the connection is available
$this->db->getConnection();
}
@ -207,4 +205,20 @@ class DbUserBackend implements UserBackend
);
return $usr;
}
/**
* Return the number of users in this database connection
*
* This class is mainly used for determining whether the authentication backend is valid or not
*
* @return int The number of users set in this backend
* @see UserBackend::getUserCount
*/
public function getUserCount()
{
$this->db->getConnection();
$query = $this->db->select()->from($this->userTable, 'COUNT(*) as count')->query();
return $query->fetch()->count;
}
}

View File

@ -122,12 +122,24 @@ class LdapUserBackend implements UserBackend
if (!$this->connection->testCredentials(
$this->connection->fetchDN($this->selectUsername($credentials->getUsername())),
$credentials->getPassword()
)
) {
)) {
return false;
}
$user = new User($credentials->getUsername());
return $user;
}
public function getUserCount()
{
return $this->connection->count(
$this->connection->select()->from(
$this->config->user_class,
array(
$this->config->user_name_attribute
)
)
);
}
}

View File

@ -28,16 +28,21 @@
namespace Icinga\Authentication;
/**
* Interface for backends that authenticate users
*/
interface UserBackend
{
/**
* Creates a new object
* Create a userbackend from the given configuration or resource
*
* @param $config
*/
public function __construct($config);
/**
* Test if the username exists
*
* @param Credentials $credentials
* @return boolean
*/
@ -45,8 +50,16 @@ interface UserBackend
/**
* Authenticate
*
* @param Credentials $credentials
* @return User
*/
public function authenticate(Credentials $credentials);
/**
* Get the number of users available through this backend
*
* @return int
*/
public function getUserCount();
}

View File

@ -28,13 +28,16 @@
namespace Icinga\User\Preferences;
use Icinga\Application\Logger;
use Icinga\Protocol\Ldap\Exception;
use \SplObserver;
use \SplSubject;
use Icinga\User;
use Icinga\User\Preferences;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\ProgrammingError;
use \Icinga\User;
use \Icinga\User\Preferences;
use \Icinga\Exception\ConfigurationError;
use \Icinga\Exception\ProgrammingError;
use \Zend_Config;
use \Icinga\Application\Config as IcingaConfig;
use \Zend_Config_Writer_Ini;
/**
@ -84,7 +87,7 @@ class IniStore implements LoadInterface, FlushObserverInterface
*
* @param string|null $configPath
*/
public function __construct($configPath=null)
public function __construct($configPath = null)
{
if ($configPath !== null) {
$this->setConfigPath($configPath);
@ -99,6 +102,7 @@ class IniStore implements LoadInterface, FlushObserverInterface
*/
public function setConfigPath($configPath)
{
$configPath = IcingaConfig::resolvePath($configPath);
if (!is_dir($configPath)) {
throw new ConfigurationError('Config dir dos not exist: '. $configPath);
}
@ -124,18 +128,22 @@ class IniStore implements LoadInterface, FlushObserverInterface
if (file_exists($this->preferencesFile) === false) {
$this->createDefaultIniFile();
}
try {
$this->iniConfig = new Zend_Config(
parse_ini_file($this->preferencesFile),
true
);
$this->iniConfig = new Zend_Config(
parse_ini_file($this->preferencesFile),
true
);
$this->iniWriter = new Zend_Config_Writer_Ini(
array(
'config' => $this->iniConfig,
'filename' => $this->preferencesFile
)
);
$this->iniWriter = new Zend_Config_Writer_Ini(
array(
'config' => $this->iniConfig,
'filename' => $this->preferencesFile
)
);
} catch (Exception $e) {
Logger::error('Could not create IniStore backend: %s', $e->getMessage());
throw new \RuntimeException("Creating user preference backend failed");
}
}
/**
@ -144,6 +152,8 @@ class IniStore implements LoadInterface, FlushObserverInterface
private function createDefaultIniFile()
{
touch($this->preferencesFile);
chmod($this->preferencesFile, 0664);
}
/**

View File

@ -230,4 +230,25 @@ class ActionController extends ZfController
}
}
}
/**
* Try to call compatible methods from older zend versions
*
* Methods like getParam and redirect are _getParam/_redirect in older Zend versions (which reside for example
* in Debian Wheezy). Using those methods without the "_" causes the application to fail on those platforms, but
* using the version with "_" forces us to use deprecated code. So we try to catch this issue by looking for methods
* with the same name, but with a "_" prefix prepended.
*
* @param string $name The method name to check
* @param array $params The method parameters
*/
public function __call($name, $params)
{
$deprecatedMethod = '_'.$name;
if (method_exists($this, $deprecatedMethod)) {
return call_user_func_array(array($this, $deprecatedMethod), $params);
}
return parent::__call($name, $params);
}
}

View File

@ -38,7 +38,7 @@ use \Icinga\Web\Form\Element\Note;
/**
* Base class for forms providing CSRF protection, confirmation logic and auto submission
*/
abstract class Form extends Zend_Form
class Form extends Zend_Form
{
/**
* The form's request object
@ -161,7 +161,9 @@ abstract class Form extends Zend_Form
/**
* Add elements to this form (used by extending classes)
*/
abstract protected function create();
protected function create()
{
}
/**
* Method called before validation
@ -322,7 +324,9 @@ abstract class Form extends Zend_Form
* 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
* @return bool True when the form is submitted and valid, otherwise false
* @see Form::isValid()
* @see Form::isSubmitted()
*/
public function isSubmittedAndValid()
{
@ -334,12 +338,7 @@ abstract class Form extends Zend_Form
$checkData = $this->getRequest()->getParams();
$this->assertValidCsrfToken($checkData);
$submitted = true;
if ($this->submitLabel) {
$submitted = isset($checkData['btn_submit']);
}
if ($submitted) {
if ($this->isSubmitted()) {
// perform full validation if submitted
$this->preValidation($checkData);
return $this->isValid($checkData);
@ -350,6 +349,24 @@ abstract class Form extends Zend_Form
}
}
/**
* 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()
{
$submitted = true;
if ($this->submitLabel) {
$checkData = $this->getRequest()->getParams();
$submitted = isset($checkData['btn_submit']);
}
return $submitted;
}
/**
* Disable CSRF counter measure and remove its field if already added
*

View File

@ -29,6 +29,7 @@
namespace Icinga\Web\Form\Validator;
use \Zend_Validate_Abstract;
use \Icinga\Application\Config as IcingaConfig;
/**
* Validator that interprets the value as a path and checks if it's writable
@ -77,8 +78,9 @@ class WritablePathValidator extends Zend_Validate_Abstract
public function isValid($value, $context = null)
{
$value = (string) $value;
$this->_setValue($value);
$this->_setValue($value);
$value = IcingaConfig::resolvePath($value);
if ($this->requireExistence && !file_exists($value)) {
$this->_error('DOES_NOT_EXIST');
return false;

View File

@ -70,6 +70,7 @@ class Monitoring_ConfigController extends BaseConfigController {
{
$this->view->backends = IcingaConfig::module('monitoring', 'backends')->toArray();
$this->view->instances = IcingaConfig::module('monitoring', 'instances')->toArray();
$this->render('index');
}
/**
@ -114,11 +115,12 @@ class Monitoring_ConfigController extends BaseConfigController {
$configArray[$form->getBackendName()] = $form->getConfig();
if ($this->writeConfiguration(new Zend_Config($configArray), 'backends')) {
$this->redirectNow('monitoring/config');
$this->view->successMessage = 'Backend Creation Succeeded';
$this->indexAction();
} else {
$this->render('show-configuration');
return;
}
return;
}
$this->view->form = $form;
$this->render('editbackend');
@ -143,11 +145,12 @@ class Monitoring_ConfigController extends BaseConfigController {
unset($configArray[$backend]);
if ($this->writeConfiguration(new Zend_Config($configArray), 'backends')) {
$this->redirectNow('monitoring/config');
$this->view->successMessage = 'Backend "' . $backend . '" Removed';
$this->indexAction();
} else {
$this->render('show-configuration');
return;
}
return;
}
$this->view->form = $form;
@ -174,11 +177,12 @@ class Monitoring_ConfigController extends BaseConfigController {
unset($configArray[$instance]);
if ($this->writeConfiguration(new Zend_Config($configArray), 'instances')) {
$this->redirectNow('monitoring/config');
$this->view->successMessage = 'Instance "' . $instance . '" Removed';
$this->indexAction();
} else {
$this->render('show-configuration');
return;
}
return;
}
$this->view->form = $form;
@ -202,7 +206,8 @@ class Monitoring_ConfigController extends BaseConfigController {
$instanceConfig = IcingaConfig::module('monitoring', 'instances')->toArray();
$instanceConfig[$instance] = $form->getConfig();
if ($this->writeConfiguration(new Zend_Config($instanceConfig), 'instances')) {
$this->redirectNow('monitoring/config');
$this->view->successMessage = 'Instance Modified';
$this->indexAction();
} else {
$this->render('show-configuration');
return;
@ -222,11 +227,12 @@ class Monitoring_ConfigController extends BaseConfigController {
$instanceConfig = IcingaConfig::module('monitoring', 'instances')->toArray();
$instanceConfig[$form->getInstanceName()] = $form->getConfig()->toArray();
if ($this->writeConfiguration(new Zend_Config($instanceConfig), 'instances')) {
$this->redirectNow('monitoring/config');
$this->view->successMessage = 'Instance Creation Succeeded';
$this->indexAction();
} else {
$this->render('show-configuration');
return;
}
return;
}
$this->view->form = $form;
$this->render('editinstance');

View File

@ -3,6 +3,13 @@
<h3>Monitoring Backends</h3>
<?php if ($this->successMessage): ?>
<div class="alert alert-success">
<i>{{OK_ICON}}</i>
<strong><?= $this->escape($this->successMessage); ?></strong>
</div>
<?php endif; ?>
<div>
<a href="<?= Url::fromPath('/monitoring/config/createbackend')->getAbsoluteUrl();?>">
{{CREATE_ICON}} Create New Monitoring Backend
@ -16,9 +23,6 @@
<?php $editUrl = Url::fromPath('/monitoring/config/editbackend', array('backend' => $backendName)); ?>
<b><?= $this->escape($backendName); ?></b>
<small>(Type: <?= $this->escape($config['type'] === 'ido' ? 'IDO' : ucfirst($config['type'])); ?>)</small>
<?php if ($config['disabled']): ?>
- <b>{{DISABLED_ICON}} Disabled</b>
<?php endif; ?>
<div>
<a href="<?= $removeUrl; ?>">{{REMOVE_ICON}} Remove This Backend</a><br/>
<a href="<?= $editUrl; ?>">{{EDIT_ICON}} Edit This Backend</a>

View File

@ -1,6 +1,7 @@
SetEnv APPLICATION_ENV development
RewriteEngine on
RewriteBase /icinga2-web
RewriteRule ^css/icinga.css css.php
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]

14
public/.htaccess.in Normal file
View File

@ -0,0 +1,14 @@
SetEnv APPLICATION_ENV development
RewriteEngine on
RewriteBase @web_path@
RewriteRule ^css/icinga.css css.php
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
php_flag short_open_tag on
php_value xdebug.idekey PHPSTORM

View File

@ -1,10 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
require_once dirname(__FILE__). '/../library/Icinga/Application/ApplicationBootstrap.php';
require_once dirname(__FILE__). '/../library/Icinga/Application/Web.php';
use Icinga\Application\Web;
Web::start(@icinga2web_config_path@)->dispatch();

View File

@ -1,61 +0,0 @@
var i2w = require('./i2w-config');
var casper = i2w.getTestEnv();
casper.start("http://localhost:12999/generic.html");
casper.then(function() {
casper.page.evaluate(i2w.setupRequireJs, {icinga: true});
});
casper.then(function() {
this.test.assertTitle("Icinga test page");
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment1.html");
});
});
/*this.waitFor(function() {
return document.querySelectorAll("#icinga-main a") ;
}, */
casper.waitForSelector("div#icinga-main a", onFirstLink);
});
var onFirstLink = function() {
var links = casper.page.evaluate(function() {
return document.querySelectorAll("div#icinga-main a");
});
// assert no reload
this.test.assertTitle("Icinga test page");
this.test.assertUrlMatch(/.*testFragment1.html/);
this.test.assertEquals(links.length, 2);
casper.clickLabel('Fragment 2');
casper.waitForText('Fragment 1', onSecondLink);
};
var onSecondLink = function() {
var links = casper.page.evaluate(function() {
return document.querySelectorAll("div#icinga-main a");
});
this.test.assertTitle("Icinga test page");
this.test.assertUrlMatch(/.*testFragment2.html/);
this.test.assertEquals(links.length, 2);
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment3.html?this=is_a_param", "icinga-detail");
});
});
this.wait(400, function() {
console.log(casper.page.evaluate(function() {
return window.location.href;
}));
this.test.assertUrlMatch(/testFragment2.html.*testFragment3.html/);
});
};
casper.run(function() {
this.test.done();
});

View File

@ -0,0 +1,175 @@
/**
* Test case for the login page
*
* Steps:
* - Request application root path
* - Assert login page to appear
* - Enter invalid credentials
* - Enter valid credentials
* - Reload page without credentials
* - Logout
**/
/**
* The icinga util object
*
* @type object
*/
var icinga = require('./icingawebtest');
/**
* The casperjs object
*
* @type Casper
*/
var casper = icinga.getTestEnv();
/**
* Test whether the login form exists and has valid input elements
*
* @param {testing} The casperjs testing module to perform assertions
*/
var assertLoginFormExists = function(test) {
test.assertExists(
'form#form_login',
'Test whether the login form exists'
);
test.assertExists(
'form#form_login input#username',
'Test whether a username input field exists'
);
test.assertExists(
'form#form_login input#password',
'Test whether a password input field exists'
);
test.assertExists(
'form#form_login input#submit',
'Test whether a submit input field exists'
);
};
/**
* Request the initial application path
*/
casper.start('/', function() {
if (this.getCurrentUrl() === 'about:blank') {
this.die('Url can\'t be accessed');
}
this.test.assertTitle(
"Icinga Web Login",
"Test whether the login page (" + this.getCurrentUrl() + ") has a correct title"
);
assertLoginFormExists(this.test);
this.test.assertDoesntExist(
'#icinga_app_username',
'Test if no username is set in the frontend after initial page load'
);
});
/**
* Login with invalid credentials
*/
casper.then(function() {
this.fill('form#form_login', {
'username' : 'no',
'password' : 'existing_user'
});
this.click('form#form_login input#submit');
});
/**
* Test if login failed and feedback is given
*/
casper.then(function() {
this.test.assertTextExists(
'Please provide a valid username and password',
'Test if the user gets a note that authorization failed if providing wrong credentials'
);
assertLoginFormExists(this.test);
this.test.assertDoesntExist(
'#icinga_app_username',
'Test if no username is set in the frontend after entering wrong credentials'
);
});
/**
* Login with valid credentials
*/
casper.then(function() {
this.fill('form#form_login', icinga.getCredentials());
this.click('form#form_login input#submit');
});
/**
* Test if the login suceeded and the username is shown in the navigation bar
*/
casper.then(function() {
this.test.assertTextDoesntExist(
'Please provide a valid username and password',
'Test if valid credentials don\'t end cause a note that credentials are wrong to appear'
);
this.test.assertSelectorHasText(
'#icinga_app_nav_username',
icinga.getCredentials().username,
'Test if the username is set in the frontend after successful login'
);
});
/**
* Test if session is persisted after reloading the page
*/
casper.thenOpen('/', function() {
this.test.assertSelectorHasText(
'#icinga_app_nav_username',
icinga.getCredentials().username,
'Test if the username is still set if reloading the page via GET'
);
this.test.assertExists(
'#icinga_app_nav_logout',
'Test if the logout button exists'
);
this.test.assertExists(
'#icinga_app_nav_useraction',
'Test whether the dropdown for user specific actions exists'
);
});
/**
* Test if logout button is displayed when username is clicked and test for correct logout
*/
casper.then(function() {
this.test.assertNotVisible(
'#icinga_app_nav_logout',
'Test if the logout button is hidden when not clicked'
);
this.wait(500, function() { // wait until everything is initialized, sometimes this takes a while
this.click('#icinga_app_nav_useraction');
this.waitUntilVisible('#icinga_app_nav_logout', function() {
this.click('#icinga_app_nav_logout a');
this.waitForSelector('form#form_login', function() {
this.test.assertDoesntExist(
'#icinga_app_username',
'Test if no username is set in the frontend after logout'
);
assertLoginFormExists(this.test);
});
}, function() {
this.test.assertVisible(
'#icinga_app_nav_logout',
'Test if the logout button is visible when click on username occurs'
);
}, 500);
});
});
/**
* Run the tests
*/
casper.run(function() {
this.test.done();
});

View File

@ -1,21 +0,0 @@
/**
*
* This test simply checks the icinga build server and tests
* if the title is correct
**/
i2w = require('./i2w-config');
var casper = i2w.getTestEnv();
casper.start("http://localhost:12999/empty.html");
casper.then(function() {
this.test.assertTitle("Just an empty page");
});
casper.run(function() {
this.test.done();
});

View File

@ -1,5 +0,0 @@
{
"host": "localhost",
"port": 80,
"path": "icinga2-web"
}

View File

@ -1,158 +0,0 @@
/**
* Tools for setting up the casperjs tests
* mainly setting host, port and path path
**/
// load config files
var fs = require('fs');
var env = require('system').env;
var args = require('system').args;
var utils = require('utils');
var configFile = fs.absolute('./casperjs.config');
var host = null;
var port = null;
var path = null;
var verbose = false;
if (typeof(env.CASPERJS_HOST) === "string")
host = env.CASPERJS_HOST;
if (typeof(env.CASPERJS_PORT) === "string")
port = parseInt(env.CASPERJS_PORT, 10);
if (typeof(env.CASPERJS_PATH) === "string")
path = env.CASPERJS_PATH;
for (var i=0;i<args.length;i++) {
switch(args[i]) {
case '--verbose':
verbose = true;
break;
case '--configFile':
configFile = args[++i];
break;
case '--host':
host = args[++i];
break;
case '--port':
port = parseInt(args[++i], 10);
break;
case '--path':
path = args[++i];
break;
}
}
if (fs.isReadable(configFile)) {
var cfg = fs.read(configFile);
try {
config = JSON.parse(cfg);
if(host === null)
host = config.host;
if(port === null)
port = parseInt(config.port, 10);
if(path === null)
path = config.path;
} catch(e) {
console.error("Configuration "+cfg+" is invalid: "+e);
}
}
if (host === null)
throw "Can't initialize tests: No host given in casperjs.config or via CASPERJS_HOST environment";
if (port === null)
throw "Can't initialize tests: No port given in casperjs.config or via CASPERJS_PORT environment";
if (path === null)
throw "Can't initialize tests: No path given in casperjs.config or via CASPERJS_PATH environment";
(function() {
"use strict";
var getBaseURL = function(url) {
url = url || "";
if (url.substr(0,4) == "http") {
return url;
}
url = "http://"+host+":"+port+"/"+path+"/"+url;
};
var cstart = casper.start;
var copen = casper.open;
var copenFrom = casper.openFrom;
var startFromBase = function(url, then) {
return cstart.apply(casper,[this.getBaseURL(url), then]);
};
var thenOpenFromBase = function(url, options) {
return copen.apply(casper,[this.getBaseURL(url), options]);
};
var openFromBase = function(url, options) {
return copenFrom.apply(casper,[this.getBaseURL(url), options]);
};
casper.on('remote.message', function(message) {
console.log(message);
});
casper.on('page.error', function(message, trace) {
console.error(message, JSON.stringify(trace));
});
exports.getTestEnv = function() {
casper.getBaseURL = getBaseURL;
casper.start = startFromBase;
casper.thenOpen = thenOpenFromBase;
casper.open = openFromBase;
return casper;
};
exports.setupRequireJs = function(libraries) {
if (typeof libraries === "undefined") {
libraries = {
jquery: 'vendor/jquery-1.8.3',
bootstrap: 'vendor/bootstrap.min',
eve: 'vendor/raphael/eve'
};
} else {
libraries = libraries || {};
libraries.logging = 'icinga/util/logging';
libraries.jquery = 'vendor/jquery-1.8.3';
libraries["modules/list"] = "/moduleMock";
if (libraries.bootstrap || libraries.icinga) {
libraries.bootstrap = 'vendor/bootstrap.min';
libraries.history = 'vendor/history';
libraries.eve = 'vendor/raphael/eve';
libraries.raphael = 'vendor/raphael/raphael.amd';
libraries["raphael.core"] = 'vendor/raphael/raphael.core';
libraries["raphael.svg"] = 'vendor/raphael/raphael.svg';
libraries["raphael.vml"] = 'vendor/raphael/raphael.vml';
}
if (libraries.ace) {
libraries.ace = 'vendor/ace/ace';
}
}
var bootstrap = libraries.icinga;
delete(libraries.icinga);
requirejs.config({
baseUrl: window.base_url + '/js',
paths: libraries
});
if (bootstrap) {
requirejs(['jquery', 'history']);
requirejs(['bootstrap']);
requirejs(['icinga/icinga'], function (Icinga) {
window.$ = $;
window.jQuery = $;
window.Icinga = Icinga;
window.History = History;
});
}
};
})();

View File

@ -0,0 +1,119 @@
/**
* Tools for setting up the casperjs tests
* mainly setting host, port and path path
**/
// load config files
var fs = require('fs');
var env = require('system').env;
var args = require('system').args;
var utils = require('utils');
var host = 'localhost';
var port = 80;
var path = 'icingaweb';
var verbose = false;
var user = 'jdoe';
var pass = 'password';
if (typeof(env.CASPERJS_HOST) === 'string')
host = env.CASPERJS_HOST;
if (typeof(env.CASPERJS_PORT) === 'string')
port = parseInt(env.CASPERJS_PORT, 10);
if (typeof(env.CASPERJS_PATH) === 'string')
path = env.CASPERJS_PATH;
if (typeof(env.CASPERJS_USER) === 'string')
user = env.CASPERJS_USER;
if (typeof(env.CASPERJS_PASS) === 'string')
pass = env.CASPERJS_PASS;
for (var i=0;i<args.length;i++) {
switch(args[i]) {
case '--verbose':
verbose = true;
break;
case '--host':
host = args[++i];
break;
case '--port':
port = parseInt(args[++i], 10);
break;
case '--path':
path = args[++i];
break;
}
}
if (host === null) {
console.error('Can\'t initialize tests: No host given in casperjs.config or via CASPERJS_HOST environment');
return false;
}
if (port === null) {
console.error('Can\'t initialize tests: No port given in casperjs.config or via CASPERJS_PORT environment');
return false;
}
if (path === null) {
console.error('Can\'t initialize tests: No path given in casperjs.config or via CASPERJS_PATH environment');
return false;
}
(function() {
'use strict';
var getBaseURL = function(url) {
url = url || '';
if (url.substr(0,4) == 'http') {
return url;
}
return 'http://'+host+':'+port+'/'+path+'/'+url;
};
var cstart = casper.start;
var cthenOpen = casper.thenOpen;
var copen = casper.open;
var startFromBase = function(url, then) {
return cstart.call(casper, getBaseURL(url), then);
};
var thenOpenFromBase = function(url, options) {
return cthenOpen.apply(casper, [getBaseURL(url), options]);
};
var openFromBase = function(url, options) {
return copen.apply(casper, [getBaseURL(url), options]);
};
casper.on('remote.message', function(message) {
console.log(message);
});
casper.on('page.error', function(message, trace) {
console.error(message, JSON.stringify(trace));
});
exports.getTestEnv = function() {
casper.getBaseURL = getBaseURL;
casper.start = startFromBase;
casper.thenOpen = thenOpenFromBase;
casper.open = openFromBase;
return casper;
};
exports.getCredentials = function() {
return {
'username' : user,
'password' : pass
};
};
exports.performLogin = function() {
casper.start("/authentication/login", function() {
this.fill('form#form_login', icinga.getCredentials());
this.click('form#form_login input#submit');
});
};
})();

View File

@ -1,51 +0,0 @@
/**
*
* Regression test for #4408
# History api double encodes and causes messy behaviour
*
**/
var i2w = require('./i2w-config');
var casper = i2w.getTestEnv();
var URL = "http://localhost:12999";
var firstLink = "/fragments/testFragment1.html?c[test]=test_test";
var secondLink = "/fragments/testFragment3.html?this=is_a_param";
casper.start(URL+"/generic.html");
casper.then(function() {
casper.page.evaluate(i2w.setupRequireJs, {icinga: true});
});
casper.then(function() {
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment1.html?c[test]=test_test");
});
});
casper.waitForSelector("div#icinga-main a", onFirstCall);
});
/**
* First call of the loadUrl
**/
var onFirstCall = function() {
this.test.assertUrlMatch(URL+firstLink);
casper.page.evaluate(function() {
requirejs(["icinga/icinga"], function(icinga) {
icinga.loadUrl("/fragments/testFragment3.html?this=is_a_param", "icinga-detail");
});
});
this.wait(400, function() {
var expected =
URL +
firstLink+"&c[icinga-detail]=" +
secondLink;
this.test.assertUrlMatch(expected);
});
};
casper.run(function() {
this.test.done();
});

View File

@ -0,0 +1,148 @@
/**
* Configuration: Show message that changes were saved successfully
*
* As a user I want too see that configuration changes were successful.
*
* This test performs the following steps
*
* - Login using the provided credentials
* - Open the configuration dialog and change the timezone
* - Save and test for a success bubble to appear
* - Open the authentication dialog
* - Open the edit link of the first backend
* - Hit save and test for a success bubble to apper
* - Open the logging dialog, hit save and test for a success bubble to appear
**/
/**
* The icinga util object
*
* @type object
*/
var icinga = require('./icingawebtest');
/**
* The casperjs object
*
* @type Casper
*/
var casper = icinga.getTestEnv();
/**
* Login to the instance
*/
icinga.performLogin();
/**
* Open the config dialog and test if the form exists
*/
casper.thenOpen('/config', function() {
this.test.assertExists(
'#form_config_general',
'Test whether the general settings dialog exists in the general form'
);
this.test.assertExists(
'#form_config_general select#timezone',
'Assert the timezone input to exist'
);
});
/**
* Change the timezone and submit
*/
casper.then(function() {
this.test.assertDoesntExist(
'div.alert.alert-success',
'Assert no success notice existing when no changes have been done in the general form'
);
this.echo("Changing the default timezone");
this.fill('#form_config_general', {
'timezone': 'Europe/Minsk'
});
this.click('#form_config_general input#btn_submit');
});
/**
* Check for the 'Successfully Update' information bubble
*/
casper.then(function() {
this.echo("Clicked on save button of the general form, waiting for success");
this.waitForSelector('div.alert.alert-success', function() {
this.test.assertSelectorHasText(
'div.alert.alert-success',
'Config Sucessfully Updated',
'Assert a success text to appear in the general form'
);
}, function() {
this.test.fail("No success text appeared in the general form");
});
});
/**
* Open the config dialog and click on the first 'Edit This Authentication Backend' Link
*/
casper.thenOpen('/config/authentication', function() {
var link = this.evaluate(function() {
var links = document.querySelectorAll('#icingamain a');
for (var i=0; i<links.length; i++) {
if (/.* Edit This Authentication/.test(links[i].text)) {
document.location.href = links[i].getAttribute('href');
return;
}
}
});
this.echo("Clicked on first authentication backend link");
});
/**
* Submit the authenticaton backend without any changes and test for the success bubble
*/
casper.then(function() {
this.waitForSelector('input#btn_submit', function() {
this.click('input#btn_submit');
this.echo("Submitted authentication form");
this.waitForSelector('div.alert', function() {
// Force creation when message bubbled
if (this.exists('form#form_modify_backend input#backend_force_creation')) {
this.echo("Backend persistence requires an additional confirmation in this case");
this.fill('#form_modify_backend', {
'backend_force_creation' : '1'
});
this.click('input#btn_submit');
}
this.echo("Waiting for success feedback");
this.waitForSelector('div.alert.alert-success', function() {
this.test.assertExists('div.alert.alert-success', 'Assert a success message to exist');
});
}, function() {
this.test.fail("Success message for authentication provider tests didn't pop up");
});
}, function() {
this.test.fail('No submit button found when expected the "Edit this authentication provider" form');
});
});
/**
* Submit the logging dialog without any changes and test for the success bubble
*/
casper.thenOpen('/config/logging', function() {
this.test.assertExists('form#form_config_logging', 'Asserting the logging form to exist');
this.click('form#form_config_logging input#btn_submit');
this.waitForSelector('div.alert.alert-success', function() {
this.test.assertExists('div.alert.alert-success', 'Assert a success message to exist');
}, function() {
this.test.fail('No success message popped up when saving logging configuration');
});
});
/**
* Run the tests
*/
casper.run(function() {
this.test.done();
});

View File

@ -1 +0,0 @@
test

View File

@ -11,15 +11,17 @@ VERBOSE=0
VAGRANT=0
BUILD=0
CASPERJS_HOST="localhost"
CASPERJS_PORT=80
CASPERJS_USER="jdoe"
CASPERJS_PASS="password"
CASPERJS_PATH="icinga2-web"
if [ ! -x $CASPER ]; then
echo "CasperJS is not installed but required to run frontend tests\n"\
"Take a look at http://casperjs.org/installation.html to see how the installation works for your system"
exit 1
fi;
if [ ! -e "${DIR}/static/public" ]; then
echo "!"
ln -s "${DIR}/../../public" "${DIR}/static/public"
fi;
PARAM="0"
@ -48,16 +50,41 @@ for arg in $@;do
BUILD=1
continue
;;
-h|--host)
PARAM="CASPERJS_HOST"
continue
;;
-p|--port)
PARAM="CASPERJS_PORT"
continue
;;
--path)
PARAM="CASPERJS_PATH"
continue
;;
-U|--user)
PARAM="CASPERJS_USER"
continue
;;
-P|--pass)
PARAM="CASPERJS_PASS"
continue
;;
**)
if [ "$arg" != "--help" ]; then
echo "Unknown option $arg"
fi;
printf "%b" "Testrunner for interface tests\n\n"
printf "%b" "Usage: ./$0 [--verbose] [--include %include%] [--exclude %exclude%] [--build]\n\n"
printf "%b" "Usage: $0 [--verbose] [--include %include%] [--exclude %exclude%] [--build]\n\n"
printf "%b" " --verbose \t\t\t Print verbose output when testing\n"
printf "%b" " --include %filelist%\t\t Include only files matching this patterns\n"
printf "%b" " --exclude %filelist%\t\t Exclude files matching this patterns\n"
printf "%b" " --build \t\t\t Write test results to ../../build/log/casper_results.xml\n"
printf "%b" " --host \t\t\t Host to run frontend tests on, default is localhost\n"
printf "%b" " --port \t\t\t Port to use for the host, default is 80 \n"
printf "%b" " --path \t\t\t Base path where icinga can be found (default is icingaweb)\n"
printf "%b" " --user \t\t\t User to use for authentication (default jdoe)\n"
printf "%b" " --pass \t\t\t Password to use for authentication (default password)\n"
printf "%b" " --help \t\t\t Print this message\n\n"
exit 1
esac;
@ -84,7 +111,7 @@ if [ "$CASPER" = "" -o ! -x $CASPER ]; then
exit 1
fi;
EXEC="$CASPER test"
EXEC="$CASPER test --ignore-ssl-errors=true "
#
# If build is set, the results are written for our jenkins server
@ -137,16 +164,13 @@ if [ "$EXCLUDE" != "" ];then
FILELIST=`echo $FILELIST | grep -v "$NAME"`
fi;
cd $DIR/static
PROC=`ps ax|grep "SimpleHTTPServer 12999"|awk '{ print $1 }'`
if [ "$PROC" != "" ]; then
kill $PROC
fi;
python -m SimpleHTTPServer 12999&
PID=$!
cd $DIR
echo $EXEC $FILELIST
$EXEC $FILELIST
kill $PID
export CASPERJS_HOST=$CASPERJS_HOST
export CASPERJS_PORT=$CASPERJS_PORT
export CASPERJS_USER=$CASPERJS_USER
export CASPERJS_PASS=$CASPERJS_PASS
export CASPERJS_PATH=$CASPERJS_PATH
echo Executing $EXEC $FILELIST
$EXEC $FILELIST
exit 0

View File

@ -1,7 +0,0 @@
<html>
<head>
<title>Just an empty page</title>
</head>
<body>
</body>
</html>

View File

@ -1,6 +0,0 @@
<div>
<h1>Test fragment</h1>
<a href="/fragments/testFragment2.html?this=istesting">Fragment 2</a>
<a href="/fragments/testFragment3.html">Fragment 3</a>
</div>

View File

@ -1,6 +0,0 @@
<div>
<h1>Test fragment 2</h1>
<a href="/fragments/testFragment1.html">Fragment 1</a>
<a href="/fragments/testFragment3.html">Fragment 3</a>
</div>

View File

@ -1,6 +0,0 @@
<div>
<h1>Test fragment 3</h1>
<a href="/fragments/testfragment1.html">Fragment 1</a>
<a href="/fragments/testfragment2.html">Fragment 2</a>
</div>

View File

@ -1,39 +0,0 @@
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Icinga test page</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<script>
window.base_url = "/public";
</script>
<link rel="stylesheet" href="/public/css/normalize.min.css">
<link rel="stylesheet" href="/public/css/vendor/bootstrap.css">
<link rel="stylesheet" href="/public/css/main.css">
<link rel="stylesheet" href="/public/css/vendor/jquery.qtip.min.css">
<script src="/public/js/vendor/modernizr-2.6.2.min.js"></script>
<link rel="stylesheet" href="/public/css/icinga.css">
<link rel="stylesheet" href="/public/css/vendor/bootstrap-responsive.min.css">
<script src="/public/js/vendor/require.js"></script>
</head>
<body class="cranberry">
<div class="main">
<div class="tabbable tabs-left" style="height:100%;">
</div>
<div class="layout-main-detail collapsed">
<div id="icinga-main" container-id="icinga-main" class="icinga-container">
</div>
<div id="icinga-detail" class="icinga-container " container-id="icinga-detail">
</div><!-- End of icinga-detail -->
</div><!-- End of layout-main-detail -->
</div><!-- End of main -->
</body>
</html>

View File

@ -1,4 +0,0 @@
define([], function() {
"use strict";
return {};
});

View File

@ -1 +0,0 @@
<testsuite time="0"><testcase classname="cases/static-page-test" name="The jenkins page" time="0.626"><failure type="assertTitle">Page title is: "i4cinga-web test [Jenkins]"</failure></testcase></testsuite>

View File

@ -38,17 +38,21 @@ use Icinga\Test\BaseTestCase;
require_once 'Zend/Form.php';
require_once 'Zend/Config.php';
require_once 'Zend/Config/Ini.php';
require_once BaseTestCase::$testDir . '/library/Icinga/Web/RequestMock.php';
require_once BaseTestCase::$libDir . '/Web/Form.php';
require_once BaseTestCase::$appDir . '/forms/Config/AuthenticationForm.php';
require_once BaseTestCase::$libDir . '/Web/Url.php';
require_once BaseTestCase::$appDir . '/forms/Config/Authentication/BaseBackendForm.php';
require_once BaseTestCase::$appDir . '/forms/Config/Authentication/DbBackendForm.php';
require_once BaseTestCase::$appDir . '/forms/Config/Authentication/LdapBackendForm.php';
// @codingStandardsIgnoreEnd
use \Icinga\Web\Form;
use \DOMDocument;
use Icinga\Web\Url;
use Tests\Icinga\Web\RequestMock;
use \Zend_Config;
use \Zend_View;
/**
* Test for the authentication provider form
@ -92,27 +96,26 @@ class AuthenticationFormTest extends BaseTestCase
public function testLdapProvider()
{
$this->requireFormLibraries();
$form = $this->createForm('Icinga\Form\Config\AuthenticationForm');
$form = $this->createForm('Icinga\Form\Config\Authentication\LdapBackendForm');
$config = new Zend_Config(
array(
'test-ldap' => array(
'backend' => 'ldap',
'target' => 'user',
'hostname' => 'test host',
'root_dn' => 'ou=test,dc=icinga,dc=org',
'bind_dn' => 'cn=testuser,cn=config',
'bind_pw' => 'password',
'user_class' => 'testClass',
'user_name_attribute' => 'testAttribute'
)
'backend' => 'ldap',
'target' => 'user',
'hostname' => 'test host',
'root_dn' => 'ou=test,dc=icinga,dc=org',
'bind_dn' => 'cn=testuser,cn=config',
'bind_pw' => 'password',
'user_class' => 'testClass',
'user_name_attribute' => 'testAttribute'
)
);
$form->setConfiguration($config);
$form->setBackendName('testldap');
$form->setBackend($config);
$form->create();
// parameters to be hidden
$notShown = array('backend', 'target');
foreach ($config->get('test-ldap')->toArray() as $name => $value) {
foreach ($config->toArray() as $name => $value) {
if (in_array($name, $notShown)) {
continue;
}
@ -123,22 +126,19 @@ class AuthenticationFormTest extends BaseTestCase
);
}
}
/*
/**
* Test the database provider form population from config
*
*/
public function testDbProvider()
{
$this->requireFormLibraries();
$form = $this->createForm('Icinga\Form\Config\AuthenticationForm');
$form = $this->createForm('Icinga\Form\Config\Authentication\DbBackendForm');
$config = new Zend_Config(
array(
'test-db' => array(
'backend' => 'db',
'target' => 'user',
'resource' => 'db_resource'
)
'backend' => 'db',
'target' => 'user',
'resource' => 'db_resource'
)
);
$form->setResources(
@ -149,12 +149,13 @@ class AuthenticationFormTest extends BaseTestCase
)
);
$form->setConfiguration($config);
$form->setBackendName('test-db');
$form->setBackend($config);
$form->create();
// parameters to be hidden
$notShown = array('backend', 'target');
foreach ($config->get('test-db')->toArray() as $name => $value) {
foreach ($config->toArray() as $name => $value) {
if (in_array($name, $notShown)) {
continue;
}
@ -169,171 +170,70 @@ class AuthenticationFormTest extends BaseTestCase
/**
* Test whether order modifications via 'priority' are considered
*
* @backupStaticAttributes enabled
*/
public function testShowModifiedOrder()
public function testModifyOrder()
{
Url::$overwrittenRequest = new RequestMock();
$this->requireFormLibraries();
$form = $this->createForm(
'Icinga\Form\Config\AuthenticationForm',
array(
'priority' => 'test-ldap,test-db'
)
);
$config = $this->getTestConfig();
$form->setResources(
array(
'db_resource' => array(
'type' => 'db'
)
)
);
$form = $this->createForm('Icinga\Form\Config\Authentication\ReorderForm');
$form->setAuthenticationBackend('backend2');
$form->setCurrentOrder(array('backend1', 'backend2', 'backend3', 'backend4'));
$form->setConfiguration($config);
$form->create();
$this->assertSame(
2,
count($form->getSubForms()),
'Assert that a form for moving backend up and down exists'
);
$this->assertTrue(
$form->upForm->getElement('form_backend_order') !== null,
'Assert that a "move backend up" button exists'
);
$this->assertSame(
array('backend2', 'backend1', 'backend3', 'backend4'),
explode(',', $form->upForm->getElement('form_backend_order')->getValue()),
'Assert the "move backend up" button containing the correct order'
);
$prio = array_keys($form->getConfig());
$this->assertEquals('test-ldap', $prio[0], "Asserting priority changes to be persisted");
$this->assertEquals('test-db', $prio[1], "Asserting priority changes to be persisted");
$this->assertTrue(
$form->downForm->getElement('form_backend_order') !== null,
'Assert that a "move backend down" button exists'
);
$this->assertSame(
array('backend1', 'backend3', 'backend2', 'backend4'),
explode(',', $form->downForm->getElement('form_backend_order')->getValue()),
'Assert the "move backend up" button containing the correct order'
);
}
/**
* Test whether configuration changes are correctly returned when calling getConfig
* Test whether the reorder form doesn't display senseless ordering (like moving the uppermost element up or
* the lowermose down)
*
* @backupStaticAttributes enabled
*/
public function testConfigurationCreation()
public function testInvalidOrderingNotShown()
{
Url::$overwrittenRequest = new RequestMock();
$this->requireFormLibraries();
$form = $this->createForm(
'Icinga\Form\Config\AuthenticationForm',
array(
'priority' => 'test-ldap,test-db',
'backend_testdb_resource' => 'db_resource_2',
'backend_testldap_hostname' => 'modified_host',
'backend_testldap_root_dn' => 'modified_root_dn',
'backend_testldap_bind_dn' => 'modified_bind_dn',
'backend_testldap_bind_pw' => 'modified_bind_pw',
'backend_testldap_user_class' => 'modified_user_class',
'backend_testldap_user_name_attribute' => 'modified_user_name_attribute'
)
);
$form = $this->createForm('Icinga\Form\Config\Authentication\ReorderForm');
$form->setAuthenticationBackend('backend1');
$form->setCurrentOrder(array('backend1', 'backend2', 'backend3', 'backend4'));
$form->setResources(
array(
'db_resource' => array(
'type' => 'db'
),
'db_resource_2' => array(
'type' => 'db'
)
)
);
$form->setConfiguration($this->getTestConfig());
$form->create();
$modified = new Zend_Config($form->getConfig());
$this->assertEquals(
'db_resource_2',
$modified->get('test-db')->resource,
'Asserting database resource modifications to be applied'
$this->assertSame(
2,
count($form->getSubForms()),
'Assert that a form for moving backend up and down exists, even when moving up is not possible'
);
$this->assertEquals(
'user',
$modified->get('test-db')->target,
'Asserting database target still being user when modifying'
$this->assertTrue(
$form->downForm->getElement('form_backend_order') !== null,
'Assert that a "move backend down" button exists when moving up is not possible'
);
$this->assertEquals(
'db',
$modified->get('test-db')->backend,
'Asserting database backend still being db when modifying'
$this->assertTrue(
$form->upForm->getElement('form_backend_order') === null,
'Assert that a "move backend up" button does not exist when moving up is not possible'
);
$ldap = $modified->get('test-ldap');
$this->assertEquals(
'modified_host',
$ldap->hostname,
'Asserting hostname modifications to be applied when modifying ldap authentication backends'
);
$this->assertEquals(
'modified_root_dn',
$ldap->root_dn,
'Asserting root dn modifications to be applied when modifying ldap authentication backends'
);
$this->assertEquals(
'modified_bind_dn',
$ldap->bind_dn,
'Asserting bind dn modifications to be applied when modifying ldap authentication backends'
);
$this->assertEquals(
'modified_bind_pw',
$ldap->bind_pw,
'Asserting bind pw modifications to be applied when modifying ldap authentication backends'
);
$this->assertEquals(
'modified_user_class',
$ldap->user_class,
'Asserting user class modifications to be applied when modifying ldap authentication backends'
);
$this->assertEquals(
'modified_user_name_attribute',
$ldap->user_name_attribute,
'Asserting user name attribute modifications to be applied when modifying ldap authentication backends'
);
}
/**
* Test correct behaviour when ticking the 'remove backend' option
*/
public function testBackendRemoval()
{
$this->requireFormLibraries();
$form = $this->createForm(
'Icinga\Form\Config\AuthenticationForm',
array(
'priority' => 'test-ldap,test-db',
'backend_testdb_resource' => 'db_resource_2',
'backend_testldap_remove' => 1,
'backend_testldap_hostname' => 'modified_host',
'backend_testldap_root_dn' => 'modified_root_dn',
'backend_testldap_bind_dn' => 'modified_bind_dn',
'backend_testldap_bind_pw' => 'modified_bind_pw',
'backend_testldap_user_class' => 'modified_user_class',
'backend_testldap_user_name_attribute' => 'modified_user_name_attribute'
)
);
$form->setResources(
array(
'db_resource' => array(
'type' => 'db'
),
'db_resource_2' => array(
'type' => 'db'
)
)
);
$form->setConfiguration($this->getTestConfig());
$form->create();
$view = new Zend_View();
$html = new DOMDocument();
$html->loadHTML($form->render($view));
$this->assertEquals(
null,
$html->getElementById('backend_testldap_hostname-element'),
'Asserting configuration to be hidden when an authentication is marked as to be removed'
);
$config = $form->getConfig();
$this->assertFalse(
isset($config['test-ldap']),
'Asserting deleted backends not being persisted in the configuration'
);
}
}

View File

@ -87,7 +87,7 @@ class GeneralFormTest extends BaseTestCase
* Test whether fields with preferences are enabled
*
*/
public function testEnsableFormIfUsingPreference()
public function testEnableFormIfUsingPreference()
{
$this->requireFormLibraries();
$form = $this->createForm('Icinga\Form\Preference\GeneralForm');

View File

@ -49,7 +49,11 @@ class BackendMock implements UserBackend
"user@test.local"
);
}
public function getUserCount() {
return count($this->allowedCredentials);
}
public function authenticate(Credentials $credentials)
{
if (!in_array($credentials, $this->allowedCredentials)) {

View File

@ -30,6 +30,7 @@ namespace Test\Icinga\Web\Form\Validator;
require_once('Zend/Validate/Abstract.php');
require_once(realpath('../../library/Icinga/Web/Form/Validator/WritablePathValidator.php'));
require_once(realpath('../../library/Icinga/Application/Config.php'));
use \PHPUnit_Framework_TestCase;
use \Icinga\Web\Form\Validator\WritablePathValidator;