mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-25 06:44:33 +02:00
Merge branch 'master' into bugfix/allow-to-configure-how-to-manage-groups-9609
This commit is contained in:
commit
316a4d8b82
@ -6,20 +6,14 @@
|
|||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Authentication\AuthChain;
|
|
||||||
use Icinga\Authentication\User\ExternalBackend;
|
|
||||||
use Icinga\Exception\AuthenticationException;
|
|
||||||
use Icinga\Exception\ConfigurationError;
|
|
||||||
use Icinga\Exception\NotReadableError;
|
|
||||||
use Icinga\Forms\Authentication\LoginForm;
|
use Icinga\Forms\Authentication\LoginForm;
|
||||||
use Icinga\User;
|
use Icinga\Web\Controller;
|
||||||
use Icinga\Web\Controller\ActionController;
|
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application wide controller for authentication
|
* Application wide controller for authentication
|
||||||
*/
|
*/
|
||||||
class AuthenticationController extends ActionController
|
class AuthenticationController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* This controller does not require authentication
|
* This controller does not require authentication
|
||||||
@ -34,118 +28,19 @@ class AuthenticationController extends ActionController
|
|||||||
public function loginAction()
|
public function loginAction()
|
||||||
{
|
{
|
||||||
$icinga = Icinga::app();
|
$icinga = Icinga::app();
|
||||||
if ($icinga->setupTokenExists() && $icinga->requiresSetup()) {
|
if (($requiresSetup = $icinga->requiresSetup()) && $icinga->setupTokenExists()) {
|
||||||
$this->redirectNow(Url::fromPath('setup'));
|
$this->redirectNow(Url::fromPath('setup'));
|
||||||
}
|
}
|
||||||
|
$form = new LoginForm();
|
||||||
$triedOnlyExternalAuth = null;
|
if ($this->Auth()->isAuthenticated()) {
|
||||||
$auth = $this->Auth();
|
$this->redirectNow($form->getRedirectUrl());
|
||||||
$this->view->form = $form = new LoginForm();
|
|
||||||
$this->view->title = $this->translate('Icingaweb Login');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$redirectUrl = $this->view->form->getValue('redirect');
|
|
||||||
if ($redirectUrl) {
|
|
||||||
$redirectUrl = Url::fromPath($redirectUrl);
|
|
||||||
} else {
|
|
||||||
$redirectUrl = Url::fromPath('dashboard');
|
|
||||||
}
|
}
|
||||||
|
if (! $requiresSetup) {
|
||||||
if ($auth->isAuthenticated()) {
|
$form->handleRequest();
|
||||||
$this->rerenderLayout()->redirectNow($redirectUrl);
|
|
||||||
}
|
}
|
||||||
|
$this->view->form = $form;
|
||||||
try {
|
$this->view->title = $this->translate('Icinga Web 2 Login');
|
||||||
$config = Config::app('authentication');
|
$this->view->requiresSetup = $requiresSetup;
|
||||||
} catch (NotReadableError $e) {
|
|
||||||
throw new ConfigurationError(
|
|
||||||
$this->translate('Could not read your authentication.ini, no authentication methods are available.'),
|
|
||||||
0,
|
|
||||||
$e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$chain = new AuthChain($config);
|
|
||||||
$request = $this->getRequest();
|
|
||||||
if ($request->isPost() && $this->view->form->isValid($request->getPost())) {
|
|
||||||
$user = new User($this->view->form->getValue('username'));
|
|
||||||
$password = $this->view->form->getValue('password');
|
|
||||||
$backendsTried = 0;
|
|
||||||
$backendsWithError = 0;
|
|
||||||
|
|
||||||
$redirectUrl = $form->getValue('redirect');
|
|
||||||
|
|
||||||
if ($redirectUrl) {
|
|
||||||
$redirectUrl = Url::fromPath($redirectUrl);
|
|
||||||
} else {
|
|
||||||
$redirectUrl = Url::fromPath('dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($chain as $backend) {
|
|
||||||
if ($backend instanceof ExternalBackend) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++$backendsTried;
|
|
||||||
try {
|
|
||||||
$authenticated = $backend->authenticate($user, $password);
|
|
||||||
} catch (AuthenticationException $e) {
|
|
||||||
Logger::error($e);
|
|
||||||
++$backendsWithError;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($authenticated === true) {
|
|
||||||
$auth->setAuthenticated($user);
|
|
||||||
$this->rerenderLayout()->redirectNow($redirectUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($backendsTried === 0) {
|
|
||||||
$this->view->form->addError(
|
|
||||||
$this->translate(
|
|
||||||
'No authentication methods available. Did you create'
|
|
||||||
. ' authentication.ini when setting up Icinga Web 2?'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else if ($backendsTried === $backendsWithError) {
|
|
||||||
$this->view->form->addError(
|
|
||||||
$this->translate(
|
|
||||||
'All configured authentication methods failed.'
|
|
||||||
. ' Please check the system log or Icinga Web 2 log for more information.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} elseif ($backendsWithError) {
|
|
||||||
$this->view->form->addError(
|
|
||||||
$this->translate(
|
|
||||||
'Please note that not all authentication methods were available.'
|
|
||||||
. ' Check the system log or Icinga Web 2 log for more information.'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ($backendsTried > 0 && $backendsTried !== $backendsWithError) {
|
|
||||||
$this->view->form->getElement('password')->addError($this->translate('Incorrect username or password'));
|
|
||||||
}
|
|
||||||
} elseif ($request->isGet()) {
|
|
||||||
$user = new User('');
|
|
||||||
foreach ($chain as $backend) {
|
|
||||||
$triedOnlyExternalAuth = $triedOnlyExternalAuth === null;
|
|
||||||
if ($backend instanceof ExternalBackend) {
|
|
||||||
$authenticated = $backend->authenticate($user);
|
|
||||||
if ($authenticated === true) {
|
|
||||||
$auth->setAuthenticated($user);
|
|
||||||
$this->rerenderLayout()->redirectNow(
|
|
||||||
Url::fromPath(Url::fromRequest()->getParam('redirect', 'dashboard'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$triedOnlyExternalAuth = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->view->form->addError($e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->view->requiresExternalAuth = $triedOnlyExternalAuth && ! $auth->isAuthenticated();
|
|
||||||
$this->view->requiresSetup = Icinga::app()->requiresSetup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,10 +52,12 @@ class AuthenticationController extends ActionController
|
|||||||
if (! $auth->isAuthenticated()) {
|
if (! $auth->isAuthenticated()) {
|
||||||
$this->redirectToLogin();
|
$this->redirectToLogin();
|
||||||
}
|
}
|
||||||
$isRemoteUser = $auth->getUser()->isRemoteUser();
|
// Get info whether the user is externally authenticated before removing authorization which destroys the
|
||||||
|
// session and the user object
|
||||||
|
$isExternalUser = $auth->getUser()->isExternalUser();
|
||||||
$auth->removeAuthorization();
|
$auth->removeAuthorization();
|
||||||
if ($isRemoteUser === true) {
|
if ($isExternalUser) {
|
||||||
$this->_response->setHttpResponseCode(401);
|
$this->getResponse()->setHttpResponseCode(401);
|
||||||
} else {
|
} else {
|
||||||
$this->redirectToLogin();
|
$this->redirectToLogin();
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,14 @@ class ConfigController extends Controller
|
|||||||
$tabs->add('general', array(
|
$tabs->add('general', array(
|
||||||
'title' => $this->translate('Adjust the general configuration of Icinga Web 2'),
|
'title' => $this->translate('Adjust the general configuration of Icinga Web 2'),
|
||||||
'label' => $this->translate('General'),
|
'label' => $this->translate('General'),
|
||||||
'url' => 'config/general'
|
'url' => 'config/general',
|
||||||
|
'baseTarget' => '_main'
|
||||||
));
|
));
|
||||||
$tabs->add('resource', array(
|
$tabs->add('resource', array(
|
||||||
'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'),
|
'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'),
|
||||||
'label' => $this->translate('Resources'),
|
'label' => $this->translate('Resources'),
|
||||||
'url' => 'config/resource'
|
'url' => 'config/resource',
|
||||||
|
'baseTarget' => '_main'
|
||||||
));
|
));
|
||||||
return $tabs;
|
return $tabs;
|
||||||
}
|
}
|
||||||
@ -51,12 +53,14 @@ class ConfigController extends Controller
|
|||||||
$tabs->add('userbackend', array(
|
$tabs->add('userbackend', array(
|
||||||
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
|
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
|
||||||
'label' => $this->translate('User Backends'),
|
'label' => $this->translate('User Backends'),
|
||||||
'url' => 'config/userbackend'
|
'url' => 'config/userbackend',
|
||||||
|
'baseTarget' => '_main'
|
||||||
));
|
));
|
||||||
$tabs->add('usergroupbackend', array(
|
$tabs->add('usergroupbackend', array(
|
||||||
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
|
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
|
||||||
'label' => $this->translate('User Group Backends'),
|
'label' => $this->translate('User Group Backends'),
|
||||||
'url' => 'usergroupbackend/list'
|
'url' => 'usergroupbackend/list',
|
||||||
|
'baseTarget' => '_main'
|
||||||
));
|
));
|
||||||
return $tabs;
|
return $tabs;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,8 @@ class RoleController extends AuthBackendController
|
|||||||
'Configure roles to permit or restrict users and groups accessing Icinga Web 2'
|
'Configure roles to permit or restrict users and groups accessing Icinga Web 2'
|
||||||
),
|
),
|
||||||
'label' => $this->translate('Roles'),
|
'label' => $this->translate('Roles'),
|
||||||
'url' => 'role/list'
|
'url' => 'role/list',
|
||||||
|
'baseTarget' => '_main'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3,16 +3,24 @@
|
|||||||
|
|
||||||
namespace Icinga\Forms\Authentication;
|
namespace Icinga\Forms\Authentication;
|
||||||
|
|
||||||
|
use Icinga\Authentication\Auth;
|
||||||
|
use Icinga\Authentication\User\ExternalBackend;
|
||||||
|
use Icinga\User;
|
||||||
use Icinga\Web\Form;
|
use Icinga\Web\Form;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class LoginForm
|
* Form for user authentication
|
||||||
*/
|
*/
|
||||||
class LoginForm extends Form
|
class LoginForm extends Form
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Initialize this login form
|
* Redirect URL
|
||||||
|
*/
|
||||||
|
const REDIRECT_URL = 'dashboard';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
@ -22,7 +30,7 @@ class LoginForm extends Form
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Form::createElements()
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function createElements(array $formData)
|
public function createElements(array $formData)
|
||||||
{
|
{
|
||||||
@ -54,4 +62,83 @@ class LoginForm extends Form
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getRedirectUrl()
|
||||||
|
{
|
||||||
|
$redirect = null;
|
||||||
|
if ($this->created) {
|
||||||
|
$redirect = $this->getElement('redirect')->getValue();
|
||||||
|
}
|
||||||
|
if (empty($redirect)) {
|
||||||
|
$redirect = static::REDIRECT_URL;
|
||||||
|
}
|
||||||
|
return Url::fromPath($redirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$auth = Auth::getInstance();
|
||||||
|
$authChain = $auth->getAuthChain();
|
||||||
|
$authChain->setSkipExternalBackends(true);
|
||||||
|
$user = new User($this->getElement('username')->getValue());
|
||||||
|
$password = $this->getElement('password')->getValue();
|
||||||
|
$authenticated = $authChain->authenticate($user, $password);
|
||||||
|
if ($authenticated) {
|
||||||
|
$auth->setAuthenticated($user);
|
||||||
|
$this->getResponse()->setRerenderLayout(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
switch ($authChain->getError()) {
|
||||||
|
case $authChain::EEMPTY:
|
||||||
|
$this->addError($this->translate(
|
||||||
|
'No authentication methods available.'
|
||||||
|
. ' Did you create authentication.ini when setting up Icinga Web 2?'
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case $authChain::EFAIL:
|
||||||
|
$this->addError($this->translate(
|
||||||
|
'All configured authentication methods failed.'
|
||||||
|
. ' Please check the system log or Icinga Web 2 log for more information.'
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
/** @noinspection PhpMissingBreakStatementInspection */
|
||||||
|
case $authChain::ENOTALL:
|
||||||
|
$this->addError($this->translate(
|
||||||
|
'Please note that not all authentication methods were available.'
|
||||||
|
. ' Check the system log or Icinga Web 2 log for more information.'
|
||||||
|
));
|
||||||
|
// Move to default
|
||||||
|
default:
|
||||||
|
$this->getElement('password')->addError($this->translate('Incorrect username or password'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onRequest()
|
||||||
|
{
|
||||||
|
$auth = Auth::getInstance();
|
||||||
|
$onlyExternal = true;
|
||||||
|
// TODO(el): This may be set on the auth chain once iterated. See Auth::authExternal().
|
||||||
|
foreach ($auth->getAuthChain() as $backend) {
|
||||||
|
if (! $backend instanceof ExternalBackend) {
|
||||||
|
$onlyExternal = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($onlyExternal) {
|
||||||
|
$this->addError($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.'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace Icinga\Forms;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\User\Preferences;
|
use Icinga\User\Preferences;
|
||||||
use Icinga\User\Preferences\PreferencesStore;
|
use Icinga\User\Preferences\PreferencesStore;
|
||||||
use Icinga\Util\TimezoneDetect;
|
use Icinga\Util\TimezoneDetect;
|
||||||
@ -123,7 +123,7 @@ class PreferenceForm extends Form
|
|||||||
*/
|
*/
|
||||||
public function onRequest()
|
public function onRequest()
|
||||||
{
|
{
|
||||||
$auth = Manager::getInstance();
|
$auth = Auth::getInstance();
|
||||||
$values = $auth->getUser()->getPreferences()->get('icingaweb');
|
$values = $auth->getUser()->getPreferences()->get('icingaweb');
|
||||||
|
|
||||||
if (! isset($values['language'])) {
|
if (! isset($values['language'])) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Notification;
|
use Icinga\Web\Notification;
|
||||||
use Icinga\Authentication\Manager as Auth;
|
use Icinga\Authentication\Auth;
|
||||||
|
|
||||||
|
|
||||||
if (Auth::getInstance()->isAuthenticated()):
|
if (Auth::getInstance()->isAuthenticated()):
|
||||||
@ -51,7 +51,7 @@ if (Auth::getInstance()->isAuthenticated()):
|
|||||||
<ul id="notifications"><?php
|
<ul id="notifications"><?php
|
||||||
$notifications = Notification::getInstance();
|
$notifications = Notification::getInstance();
|
||||||
if ($notifications->hasMessages()) {
|
if ($notifications->hasMessages()) {
|
||||||
foreach ($notifications->getMessages() as $m) {
|
foreach ($notifications->popMessages() as $m) {
|
||||||
echo '<li class="' . $m->type . '">' . $this->escape($m->message) . '</li>';
|
echo '<li class="' . $m->type . '">' . $this->escape($m->message) . '</li>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,6 @@
|
|||||||
'<a href="' . $this->href('setup') . '" title="' . $this->translate('Icinga Web 2 Setup-Wizard') . '">',
|
'<a href="' . $this->href('setup') . '" title="' . $this->translate('Icinga Web 2 Setup-Wizard') . '">',
|
||||||
'</a>'
|
'</a>'
|
||||||
); ?></p>
|
); ?></p>
|
||||||
<?php elseif ($requiresExternalAuth): ?>
|
|
||||||
<p class="info-box"><?= $this->icon('info'); ?><?= $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 ?>
|
<?php endif ?>
|
||||||
<?= $this->form ?>
|
<?= $this->form ?>
|
||||||
<div class="footer">Icinga Web 2 © 2013-2015<br><a href="https://www.icinga.org"><?= $this->translate('The Icinga Project'); ?></a></div>
|
<div class="footer">Icinga Web 2 © 2013-2015<br><a href="https://www.icinga.org"><?= $this->translate('The Icinga Project'); ?></a></div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="controls" data-base-target="_main">
|
<div class="controls">
|
||||||
<?= $tabs; ?>
|
<?= $tabs; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" data-base-target="_next">
|
<div class="content" data-base-target="_next">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="controls" data-base-target="_main">
|
<div class="controls">
|
||||||
<?= $tabs; ?>
|
<?= $tabs; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" data-base-target="_next">
|
<div class="content" data-base-target="_next">
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
array('backend' => $backendNames[$i]),
|
array('backend' => $backendNames[$i]),
|
||||||
array(
|
array(
|
||||||
'icon' => 'edit',
|
'icon' => 'edit',
|
||||||
'title' => sprintf($this->translate('Edit user backend %s'), $backendNames[$i])
|
'class' => 'rowaction',
|
||||||
|
'title' => sprintf($this->translate('rEdit user backend %s'), $backendNames[$i])
|
||||||
)
|
)
|
||||||
); ?>
|
); ?>
|
||||||
</td>
|
</td>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="controls" data-base-target="_main">
|
<div class="controls">
|
||||||
<?= $tabs ?>
|
<?= $tabs ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -12,7 +12,7 @@ use Zend_Layout;
|
|||||||
use Zend_Paginator;
|
use Zend_Paginator;
|
||||||
use Zend_View_Helper_PaginationControl;
|
use Zend_View_Helper_PaginationControl;
|
||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use Icinga\Util\TimezoneDetect;
|
use Icinga\Util\TimezoneDetect;
|
||||||
use Icinga\Util\Translator;
|
use Icinga\Util\Translator;
|
||||||
@ -55,6 +55,13 @@ class Web extends ApplicationBootstrap
|
|||||||
*/
|
*/
|
||||||
private $request;
|
private $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response
|
||||||
|
*
|
||||||
|
* @var Response
|
||||||
|
*/
|
||||||
|
protected $response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session object
|
* Session object
|
||||||
*
|
*
|
||||||
@ -91,11 +98,12 @@ class Web extends ApplicationBootstrap
|
|||||||
->setupResourceFactory()
|
->setupResourceFactory()
|
||||||
->setupSession()
|
->setupSession()
|
||||||
->setupNotifications()
|
->setupNotifications()
|
||||||
|
->setupRequest()
|
||||||
|
->setupResponse()
|
||||||
->setupUser()
|
->setupUser()
|
||||||
->setupTimezone()
|
->setupTimezone()
|
||||||
->setupLogger()
|
->setupLogger()
|
||||||
->setupInternationalization()
|
->setupInternationalization()
|
||||||
->setupRequest()
|
|
||||||
->setupZendMvc()
|
->setupZendMvc()
|
||||||
->setupFormNamespace()
|
->setupFormNamespace()
|
||||||
->setupModuleManager()
|
->setupModuleManager()
|
||||||
@ -137,6 +145,26 @@ class Web extends ApplicationBootstrap
|
|||||||
return $this->frontController;
|
return $this->frontController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the request
|
||||||
|
*
|
||||||
|
* @return Request
|
||||||
|
*/
|
||||||
|
public function getRequest()
|
||||||
|
{
|
||||||
|
return $this->request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for view
|
* Getter for view
|
||||||
*
|
*
|
||||||
@ -152,7 +180,7 @@ class Web extends ApplicationBootstrap
|
|||||||
*/
|
*/
|
||||||
public function dispatch()
|
public function dispatch()
|
||||||
{
|
{
|
||||||
$this->frontController->dispatch($this->request, new Response());
|
$this->frontController->dispatch($this->getRequest(), $this->getResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,9 +208,11 @@ class Web extends ApplicationBootstrap
|
|||||||
*/
|
*/
|
||||||
private function setupUser()
|
private function setupUser()
|
||||||
{
|
{
|
||||||
$auth = Manager::getInstance();
|
$auth = Auth::getInstance();
|
||||||
if ($auth->isAuthenticated()) {
|
if ($auth->isAuthenticated()) {
|
||||||
$this->user = $auth->getUser();
|
$user = $auth->getUser();
|
||||||
|
$this->request->setUser($user);
|
||||||
|
$this->user = $user;
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -210,16 +240,24 @@ class Web extends ApplicationBootstrap
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject dependencies into request
|
* Set the request
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
private function setupRequest()
|
private function setupRequest()
|
||||||
{
|
{
|
||||||
$this->request = new Request();
|
$this->request = new Request();
|
||||||
if ($this->user instanceof User) {
|
return $this;
|
||||||
$this->request->setUser($this->user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the response
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function setupResponse()
|
||||||
|
{
|
||||||
|
$this->response = new Response();
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +321,7 @@ class Web extends ApplicationBootstrap
|
|||||||
*/
|
*/
|
||||||
protected function detectTimezone()
|
protected function detectTimezone()
|
||||||
{
|
{
|
||||||
$auth = Manager::getInstance();
|
$auth = Auth::getInstance();
|
||||||
if (! $auth->isAuthenticated()
|
if (! $auth->isAuthenticated()
|
||||||
|| ($timezone = $auth->getUser()->getPreferences()->getValue('icingaweb', 'timezone')) === null
|
|| ($timezone = $auth->getUser()->getPreferences()->getValue('icingaweb', 'timezone')) === null
|
||||||
) {
|
) {
|
||||||
@ -304,7 +342,7 @@ class Web extends ApplicationBootstrap
|
|||||||
*/
|
*/
|
||||||
protected function detectLocale()
|
protected function detectLocale()
|
||||||
{
|
{
|
||||||
$auth = Manager::getInstance();
|
$auth = Auth::getInstance();
|
||||||
if ($auth->isAuthenticated()
|
if ($auth->isAuthenticated()
|
||||||
&& ($locale = $auth->getUser()->getPreferences()->getValue('icingaweb', 'language')) !== null
|
&& ($locale = $auth->getUser()->getPreferences()->getValue('icingaweb', 'language')) !== null
|
||||||
) {
|
) {
|
||||||
|
@ -4,18 +4,20 @@
|
|||||||
namespace Icinga\Authentication;
|
namespace Icinga\Authentication;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Icinga\Authentication\UserGroup\UserGroupBackend;
|
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Application\Icinga;
|
||||||
|
use Icinga\Application\Logger;
|
||||||
|
use Icinga\Authentication\User\ExternalBackend;
|
||||||
|
use Icinga\Authentication\UserGroup\UserGroupBackend;
|
||||||
use Icinga\Data\ConfigObject;
|
use Icinga\Data\ConfigObject;
|
||||||
use Icinga\Exception\IcingaException;
|
use Icinga\Exception\IcingaException;
|
||||||
use Icinga\Exception\NotReadableError;
|
use Icinga\Exception\NotReadableError;
|
||||||
use Icinga\Application\Logger;
|
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use Icinga\User\Preferences;
|
use Icinga\User\Preferences;
|
||||||
use Icinga\User\Preferences\PreferencesStore;
|
use Icinga\User\Preferences\PreferencesStore;
|
||||||
use Icinga\Web\Session;
|
use Icinga\Web\Session;
|
||||||
|
|
||||||
class Manager
|
class Auth
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Singleton instance
|
* Singleton instance
|
||||||
@ -24,6 +26,20 @@ class Manager
|
|||||||
*/
|
*/
|
||||||
private static $instance;
|
private static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request
|
||||||
|
*
|
||||||
|
* @var \Icinga\Web\Request
|
||||||
|
*/
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response
|
||||||
|
*
|
||||||
|
* @var \Icinga\Web\Response
|
||||||
|
*/
|
||||||
|
protected $response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticated user
|
* Authenticated user
|
||||||
*
|
*
|
||||||
@ -32,6 +48,9 @@ class Manager
|
|||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see getInstance()
|
||||||
|
*/
|
||||||
private function __construct()
|
private function __construct()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -44,11 +63,39 @@ class Manager
|
|||||||
public static function getInstance()
|
public static function getInstance()
|
||||||
{
|
{
|
||||||
if (self::$instance === null) {
|
if (self::$instance === null) {
|
||||||
self::$instance = new static();
|
self::$instance = new self();
|
||||||
}
|
}
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the auth chain
|
||||||
|
*
|
||||||
|
* @return AuthChain
|
||||||
|
*/
|
||||||
|
public function getAuthChain()
|
||||||
|
{
|
||||||
|
return new AuthChain();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user is authenticated
|
||||||
|
*
|
||||||
|
* @param bool $ignoreSession True to prevent session authentication
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isAuthenticated($ignoreSession = false)
|
||||||
|
{
|
||||||
|
if ($this->user === null && ! $ignoreSession) {
|
||||||
|
$this->authenticateFromSession();
|
||||||
|
}
|
||||||
|
if ($this->user === null && ! $this->authExternal()) {
|
||||||
|
return $this->authHttp();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function setAuthenticated(User $user, $persist = true)
|
public function setAuthenticated(User $user, $persist = true)
|
||||||
{
|
{
|
||||||
$username = $user->getUsername();
|
$username = $user->getUsername();
|
||||||
@ -121,58 +168,40 @@ class Manager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the current user to the session
|
* Getter for groups belonged to authenticated user
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @see User::getGroups
|
||||||
*/
|
*/
|
||||||
public function persistCurrentUser()
|
public function getGroups()
|
||||||
{
|
{
|
||||||
Session::getSession()->set('user', $this->user)->refreshId();
|
return $this->user->getGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to authenticate the user with the current session
|
* Get the request
|
||||||
*
|
*
|
||||||
* Authentication for externally-authenticated users will be revoked if the username changed or external
|
* @return \Icinga\Web\Request
|
||||||
* authentication is no longer in effect
|
|
||||||
*/
|
*/
|
||||||
public function authenticateFromSession()
|
public function getRequest()
|
||||||
{
|
{
|
||||||
$this->user = Session::getSession()->get('user');
|
if ($this->request === null) {
|
||||||
if ($this->user !== null && $this->user->isRemoteUser() === true) {
|
$this->request = Icinga::app()->getRequest();
|
||||||
list($originUsername, $field) = $this->user->getRemoteUserInformation();
|
|
||||||
if (! array_key_exists($field, $_SERVER) || $_SERVER[$field] !== $originUsername) {
|
|
||||||
$this->removeAuthorization();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return $this->request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the user is authenticated
|
* Get the response
|
||||||
*
|
*
|
||||||
* @param bool $ignoreSession True to prevent session authentication
|
* @return \Icinga\Web\Response
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function isAuthenticated($ignoreSession = false)
|
public function getResponse()
|
||||||
{
|
{
|
||||||
if ($this->user === null && ! $ignoreSession) {
|
if ($this->response === null) {
|
||||||
$this->authenticateFromSession();
|
$this->response = Icinga::app()->getResponse();
|
||||||
}
|
}
|
||||||
return is_object($this->user);
|
return $this->response;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether an authenticated user has a given permission
|
|
||||||
*
|
|
||||||
* @param string $permission Permission name
|
|
||||||
*
|
|
||||||
* @return bool True if the user owns the given permission, false if not or if not authenticated
|
|
||||||
*/
|
|
||||||
public function hasPermission($permission)
|
|
||||||
{
|
|
||||||
if (! $this->isAuthenticated()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return $this->user->can($permission);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,15 +221,6 @@ class Manager
|
|||||||
return $this->user->getRestrictions($restriction);
|
return $this->user->getRestrictions($restriction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Purges the current authorization information and session
|
|
||||||
*/
|
|
||||||
public function removeAuthorization()
|
|
||||||
{
|
|
||||||
$this->user = null;
|
|
||||||
Session::getSession()->purge();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current user or null if no user is authenticated
|
* Returns the current user or null if no user is authenticated
|
||||||
*
|
*
|
||||||
@ -212,13 +232,124 @@ class Manager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for groups belonged to authenticated user
|
* Try to authenticate the user with the current session
|
||||||
*
|
*
|
||||||
* @return array
|
* Authentication for externally-authenticated users will be revoked if the username changed or external
|
||||||
* @see User::getGroups
|
* authentication is no longer in effect
|
||||||
*/
|
*/
|
||||||
public function getGroups()
|
public function authenticateFromSession()
|
||||||
{
|
{
|
||||||
return $this->user->getGroups();
|
$this->user = Session::getSession()->get('user');
|
||||||
|
if ($this->user !== null && $this->user->isExternalUser() === true) {
|
||||||
|
list($originUsername, $field) = $this->user->getExternalUserInformation();
|
||||||
|
if (! array_key_exists($field, $_SERVER) || $_SERVER[$field] !== $originUsername) {
|
||||||
|
$this->removeAuthorization();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to authenticate a user from external user backends
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function authExternal()
|
||||||
|
{
|
||||||
|
$user = new User('');
|
||||||
|
foreach ($this->getAuthChain() as $userBackend) {
|
||||||
|
if ($userBackend instanceof ExternalBackend) {
|
||||||
|
if ($userBackend->authenticate($user)) {
|
||||||
|
$this->setAuthenticated($user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to authenticate a user using HTTP authentication
|
||||||
|
*
|
||||||
|
* Supports only the Basic HTTP authentication scheme. XHR will be ignored.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function authHttp()
|
||||||
|
{
|
||||||
|
if ($this->getRequest()->isXmlHttpRequest()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (($header = $this->getRequest()->getHeader('Authorization')) === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (empty($header)) {
|
||||||
|
$this->challengeHttp();
|
||||||
|
}
|
||||||
|
list($scheme) = explode(' ', $header, 2);
|
||||||
|
if ($scheme !== 'Basic') {
|
||||||
|
$this->challengeHttp();
|
||||||
|
}
|
||||||
|
$authorization = substr($header, strlen('Basic '));
|
||||||
|
$credentials = base64_decode($authorization);
|
||||||
|
$credentials = array_filter(explode(':', $credentials, 2));
|
||||||
|
if (count($credentials) !== 2) {
|
||||||
|
// Deny empty username and/or password
|
||||||
|
$this->challengeHttp();
|
||||||
|
}
|
||||||
|
$user = new User($credentials[0]);
|
||||||
|
$password = $credentials[1];
|
||||||
|
if ($this->getAuthChain()->setSkipExternalBackends(true)->authenticate($user, $password)) {
|
||||||
|
$this->setAuthenticated($user, false);
|
||||||
|
$user->setIsHttpUser(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$this->challengeHttp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Challenge client immediately for HTTP authentication
|
||||||
|
*
|
||||||
|
* Sends the response w/ the 401 Unauthorized status code and WWW-Authenticate header.
|
||||||
|
*/
|
||||||
|
protected function challengeHttp()
|
||||||
|
{
|
||||||
|
$response = $this->getResponse();
|
||||||
|
$response->setHttpResponseCode(401);
|
||||||
|
$response->setHeader('WWW-Authenticate', 'Basic realm="Icinga Web 2"');
|
||||||
|
$response->sendHeaders();
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether an authenticated user has a given permission
|
||||||
|
*
|
||||||
|
* @param string $permission Permission name
|
||||||
|
*
|
||||||
|
* @return bool True if the user owns the given permission, false if not or if not authenticated
|
||||||
|
*/
|
||||||
|
public function hasPermission($permission)
|
||||||
|
{
|
||||||
|
if (! $this->isAuthenticated()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $this->user->can($permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the current user to the session
|
||||||
|
*/
|
||||||
|
public function persistCurrentUser()
|
||||||
|
{
|
||||||
|
Session::getSession()->set('user', $this->user)->refreshId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purges the current authorization information and session
|
||||||
|
*/
|
||||||
|
public function removeAuthorization()
|
||||||
|
{
|
||||||
|
$this->user = null;
|
||||||
|
Session::getSession()->purge();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,41 +4,175 @@
|
|||||||
namespace Icinga\Authentication;
|
namespace Icinga\Authentication;
|
||||||
|
|
||||||
use Iterator;
|
use Iterator;
|
||||||
use Icinga\Data\ConfigObject;
|
|
||||||
use Icinga\Authentication\User\UserBackend;
|
|
||||||
use Icinga\Authentication\User\UserBackendInterface;
|
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
|
use Icinga\Authentication\User\ExternalBackend;
|
||||||
|
use Icinga\Authentication\User\UserBackend;
|
||||||
|
use Icinga\Authentication\User\UserBackendInterface;
|
||||||
|
use Icinga\Data\ConfigObject;
|
||||||
|
use Icinga\Exception\AuthenticationException;
|
||||||
use Icinga\Exception\ConfigurationError;
|
use Icinga\Exception\ConfigurationError;
|
||||||
|
use Icinga\Exception\NotReadableError;
|
||||||
|
use Icinga\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate user backends created from config
|
* Iterate user backends created from config
|
||||||
*/
|
*/
|
||||||
class AuthChain implements Iterator
|
class AuthChain implements Authenticatable, Iterator
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Authentication config file
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const AUTHENTICATION_CONFIG = 'authentication';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error code if the authentication configuration was not readable
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const EPERM = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error code if the authentication configuration is empty
|
||||||
|
*/
|
||||||
|
const EEMPTY = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error code if all authentication methods failed
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const EFAIL = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error code if not all authentication methods were available
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const ENOTALL = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User backends configuration
|
* User backends configuration
|
||||||
*
|
*
|
||||||
* @var Config
|
* @var Config
|
||||||
*/
|
*/
|
||||||
private $config;
|
protected $config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The consecutive user backend while looping
|
* The consecutive user backend while looping
|
||||||
*
|
*
|
||||||
* @var UserBackendInterface
|
* @var UserBackendInterface
|
||||||
*/
|
*/
|
||||||
private $currentBackend;
|
protected $currentBackend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last error code
|
||||||
|
*
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
protected $error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether external user backends should be skipped on iteration
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $skipExternalBackends = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new authentication chain from config
|
* Create a new authentication chain from config
|
||||||
*
|
*
|
||||||
* @param Config $config User backends configuration
|
* @param Config $config User backends configuration
|
||||||
*/
|
*/
|
||||||
public function __construct(Config $config)
|
public function __construct(Config $config = null)
|
||||||
{
|
{
|
||||||
|
if ($config === null) {
|
||||||
|
try {
|
||||||
|
$this->config = Config::app(static::AUTHENTICATION_CONFIG);
|
||||||
|
} catch (NotReadableError $e) {
|
||||||
|
$this->config = new Config();
|
||||||
|
$this->error = static::EPERM;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function authenticate(User $user, $password)
|
||||||
|
{
|
||||||
|
$this->error = null;
|
||||||
|
$backendsTried = 0;
|
||||||
|
$backendsWithError = 0;
|
||||||
|
foreach ($this as $backend) {
|
||||||
|
++$backendsTried;
|
||||||
|
try {
|
||||||
|
$authenticated = $backend->authenticate($user, $password);
|
||||||
|
} catch (AuthenticationException $e) {
|
||||||
|
Logger::error($e);
|
||||||
|
++$backendsWithError;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($authenticated) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($backendsTried === 0) {
|
||||||
|
$this->error = static::EEMPTY;
|
||||||
|
} elseif ($backendsTried === $backendsWithError) {
|
||||||
|
$this->error = static::EFAIL;
|
||||||
|
} elseif ($backendsWithError) {
|
||||||
|
$this->error = static::ENOTALL;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last error code
|
||||||
|
*
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function getError()
|
||||||
|
{
|
||||||
|
return $this->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether authentication had errors
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasError()
|
||||||
|
{
|
||||||
|
return $this->error !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether to skip external user backends on iteration
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getSkipExternalBackends()
|
||||||
|
{
|
||||||
|
return $this->skipExternalBackends;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to skip external user backends on iteration
|
||||||
|
*
|
||||||
|
* @param bool $skipExternalBackends
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setSkipExternalBackends($skipExternalBackends = true)
|
||||||
|
{
|
||||||
|
$this->skipExternalBackends = (bool) $skipExternalBackends;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rewind the chain
|
* Rewind the chain
|
||||||
@ -52,7 +186,7 @@ class AuthChain implements Iterator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current user backend
|
* Get the current user backend
|
||||||
*
|
*
|
||||||
* @return UserBackendInterface
|
* @return UserBackendInterface
|
||||||
*/
|
*/
|
||||||
@ -62,7 +196,7 @@ class AuthChain implements Iterator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the key of the current user backend config
|
* Get the key of the current user backend config
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -82,7 +216,8 @@ class AuthChain implements Iterator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current user backend is valid, i.e. it's enabled and the config is valid
|
* Check whether the current user backend is valid, i.e. it's enabled, not an external user backend and whether its
|
||||||
|
* config is valid
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -94,7 +229,7 @@ class AuthChain implements Iterator
|
|||||||
}
|
}
|
||||||
|
|
||||||
$backendConfig = $this->config->current();
|
$backendConfig = $this->config->current();
|
||||||
if ((bool) $backendConfig->get('disabled', false) === true) {
|
if ((bool) $backendConfig->get('disabled', false)) {
|
||||||
$this->next();
|
$this->next();
|
||||||
return $this->valid();
|
return $this->valid();
|
||||||
}
|
}
|
||||||
@ -105,15 +240,20 @@ class AuthChain implements Iterator
|
|||||||
} catch (ConfigurationError $e) {
|
} catch (ConfigurationError $e) {
|
||||||
Logger::error(
|
Logger::error(
|
||||||
new ConfigurationError(
|
new ConfigurationError(
|
||||||
'Cannot create authentication backend "%s". An exception was thrown:',
|
'Can\'t create authentication backend "%s". An exception was thrown:', $name, $e
|
||||||
$name,
|
|
||||||
$e
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$this->next();
|
$this->next();
|
||||||
return $this->valid();
|
return $this->valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->getSkipExternalBackends()
|
||||||
|
&& $backend instanceof ExternalBackend
|
||||||
|
) {
|
||||||
|
$this->next();
|
||||||
|
return $this->valid();
|
||||||
|
}
|
||||||
|
|
||||||
$this->currentBackend = $backend;
|
$this->currentBackend = $backend;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
21
library/Icinga/Authentication/Authenticatable.php
Normal file
21
library/Icinga/Authentication/Authenticatable.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Authentication;
|
||||||
|
|
||||||
|
use Icinga\User;
|
||||||
|
|
||||||
|
interface Authenticatable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Authenticate a user
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @param string $password
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
* @throws \Icinga\Exception\AuthenticationException If authentication errors
|
||||||
|
*/
|
||||||
|
public function authenticate(User $user, $password);
|
||||||
|
}
|
@ -36,11 +36,7 @@ class ExternalBackend implements UserBackendInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this backend's name
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
*/
|
||||||
public function setName($name)
|
public function setName($name)
|
||||||
{
|
{
|
||||||
@ -49,30 +45,22 @@ class ExternalBackend implements UserBackendInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this backend's name
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate the given user
|
* {@inheritdoc}
|
||||||
*
|
|
||||||
* @param User $user
|
|
||||||
* @param string $password
|
|
||||||
*
|
|
||||||
* @return bool True on success, false on failure
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException In case authentication is not possible due to an error
|
|
||||||
*/
|
*/
|
||||||
public function authenticate(User $user, $password = null)
|
public function authenticate(User $user, $password = null)
|
||||||
{
|
{
|
||||||
if (isset($_SERVER['REMOTE_USER'])) {
|
if (isset($_SERVER['REMOTE_USER'])) {
|
||||||
$username = $_SERVER['REMOTE_USER'];
|
$username = $_SERVER['REMOTE_USER'];
|
||||||
$user->setRemoteUserInformation($username, 'REMOTE_USER');
|
$user->setExternalUserInformation($username, 'REMOTE_USER');
|
||||||
|
|
||||||
if ($this->stripUsernameRegexp) {
|
if ($this->stripUsernameRegexp) {
|
||||||
$stripped = preg_replace($this->stripUsernameRegexp, '', $username);
|
$stripped = preg_replace($this->stripUsernameRegexp, '', $username);
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
namespace Icinga\Authentication\User;
|
namespace Icinga\Authentication\User;
|
||||||
|
|
||||||
use Icinga\Exception\AuthenticationException;
|
use Icinga\Authentication\Authenticatable;
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for user backends
|
* Interface for user backends
|
||||||
*/
|
*/
|
||||||
interface UserBackendInterface
|
interface UserBackendInterface extends Authenticatable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Set this backend's name
|
* Set this backend's name
|
||||||
@ -26,16 +26,4 @@ interface UserBackendInterface
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName();
|
public function getName();
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticate the given user
|
|
||||||
*
|
|
||||||
* @param User $user
|
|
||||||
* @param string $password
|
|
||||||
*
|
|
||||||
* @return bool True on success, false on failure
|
|
||||||
*
|
|
||||||
* @throws AuthenticationException In case authentication is not possible due to an error
|
|
||||||
*/
|
|
||||||
public function authenticate(User $user, $password);
|
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ class PivotTable
|
|||||||
*/
|
*/
|
||||||
protected function getPaginationParameter($axis, $param, $default = null)
|
protected function getPaginationParameter($axis, $param, $default = null)
|
||||||
{
|
{
|
||||||
$request = Icinga::app()->getFrontController()->getRequest();
|
$request = Icinga::app()->getRequest();
|
||||||
|
|
||||||
$value = $request->getParam($param, '');
|
$value = $request->getParam($param, '');
|
||||||
if (strpos($value, ',') > 0) {
|
if (strpos($value, ',') > 0) {
|
||||||
|
@ -435,7 +435,7 @@ class SimpleQuery implements QueryInterface, Queryable, Iterator
|
|||||||
|
|
||||||
if ($itemsPerPage === null || $pageNumber === null) {
|
if ($itemsPerPage === null || $pageNumber === null) {
|
||||||
// Detect parameters from request
|
// Detect parameters from request
|
||||||
$request = Icinga::app()->getFrontController()->getRequest();
|
$request = Icinga::app()->getRequest();
|
||||||
if ($itemsPerPage === null) {
|
if ($itemsPerPage === null) {
|
||||||
$itemsPerPage = $request->getParam('limit', 25);
|
$itemsPerPage = $request->getParam('limit', 25);
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ namespace Icinga\Test {
|
|||||||
*/
|
*/
|
||||||
public function getRequestMock()
|
public function getRequestMock()
|
||||||
{
|
{
|
||||||
return Icinga::app()->getFrontController()->getRequest();
|
return Icinga::app()->getRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +57,7 @@ class User
|
|||||||
protected $additionalInformation = array();
|
protected $additionalInformation = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information if the user is external authenticated
|
* Information if the user is externally authenticated
|
||||||
*
|
*
|
||||||
* Keys:
|
* Keys:
|
||||||
*
|
*
|
||||||
@ -66,7 +66,7 @@ class User
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $remoteUserInformation = array();
|
protected $externalUserInformation = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of permissions
|
* Set of permissions
|
||||||
@ -96,6 +96,13 @@ class User
|
|||||||
*/
|
*/
|
||||||
protected $preferences;
|
protected $preferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user is authenticated using a HTTP authentication mechanism
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $isHttpUser = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a user object given the provided information
|
* Creates a user object given the provided information
|
||||||
*
|
*
|
||||||
@ -380,34 +387,57 @@ class User
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set additional remote user information
|
* Set additional external user information
|
||||||
*
|
*
|
||||||
* @param stirng $username
|
* @param string $username
|
||||||
* @param string $field
|
* @param string $field
|
||||||
*/
|
*/
|
||||||
public function setRemoteUserInformation($username, $field)
|
public function setExternalUserInformation($username, $field)
|
||||||
{
|
{
|
||||||
$this->remoteUserInformation = array($username, $field);
|
$this->externalUserInformation = array($username, $field);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get additional remote user information
|
* Get additional external user information
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getRemoteUserInformation()
|
public function getExternalUserInformation()
|
||||||
{
|
{
|
||||||
return $this->remoteUserInformation;
|
return $this->externalUserInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if user has remote user information set
|
* Return true if user has external user information set
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isRemoteUser()
|
public function isExternalUser()
|
||||||
{
|
{
|
||||||
return ! empty($this->remoteUserInformation);
|
return ! empty($this->externalUserInformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether the user is authenticated using a HTTP authentication mechanism
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getIsHttpUser()
|
||||||
|
{
|
||||||
|
return $this->isHttpUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether the user is authenticated using a HTTP authentication mechanism
|
||||||
|
*
|
||||||
|
* @param bool $isHttpUser
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setIsHttpUser($isHttpUser = true)
|
||||||
|
{
|
||||||
|
$this->isHttpUser = (bool) $isHttpUser;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,7 @@ namespace Icinga\Web\Controller;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Icinga\Application\Benchmark;
|
use Icinga\Application\Benchmark;
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Exception\Http\HttpMethodNotAllowedException;
|
use Icinga\Exception\Http\HttpMethodNotAllowedException;
|
||||||
use Icinga\Exception\IcingaException;
|
use Icinga\Exception\IcingaException;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
@ -52,7 +52,7 @@ class ActionController extends Zend_Controller_Action
|
|||||||
/**
|
/**
|
||||||
* Authentication manager
|
* Authentication manager
|
||||||
*
|
*
|
||||||
* @var Manager|null
|
* @var Auth|null
|
||||||
*/
|
*/
|
||||||
private $auth;
|
private $auth;
|
||||||
|
|
||||||
@ -124,12 +124,12 @@ class ActionController extends Zend_Controller_Action
|
|||||||
/**
|
/**
|
||||||
* Get the authentication manager
|
* Get the authentication manager
|
||||||
*
|
*
|
||||||
* @return Manager
|
* @return Auth
|
||||||
*/
|
*/
|
||||||
public function Auth()
|
public function Auth()
|
||||||
{
|
{
|
||||||
if ($this->auth === null) {
|
if ($this->auth === null) {
|
||||||
$this->auth = Manager::getInstance();
|
$this->auth = Auth::getInstance();
|
||||||
}
|
}
|
||||||
return $this->auth;
|
return $this->auth;
|
||||||
}
|
}
|
||||||
@ -455,7 +455,7 @@ class ActionController extends Zend_Controller_Action
|
|||||||
$notifications = Notification::getInstance();
|
$notifications = Notification::getInstance();
|
||||||
if ($notifications->hasMessages()) {
|
if ($notifications->hasMessages()) {
|
||||||
$notificationList = array();
|
$notificationList = array();
|
||||||
foreach ($notifications->getMessages() as $m) {
|
foreach ($notifications->popMessages() as $m) {
|
||||||
$notificationList[] = rawurlencode($m->type . ' ' . $m->message);
|
$notificationList[] = rawurlencode($m->type . ' ' . $m->message);
|
||||||
}
|
}
|
||||||
$resp->setHeader('X-Icinga-Notification', implode('&', $notificationList), true);
|
$resp->setHeader('X-Icinga-Notification', implode('&', $notificationList), true);
|
||||||
|
@ -77,6 +77,6 @@ class ModuleActionController extends ActionController
|
|||||||
public function postDispatchXhr()
|
public function postDispatchXhr()
|
||||||
{
|
{
|
||||||
parent::postDispatchXhr();
|
parent::postDispatchXhr();
|
||||||
$this->getResponse()->setHeader('X-Icinga-Module', $this->moduleName);
|
$this->getResponse()->setHeader('X-Icinga-Module', $this->moduleName, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use Zend_Form;
|
|||||||
use Zend_Form_Element;
|
use Zend_Form_Element;
|
||||||
use Zend_View_Interface;
|
use Zend_View_Interface;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Security\SecurityException;
|
use Icinga\Security\SecurityException;
|
||||||
use Icinga\Util\Translator;
|
use Icinga\Util\Translator;
|
||||||
@ -179,7 +179,7 @@ class Form extends Zend_Form
|
|||||||
/**
|
/**
|
||||||
* Authentication manager
|
* Authentication manager
|
||||||
*
|
*
|
||||||
* @var Manager|null
|
* @var Auth|null
|
||||||
*/
|
*/
|
||||||
private $auth;
|
private $auth;
|
||||||
|
|
||||||
@ -948,10 +948,17 @@ class Form extends Zend_Form
|
|||||||
*/
|
*/
|
||||||
public function addCsrfCounterMeasure()
|
public function addCsrfCounterMeasure()
|
||||||
{
|
{
|
||||||
if (! $this->tokenDisabled && $this->getElement($this->tokenElementName) === null) {
|
if (! $this->tokenDisabled) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
if (! $request->isXmlHttpRequest()
|
||||||
|
&& $request->getIsApiRequest()
|
||||||
|
) {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if ($this->getElement($this->tokenElementName) === null) {
|
||||||
$this->addElement(new CsrfCounterMeasure($this->tokenElementName));
|
$this->addElement(new CsrfCounterMeasure($this->tokenElementName));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1245,7 +1252,7 @@ class Form extends Zend_Form
|
|||||||
public function getRequest()
|
public function getRequest()
|
||||||
{
|
{
|
||||||
if ($this->request === null) {
|
if ($this->request === null) {
|
||||||
$this->request = Icinga::app()->getFrontController()->getRequest();
|
$this->request = Icinga::app()->getRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->request;
|
return $this->request;
|
||||||
@ -1344,12 +1351,12 @@ class Form extends Zend_Form
|
|||||||
/**
|
/**
|
||||||
* Get the authentication manager
|
* Get the authentication manager
|
||||||
*
|
*
|
||||||
* @return Manager
|
* @return Auth
|
||||||
*/
|
*/
|
||||||
public function Auth()
|
public function Auth()
|
||||||
{
|
{
|
||||||
if ($this->auth === null) {
|
if ($this->auth === null) {
|
||||||
$this->auth = Manager::getInstance();
|
$this->auth = Auth::getInstance();
|
||||||
}
|
}
|
||||||
return $this->auth;
|
return $this->auth;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,6 @@ class Button extends FormElement
|
|||||||
*/
|
*/
|
||||||
protected function getRequest()
|
protected function getRequest()
|
||||||
{
|
{
|
||||||
return Icinga::app()->getFrontController()->getRequest();
|
return Icinga::app()->getRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use RecursiveIterator;
|
|||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Data\ConfigObject;
|
use Icinga\Data\ConfigObject;
|
||||||
use Icinga\Exception\ConfigurationError;
|
use Icinga\Exception\ConfigurationError;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
@ -208,7 +208,7 @@ class Menu implements RecursiveIterator
|
|||||||
{
|
{
|
||||||
$menu = new static('menu');
|
$menu = new static('menu');
|
||||||
$menu->addMainMenuItems();
|
$menu->addMainMenuItems();
|
||||||
$auth = Manager::getInstance();
|
$auth = Auth::getInstance();
|
||||||
$manager = Icinga::app()->getModuleManager();
|
$manager = Icinga::app()->getModuleManager();
|
||||||
foreach ($manager->getLoadedModules() as $module) {
|
foreach ($manager->getLoadedModules() as $module) {
|
||||||
if ($auth->hasPermission($manager::MODULE_PERMISSION_NS . $module->getName())) {
|
if ($auth->hasPermission($manager::MODULE_PERMISSION_NS . $module->getName())) {
|
||||||
@ -223,7 +223,7 @@ class Menu implements RecursiveIterator
|
|||||||
*/
|
*/
|
||||||
protected function addMainMenuItems()
|
protected function addMainMenuItems()
|
||||||
{
|
{
|
||||||
$auth = Manager::getInstance();
|
$auth = Auth::getInstance();
|
||||||
|
|
||||||
if ($auth->isAuthenticated()) {
|
if ($auth->isAuthenticated()) {
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace Icinga\Web\Menu;
|
namespace Icinga\Web\Menu;
|
||||||
|
|
||||||
use RecursiveFilterIterator;
|
use RecursiveFilterIterator;
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Web\Menu;
|
use Icinga\Web\Menu;
|
||||||
|
|
||||||
class PermittedMenuItemFilter extends RecursiveFilterIterator
|
class PermittedMenuItemFilter extends RecursiveFilterIterator
|
||||||
@ -18,7 +18,7 @@ class PermittedMenuItemFilter extends RecursiveFilterIterator
|
|||||||
$item = $this->current();
|
$item = $this->current();
|
||||||
/** @var Menu $item */
|
/** @var Menu $item */
|
||||||
if (($permission = $item->getPermission()) !== null) {
|
if (($permission = $item->getPermission()) !== null) {
|
||||||
$auth = Manager::getInstance();
|
$auth = Auth::getInstance();
|
||||||
if (! $auth->isAuthenticated()) {
|
if (! $auth->isAuthenticated()) {
|
||||||
// Don't accept menu item because user is not authenticated and the menu item requires a permission
|
// Don't accept menu item because user is not authenticated and the menu item requires a permission
|
||||||
return false;
|
return false;
|
||||||
|
@ -17,86 +17,72 @@ use Icinga\Web\Session;
|
|||||||
*/
|
*/
|
||||||
class Notification
|
class Notification
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Notification type info
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const INFO = 'info';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification type error
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const ERROR = 'error';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification type success
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const SUCCESS = 'success';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification type warning
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const WARNING = 'warning';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the session key for notification messages
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const SESSION_KEY = 'session';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton instance
|
||||||
|
*
|
||||||
|
* @var self
|
||||||
|
*/
|
||||||
protected static $instance;
|
protected static $instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the platform is CLI
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
protected $isCli = false;
|
protected $isCli = false;
|
||||||
|
|
||||||
protected $session;
|
/**
|
||||||
|
* Notification messages
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
protected $messages = array();
|
protected $messages = array();
|
||||||
|
|
||||||
public static function info($msg)
|
/**
|
||||||
{
|
* Session
|
||||||
self::getInstance()->addMessage($msg, 'info');
|
*
|
||||||
}
|
* @var Session
|
||||||
|
*/
|
||||||
public static function success($msg)
|
protected $session;
|
||||||
{
|
|
||||||
self::getInstance()->addMessage($msg, 'success');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function warning($msg)
|
|
||||||
{
|
|
||||||
self::getInstance()->addMessage($msg, 'warning');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function error($msg)
|
|
||||||
{
|
|
||||||
self::getInstance()->addMessage($msg, 'error');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function addMessage($message, $type = 'info')
|
|
||||||
{
|
|
||||||
if (! in_array(
|
|
||||||
$type,
|
|
||||||
array(
|
|
||||||
'info',
|
|
||||||
'error',
|
|
||||||
'warning',
|
|
||||||
'success'
|
|
||||||
)
|
|
||||||
)) {
|
|
||||||
throw new ProgrammingError(
|
|
||||||
'"%s" is not a valid notification type',
|
|
||||||
$type
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isCli) {
|
|
||||||
$msg = sprintf('[%s] %s', $type, $message);
|
|
||||||
switch ($type) {
|
|
||||||
case 'info':
|
|
||||||
case 'success':
|
|
||||||
Logger::info($msg);
|
|
||||||
break;
|
|
||||||
case 'warning':
|
|
||||||
Logger::warn($msg);
|
|
||||||
break;
|
|
||||||
case 'error':
|
|
||||||
Logger::error($msg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->messages[] = (object) array(
|
|
||||||
'type' => $type,
|
|
||||||
'message' => $message,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasMessages()
|
|
||||||
{
|
|
||||||
return false === empty($this->messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMessages()
|
|
||||||
{
|
|
||||||
$messages = $this->messages;
|
|
||||||
$this->messages = array();
|
|
||||||
return $messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the notification instance
|
||||||
|
*/
|
||||||
final private function __construct()
|
final private function __construct()
|
||||||
{
|
{
|
||||||
if (Platform::isCli()) {
|
if (Platform::isCli()) {
|
||||||
@ -105,33 +91,130 @@ class Notification
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->session = Session::getSession();
|
$this->session = Session::getSession();
|
||||||
|
$messages = $this->session->get(self::SESSION_KEY);
|
||||||
$stored = $this->session->get('messages');
|
if (is_array($messages)) {
|
||||||
if (is_array($stored)) {
|
$this->messages = $messages;
|
||||||
$this->messages = $stored;
|
$this->session->delete(self::SESSION_KEY);
|
||||||
$this->session->set('messages', array());
|
|
||||||
$this->session->write();
|
$this->session->write();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Notification instance
|
||||||
|
*
|
||||||
|
* @return Notification
|
||||||
|
*/
|
||||||
public static function getInstance()
|
public static function getInstance()
|
||||||
{
|
{
|
||||||
if (self::$instance === null) {
|
if (self::$instance === null) {
|
||||||
self::$instance = new Notification();
|
self::$instance = new self();
|
||||||
}
|
}
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add info notification
|
||||||
|
*
|
||||||
|
* @param string $msg
|
||||||
|
*/
|
||||||
|
public static function info($msg)
|
||||||
|
{
|
||||||
|
self::getInstance()->addMessage($msg, self::INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add error notification
|
||||||
|
*
|
||||||
|
* @param string $msg
|
||||||
|
*/
|
||||||
|
public static function error($msg)
|
||||||
|
{
|
||||||
|
self::getInstance()->addMessage($msg, self::ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add success notification
|
||||||
|
*
|
||||||
|
* @param string $msg
|
||||||
|
*/
|
||||||
|
public static function success($msg)
|
||||||
|
{
|
||||||
|
self::getInstance()->addMessage($msg, self::SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add warning notification
|
||||||
|
*
|
||||||
|
* @param string $msg
|
||||||
|
*/
|
||||||
|
public static function warning($msg)
|
||||||
|
{
|
||||||
|
self::getInstance()->addMessage($msg, self::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a notification message
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param string $type
|
||||||
|
*/
|
||||||
|
protected function addMessage($message, $type = self::INFO)
|
||||||
|
{
|
||||||
|
if ($this->isCli) {
|
||||||
|
$msg = sprintf('[%s] %s', $type, $message);
|
||||||
|
switch ($type) {
|
||||||
|
case self::INFO:
|
||||||
|
case self::SUCCESS:
|
||||||
|
Logger::info($msg);
|
||||||
|
break;
|
||||||
|
case self::ERROR:
|
||||||
|
Logger::error($msg);
|
||||||
|
break;
|
||||||
|
case self::WARNING:
|
||||||
|
Logger::warning($msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->messages[] = (object) array(
|
||||||
|
'type' => $type,
|
||||||
|
'message' => $message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop the notification messages
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function popMessages()
|
||||||
|
{
|
||||||
|
$messages = $this->messages;
|
||||||
|
$this->messages = array();
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether notification messages have been added
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasMessages()
|
||||||
|
{
|
||||||
|
return ! empty($this->messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the notification instance
|
||||||
|
*/
|
||||||
final public function __destruct()
|
final public function __destruct()
|
||||||
{
|
{
|
||||||
if ($this->isCli) {
|
if ($this->isCli) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->session->get('messages') !== $this->messages) {
|
if ($this->hasMessages() && $this->session->get('messages') !== $this->messages) {
|
||||||
$this->session->set('messages', $this->messages);
|
$this->session->set(self::SESSION_KEY, $this->messages);
|
||||||
}
|
|
||||||
$this->session->write();
|
$this->session->write();
|
||||||
|
}
|
||||||
unset($this->session);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,24 +7,46 @@ use Zend_Controller_Request_Http;
|
|||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request to handle special attributes
|
* A request
|
||||||
*/
|
*/
|
||||||
class Request extends Zend_Controller_Request_Http
|
class Request extends Zend_Controller_Request_Http
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* User object
|
* User if authenticated
|
||||||
*
|
*
|
||||||
* @var User
|
* @var User|null
|
||||||
*/
|
*/
|
||||||
private $user;
|
protected $user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Unique identifier
|
||||||
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $uniqueId;
|
protected $uniqueId;
|
||||||
|
|
||||||
private $url;
|
/**
|
||||||
|
* Request URL
|
||||||
|
*
|
||||||
|
* @var Url
|
||||||
|
*/
|
||||||
|
protected $url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether the request seems to be an API request
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getIsApiRequest()
|
||||||
|
{
|
||||||
|
return $this->getHeader('Accept') === 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the request URL
|
||||||
|
*
|
||||||
|
* @return Url
|
||||||
|
*/
|
||||||
public function getUrl()
|
public function getUrl()
|
||||||
{
|
{
|
||||||
if ($this->url === null) {
|
if ($this->url === null) {
|
||||||
@ -34,31 +56,38 @@ class Request extends Zend_Controller_Request_Http
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setter for user
|
* Get the user if authenticated
|
||||||
*
|
*
|
||||||
* @param User $user
|
* @return User|null
|
||||||
*/
|
|
||||||
public function setUser(User $user)
|
|
||||||
{
|
|
||||||
$this->user = $user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for user
|
|
||||||
*
|
|
||||||
* @return User
|
|
||||||
*/
|
*/
|
||||||
public function getUser()
|
public function getUser()
|
||||||
{
|
{
|
||||||
return $this->user;
|
return $this->user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the authenticated user
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setUser(User $user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes an ID unique to this request, to prevent id collisions in different containers
|
* Makes an ID unique to this request, to prevent id collisions in different containers
|
||||||
*
|
*
|
||||||
* Call this whenever an ID might show up multiple times in different containers. This function is useful
|
* Call this whenever an ID might show up multiple times in different containers. This function is useful
|
||||||
* for ensuring unique ids on sites, even if we combine the HTML of different requests into one site,
|
* for ensuring unique ids on sites, even if we combine the HTML of different requests into one site,
|
||||||
* while still being able to reference elements uniquely in the same request.
|
* while still being able to reference elements uniquely in the same request.
|
||||||
|
*
|
||||||
|
* @param string $id
|
||||||
|
*
|
||||||
|
* @return string The id suffixed w/ an identifier unique to this request
|
||||||
*/
|
*/
|
||||||
public function protectId($id)
|
public function protectId($id)
|
||||||
{
|
{
|
||||||
|
@ -8,18 +8,125 @@ use Icinga\Application\Icinga;
|
|||||||
|
|
||||||
class Response extends Zend_Controller_Response_Http
|
class Response extends Zend_Controller_Response_Http
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Redirect URL
|
||||||
|
*
|
||||||
|
* @var Url|null
|
||||||
|
*/
|
||||||
|
protected $redirectUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request
|
||||||
|
*
|
||||||
|
* @var Request
|
||||||
|
*/
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to send the rerender layout header on XHR
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $rerenderLayout = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the redirect URL
|
||||||
|
*
|
||||||
|
* @return Url|null
|
||||||
|
*/
|
||||||
|
protected function getRedirectUrl()
|
||||||
|
{
|
||||||
|
return $this->redirectUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the redirect URL
|
||||||
|
*
|
||||||
|
* Unlike {@link setRedirect()} this method only sets a redirect URL on the response for later usage.
|
||||||
|
* {@link prepare()} will take care of the correct redirect handling and HTTP headers on XHR and "normal" browser
|
||||||
|
* requests.
|
||||||
|
*
|
||||||
|
* @param string|Url $redirectUrl
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function setRedirectUrl($redirectUrl)
|
||||||
|
{
|
||||||
|
if (! $redirectUrl instanceof Url) {
|
||||||
|
$redirectUrl = Url::fromPath((string) $redirectUrl);
|
||||||
|
}
|
||||||
|
$redirectUrl->getParams()->setSeparator('&');
|
||||||
|
$this->redirectUrl = $redirectUrl;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the request
|
||||||
|
*
|
||||||
|
* @return Request
|
||||||
|
*/
|
||||||
|
public function getRequest()
|
||||||
|
{
|
||||||
|
if ($this->request === null) {
|
||||||
|
$this->request = Icinga::app()->getRequest();
|
||||||
|
}
|
||||||
|
return $this->request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether to send the rerender layout header on XHR
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getRerenderLayout()
|
||||||
|
{
|
||||||
|
return $this->rerenderLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether to send the rerender layout header on XHR
|
||||||
|
*
|
||||||
|
* @param bool $rerenderLayout
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setRerenderLayout($rerenderLayout = true)
|
||||||
|
{
|
||||||
|
$this->rerenderLayout = (bool) $rerenderLayout;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the request before sending
|
||||||
|
*/
|
||||||
|
protected function prepare()
|
||||||
|
{
|
||||||
|
$redirectUrl = $this->getRedirectUrl();
|
||||||
|
if ($this->getRequest()->isXmlHttpRequest()) {
|
||||||
|
if ($redirectUrl !== null) {
|
||||||
|
$this->setHeader('X-Icinga-Redirect', rawurlencode($redirectUrl->getAbsoluteUrl()), true);
|
||||||
|
if ($this->getRerenderLayout()) {
|
||||||
|
$this->setHeader('X-Icinga-Rerender-Layout', 'yes', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->getRerenderLayout()) {
|
||||||
|
$this->setHeader('X-Icinga-Container', 'layout', true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($redirectUrl !== null) {
|
||||||
|
$this->setRedirect($redirectUrl->getAbsoluteUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to the given URL and exit immediately
|
||||||
|
*
|
||||||
|
* @param string|Url $url
|
||||||
|
*/
|
||||||
public function redirectAndExit($url)
|
public function redirectAndExit($url)
|
||||||
{
|
{
|
||||||
if (! $url instanceof Url) {
|
$this->setRedirectUrl($url);
|
||||||
$url = Url::fromPath($url);
|
|
||||||
}
|
|
||||||
$url->getParams()->setSeparator('&');
|
|
||||||
|
|
||||||
if (Icinga::app()->getFrontController()->getRequest()->isXmlHttpRequest()) {
|
|
||||||
$this->setHeader('X-Icinga-Redirect', rawurlencode($url->getAbsoluteUrl()));
|
|
||||||
} else {
|
|
||||||
$this->setRedirect($url->getAbsoluteUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
$session = Session::getSession();
|
$session = Session::getSession();
|
||||||
if ($session->hasChanged()) {
|
if ($session->hasChanged()) {
|
||||||
@ -29,4 +136,13 @@ class Response extends Zend_Controller_Response_Http
|
|||||||
$this->sendHeaders();
|
$this->sendHeaders();
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function sendHeaders()
|
||||||
|
{
|
||||||
|
$this->prepare();
|
||||||
|
return parent::sendHeaders();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ class Url
|
|||||||
if ($app->isCli()) {
|
if ($app->isCli()) {
|
||||||
return new FakeRequest();
|
return new FakeRequest();
|
||||||
} else {
|
} else {
|
||||||
return $app->getFrontController()->getRequest();
|
return $app->getRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ namespace Icinga\Web;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Zend_View_Abstract;
|
use Zend_View_Abstract;
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Util\Translator;
|
use Icinga\Util\Translator;
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ class View extends Zend_View_Abstract
|
|||||||
/**
|
/**
|
||||||
* Authentication manager
|
* Authentication manager
|
||||||
*
|
*
|
||||||
* @var \Icinga\Authentication\Manager|null
|
* @var Auth|null
|
||||||
*/
|
*/
|
||||||
private $auth;
|
private $auth;
|
||||||
|
|
||||||
@ -164,12 +164,12 @@ class View extends Zend_View_Abstract
|
|||||||
/**
|
/**
|
||||||
* Get the authentication manager
|
* Get the authentication manager
|
||||||
*
|
*
|
||||||
* @return Manager
|
* @return Auth
|
||||||
*/
|
*/
|
||||||
public function Auth()
|
public function Auth()
|
||||||
{
|
{
|
||||||
if ($this->auth === null) {
|
if ($this->auth === null) {
|
||||||
$this->auth = Manager::getInstance();
|
$this->auth = Auth::getInstance();
|
||||||
}
|
}
|
||||||
return $this->auth;
|
return $this->auth;
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
namespace Icinga\Web\View;
|
namespace Icinga\Web\View;
|
||||||
|
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Web\Widget;
|
use Icinga\Web\Widget;
|
||||||
|
|
||||||
$this->addHelperFunction('auth', function () {
|
$this->addHelperFunction('auth', function () {
|
||||||
return Manager::getInstance();
|
return Auth::getInstance();
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->addHelperFunction('widget', function ($name, $options = null) {
|
$this->addHelperFunction('widget', function ($name, $options = null) {
|
||||||
|
@ -540,11 +540,17 @@ class FilterEditor extends AbstractWidget
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setColumns(array $columns)
|
||||||
|
{
|
||||||
|
$this->cachedColumnSelect = $this->arrayForSelect($columns);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function selectColumn(Filter $filter = null)
|
protected function selectColumn(Filter $filter = null)
|
||||||
{
|
{
|
||||||
$active = $filter === null ? null : $filter->getColumn();
|
$active = $filter === null ? null : $filter->getColumn();
|
||||||
|
|
||||||
if ($this->query === null) {
|
if ($this->cachedColumnSelect === null && $this->query === null) {
|
||||||
return sprintf(
|
return sprintf(
|
||||||
'<input type="text" name="%s" value="%s" />',
|
'<input type="text" name="%s" value="%s" />',
|
||||||
$this->elementId('column', $filter),
|
$this->elementId('column', $filter),
|
||||||
|
@ -116,7 +116,7 @@ class SortBox extends AbstractWidget
|
|||||||
{
|
{
|
||||||
if ($this->query !== null) {
|
if ($this->query !== null) {
|
||||||
if ($request === null) {
|
if ($request === null) {
|
||||||
$request = Icinga::app()->getFrontController()->getRequest();
|
$request = Icinga::app()->getRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($sort = $request->getParam('sort'))) {
|
if (($sort = $request->getParam('sort'))) {
|
||||||
|
@ -91,6 +91,13 @@ class Tab extends AbstractWidget
|
|||||||
*/
|
*/
|
||||||
private $targetBlank = false;
|
private $targetBlank = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data base target that determines if the link will be opened in a side-bar or in the main container
|
||||||
|
*
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
|
private $baseTarget = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an icon image for this tab
|
* Sets an icon image for this tab
|
||||||
*
|
*
|
||||||
@ -210,6 +217,11 @@ class Tab extends AbstractWidget
|
|||||||
$this->targetBlank = $value;
|
$this->targetBlank = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setBaseTarget($value)
|
||||||
|
{
|
||||||
|
$this->baseTarget = $value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Tab with the given properties
|
* Create a new Tab with the given properties
|
||||||
*
|
*
|
||||||
@ -274,6 +286,10 @@ class Tab extends AbstractWidget
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->baseTarget !== null) {
|
||||||
|
$tagParams['data-base-target'] = $this->baseTarget;
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->icon !== null) {
|
if ($this->icon !== null) {
|
||||||
if (strpos($this->icon, '.') === false) {
|
if (strpos($this->icon, '.') === false) {
|
||||||
$caption = $view->icon($this->icon) . $caption;
|
$caption = $view->icon($this->icon) . $caption;
|
||||||
|
@ -309,7 +309,7 @@ EOT;
|
|||||||
|
|
||||||
private function renderRefreshTab()
|
private function renderRefreshTab()
|
||||||
{
|
{
|
||||||
$url = Icinga::app()->getFrontController()->getRequest()->getUrl();
|
$url = Icinga::app()->getRequest()->getUrl();
|
||||||
$tab = $this->get($this->getActiveName());
|
$tab = $this->get($this->getActiveName());
|
||||||
|
|
||||||
if ($tab !== null) {
|
if ($tab !== null) {
|
||||||
|
@ -15,7 +15,7 @@ if (count($servicegroups) === 0) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<table class="groupview" data-base-target="_next">
|
<table class="groupview action" data-base-target="_next">
|
||||||
<thead>
|
<thead>
|
||||||
<th><?= $this->translate('Last Problem'); ?></th>
|
<th><?= $this->translate('Last Problem'); ?></th>
|
||||||
<th><?= $this->translate('Service Group'); ?></th>
|
<th><?= $this->translate('Service Group'); ?></th>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Icinga\Module\Monitoring\Web\Menu;
|
namespace Icinga\Module\Monitoring\Web\Menu;
|
||||||
|
|
||||||
use Icinga\Authentication\Manager;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
use Icinga\Data\Filterable;
|
use Icinga\Data\Filterable;
|
||||||
use Icinga\Web\Menu;
|
use Icinga\Web\Menu;
|
||||||
@ -27,7 +27,7 @@ class MonitoringMenuItemRenderer extends MenuItemRenderer
|
|||||||
protected static function applyRestriction($restriction, Filterable $filterable)
|
protected static function applyRestriction($restriction, Filterable $filterable)
|
||||||
{
|
{
|
||||||
$restrictions = Filter::matchAny();
|
$restrictions = Filter::matchAny();
|
||||||
foreach (Manager::getInstance()->getRestrictions($restriction) as $filter) {
|
foreach (Auth::getInstance()->getRestrictions($restriction) as $filter) {
|
||||||
$restrictions->addFilter(Filter::fromQueryString($filter));
|
$restrictions->addFilter(Filter::fromQueryString($filter));
|
||||||
}
|
}
|
||||||
$filterable->applyFilter($restrictions);
|
$filterable->applyFilter($restrictions);
|
||||||
|
@ -19,7 +19,7 @@ $maxProgress = @max(array_keys(array_filter(
|
|||||||
|
|
||||||
$notifications = Notification::getInstance();
|
$notifications = Notification::getInstance();
|
||||||
if ($notifications->hasMessages()) {
|
if ($notifications->hasMessages()) {
|
||||||
foreach ($notifications->getMessages() as $m) {
|
foreach ($notifications->popMessages() as $m) {
|
||||||
echo '<li class="' . $m->type . '">' . $this->escape($m->message) . '</li>';
|
echo '<li class="' . $m->type . '">' . $this->escape($m->message) . '</li>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,13 +313,16 @@
|
|||||||
*/
|
*/
|
||||||
ActionTable.prototype.onRowClicked = function (event) {
|
ActionTable.prototype.onRowClicked = function (event) {
|
||||||
var self = event.data.self;
|
var self = event.data.self;
|
||||||
var $tr = $(event.target).closest('tr');
|
var $target = $(event.target);
|
||||||
|
var $tr = $target.closest('tr');
|
||||||
var table = new Selection($tr.closest('table.action')[0], self.icinga);
|
var table = new Selection($tr.closest('table.action')[0], self.icinga);
|
||||||
|
|
||||||
// allow form actions in table rows to pass through
|
// some rows may contain form actions that trigger a different action, pass those through
|
||||||
if ($(event.target).closest('form').length) {
|
if (!$target.hasClass('rowaction') && $target.closest('form').length &&
|
||||||
|
($target.closest('a').length || $target.closest('button').length)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
@ -354,18 +354,16 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special checks for link clicks in multiselect rows
|
// Special checks for link clicks in action tables
|
||||||
if (! $a.is('tr[href]') && $a.closest('tr[href]').length > 0 && $a.closest('table.multiselect').length > 0) {
|
if (! $a.is('tr[href]') && $a.closest('table.action').length > 0) {
|
||||||
|
|
||||||
// ignoray clicks to ANY link with special key pressed
|
// ignoray clicks to ANY link with special key pressed
|
||||||
if (event.ctrlKey || event.metaKey || event.shiftKey)
|
if ($a.closest('table.multiselect').length > 0 && (event.ctrlKey || event.metaKey || event.shiftKey)) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore inner links matching the row URL
|
// ignore inner links matching the row URL
|
||||||
if ($a.attr('href') === $a.closest('tr[href]').attr('href'))
|
if ($a.attr('href') === $a.closest('tr[href]').attr('href')) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,10 @@
|
|||||||
icinga.logger.debug('History state', event.originalEvent.state);
|
icinga.logger.debug('History state', event.originalEvent.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.applyLocationBar();
|
// keep the last pushed url in sync with history changes
|
||||||
|
self.lastPushUrl = location.href;
|
||||||
|
|
||||||
|
self.applyLocationBar();
|
||||||
},
|
},
|
||||||
|
|
||||||
applyLocationBar: function (onload) {
|
applyLocationBar: function (onload) {
|
||||||
|
@ -587,8 +587,6 @@
|
|||||||
if (req.$target[0].id === 'col1') {
|
if (req.$target[0].id === 'col1') {
|
||||||
self.icinga.behaviors.navigation.resetActive();
|
self.icinga.behaviors.navigation.resetActive();
|
||||||
}
|
}
|
||||||
} else if ($(el).closest('table.action').length) {
|
|
||||||
$(el).closest('table.action').find('.active').removeClass('active');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -604,8 +602,6 @@
|
|||||||
}
|
}
|
||||||
// Interrupt .each, only on menu item shall be active
|
// Interrupt .each, only on menu item shall be active
|
||||||
return false;
|
return false;
|
||||||
} else if ($(el).closest('table.action').length) {
|
|
||||||
$el.addClass('active');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user