Merge branch 'feature/accept-web-server-authentication-5405'

This commit is contained in:
Matthias Jentsch 2014-02-26 18:12:52 +01:00
commit bcfebcd937
8 changed files with 217 additions and 5 deletions

View File

@ -85,10 +85,16 @@ class AuthenticationController extends ActionController
*/
public function logoutAction()
{
$this->_helper->layout->setLayout('inline');
$auth = AuthManager::getInstance();
$auth->removeAuthorization();
$this->redirectToLogin();
if ($auth->isAuthenticatedFromRemoteUser()) {
$this->_helper->layout->setLayout('login');
$this->_response->setHttpResponseCode(401);
} else {
$this->_helper->layout->setLayout('inline');
$this->redirectToLogin();
}
}
}
// @codingStandardsIgnoreEnd

View File

@ -23,8 +23,6 @@
* is useful for preserving the detail view and the selection in that case.
*
* refs #4833
*
* TODO: Copy this snipped into the new login.phtml
*/
var url = document.URL.match(/(^[^#]*)/)[0] + encodeURIComponent(window.location.hash);
document.getElementById('form_login').action = url;

View File

@ -0,0 +1,72 @@
<!--
This view provides a workaround to logout from an external authentication provider, in case external
authentication was configured (the default is to handle authentications internally in Icingaweb2).
The <a href="http://tools.ietf.org/html/rfc2617">Http Basic and Digest Authentication</a> is not
designed to handle logout. When the user has provided valid credentials, the client is adviced to include these
in every further request until the browser was closed. To allow logout and to allow the user to change the
logged-in user this JavaScript provides a workaround to force a new authentication prompt in most browsers.
-->
<div class="row">
<br/>
<div class="md-offset-3 col-md-6 col-sm-6 col-sm-offset-3">
<div class="alert alert-warning" id="logout-status">
<b> <?= t('Logging out...'); ?> </b> <br />
<?= t(
'If this message does not disappear, it might be necessary to quit the ' .
'current session manually by clearing the cache, or by closing the current ' .
'browser session.'
); ?>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3">
<div class="container" >
<a class="button btn btn-cta form-control input-sm" href="<?= $this->href('dashboard/index'); ?>"> <?= t('Login'); ?></a>
</div>
</div>
</div>
<script type="text/javascript">
/**
* When JavaScript is available, trigger an XmlHTTPRequest with the non-existing user 'logout' and abort it
* before it is able to finish. This will cause the browser to show a new authentication prompt in the next
* request.
*/
window.onload = function () {
function getXMLHttpRequest() {
var xmlhttp = null;
try {
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}
} catch (e) {}
return xmlhttp;
}
var msg = document.getElementById('logout-status');
try {
if (navigator.userAgent.toLowerCase().indexOf('msie') !== -1) {
document.execCommand('ClearAuthenticationCache');
} else {
var xhttp = getXMLHttpRequest();
xhttp.open('GET', 'arbitrary url', true, 'logout', 'logout');
xhttp.send('');
xhttp.abort();
}
} catch (e) {
msg.innerHTML = '<?= t(
'Logout not possible, it may be necessary to quit the session manually ' .
'by clearing the cache, or closing the current browser session. Error: '
);?>' + ': ' + e.getMessage() ;
msg.setAttribute('class', 'alert alert-danger');
}
msg.innerHTML = '<?= t('Logout successful!'); ?>';
msg.setAttribute('class', 'alert alert-success');
};
</script>

View File

@ -14,6 +14,10 @@ moduleFolder = "@icingaweb_config_path@/enabledModules"
; won't show up in the list of disabled modules.
; modulePath = "/vagrant/modules:/usr/share/icingaweb/modules"
; The used authentication-mode can be either "internal" to handle the authentication in IcingaWeb
; or "external" to delegate the authentication to the used WebServer
authenticationMode = "internal"
[logging]
enable = true
; Writing to a Stream

View File

@ -0,0 +1,90 @@
# Externel 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.
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.
## Use External Authentication
Using external authentication in Icingaweb requires two steps to work:
1. The external authentication must be set up correctly to always
authenticate the users.
2. Icingaweb must be configured to use the external authentication.
### 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
#### Example Configuration for Apache and HTTPDigestAuthentication
The following example will show how to enable external authentication in Apache using
*HTTP Digest Authentication*.
##### Create 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.
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.
sudo htdigest -c /etc/httpd/conf.d/.icingawebdigest "Icingaweb 2" jdoe
##### Set up authentication
The webserver should require authentication for all public icingaweb files.
<Directory "/var/www/html/icingaweb">
AuthType digest
AuthName "Icingaweb 2"
AuthDigestProvider file
AuthUserFile /etc/httpd/conf.d/.icingawebdigest
Require valid-user
</Directory>
### Prepare Icingaweb
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"
; ...

View File

@ -230,6 +230,11 @@ class Web extends ApplicationBootstrap
{
$authenticationManager = AuthenticationManager::getInstance();
if ($this->getConfig()->get('global')->get('authenticationMode', 'internal') === 'external') {
$authenticationManager->authenticateFromRemoteUser();
}
if ($authenticationManager->isAuthenticated() === true) {
$user = $authenticationManager->getUser();

View File

@ -52,6 +52,7 @@ use Icinga\Authentication\Backend\LdapUserBackend;
**/
class Manager
{
/**
* Singleton instance
*
@ -59,6 +60,13 @@ class Manager
*/
private static $instance;
/**
* If the user was authenticated from the REMOTE_USER server variable
*
* @var Boolean
*/
private $fromRemoteUser = false;
/**
* Instance of authenticated user
*
@ -387,6 +395,27 @@ class Manager
$this->user = Session::getSession()->get('user');
}
/**
* Tries to authenticate the user from the session, and then from the REMOTE_USER superglobal, that can be set by
* an external authentication provider.
*/
public function authenticateFromRemoteUser()
{
$this->fromRemoteUser = true;
$this->authenticateFromSession();
if ($this->user !== null) {
if (array_key_exists('REMOTE_USER', $_SERVER) && $this->user->getUsername() !== $_SERVER["REMOTE_USER"]) {
// Remote user has changed, clear all sessions
$this->removeAuthorization();
}
return;
}
if (array_key_exists('REMOTE_USER', $_SERVER) && $_SERVER["REMOTE_USER"]) {
$this->user = new User($_SERVER["REMOTE_USER"]);
$this->persistCurrentUser();
}
}
/**
* Returns true when the user is currently authenticated
*
@ -472,4 +501,12 @@ class Manager
{
return $this->user->getGroups();
}
/**
* If the session was established from the REMOTE_USER server variable.
*/
public function isAuthenticatedFromRemoteUser()
{
return $this->fromRemoteUser;
}
}

View File

@ -43,7 +43,7 @@ class PieChart implements Widget
*/
private $template =<<<'EOD'
<div data-icinga-component="app/piechart">
<div>
<img class='inlinepie' src="{url}" width={width} height={height}> </img>
</div>
EOD;