Merge branch 'feature/accept-web-server-authentication-5405'
This commit is contained in:
commit
bcfebcd937
|
@ -85,10 +85,16 @@ class AuthenticationController extends ActionController
|
||||||
*/
|
*/
|
||||||
public function logoutAction()
|
public function logoutAction()
|
||||||
{
|
{
|
||||||
$this->_helper->layout->setLayout('inline');
|
|
||||||
$auth = AuthManager::getInstance();
|
$auth = AuthManager::getInstance();
|
||||||
$auth->removeAuthorization();
|
$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
|
// @codingStandardsIgnoreEnd
|
||||||
|
|
|
@ -23,8 +23,6 @@
|
||||||
* is useful for preserving the detail view and the selection in that case.
|
* is useful for preserving the detail view and the selection in that case.
|
||||||
*
|
*
|
||||||
* refs #4833
|
* refs #4833
|
||||||
*
|
|
||||||
* TODO: Copy this snipped into the new login.phtml
|
|
||||||
*/
|
*/
|
||||||
var url = document.URL.match(/(^[^#]*)/)[0] + encodeURIComponent(window.location.hash);
|
var url = document.URL.match(/(^[^#]*)/)[0] + encodeURIComponent(window.location.hash);
|
||||||
document.getElementById('form_login').action = url;
|
document.getElementById('form_login').action = url;
|
||||||
|
|
|
@ -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>
|
|
@ -14,6 +14,10 @@ moduleFolder = "@icingaweb_config_path@/enabledModules"
|
||||||
; won't show up in the list of disabled modules.
|
; won't show up in the list of disabled modules.
|
||||||
; modulePath = "/vagrant/modules:/usr/share/icingaweb/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]
|
[logging]
|
||||||
enable = true
|
enable = true
|
||||||
; Writing to a Stream
|
; Writing to a Stream
|
||||||
|
|
|
@ -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"
|
||||||
|
; ...
|
||||||
|
|
|
@ -230,6 +230,11 @@ class Web extends ApplicationBootstrap
|
||||||
{
|
{
|
||||||
$authenticationManager = AuthenticationManager::getInstance();
|
$authenticationManager = AuthenticationManager::getInstance();
|
||||||
|
|
||||||
|
|
||||||
|
if ($this->getConfig()->get('global')->get('authenticationMode', 'internal') === 'external') {
|
||||||
|
$authenticationManager->authenticateFromRemoteUser();
|
||||||
|
}
|
||||||
|
|
||||||
if ($authenticationManager->isAuthenticated() === true) {
|
if ($authenticationManager->isAuthenticated() === true) {
|
||||||
$user = $authenticationManager->getUser();
|
$user = $authenticationManager->getUser();
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ use Icinga\Authentication\Backend\LdapUserBackend;
|
||||||
**/
|
**/
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton instance
|
* Singleton instance
|
||||||
*
|
*
|
||||||
|
@ -59,6 +60,13 @@ class Manager
|
||||||
*/
|
*/
|
||||||
private static $instance;
|
private static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the user was authenticated from the REMOTE_USER server variable
|
||||||
|
*
|
||||||
|
* @var Boolean
|
||||||
|
*/
|
||||||
|
private $fromRemoteUser = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of authenticated user
|
* Instance of authenticated user
|
||||||
*
|
*
|
||||||
|
@ -387,6 +395,27 @@ class Manager
|
||||||
$this->user = Session::getSession()->get('user');
|
$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
|
* Returns true when the user is currently authenticated
|
||||||
*
|
*
|
||||||
|
@ -472,4 +501,12 @@ class Manager
|
||||||
{
|
{
|
||||||
return $this->user->getGroups();
|
return $this->user->getGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the session was established from the REMOTE_USER server variable.
|
||||||
|
*/
|
||||||
|
public function isAuthenticatedFromRemoteUser()
|
||||||
|
{
|
||||||
|
return $this->fromRemoteUser;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ class PieChart implements Widget
|
||||||
*/
|
*/
|
||||||
private $template =<<<'EOD'
|
private $template =<<<'EOD'
|
||||||
|
|
||||||
<div data-icinga-component="app/piechart">
|
<div>
|
||||||
<img class='inlinepie' src="{url}" width={width} height={height}> </img>
|
<img class='inlinepie' src="{url}" width={width} height={height}> </img>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
|
|
Loading…
Reference in New Issue