mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-31 01:34:09 +02:00
lib: Implement AuthChain::authenticate()
Right now the LoginController has all the authentication which is kind of a mess. Further, the upcoming basic access authentication has to reuse this code. Thus AuthChain::authenticate() is introduced to handle both cases. refs #9660
This commit is contained in:
parent
4d44a0625c
commit
745e30259d
@ -4,40 +4,181 @@
|
|||||||
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External user backends are excluded by the iterator
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const IT_MODE_NOT_EXTERNAL = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mode of iteration
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $iteratorMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@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 the iterator mode
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getIteratorMode()
|
||||||
|
{
|
||||||
|
return $this->iteratorMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the iterator mode
|
||||||
|
*
|
||||||
|
* @param int $iteratorMode
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setIteratorMode($iteratorMode)
|
||||||
|
{
|
||||||
|
$this->iteratorMode = (int) $iteratorMode;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,7 +193,7 @@ class AuthChain implements Iterator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current user backend
|
* Get the current user backend
|
||||||
*
|
*
|
||||||
* @return UserBackendInterface
|
* @return UserBackendInterface
|
||||||
*/
|
*/
|
||||||
@ -62,7 +203,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 +223,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
|
||||||
*/
|
*/
|
||||||
@ -105,15 +247,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->iteratorMode === static::IT_MODE_NOT_EXTERNAL
|
||||||
|
&& $backend instanceof ExternalBackend
|
||||||
|
) {
|
||||||
|
$this->next();
|
||||||
|
return $this->valid();
|
||||||
|
}
|
||||||
|
|
||||||
$this->currentBackend = $backend;
|
$this->currentBackend = $backend;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user