Merge branch 'feature/improve-autologin-setup-8274'

refs #8274
resolves #8134
fixes #7848
This commit is contained in:
Johannes Meyer 2015-01-28 18:04:55 +01:00
commit ab95ae622c
17 changed files with 171 additions and 120 deletions

View File

@ -1,5 +1,5 @@
[autologin]
backend = autologin
backend = external
[icingaweb-mysql]
backend = db

View File

@ -8,7 +8,7 @@ use Icinga\Application\Config;
use Icinga\Application\Icinga;
use Icinga\Application\Logger;
use Icinga\Authentication\AuthChain;
use Icinga\Authentication\Backend\AutoLoginBackend;
use Icinga\Authentication\Backend\ExternalBackend;
use Icinga\Exception\AuthenticationException;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotReadableError;
@ -39,6 +39,7 @@ class AuthenticationController extends ActionController
$this->redirectNow(Url::fromPath('setup'));
}
$triedOnlyExternalAuth = null;
$auth = $this->Auth();
$this->view->form = $form = new LoginForm();
$this->view->title = $this->translate('Icingaweb Login');
@ -82,7 +83,7 @@ class AuthenticationController extends ActionController
}
foreach ($chain as $backend) {
if ($backend instanceof AutoLoginBackend) {
if ($backend instanceof ExternalBackend) {
continue;
}
++$backendsTried;
@ -126,7 +127,8 @@ class AuthenticationController extends ActionController
} elseif ($request->isGet()) {
$user = new User('');
foreach ($chain as $backend) {
if ($backend instanceof AutoLoginBackend) {
$triedOnlyExternalAuth = $triedOnlyExternalAuth === null;
if ($backend instanceof ExternalBackend) {
$authenticated = $backend->authenticate($user);
if ($authenticated === true) {
$auth->setAuthenticated($user);
@ -134,6 +136,8 @@ class AuthenticationController extends ActionController
Url::fromPath(Url::fromRequest()->getParam('redirect', 'dashboard'))
);
}
} else {
$triedOnlyExternalAuth = false;
}
}
}
@ -141,6 +145,7 @@ class AuthenticationController extends ActionController
$this->view->errorInfo = $e->getMessage();
}
$this->view->requiresExternalAuth = $triedOnlyExternalAuth && !$auth->isAuthenticated();
$this->view->requiresSetup = Icinga::app()->requiresSetup();
}

View File

@ -8,16 +8,16 @@ use Zend_Validate_Callback;
use Icinga\Web\Form;
/**
* Form class for adding/modifying autologin authentication backends
* Form class for adding/modifying authentication backends of type "external"
*/
class AutologinBackendForm extends Form
class ExternalBackendForm extends Form
{
/**
* Initialize this form
*/
public function init()
{
$this->setName('form_config_authbackend_autologin');
$this->setName('form_config_authbackend_external');
}
/**
@ -69,7 +69,7 @@ class AutologinBackendForm extends Form
'backend',
array(
'disabled' => true,
'value' => 'autologin'
'value' => 'external'
)
);
@ -79,7 +79,7 @@ class AutologinBackendForm extends Form
/**
* Validate the configuration by creating a backend and requesting the user count
*
* Returns always true as autologin backends are just "passive" backends. (The webserver authenticates users.)
* Returns always true as backends of type "external" are just "passive" backends.
*
* @param Form $form The form to fetch the configuration values from
*

View File

@ -14,7 +14,7 @@ use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError;
use Icinga\Forms\Config\Authentication\DbBackendForm;
use Icinga\Forms\Config\Authentication\LdapBackendForm;
use Icinga\Forms\Config\Authentication\AutologinBackendForm;
use Icinga\Forms\Config\Authentication\ExternalBackendForm;
class AuthenticationBackendConfigForm extends ConfigForm
{
@ -67,8 +67,8 @@ class AuthenticationBackendConfigForm extends ConfigForm
} elseif ($type === 'ldap') {
$form = new LdapBackendForm();
$form->setResources(isset($this->resources['ldap']) ? $this->resources['ldap'] : array());
} elseif ($type === 'autologin') {
$form = new AutologinBackendForm();
} elseif ($type === 'external') {
$form = new ExternalBackendForm();
} else {
throw new InvalidArgumentException(sprintf($this->translate('Invalid backend type "%s" provided'), $type));
}
@ -251,14 +251,14 @@ class AuthenticationBackendConfigForm extends ConfigForm
$configValues['name'] = $authBackend;
$this->populate($configValues);
} elseif (empty($this->resources)) {
$autologinBackends = array_filter(
$externalBackends = array_filter(
$this->config->toArray(),
function ($authBackendCfg) {
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin';
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'external';
}
);
if (false === empty($autologinBackends)) {
if (false === empty($externalBackends)) {
throw new ConfigurationError($this->translate('Could not find any resources for authentication'));
}
}
@ -299,14 +299,14 @@ class AuthenticationBackendConfigForm extends ConfigForm
$backendTypes['ldap'] = 'LDAP';
}
$autologinBackends = array_filter(
$externalBackends = array_filter(
$this->config->toArray(),
function ($authBackendCfg) {
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin';
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'external';
}
);
if ($backendType === 'autologin' || empty($autologinBackends)) {
$backendTypes['autologin'] = $this->translate('Autologin');
if ($backendType === 'external' || empty($externalBackends)) {
$backendTypes['external'] = $this->translate('External');
}
if ($backendType === null) {

View File

@ -1,11 +1,28 @@
<div id="login">
<div class="logo">
<div class="image">
<img class="fade-in one" src="<?= $this->baseUrl('img/logo_icinga_big.png') ?>" alt="<?= t('The Icinga logo') ?>" >
<img class="fade-in one" src="<?= $this->baseUrl('img/logo_icinga_big.png'); ?>" alt="<?= $this->translate('The Icinga logo'); ?>" >
</div>
</div>
<div class="form" data-base-target="layout">
<h1>Welcome to Icinga Web 2</h1>
<?php if ($requiresSetup): ?>
<p class="config-note"><?= sprintf(
$this->translate(
'It appears that you did not configure Icinga Web 2 yet so it\'s not possible to log in without any defined '
. 'authentication method. Please define a authentication method by following the instructions in the'
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
),
'<a href="http://docs.icinga.org/" title="' . $this->translate('Icinga Web 2 Documentation') . '">', // TODO: More exact documentation link..
'<a href="' . $this->href('setup') . '" title="' . $this->translate('Icinga Web 2 Setup-Wizard') . '">',
'</a>'
); ?></p>
<?php elseif ($requiresExternalAuth): ?>
<p class="info-box"><span class="icon-info"></span><?= $this->translate(
'You\'re currently not authenticated using any of the web server\'s authentication mechanisms.'
. ' Make sure you\'ll configure such, otherwise you\'ll not be able to login.'
); ?></p>
<?php endif ?>
<h1><?= $this->translate('Welcome to Icinga Web 2'); ?></h1>
<?php
/* TODO: remove this as soon as notifications and forms are ready */
if (isset($this->errorInfo)): ?>
@ -14,18 +31,6 @@
</div>
<?php endif ?>
<?= $this->form ?>
<div class="footer">Icinga Web 2 &copy; 2013-2015<br><a href="https://www.icinga.org">The Icinga Project</a></div>
<?php if ($requiresSetup): ?>
<div class="config-note"><?= sprintf(
t(
'It appears that you did not configure Icinga Web 2 yet so it\'s not possible to log in without any defined '
. 'authentication method. Please define a authentication method by following the instructions in the'
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
),
'<a href="http://docs.icinga.org/" title="Icinga Web 2 Documentation">', // TODO: Documentation link
'<a href="' . $this->href('setup') . '" title="Icinga Web 2 Setup-Wizard">',
'</a>'
); ?></div>
<?php endif ?>
<div class="footer">Icinga Web 2 &copy; 2013-2015<br><a href="https://www.icinga.org"><?= $this->translate('The Icinga Project'); ?></a></div>
</div>
</div>

View File

@ -24,7 +24,7 @@ For delegating authentication to the web server simply add `autologin` to your a
````
[autologin]
backend = autologin
backend = external
````
If your web server is not configured for authentication though the `autologin` section has no effect.

View File

@ -1,90 +1,83 @@
# Externel Authentication
# External Authentication
It is possible to use the authentication mechanism of the webserver,
instead of using the internal authentication-manager to
authenticate users. This might be useful if you only have very few users, and
user management over *.htaccess* is sufficient, or if you must use some other
authentication mechanism that is only available through your webserver.
It is possible to utilize the authentication mechanism of the webserver instead
of the internal authentication of Icinga Web 2 to authenticate users. This might
be useful if you only have very few users and user management over **.htaccess**
is not sufficient or if you are required to use some other authentication
mechanism that is only available by utilizing the webserver.
When external authentication is used, Icingaweb will entrust the
complete authentication process to the external authentication provider (the webserver):
The provider should take care of authenticating the user and declining
all requests with invalid or missing credentials. When the authentication
was succesful, it should provide the authenticated users name to its php-module
and Icingaweb will assume that the user is authorized to access the page.
Because of this it is very important that the webservers authentication is
configured correctly, as wrong configuration could lead to unauthorized
access to the site, or a broken login-process.
Icinga Web 2 will entrust the complete authentication process to the
authentication provider of the webserver, if external authentication is used.
So it is very important that the webserver's authentication is configured
correctly as wrong configuration might lead to unauthorized access or a
malfunction in the login-process.
## Using External Authentication
## Use External Authentication
External authentication in Icinga Web 2 requires the following preparations:
Using external authentication in Icingaweb requires two steps to work:
1. The external authentication must be set up properly to correctly
authenticate users
2. Icinga Web 2 must be configured to use external authentication
1. The external authentication must be set up correctly to always
authenticate the users.
2. Icingaweb must be configured to use the external authentication.
### Preparing the External Authentication Provider
This step depends heavily on the used webserver and authentication mechanism you
want to use. It is not possible to cover all possibillities and you should
probably read the documentation for your webserver to get detailed instructions
on how to set up authentication properly.
### Prepare the External Authentication Provider
This step depends heavily on the used webserver and authentication
mechanism you want to use. It is not possible to cover all possibillities
and you should probably read the documentation for your webserver for
detailed instructions on how to set up authentication properly.
In general, you need to make sure that:
- All routes require authentication
- Only permitted users are allowed to authenticate
In general you need to make sure that:
- All routes require authentication
- Only permitted users are allowed to authenticate
#### Example Configuration for Apache and HTTPDigestAuthentication
The following example will show how to enable external authentication in Apache using
*HTTP Digest Authentication*.
The following example will show how to enable external authentication in Apache
using *HTTP Digest Authentication*.
##### Create users
##### Creating users
To create users for a digest authentication we can use the tool *htdigest*.
We choose *.icingawebdigest* as a name for the created file, containing
the user credentials.
To create users for digest authentication you can use the tool *htdigest*. In
this example **.icingawebdigest** is the name of the file containing the user
credentials.
This command will create a new file with the user *jdoe*. *htdigest*
will prompt you for your password, after it has been executed. If you
want to add more users to the file you need to ommit the *-c* parameter
in all further commands to avoInid the file to be overwritten.
This command creates a new file with the user *jdoe*. *htdigest* will prompt
you for a password. If you want to add more users to the file you need to omit
the *-c* parameter in all following commands to not to overwrite the file.
````
sudo htdigest -c /etc/icingaweb2/.icingawebdigest "Icinga Web 2" jdoe
````
sudo htdigest -c /etc/httpd/conf.d/.icingawebdigest "Icingaweb 2" jdoe
##### Configuring the Webserver
The webserver should require authentication for all public Icinga Web 2 files.
##### Set up authentication
````
<Directory "/usr/share/icingaweb2/public">
AuthType digest
AuthName "Icinga Web 2"
AuthDigestProvider file
AuthUserFile /etc/icingaweb2/.icingawebdigest
Require valid-user
</Directory>
````
The webserver should require authentication for all public icingaweb files.
### Preparing Icinga Web 2
Once external authentication is set up correctly you need to configure Icinga
Web 2. In case you already completed the setup wizard it is likely that you are
now finished.
<Directory "/var/www/html/icingaweb">
AuthType digest
AuthName "Icingaweb 2"
AuthDigestProvider file
AuthUserFile /etc/httpd/conf.d/.icingawebdigest
Require valid-user
</Directory>
To get Icinga Web 2 to use external authentication the file
**config/authentication.ini** is required. Just add the following section
called "autologin", or any name of your choice, and save your changes:
### Prepare Icingaweb
````
[autologin]
backend = external
````
When the external authentication is set up correctly, we need
to configure IcingaWeb to use it as an authentication source. The
configuration key *authenticationMode* in the section *global* defines
if the authentication should be handled internally or externally. Since
we want to delegate the authentication to the Webserver we choose
"external" as the new value:
[global]
; ...
authenticationMode = "external"
; ...
Congratulations! You are now logged in when visiting Icinga Web 2.

View File

@ -107,4 +107,4 @@ In case you do not remember the token you can show it using the `icingacli`:
**Step 5: Web Setup**
Visit Icinga Web 2 in your browser and complete installation using the web setup.
Visit Icinga Web 2 in your browser and complete installation using the web setup: /icingaweb2/setup

View File

@ -407,7 +407,7 @@ abstract class ApplicationBootstrap
*/
protected function loadSetupModuleIfNecessary()
{
if (! @file_exists($this->config->resolvePath('config.ini'))) {
if (! @file_exists($this->config->resolvePath('authentication.ini'))) {
$this->requiresSetup = true;
$this->moduleManager->loadModule('setup');
} elseif ($this->setupTokenExists()) {

View File

@ -11,7 +11,7 @@ use Icinga\User;
/**
* Test login with external authentication mechanism, e.g. Apache
*/
class AutoLoginBackend extends UserBackend
class ExternalBackend extends UserBackend
{
/**
* Regexp expression to strip values from a username
@ -21,7 +21,7 @@ class AutoLoginBackend extends UserBackend
private $stripUsernameRegexp;
/**
* Create new autologin backend
* Create new authentication backend of type "external"
*
* @param ConfigObject $config
*/
@ -33,7 +33,7 @@ class AutoLoginBackend extends UserBackend
/**
* Count the available users
*
* Autologin backends will always return 1
* Authenticaton backends of type "external" will always return 1
*
* @return int
*/

View File

@ -5,7 +5,7 @@
namespace Icinga\Authentication;
use Countable;
use Icinga\Authentication\Backend\AutoLoginBackend;
use Icinga\Authentication\Backend\ExternalBackend;
use Icinga\Authentication\Backend\DbUserBackend;
use Icinga\Authentication\Backend\LdapUserBackend;
use Icinga\Data\ConfigObject;
@ -69,8 +69,8 @@ abstract class UserBackend implements Countable
);
}
$backendType = strtolower($backendType);
if ($backendType === 'autologin') {
$backend = new AutoLoginBackend($backendConfig);
if ($backendType === 'external') {
$backend = new ExternalBackend($backendConfig);
$backend->setName($name);
return $backend;
}

View File

@ -7,7 +7,7 @@ namespace Icinga\Module\Setup\Forms;
use Icinga\Web\Form;
use Icinga\Forms\Config\Authentication\DbBackendForm;
use Icinga\Forms\Config\Authentication\LdapBackendForm;
use Icinga\Forms\Config\Authentication\AutologinBackendForm;
use Icinga\Forms\Config\Authentication\ExternalBackendForm;
use Icinga\Data\ConfigObject;
/**
@ -80,7 +80,7 @@ class AuthBackendPage extends Form
'Before you are able to authenticate using the LDAP connection defined earlier you need to'
. ' provide some more information so that Icinga Web 2 is able to locate account details.'
);
} else { // if ($this->config['type'] === 'autologin'
} else { // if ($this->config['type'] === 'external'
$note = $this->translate(
'You\'ve chosen to authenticate using a web server\'s mechanism so it may be necessary'
. ' to adjust usernames before any permissions, restrictions, etc. are being applied.'
@ -103,8 +103,8 @@ class AuthBackendPage extends Form
} elseif ($this->config['type'] === 'ldap') {
$backendForm = new LdapBackendForm();
$backendForm->createElements($formData)->removeElement('resource');
} else { // $this->config['type'] === 'autologin'
$backendForm = new AutologinBackendForm();
} else { // $this->config['type'] === 'external'
$backendForm = new ExternalBackendForm();
$backendForm->createElements($formData);
}

View File

@ -36,6 +36,28 @@ class AuthenticationPage extends Form
)
)
);
if (isset($formData['type']) && $formData['type'] === 'external' && !isset($_SERVER['REMOTE_USER'])) {
$this->addElement(
'note',
'external_note',
array(
'value' => $this->translate(
'You\'re currently not authenticated using any of the web server\'s authentication '
. 'mechanisms. Make sure you\'ll configure such, otherwise you\'ll not be able to '
. 'log into Icinga Web 2.'
),
'decorators' => array(
'ViewHelper',
array(
'HtmlTag',
array('tag' => 'p', 'class' => 'icon-info info-box')
)
)
)
);
}
$this->addElement(
'note',
'description',
@ -54,13 +76,14 @@ class AuthenticationPage extends Form
if (Platform::extensionLoaded('ldap')) {
$backendTypes['ldap'] = 'LDAP';
}
$backendTypes['autologin'] = $this->translate('Autologin');
$backendTypes['external'] = $this->translate('External');
$this->addElement(
'select',
'type',
array(
'required' => true,
'autosubmit' => true,
'label' => $this->translate('Authentication Type'),
'description' => $this->translate('The type of authentication to use when accessing Icinga Web 2'),
'multiOptions' => $backendTypes

View File

@ -139,7 +139,7 @@ class AuthenticationStep extends Step
. '<td><strong>' . t('User Name Attribute') . '</strong></td>'
. '<td>' . $this->data['backendConfig']['user_name_attribute'] . '</td>'
. '</tr>'
) : ($authType === 'autologin' ? (
) : ($authType === 'external' ? (
'<tr>'
. '<td><strong>' . t('Filter Pattern') . '</strong></td>'
. '<td>' . $this->data['backendConfig']['strip_username_regexp'] . '</td>'

View File

@ -113,18 +113,33 @@
margin-left: 5em;
}
div.config-note {
p.config-note {
width: 50%;
padding: 1em;
margin: 5em auto 0;
margin: 0 auto 2.5em;
text-align: center;
color: white;
background-color: @colorCritical;
a {
color: white;
font-weight: bold;
}
}
div.config-note a {
color: white;
font-weight: bold;
p.info-box {
width: 50%;
height: 2.2em;
margin: 0 auto 2.5em;
span.icon-info {
float: left;
height: 100%;
}
em {
text-decoration: underline;
}
}
}

View File

@ -203,3 +203,9 @@ table.benchmark {
[class^="icon-"]:before, [class*=" icon-"]:before {
text-decoration: none;
}
.info-box {
padding: 0.5em;
border: 1px solid lightgrey;
background-color: infobackground;
}

View File

@ -220,6 +220,10 @@
}
}
#setup_authentication_type p.info-box em {
text-decoration: underline;
}
#setup_ldap_discovery_confirm table {
margin: 1em 0;
border-collapse: separate;