Authentication: Add backend to handle external authentication

Drop external auth configuration from config.ini and move
implementation into a single backend provider named
'autologin'. This provider can strip realm names from
username with a custom regexp.

fixes #6081
This commit is contained in:
Marius Hein 2014-06-03 17:59:22 +02:00
parent a0459d0172
commit 29f593a357
8 changed files with 144 additions and 33 deletions

View File

@ -1,3 +1,9 @@
[autologin]
backend = autologin
;
; If you want to strip the domain
; strip_username_regexp = /\@[^$]+$/
[internal_ldap_authentication]
backend = ldap
resource = internal_ldap

View File

@ -30,6 +30,7 @@
# namespace Icinga\Application\Controllers;
use Icinga\Authentication\Backend\AutoLoginBackend;
use Icinga\Web\Controller\ActionController;
use Icinga\Authentication\Manager as AuthManager;
use Icinga\Form\Authentication\LoginForm;
@ -62,6 +63,8 @@ class AuthenticationController extends ActionController
$this->view->form = new LoginForm();
$this->view->form->setRequest($this->_request);
$this->view->title = $this->translate('Icingaweb Login');
$user = new User('');
$password = '';
try {
$redirectUrl = Url::fromPath($this->_request->getParam('redirect', 'dashboard'));
@ -71,29 +74,49 @@ class AuthenticationController extends ActionController
}
$auth = AuthManager::getInstance();
if ($auth->isAuthenticated()) {
$this->redirectNow($redirectUrl);
}
if ($this->view->form->isSubmittedAndValid()) {
try {
$config = Config::app('authentication');
} catch (NotReadableError $e) {
Logger::error(
new Exception('Cannot load authentication configuration. An exception was thrown:', 0, $e)
);
throw new ConfigurationError(
'No authentication methods available. It seems that none authentication method has been set'
. ' up. Please check the system log or Icinga Web 2 log for more information'
);
try {
$config = Config::app('authentication');
} catch (NotReadableError $e) {
Logger::error(
new Exception('Cannot load authentication configuration. An exception was thrown:', 0, $e)
);
throw new ConfigurationError(
'No authentication methods available. It seems that none authentication method has been set'
. ' up. Please check the system log or Icinga Web 2 log for more information'
);
}
$chain = new AuthChain($config);
if ($this->getRequest()->isGet()) {
foreach ($chain as $backend) {
if ($backend instanceof AutoLoginBackend) {
$authenticated = $backend->authenticate($user, $password);
if ($authenticated === true) {
$auth->setAuthenticated($user);
$this->redirectNow($redirectUrl);
}
}
}
} elseif ($this->view->form->isSubmittedAndValid()) {
$user = new User($this->view->form->getValue('username'));
$password = $this->view->form->getValue('password');
$backendsTried = 0;
$backendsWithError = 0;
$chain = new AuthChain($config);
foreach ($chain as $backend) {
++$backendsTried;
if ($backend instanceof AutoLoginBackend) {
continue;
}
try {
$authenticated = $backend->authenticate($user, $password);
} catch (AuthenticationException $e) {

View File

@ -6,6 +6,11 @@
; The backends will be processed from top to bottom using the first backend for authentication which reports that
; the user trying to log in is available.
[autologin]
backend = autologin
;
; If you want to strip the domain
; strip_username_regexp = /\@[^$]+$/
[internal_ldap_authentication]
@ldap_auth_disabled@

View File

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

View File

@ -211,23 +211,6 @@ class Web extends ApplicationBootstrap
if ($authenticationManager->isAuthenticated() === true) {
$this->user = $authenticationManager->getUser();
return $this;
}
try {
$config = Config::app();
} catch (NotReadableError $e) {
Logger::error(
new Exception('Cannot load global configuration (config.ini). An exception was thrown:', 0, $e)
);
$config = null;
}
if ($config !== null && $config->global !== null &&
$config->global->get('authenticationMode', 'internal') === 'external'
) {
$authenticationManager->authenticateFromRemoteUser();
$this->user = $authenticationManager->getUser();
}
return $this;

View File

@ -0,0 +1,89 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Authentication\Backend;
use Icinga\Authentication\UserBackend;
use Icinga\User;
use \Zend_Config;
/**
* Test login with external authentication mechanism, e.g. Apache
*/
class AutoLoginBackend extends UserBackend
{
/**
* Regexp expression to strip values from a username
*
* @var string
*/
private $stripUsernameRegexp;
/**
* Create new autologin backend
*
* @param Zend_Config $config
*/
public function __construct(Zend_Config $config)
{
$this->stripUsernameRegexp = $config->get('strip_username_regexp');
}
/**
* (PHP 5 &gt;= 5.1.0)<br/>
* Count elements of an object
* @link http://php.net/manual/en/countable.count.php
* @return int The custom count as an integer.
* </p>
* <p>
* The return value is cast to an integer.
*/
public function count()
{
return 1;
}
/**
* Test whether the given user exists
*
* @param User $user
*
* @return bool
*/
public function hasUser(User $user)
{
if (isset($_SERVER['PHP_AUTH_USER'])
&& isset($_SERVER['AUTH_TYPE'])
&& in_array($_SERVER['AUTH_TYPE'], array('Basic', 'Digest')) === true
) {
$username = filter_var(
$_SERVER['PHP_AUTH_USER'],
FILTER_SANITIZE_STRING,
FILTER_FLAG_ENCODE_HIGH|FILTER_FLAG_ENCODE_LOW
);
if ($username !== false) {
if ($this->stripUsernameRegexp !== null) {
$username = preg_replace($this->stripUsernameRegexp, '', $username);
}
return true;
}
}
return false;
}
/**
* Authenticate
*
* @param User $user
* @param string $password
*
* @return bool
*/
public function authenticate(User $user, $password)
{
return $this->hasUser($user);
}
}

View File

@ -30,6 +30,7 @@
namespace Icinga\Authentication;
use Countable;
use Icinga\Authentication\Backend\AutoLoginBackend;
use Zend_Config;
use Icinga\Authentication\Backend\DbUserBackend;
use Icinga\Authentication\Backend\LdapUserBackend;
@ -84,6 +85,11 @@ abstract class UserBackend implements Countable
}
return new $backendConfig->class($backendConfig);
}
if ($name === 'autologin') {
$backend = new AutoLoginBackend($backendConfig);
$backend->setName($name);
return $backend;
}
if ($backendConfig->resource === null) {
throw new ConfigurationError(
'Authentication configuration for backend "' . $name

View File

@ -287,6 +287,9 @@ class Monitoring_ListController extends Controller
)
)->getQuery();
$this->view->contacts = $query->paginate();
file_put_contents('/tmp/query.txt', (string) $query);
$this->setupSortControl(array(
'contact_name' => 'Name',
'contact_alias' => 'Alias',