From ae35650c7e516b2005f7bf2a6df269306eedff2e Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 29 Aug 2014 15:16:13 +0200 Subject: [PATCH] Adjust authentication backend forms to suit.. some form implementation refs #5525 --- application/controllers/ConfigController.php | 233 +++---------- .../Authentication/AutologinBackendForm.php | 18 +- .../Config/Authentication/BaseBackendForm.php | 94 ------ .../Config/Authentication/DbBackendForm.php | 76 +++-- .../Config/Authentication/LdapBackendForm.php | 87 ++--- .../AuthenticationBackendConfigForm.php | 318 ++++++++++++++++++ .../AuthenticationBackendReorderForm.php | 68 ++++ .../views/scripts/config/authentication.phtml | 57 ---- .../config/authentication/create.phtml | 18 +- .../config/authentication/modify.phtml | 10 +- .../config/authentication/remove.phtml | 10 +- .../config/authentication/reorder.phtml | 11 + .../scripts/form/reorder-authbackend.phtml | 40 +++ 13 files changed, 591 insertions(+), 449 deletions(-) delete mode 100644 application/forms/Config/Authentication/BaseBackendForm.php create mode 100644 application/forms/Config/AuthenticationBackendConfigForm.php create mode 100644 application/forms/Config/AuthenticationBackendReorderForm.php delete mode 100644 application/views/scripts/config/authentication.phtml create mode 100644 application/views/scripts/config/authentication/reorder.phtml create mode 100644 application/views/scripts/form/reorder-authbackend.phtml diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index 423a59902..f5da2952a 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -6,19 +6,16 @@ use Icinga\Web\Controller\BaseConfigController; use Icinga\Web\Widget\AlertMessageBox; use Icinga\Web\Notification; use Icinga\Application\Modules\Module; -use Icinga\Web\Form; use Icinga\Web\Widget; use Icinga\Application\Icinga; use Icinga\Application\Config as IcingaConfig; use Icinga\Form\Config\GeneralForm; -use Icinga\Form\Config\Authentication\LdapBackendForm; -use Icinga\Form\Config\Authentication\DbBackendForm; -use Icinga\Form\Config\Authentication\AutologinBackendForm; +use Icinga\Form\Config\AuthenticationBackendReorderForm; +use Icinga\Form\Config\AuthenticationBackendConfigForm; use Icinga\Form\Config\ResourceForm; -use Icinga\Form\Config\LoggingForm; use Icinga\Form\Config\ConfirmRemovalForm; use Icinga\Config\PreservingIniWriter; -use Icinga\Exception\ConfigurationError; +use Icinga\Data\ResourceFactory; /** @@ -142,47 +139,17 @@ class ConfigController extends BaseConfigController } /** - * Action for reordering authentication backends + * Action for listing and reordering authentication backends */ public function authenticationAction() { - $this->view->messageBox = new AlertMessageBox(true); + $form = new AuthenticationBackendReorderForm(); + $form->setConfig(IcingaConfig::app('authentication')); + $form->handleRequest(); + + $this->view->form = $form; $this->view->tabs->activate('authentication'); - - $config = IcingaConfig::app('authentication'); - $backendOrder = array_keys($config->toArray()); - $form = new Form(); - $form->setName('form_reorder_authbackend'); - $request = $this->getRequest(); - if ($request->isPost()) { - $requestData = $request->getPost(); - if ($form->isValid($requestData)) { // Validate the CSRF token - $reordered = false; - foreach ($backendOrder as $backendName) { - if (isset($requestData[$backendName])) { - array_splice($backendOrder, array_search($backendName, $backendOrder), 1); - array_splice($backendOrder, $requestData[$backendName], 0, $backendName); - $reordered = true; - break; - } - } - - if ($reordered) { - $reorderedConfig = array(); - foreach ($backendOrder as $backendName) { - $reorderedConfig[$backendName] = $config->{$backendName}; - } - - if ($this->writeAuthenticationFile($reorderedConfig)) { - Notification::success($this->translate('Authentication order updated!')); - $this->redirectNow('config/authentication'); - } - } - } - } - - $this->view->form = $form->create(); // Necessary in case its a GET request - $this->view->backendNames = $backendOrder; + $this->render('authentication/reorder'); } /** @@ -190,172 +157,66 @@ class ConfigController extends BaseConfigController */ public function createauthenticationbackendAction() { - $this->view->messageBox = new AlertMessageBox(true); - $this->view->tabs->activate('authentication'); + $form = new AuthenticationBackendConfigForm(); + $form->setConfig(IcingaConfig::app('authentication')); + $form->setResourceConfig(ResourceFactory::getResourceConfigs()); + $form->setRedirectUrl('config/authentication'); + $form->handleRequest(); - $backendType = $this->getRequest()->getParam('type'); - $authenticationConfig = IcingaConfig::app('authentication')->toArray(); - try { - switch ($backendType) { - case 'ldap': - $form = new LdapBackendForm(); - break; - case 'db': - $form = new DbBackendForm(); - break; - case 'autologin': - foreach ($authenticationConfig as $ac) { - if (array_key_exists('backend', $ac) && $ac['backend'] === 'autologin') { - throw new ConfigurationError( - $this->translate('An autologin backend already exists') - ); - } - } - $form = new AutologinBackendForm(); - break; - default: - $this->addErrorMessage(sprintf( - $this->translate('There is no backend type `%s\''), - $backendType - )); - $this->redirectNow('config/configurationerror'); - } - } catch (ConfigurationError $e) { - $this->addErrorMessage($e->getMessage()); - $this->redirectNow('config/configurationerror'); - } - - $request = $this->getRequest(); - if ($request->isPost() && $form->isValid($request->getPost())) { - list($backendName, $backendConfig) = $form->getBackendConfig(); - if (isset($authenticationConfig[$backendName])) { - $this->addErrorMessage( - $this->translate('Backend name already exists') - ); - } else { - $authenticationConfig[$backendName] = $backendConfig; - if ($this->writeConfigFile($authenticationConfig, 'authentication')) { - $this->addSuccessMessage( - $this->translate('Backend Modification Written.') - ); - $this->redirectNow('config/authentication'); - } - } - } - - $this->view->messageBox->addForm($form); $this->view->form = $form; + $this->view->tabs->activate('authentication'); $this->render('authentication/create'); } - /** - * Form for editing backends - * - * Mostly the same like the createAuthenticationBackendAction, but with additional checks for backend existence - * and form population + * Action for editing authentication backends */ public function editauthenticationbackendAction() { - $this->view->messageBox = new AlertMessageBox(true); + $form = new AuthenticationBackendConfigForm(); + $form->setConfig(IcingaConfig::app('authentication')); + $form->setResourceConfig(ResourceFactory::getResourceConfigs()); + $form->setRedirectUrl('config/authentication'); + $form->handleRequest(); - $configArray = IcingaConfig::app('authentication', true)->toArray(); - $authBackend = $this->getParam('auth_backend'); - if (false === isset($configArray[$authBackend])) { - $this->addErrorMessage( - $this->translate('Can\'t edit: Unknown Authentication Backend Provided') - ); - $this->redirectNow('config/configurationerror'); - } - - if (false === array_key_exists('backend', $configArray[$authBackend])) { - $this->addErrorMessage(sprintf( - $this->translate('Backend "%s" has no `backend\' setting'), - $authBackend - )); - $this->redirectNow('config/configurationerror'); - } - $type = $configArray[$authBackend]['backend']; - switch ($type) { - case 'ldap': - $form = new LdapBackendForm(); - break; - case 'db': - $form = new DbBackendForm(); - break; - case 'autologin': - $form = new AutologinBackendForm(); - break; - default: - $this->addErrorMessage(sprintf( - $this->translate('Can\'t edit: backend type "%s" of given resource not supported.'), - $type - )); - $this->redirectNow('config/configurationerror'); - } - - $request = $this->getRequest(); - if ($request->isPost()) { - if ($form->isValid($request->getPost())) { - list($backendName, $backendConfig) = $form->getBackendConfig(); - $configArray[$backendName] = $backendConfig; - if ($backendName != $authBackend) { - unset($configArray[$authBackend]); - } - if ($this->writeAuthenticationFile($configArray)) { - // redirect to overview with success message - Notification::success(sprintf( - $this->translate('Backend "%s" saved'), - $backendName - )); - $this->redirectNow('config/authentication'); - } - return; - } - } else { - $form->setBackendConfig($authBackend, $configArray[$authBackend]); - } - - $this->view->messageBox->addForm($form); - $this->view->name = $authBackend; $this->view->form = $form; + $this->view->tabs->activate('authentication'); $this->render('authentication/modify'); } /** - * Action for removing a backend from the authentication list. - * - * Redirects to the overview after removal is finished + * Action for removing a backend from the authentication list */ public function removeauthenticationbackendAction() { - $this->view->messageBox = new AlertMessageBox(true); + $form = new ConfirmRemovalForm(array( + 'onSuccess' => function ($request) { + $configForm = new AuthenticationBackendConfigForm(); + $configForm->setConfig(IcingaConfig::app('authentication')); + $authBackend = $request->getQuery('auth_backend'); - $configArray = IcingaConfig::app('authentication', true)->toArray(); - $authBackend = $this->getParam('auth_backend'); - if (false === array_key_exists($authBackend, $configArray)) { - $this->addErrorMessage( - $this->translate('Can\'t perform removal: Unknown authentication backend provided') - ); - $this->redirectNow('config/configurationerror'); - } + try { + $configForm->remove($authBackend); + } catch (InvalidArgumentException $e) { + Notification::error($e->getMessage()); + return; + } - $form = new ConfirmRemovalForm(); - $request = $this->getRequest(); - - if ($request->isPost() && $form->isValid($request->getPost())) { - unset($configArray[$authBackend]); - if ($this->writeAuthenticationFile($configArray)) { - Notification::success(sprintf( - $this->translate('Authentication Backend "%s" Removed'), - $authBackend - )); - $this->redirectNow('config/authentication'); + if ($configForm->save()) { + Notification::success(sprintf( + t('Authentication backend "%s" has been successfully removed'), + $authBackend + )); + } else { + return false; + } } - } + )); + $form->setRedirectUrl('config/authentication'); + $form->handleRequest(); $this->view->form = $form; - $this->view->name = $authBackend; + $this->view->tabs->activate('authentication'); $this->render('authentication/remove'); } diff --git a/application/forms/Config/Authentication/AutologinBackendForm.php b/application/forms/Config/Authentication/AutologinBackendForm.php index c3cf56fa7..662106bcd 100644 --- a/application/forms/Config/Authentication/AutologinBackendForm.php +++ b/application/forms/Config/Authentication/AutologinBackendForm.php @@ -5,19 +5,19 @@ namespace Icinga\Form\Config\Authentication; use Zend_Validate_Callback; +use Icinga\Web\Form; /** * Form class for adding/modifying autologin authentication backends */ -class AutologinBackendForm extends BaseBackendForm +class AutologinBackendForm extends Form { /** * Initialize this form */ public function init() { - $this->setName('form_config_authentication_autologin'); - $this->setSubmitLabel(t('Save Changes')); + $this->setName('form_config_authbackend_autologin'); } /** @@ -31,7 +31,6 @@ class AutologinBackendForm extends BaseBackendForm 'name', array( 'required' => true, - 'allowEmpty' => false, 'label' => t('Backend Name'), 'helptext' => t('The name of this authentication backend'), 'validators' => array( @@ -53,7 +52,6 @@ class AutologinBackendForm extends BaseBackendForm 'strip_username_regexp', array( 'required' => true, - 'allowEmpty' => false, 'label' => t('Backend Domain Pattern'), 'helptext' => t('The domain pattern of this authentication backend'), 'value' => '/\@[^$]+$/', @@ -76,13 +74,15 @@ class AutologinBackendForm extends BaseBackendForm } /** - * Validate the configuration state of this backend + * Validate the configuration by creating a backend and requesting the user count * - * Returns just true as autologins are being handled externally by the webserver. + * Returns always true as autologin backends are just "passive" backends. (The webserver authenticates users.) * - * @return true + * @param Form $form The form to fetch the configuration values from + * + * @return bool Whether validation succeeded or not */ - public function isValidAuthenticationBackend() + public function isValidAuthenticationBackend(Form $form) { return true; } diff --git a/application/forms/Config/Authentication/BaseBackendForm.php b/application/forms/Config/Authentication/BaseBackendForm.php deleted file mode 100644 index 840b5f34c..000000000 --- a/application/forms/Config/Authentication/BaseBackendForm.php +++ /dev/null @@ -1,94 +0,0 @@ -isValidAuthenticationBackend() - ) { - $this->addForceCreationCheckbox(); - return false; - } - - return true; - } - - /** - * 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 'force_creation' checkbox is set, this method won't be called. - * - * @return bool Whether validation succeeded or not - */ - abstract public function isValidAuthenticationBackend(); - - /** - * Return the backend's configuration values and its name - * - * The first value is the name and the second one the values as array. - * - * @return array - */ - public function getBackendConfig() - { - $values = $this->getValues(); - $name = $values['name']; - unset($values['name']); - return array($name, $values); - } - - /** - * Populate the form with the given configuration values - * - * @param string $name The name of the backend - * @param array $config The configuration values - */ - public function setBackendConfig($name, array $config) - { - $config['name'] = $name; - $this->populate($config); - } - - /** - * Add a checkbox to be displayed at the beginning of the form - * which allows the user to skip the connection validation - */ - protected function addForceCreationCheckbox() - { - $this->addElement( - 'checkbox', - 'force_creation', - array( - 'order' => 0, - 'ignore' => true, - 'label' => t('Force Changes'), - 'helptext' => t('Check this box to enforce changes without connectivity validation') - ) - ); - } -} diff --git a/application/forms/Config/Authentication/DbBackendForm.php b/application/forms/Config/Authentication/DbBackendForm.php index 521414094..7ec9c3c26 100644 --- a/application/forms/Config/Authentication/DbBackendForm.php +++ b/application/forms/Config/Authentication/DbBackendForm.php @@ -5,17 +5,18 @@ namespace Icinga\Form\Config\Authentication; use Exception; +use Icinga\Web\Form; +use Icinga\Web\Request; use Icinga\Data\ResourceFactory; -use Icinga\Exception\ConfigurationError; use Icinga\Authentication\Backend\DbUserBackend; /** * Form class for adding/modifying database authentication backends */ -class DbBackendForm extends BaseBackendForm +class DbBackendForm extends Form { /** - * The available database resources prepared to be used as select input data + * The database resource names the user can choose from * * @var array */ @@ -23,28 +24,23 @@ class DbBackendForm extends BaseBackendForm /** * Initialize this form - * - * Populates $this->resources. - * - * @throws ConfigurationError In case no database resources can be found */ public function init() { - $this->setName('form_config_authentication_db'); - $this->setSubmitLabel(t('Save Changes')); + $this->setName('form_config_authbackend_db'); + } - $dbResources = array_keys( - ResourceFactory::getResourceConfigs('db')->toArray() - ); - - if (empty($dbResources)) { - throw new ConfigurationError( - t('There are no database resources') - ); - } - - // array_combine() is necessary in order to use the array as select input data - $this->resources = array_combine($dbResources, $dbResources); + /** + * Set the resource names the user can choose from + * + * @param array $resources The resources to choose from + * + * @return self + */ + public function setResources(array $resources) + { + $this->resources = $resources; + return $this; } /** @@ -69,7 +65,9 @@ class DbBackendForm extends BaseBackendForm 'required' => true, 'label' => t('Database Connection'), 'helptext' => t('The database connection to use for authenticating with this provider'), - 'multiOptions' => $this->resources + 'multiOptions' => false === empty($this->resources) + ? array_combine($this->resources, $this->resources) + : array() ) ), $this->createElement( @@ -84,25 +82,39 @@ class DbBackendForm extends BaseBackendForm } /** - * Validate the current configuration by creating a backend and requesting the user count + * Validate that the selected resource is a valid database authentication backend * - * @return bool Whether validation succeeded or not - * - * @see BaseBackendForm::isValidAuthenticationBackend() + * @see Form::onSuccess() */ - public function isValidAuthenticationBackend() + public function onSuccess(Request $request) { + if (false === $this->isValidAuthenticationBackend($this)) { + return false; + } + } + + /** + * Validate the configuration by creating a backend and requesting the user count + * + * @param Form $form The form to fetch the configuration values from + * + * @return bool Whether validation succeeded or not + */ + public function isValidAuthenticationBackend(Form $form) + { + $element = $form->getElement('resource'); + try { - $testConnection = ResourceFactory::createResource(ResourceFactory::getResourceConfig( - $this->getValue('resource') - )); + $testConnection = ResourceFactory::createResource( + ResourceFactory::getResourceConfig($element->getValue()) + ); $dbUserBackend = new DbUserBackend($testConnection); if ($dbUserBackend->count() < 1) { - $this->addErrorMessage(t('No users found under the specified database backend')); + $element->addError(t('No users found under the specified database backend')); return false; } } catch (Exception $e) { - $this->addErrorMessage(sprintf(t('Using the specified backend failed: %s'), $e->getMessage())); + $element->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage())); return false; } diff --git a/application/forms/Config/Authentication/LdapBackendForm.php b/application/forms/Config/Authentication/LdapBackendForm.php index ed261c1f9..af627df48 100644 --- a/application/forms/Config/Authentication/LdapBackendForm.php +++ b/application/forms/Config/Authentication/LdapBackendForm.php @@ -5,17 +5,17 @@ namespace Icinga\Form\Config\Authentication; use Exception; +use Icinga\Web\Form; use Icinga\Data\ResourceFactory; -use Icinga\Exception\ConfigurationError; use Icinga\Authentication\Backend\LdapUserBackend; /** - * Form for adding or modifying LDAP authentication backends + * Form class for adding/modifying LDAP authentication backends */ -class LdapBackendForm extends BaseBackendForm +class LdapBackendForm extends Form { /** - * The available ldap resources prepared to be used as select input data + * The ldap resource names the user can choose from * * @var array */ @@ -23,28 +23,23 @@ class LdapBackendForm extends BaseBackendForm /** * Initialize this form - * - * Populates $this->resources. - * - * @throws ConfigurationError In case no database resources can be found */ public function init() { - $this->setName('form_config_authentication_ldap'); - $this->setSubmitLabel(t('Save Changes')); + $this->setName('form_config_authbackend_ldap'); + } - $ldapResources = array_keys( - ResourceFactory::getResourceConfigs('ldap')->toArray() - ); - - if (empty($ldapResources)) { - throw new ConfigurationError( - t('There are no LDAP resources') - ); - } - - // array_combine() is necessary in order to use the array as select input data - $this->resources = array_combine($ldapResources, $ldapResources); + /** + * Set the resource names the user can choose from + * + * @param array $resources The resources to choose from + * + * @return self + */ + public function setResources(array $resources) + { + $this->resources = $resources; + return $this; } /** @@ -69,7 +64,9 @@ class LdapBackendForm extends BaseBackendForm 'required' => true, 'label' => t('LDAP Resource'), 'helptext' => t('The resource to use for authenticating with this provider'), - 'multiOptions' => $this->resources + 'multiOptions' => false === empty($this->resources) + ? array_combine($this->resources, $this->resources) + : array() ) ), $this->createElement( @@ -104,33 +101,39 @@ class LdapBackendForm extends BaseBackendForm } /** - * Validate the current configuration by connecting to a backend and requesting the user count + * Validate that the selected resource is a valid ldap authentication backend * - * @return bool Whether validation succeeded or not - * - * @see BaseBackendForm::isValidAuthenticationBacken() + * @see Form::onSuccess() */ - public function isValidAuthenticationBackend() + public function onSuccess(Request $request) { - if (false === ResourceFactory::ldapAvailable()) { - // It should be possible to run icingaweb without the php ldap extension. When the user - // tries to create an ldap backend without ldap being installed we display an error. - $this->addErrorMessage(t('Using ldap is not possible, the php extension "ldap" is not installed.')); + if (false === $this->isValidAuthenticationBackend($this)) { return false; } + } + + /** + * Validate the configuration by creating a backend and requesting the user count + * + * @param Form $form The form to fetch the configuration values from + * + * @return bool Whether validation succeeded or not + */ + public function isValidAuthenticationBackend(Form $form) + { + $element = $form->getElement('resource'); try { - $backend = ResourceFactory::createResource( - ResourceFactory::getResourceConfig($this->getValue('resource')) + $ldapUserBackend = new LdapUserBackend( + ResourceFactory::createResource( + ResourceFactory::getResourceConfig($element->getValue()) + ), + $form->getElement('user_class')->getValue(), + $form->getElement('user_name_attribute')->getValue() ); - $testConn = new LdapUserBackend( - $backend, - $this->getValue('user_class'), - $this->getValue('user_name_attribute') - ); - $testConn->assertAuthenticationPossible(); - } catch (Exception $exc) { - $this->addErrorMessage(sprintf(t('Connection validation failed: %s'), $exc->getMessage())); + $ldapUserBackend->assertAuthenticationPossible(); + } catch (Exception $e) { + $element->addError(sprintf(t('Connection validation failed: %s'), $e->getMessage())); return false; } diff --git a/application/forms/Config/AuthenticationBackendConfigForm.php b/application/forms/Config/AuthenticationBackendConfigForm.php new file mode 100644 index 000000000..6aeccdd20 --- /dev/null +++ b/application/forms/Config/AuthenticationBackendConfigForm.php @@ -0,0 +1,318 @@ +setName('form_config_authbackend'); + $this->setSubmitLabel(t('Save Changes')); + } + + /** + * Set the resource configuration to use + * + * @param Config $resources The resource configuration + * + * @return self + * + * @throws ConfigurationError In case no resources are available for authentication + */ + public function setResourceConfig(Config $resourceConfig) + { + $resources = array(); + foreach ($resourceConfig as $name => $resource) { + $resources[strtolower($resource->type)][] = $name; + } + + if (empty($resources)) { + throw new ConfigurationError(t('Could not find any resources for authentication')); + } + + $this->resources = $resources; + return $this; + } + + /** + * Return a form object for the given backend type + * + * @param string $type The backend type for which to return a form + * + * @return Form + */ + public function getBackendForm($type) + { + if ($type === 'db') { + $form = new DbBackendForm(); + $form->setResources(isset($this->resources['db']) ? $this->resources['db'] : array()); + } elseif ($type === 'ldap') { + $form = new LdapBackendForm(); + $form->setResources(isset($this->resources['ldap']) ? $this->resources['ldap'] : array()); + } elseif ($type === 'autologin') { + $form = new AutologinBackendForm(); + } else { + throw new InvalidArgumentException(sprintf(t('Invalid backend type "%s" provided'), $type)); + } + + return $form; + } + + /** + * Add a particular authentication backend + * + * The backend to add is identified by the array-key `name'. + * + * @param array $values The values to extend the configuration with + * + * @return self + * + * @throws InvalidArgumentException In case the backend does already exist + */ + public function add(array $values) + { + $name = isset($values['name']) ? $values['name'] : ''; + if (! $name) { + throw new InvalidArgumentException(t('Authentication backend name missing')); + } elseif ($this->config->get($name) !== null) { + throw new InvalidArgumentException(t('Authentication backend already exists')); + } + + unset($values['name']); + $this->config->{$name} = $values; + return $this; + } + + /** + * Edit a particular authentication backend + * + * @param string $name The name of the backend to edit + * @param array $values The values to edit the configuration with + * + * @return array The edited backend configuration + * + * @throws InvalidArgumentException In case the backend does not exist + */ + public function edit($name, array $values) + { + if (! $name) { + throw new InvalidArgumentException(t('Old authentication backend name missing')); + } elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) { + throw new InvalidArgumentException(t('New authentication backend name missing')); + } elseif (($backendConfig = $this->config->get($name)) === null) { + throw new InvalidArgumentException(t('Unknown authentication backend provided')); + } + + if ($newName !== $name) { + // Only remove the old entry if it has changed as the order gets screwed when editing backend names + unset($this->config->{$name}); + } + + unset($values['name']); + $this->config->{$newName} = array_merge($backendConfig->toArray(), $values); + return $this->config->{$newName}; + } + + /** + * Remove the given authentication backend + * + * @param string $name The name of the backend to remove + * + * @return array The removed backend configuration + * + * @throws InvalidArgumentException In case the backend does not exist + */ + public function remove($name) + { + if (! $name) { + throw new InvalidArgumentException(t('Authentication backend name missing')); + } elseif (($backendConfig = $this->config->get($name)) === null) { + throw new InvalidArgumentException(t('Unknown authentication backend provided')); + } + + unset($this->config->{$name}); + return $backendConfig; + } + + /** + * Move the given authentication backend up or down in order + * + * @param string $name The name of the backend to be moved + * @param int $position The new (absolute) position of the backend + * + * @return self + * + * @throws InvalidArgumentException In case the backend does not exist + */ + public function move($name, $position) + { + if (! $name) { + throw new InvalidArgumentException(t('Authentication backend name missing')); + } elseif ($this->config->get($name) === null) { + throw new InvalidArgumentException(t('Unknown authentication backend provided')); + } + + $backendOrder = $this->config->keys(); + array_splice($backendOrder, array_search($name, $backendOrder), 1); + array_splice($backendOrder, $position, 0, $name); + + $newConfig = array(); + foreach ($backendOrder as $backendName) { + $newConfig[$backendName] = $this->config->get($backendName); + } + + $config = new Config($newConfig); + $this->config = $config->setConfigFile($this->config->getConfigFile()); + return $this; + } + + /** + * Add or edit an authentication backend and save the configuration + * + * Performs a connectivity validation using the submitted values. A checkbox is + * added to the form to skip the check if it fails and redirection is aborted. + * + * @see Form::onSuccess() + */ + public function onSuccess(Request $request) + { + if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { + $backendForm = $this->getBackendForm($this->getElement('type')->getValue()); + if (false === $backendForm->isValidAuthenticationBackend($this)) { + $this->addForceCreationCheckbox(); + return false; + } + } + + $authBackend = $request->getQuery('auth_backend'); + try { + if ($authBackend === null) { // create new backend + $this->add($this->getValues()); + $message = t('Authentication backend "%s" has been successfully created'); + } else { // edit existing backend + $this->edit($authBackend, $this->getValues()); + $message = t('Authentication backend "%s" has been successfully changed'); + } + } catch (InvalidArgumentException $e) { + Notification::error($e->getMessage()); + return; + } + + if ($this->save()) { + Notification::success(sprintf($message, $this->getElement('name')->getValue())); + } else { + return false; + } + } + + /** + * Populate the form in case an authentication backend is being edited + * + * @see Form::onShow() + * + * @throws ConfigurationError In case the backend name is missing in the request or is invalid + */ + public function onShow(Request $request) + { + $authBackend = $request->getQuery('auth_backend'); + if ($authBackend !== null) { + if ($authBackend === '') { + throw new ConfigurationError(t('Authentication backend name missing')); + } elseif (false === isset($this->config->{$authBackend})) { + throw new ConfigurationError(t('Unknown authentication backend provided')); + } elseif (false === isset($this->config->{$authBackend}->backend)) { + throw new ConfigurationError(sprintf(t('Backend "%s" has no `backend\' setting'), $authBackend)); + } + + $configValues = $this->config->{$authBackend}->toArray(); + $configValues['type'] = $configValues['backend']; + $configValues['name'] = $authBackend; + $this->populate($configValues); + } + } + + /** + * Add a checkbox to be displayed at the beginning of the form + * which allows the user to skip the connection validation + */ + protected function addForceCreationCheckbox() + { + $this->addElement( + 'checkbox', + 'force_creation', + array( + 'order' => 0, + 'ignore' => true, + 'label' => t('Force Changes'), + 'helptext' => t('Check this box to enforce changes without connectivity validation') + ) + ); + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $backendTypes = array(); + $backendType = isset($formData['type']) ? $formData['type'] : 'db'; + + if (isset($this->resources['db'])) { + $backendTypes['db'] = t('Database'); + } + if (isset($this->resources['ldap']) && ($backendType === 'ldap' || ResourceFactory::ldapAvailable())) { + $backendTypes['ldap'] = 'LDAP'; + } + + $autologinBackends = array_filter( + $this->config->toArray(), + function ($authBackendCfg) { + return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin'; + } + ); + if ($backendType === 'autologin' || empty($autologinBackends)) { + $backendTypes['autologin'] = t('Autologin'); + } + + $typeSelection = $this->createElement( + 'select', + 'type', + array( + 'ignore' => true, + 'required' => true, + 'autosubmit' => true, + 'label' => t('Backend Type'), + 'helptext' => t('The type of the resource to use for this authenticaton backend'), + 'multiOptions' => $backendTypes + ) + ); + + return array_merge( + array($typeSelection), + $this->getBackendForm($backendType)->createElements($formData) + ); + } +} diff --git a/application/forms/Config/AuthenticationBackendReorderForm.php b/application/forms/Config/AuthenticationBackendReorderForm.php new file mode 100644 index 000000000..d4be16c30 --- /dev/null +++ b/application/forms/Config/AuthenticationBackendReorderForm.php @@ -0,0 +1,68 @@ +setName('form_reorder_authbackend'); + $this->setViewScript('form/reorder-authbackend.phtml'); + } + + /** + * Return the ordered backend names + * + * @return array + */ + public function getBackendOrder() + { + return $this->config->keys(); + } + + /** + * Update the authentication backend order and save the configuration + * + * @see Form::onSuccess() + */ + public function onSuccess(Request $request) + { + $formData = $this->getRequestData($request); + if (isset($formData['backend_newpos'])) { + $configForm = $this->getConfigForm(); + list($backendName, $position) = explode('|', $formData['backend_newpos'], 2); + + try { + if ($configForm->move($backendName, $position)->save()) { + Notification::success(t('Authentication order updated!')); + } else { + return false; + } + } catch (InvalidArgumentException $e) { + Notification::error($e->getMessage()); + } + } + } + + /** + * Return the config form for authentication backends + * + * @return ConfigForm + */ + protected function getConfigForm() + { + $form = new AuthenticationBackendConfigForm(); + $form->setConfig($this->config); + return $form; + } +} diff --git a/application/views/scripts/config/authentication.phtml b/application/views/scripts/config/authentication.phtml deleted file mode 100644 index 5f1be17bd..000000000 --- a/application/views/scripts/config/authentication.phtml +++ /dev/null @@ -1,57 +0,0 @@ -
- -
-
- -

- - icon('create.png'); ?>translate('Create A New LDAP Authentication Backend'); ?> - -
- - icon('create.png'); ?>translate('Create A New DB Authentication Backend'); ?> - -
- - icon('create.png'); ?>translate('Create A New Autologin Authentication Backend'); ?> - -

-
- getElement($form->getTokenElementName()); ?> - - - - - - - - - - - - - - - -
Backendtranslate('Remove'); ?>translate('Order'); ?>
- - icon('edit.png'); ?> escape($backendNames[$i]); ?> - - - - icon('remove.png', $this->translate('Remove')); ?> - - - 0): ?> - - - - - -
-
-
diff --git a/application/views/scripts/config/authentication/create.phtml b/application/views/scripts/config/authentication/create.phtml index fd329b63a..52fcbceb3 100644 --- a/application/views/scripts/config/authentication/create.phtml +++ b/application/views/scripts/config/authentication/create.phtml @@ -1,15 +1,7 @@ -

- - Create New Authentication Backend -

- - -messageBox)): ?> - messageBox->render() ?> - - +

translate('Create New Authentication Backend'); ?>

- Create a new backend for authenticating your users. This backend will be added at the end of your authentication order. + translate( + 'Create a new backend for authenticating your users. This backend will be added at the end of your authentication order.' + ); ?>

- -form ?> \ No newline at end of file + \ No newline at end of file diff --git a/application/views/scripts/config/authentication/modify.phtml b/application/views/scripts/config/authentication/modify.phtml index 4666ce686..19901ae5b 100644 --- a/application/views/scripts/config/authentication/modify.phtml +++ b/application/views/scripts/config/authentication/modify.phtml @@ -1,8 +1,2 @@ -

- translate('Edit Backend "%s"'), - $this->escape($this->name) - ); ?> -

- -form; ?> +

translate('Edit Backend'); ?>

+ \ No newline at end of file diff --git a/application/views/scripts/config/authentication/remove.phtml b/application/views/scripts/config/authentication/remove.phtml index 23b85f6d7..e1050db0d 100644 --- a/application/views/scripts/config/authentication/remove.phtml +++ b/application/views/scripts/config/authentication/remove.phtml @@ -1,8 +1,2 @@ -

- translate('Remove Backend "%s"'), - $this->escape($name) - ); ?> -

- - +

translate('Remove Backend'); ?>

+ \ No newline at end of file diff --git a/application/views/scripts/config/authentication/reorder.phtml b/application/views/scripts/config/authentication/reorder.phtml new file mode 100644 index 000000000..0ae7850eb --- /dev/null +++ b/application/views/scripts/config/authentication/reorder.phtml @@ -0,0 +1,11 @@ +
+ +
+
+

+ + icon('create.png'); ?>translate('Create A New Authentication Backend'); ?> + +

+ +
\ No newline at end of file diff --git a/application/views/scripts/form/reorder-authbackend.phtml b/application/views/scripts/form/reorder-authbackend.phtml new file mode 100644 index 000000000..8153e17d2 --- /dev/null +++ b/application/views/scripts/form/reorder-authbackend.phtml @@ -0,0 +1,40 @@ +
+ + + + + + + +getBackendOrder(); ?> + + + + + + + + +
Backendtranslate('Remove'); ?>translate('Order'); ?>
+ + icon('edit.png'); ?> escape($backendNames[$i]); ?> + + + + icon('remove.png', $this->translate('Remove')); ?> + + + 0): ?> + + + + + +
+ getElement($form->getTokenElementName()); ?> + getElement($form->getUidElementName()); ?> +
\ No newline at end of file