Merge branch 'bugfix/fix-auth-manager-4641'
fixes #4641 fixes #4590 fixes #4593
This commit is contained in:
commit
649dcd434c
|
@ -27,7 +27,7 @@
|
|||
# namespace Icinga\Application\Controllers;
|
||||
|
||||
use \Icinga\Web\Controller\ActionController;
|
||||
use \Icinga\Authentication\Credentials;
|
||||
use \Icinga\Authentication\Credential;
|
||||
use \Icinga\Authentication\Manager as AuthManager;
|
||||
use \Icinga\Form\Authentication\LoginForm;
|
||||
use \Icinga\Exception\ConfigurationError;
|
||||
|
@ -60,7 +60,7 @@ class AuthenticationController extends ActionController
|
|||
public function loginAction()
|
||||
{
|
||||
$this->replaceLayout = true;
|
||||
$credentials = new Credentials();
|
||||
$credentials = new Credential();
|
||||
$this->view->form = new LoginForm();
|
||||
$this->view->form->setRequest($this->_request);
|
||||
$this->view->title = "Icinga Web Login";
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Icinga\Form\Config\Authentication;
|
|||
|
||||
use \Icinga\Authentication\Backend\DbUserBackend;
|
||||
use \Icinga\Application\DbAdapterFactory;
|
||||
use \Zend_Config;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying database authentication backends
|
||||
|
@ -126,10 +127,13 @@ class DbBackendForm extends BaseBackendForm
|
|||
{
|
||||
try {
|
||||
$name = $this->getBackendName();
|
||||
$db = DbAdapterFactory::getDbAdapter(
|
||||
$this->getValue('backend_' . $this->filterName($name) . '_' . 'resource')
|
||||
);
|
||||
$dbBackend = new DbUserBackend($db);
|
||||
$dbBackend = new DbUserBackend(new Zend_Config(
|
||||
array(
|
||||
'backend' => 'db',
|
||||
'target' => 'user',
|
||||
'resource' => $this->getValue('backend_' . $this->filterName($name) . '_resource'),
|
||||
)
|
||||
));
|
||||
if ($dbBackend->getUserCount() < 1) {
|
||||
$this->addErrorMessage("No users found under the specified database backend");
|
||||
return false;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<?php
|
||||
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/**
|
||||
* This file is part of Icinga 2 Web.
|
||||
|
@ -29,12 +28,19 @@
|
|||
|
||||
namespace Icinga\Authentication\Backend;
|
||||
|
||||
use \Exception;
|
||||
use \stdClass;
|
||||
use \Zend_Config;
|
||||
use \Zend_Db;
|
||||
use \Zend_Db_Adapter_Abstract;
|
||||
use \Icinga\Application\DbAdapterFactory;
|
||||
use \Icinga\Exception\ProgrammingError;
|
||||
use \Icinga\User;
|
||||
use \Icinga\Authentication\UserBackend;
|
||||
use \Icinga\Authentication\Credentials;
|
||||
use \Icinga\Authentication\Credential;
|
||||
use \Icinga\Authentication;
|
||||
use \Icinga\Application\Logger;
|
||||
use \Icinga\Exception\ConfigurationError;
|
||||
|
||||
/**
|
||||
* User authentication backend (@see Icinga\Authentication\UserBackend) for
|
||||
|
@ -47,57 +53,93 @@ use \Icinga\Application\Logger;
|
|||
class DbUserBackend implements UserBackend
|
||||
{
|
||||
/**
|
||||
* Mapping of all table column names
|
||||
* Table map for column username
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const USER_NAME_COLUMN = 'username';
|
||||
|
||||
const USER_NAME_COLUMN = 'username';
|
||||
/**
|
||||
* Table map for column salt
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const SALT_COLUMN = 'salt';
|
||||
|
||||
const SALT_COLUMN = 'salt';
|
||||
/**
|
||||
* Table map for column password
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PASSWORD_COLUMN = 'password';
|
||||
|
||||
const PASSWORD_COLUMN = 'password';
|
||||
|
||||
const ACTIVE_COLUMN = 'active';
|
||||
/**
|
||||
* Table map for column active
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const ACTIVE_COLUMN = 'active';
|
||||
|
||||
/**
|
||||
* The database connection that will be used for fetching users
|
||||
*
|
||||
* @var \Zend_Db
|
||||
* @var Zend_Db
|
||||
*/
|
||||
private $db = null;
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* The name of the user table
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
private $userTable = "account";
|
||||
private $userTable = 'account';
|
||||
|
||||
/**
|
||||
* Name of the backend
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Create a DbUserBackend
|
||||
*
|
||||
* @param Zend_Db The database that provides the authentication data
|
||||
* @param Zend_Config $config The database that provides the authentication data
|
||||
* @throws ConfigurationError
|
||||
*/
|
||||
public function __construct($database)
|
||||
public function __construct(Zend_Config $config)
|
||||
{
|
||||
$this->db = $database;
|
||||
$this->name = $config->name;
|
||||
|
||||
// Test if the connection is available
|
||||
if ($config->resource instanceof Zend_Db_Adapter_Abstract) {
|
||||
$this->db = $config->resource;
|
||||
} else {
|
||||
$this->db = DbAdapterFactory::getDbAdapter($config->resource);
|
||||
}
|
||||
|
||||
// Throw any errors for Authentication/Manager
|
||||
$this->db->getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the backend
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user identified by the given credentials is available
|
||||
*
|
||||
* @param Credentials $credentials The login credentials
|
||||
* @param Credential $credential Credential to find a user in the database
|
||||
*
|
||||
* @return boolean True when the username is known and currently active.
|
||||
* @return boolean True when the username is known and currently active.
|
||||
*/
|
||||
public function hasUsername(Credentials $credential)
|
||||
public function hasUsername(Credential $credential)
|
||||
{
|
||||
if ($this->db === null) {
|
||||
Logger::warn('Ignoring hasUsername in database as no connection is available');
|
||||
return false;
|
||||
}
|
||||
$user = $this->getUserByName($credential->getUsername());
|
||||
return isset($user);
|
||||
}
|
||||
|
@ -105,29 +147,28 @@ class DbUserBackend implements UserBackend
|
|||
/**
|
||||
* Authenticate a user with the given credentials
|
||||
*
|
||||
* @param Credentials $credentials The login credentials
|
||||
* @param Credential $credential Credential to authenticate
|
||||
*
|
||||
* @return User|null The authenticated user or Null.
|
||||
* @return User|null The authenticated user or Null.
|
||||
*/
|
||||
public function authenticate(Credentials $credential)
|
||||
public function authenticate(Credential $credential)
|
||||
{
|
||||
if ($this->db === null) {
|
||||
Logger::warn('Ignoring database authentication as no connection is available');
|
||||
return null;
|
||||
}
|
||||
$this->db->getConnection();
|
||||
try {
|
||||
$salt = $this->getUserSalt($credential->getUsername());
|
||||
} catch (\Exception $e) {
|
||||
Logger::error($e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
Logger::error(
|
||||
'Could not fetch salt from database for user %s. Exception was thrown: %s',
|
||||
$credential->getUsername(),
|
||||
$e->getMessage()
|
||||
);
|
||||
return null;
|
||||
}
|
||||
$res = $this->db
|
||||
->select()->from($this->userTable)
|
||||
->where(self::USER_NAME_COLUMN.' = ?', $credential->getUsername())
|
||||
->where(self::ACTIVE_COLUMN. ' = ?', true)
|
||||
->where(self::USER_NAME_COLUMN . ' = ?', $credential->getUsername())
|
||||
->where(self::ACTIVE_COLUMN . ' = ?', true)
|
||||
->where(
|
||||
self::PASSWORD_COLUMN. ' = ?',
|
||||
self::PASSWORD_COLUMN . ' = ?',
|
||||
hash_hmac(
|
||||
'sha256',
|
||||
$salt,
|
||||
|
@ -138,18 +179,20 @@ class DbUserBackend implements UserBackend
|
|||
if ($res !== false) {
|
||||
return $this->createUserFromResult($res);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the users salt from the database
|
||||
*
|
||||
* @param $username The user whose salt should be fetched.
|
||||
* @param string$username The user whose salt should be fetched
|
||||
*
|
||||
* @return String|null Returns the salt-string or Null, when the user does not exist.
|
||||
* @return string|null Return the salt-string or null, when the user does not exist
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
private function getUserSalt($username)
|
||||
{
|
||||
$this->db->getConnection();
|
||||
$res = $this->db->select()
|
||||
->from($this->userTable, self::SALT_COLUMN)
|
||||
->where(self::USER_NAME_COLUMN.' = ?', $username)
|
||||
|
@ -157,48 +200,40 @@ class DbUserBackend implements UserBackend
|
|||
if ($res !== false) {
|
||||
return $res->{self::SALT_COLUMN};
|
||||
} else {
|
||||
throw new \Exception('No Salt found for user "' . $username . '"');
|
||||
throw new ProgrammingError('No Salt found for user "' . $username . '"');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the user information from the database
|
||||
*
|
||||
* @param $username The name of the user.
|
||||
* @param string $username The name of the user
|
||||
*
|
||||
* @return User|null Returns the user object, or null when the user does not exist.
|
||||
* @return User|null Returns the user object, or null when the user does not exist
|
||||
*/
|
||||
private function getUserByName($username)
|
||||
{
|
||||
if ($this->db === null) {
|
||||
Logger::warn('Ignoring getUserByName as no database connection is available');
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$this->db->getConnection();
|
||||
$res = $this->db->
|
||||
select()->from($this->userTable)
|
||||
->where(self::USER_NAME_COLUMN.' = ?', $username)
|
||||
->where(self::ACTIVE_COLUMN.' = ?', true)
|
||||
->query()->fetch();
|
||||
if ($res !== false) {
|
||||
return $this->createUserFromResult($res);
|
||||
}
|
||||
return null;
|
||||
} catch (\Zend_Db_Statement_Exception $exc) {
|
||||
Logger::error("Could not fetch users from db : %s ", $exc->getMessage());
|
||||
return null;
|
||||
$this->db->getConnection();
|
||||
$res = $this->db->
|
||||
select()->from($this->userTable)
|
||||
->where(self::USER_NAME_COLUMN .' = ?', $username)
|
||||
->where(self::ACTIVE_COLUMN .' = ?', true)
|
||||
->query()->fetch();
|
||||
if ($res !== false) {
|
||||
return $this->createUserFromResult($res);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of User from a query result
|
||||
*
|
||||
* @param $result The query result containing the user row
|
||||
* @param stdClass $resultRow Result object from database
|
||||
*
|
||||
* @return User The created instance of User.
|
||||
* @return User The created instance of User.
|
||||
*/
|
||||
private function createUserFromResult($resultRow)
|
||||
private function createUserFromResult(stdClass $resultRow)
|
||||
{
|
||||
$usr = new User(
|
||||
$resultRow->{self::USER_NAME_COLUMN}
|
||||
|
@ -211,13 +246,11 @@ class DbUserBackend implements UserBackend
|
|||
*
|
||||
* This class is mainly used for determining whether the authentication backend is valid or not
|
||||
*
|
||||
* @return int The number of users set in this backend
|
||||
* @see UserBackend::getUserCount
|
||||
* @return int The number of users set in this backend
|
||||
* @see UserBackend::getUserCount
|
||||
*/
|
||||
public function getUserCount()
|
||||
{
|
||||
|
||||
$this->db->getConnection();
|
||||
$query = $this->db->select()->from($this->userTable, 'COUNT(*) as count')->query();
|
||||
return $query->fetch()->count;
|
||||
}
|
||||
|
|
|
@ -28,50 +28,71 @@
|
|||
|
||||
namespace Icinga\Authentication\Backend;
|
||||
|
||||
use Icinga\User;
|
||||
use Icinga\Authentication\UserBackend;
|
||||
use Icinga\Authentication\Credentials;
|
||||
use Icinga\Protocol\Ldap;
|
||||
use \stdClass;
|
||||
use \Zend_Config;
|
||||
use \Icinga\User;
|
||||
use \Icinga\Authentication\UserBackend;
|
||||
use \Icinga\Authentication\Credential;
|
||||
use \Icinga\Protocol\Ldap;
|
||||
use \Icinga\Protocol\Ldap\Connection;
|
||||
use \Icinga\Application\Config as IcingaConfig;
|
||||
|
||||
/**
|
||||
* User authentication backend (@see Icinga\Authentication\UserBackend) for
|
||||
* authentication of users via LDAP. The attributes and location of the
|
||||
* user is configurable via the application.ini
|
||||
*
|
||||
* See the UserBackend class (@see Icinga\Authentication\UserBackend) for
|
||||
* usage information
|
||||
**/
|
||||
* User authentication backend
|
||||
*/
|
||||
class LdapUserBackend implements UserBackend
|
||||
{
|
||||
/**
|
||||
* @var Ldap\Connection
|
||||
* Ldap resource
|
||||
*
|
||||
* @var Connection
|
||||
**/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The ldap connection information
|
||||
*
|
||||
* @var object
|
||||
* @var Zend_Config
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* Creates a new Authentication backend using the
|
||||
* connection information provided in $config
|
||||
* Name of the backend
|
||||
*
|
||||
* @param object $config The ldap connection information
|
||||
**/
|
||||
public function __construct($config)
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Create new Ldap User backend
|
||||
*
|
||||
* @param Zend_Config $config Configuration to create instance
|
||||
*/
|
||||
public function __construct(Zend_Config $config)
|
||||
{
|
||||
$this->connection = new Ldap\Connection($config);
|
||||
$this->config = $config;
|
||||
$this->name = $config->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Icinga\Authentication\UserBackend::hasUsername
|
||||
**/
|
||||
public function hasUsername(Credentials $credential)
|
||||
* Name of the backend
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the username exists
|
||||
*
|
||||
* @param Credential $credential Credential to find user in database
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasUsername(Credential $credential)
|
||||
{
|
||||
return $this->connection->fetchOne(
|
||||
$this->selectUsername($credential->getUsername())
|
||||
|
@ -79,11 +100,11 @@ class LdapUserBackend implements UserBackend
|
|||
}
|
||||
|
||||
/**
|
||||
* Removes the '*' characted from $string
|
||||
* Removes the '*' character from $string
|
||||
*
|
||||
* @param String $string
|
||||
* @param string $string Input string
|
||||
*
|
||||
* @return String
|
||||
* @return string
|
||||
**/
|
||||
protected function stripAsterisks($string)
|
||||
{
|
||||
|
@ -91,13 +112,11 @@ class LdapUserBackend implements UserBackend
|
|||
}
|
||||
|
||||
/**
|
||||
* Tries to fetch the username given in $username from
|
||||
* the ldap connection, using the configuration parameters
|
||||
* given in the Authentication configuration
|
||||
* Tries to fetch the username
|
||||
*
|
||||
* @param String $username The username to select
|
||||
* @param string $username The username to select
|
||||
*
|
||||
* @return object $result
|
||||
* @return stdClass $result
|
||||
**/
|
||||
protected function selectUsername($username)
|
||||
{
|
||||
|
@ -115,9 +134,13 @@ class LdapUserBackend implements UserBackend
|
|||
}
|
||||
|
||||
/**
|
||||
* @see Icinga\Authentication\UserBackend::authenticate
|
||||
**/
|
||||
public function authenticate(Credentials $credentials)
|
||||
* Authenticate
|
||||
*
|
||||
* @param Credential $credentials Credential to authenticate
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function authenticate(Credential $credentials)
|
||||
{
|
||||
if (!$this->connection->testCredentials(
|
||||
$this->connection->fetchDN($this->selectUsername($credentials->getUsername())),
|
||||
|
@ -130,6 +153,12 @@ class LdapUserBackend implements UserBackend
|
|||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of users in this backend
|
||||
*
|
||||
* @return int The number of users set in this backend
|
||||
* @see UserBackend::getUserCount
|
||||
*/
|
||||
public function getUserCount()
|
||||
{
|
||||
return $this->connection->count(
|
||||
|
|
|
@ -29,26 +29,43 @@
|
|||
namespace Icinga\Authentication;
|
||||
|
||||
/**
|
||||
* Data holder object for authentication information
|
||||
*
|
||||
* This object should be used instead of passing names and
|
||||
* passwords as primitives in order to allow additional information
|
||||
* to be provided (like the domain) when needed
|
||||
**/
|
||||
class Credentials
|
||||
* Data holder object for authentication information
|
||||
*
|
||||
* This object should be used instead of passing names and
|
||||
* passwords as primitives in order to allow additional information
|
||||
* to be provided (like the domain) when needed.
|
||||
*/
|
||||
class Credential
|
||||
{
|
||||
protected $username;
|
||||
protected $password;
|
||||
protected $domain;
|
||||
|
||||
/**
|
||||
* Create a new credential object
|
||||
*
|
||||
* @param String $username
|
||||
* @param String $password
|
||||
* @param String $domain
|
||||
**/
|
||||
public function __construct($username = "", $password = null, $domain = null)
|
||||
* Username
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* Password
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* Domain
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $domain;
|
||||
|
||||
/**
|
||||
* Create a new credential object
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $domain
|
||||
*/
|
||||
public function __construct($username = '', $password = null, $domain = null)
|
||||
{
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
|
@ -56,50 +73,62 @@ class Credentials
|
|||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
**/
|
||||
* Getter for username
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $username
|
||||
**/
|
||||
* Setter for username
|
||||
*
|
||||
* @param string $username
|
||||
*/
|
||||
public function setUsername($username)
|
||||
{
|
||||
return $this->username = $username;
|
||||
$this->username = $username;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return String
|
||||
**/
|
||||
* Getter for password
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $password
|
||||
**/
|
||||
* Setter for password
|
||||
*
|
||||
* @param string $password
|
||||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
return $this->password = $password;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
**/
|
||||
* Getter for domain
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDomain()
|
||||
{
|
||||
return $this->domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $domain
|
||||
**/
|
||||
* Setter for domain
|
||||
*
|
||||
* @param string $domain
|
||||
*/
|
||||
public function setDomain($domain)
|
||||
{
|
||||
return $this->domain = $domain;
|
||||
$this->domain = $domain;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/**
|
||||
* This file is part of Icinga 2 Web.
|
||||
*
|
||||
* Icinga 2 Web - Head for multiple monitoring backends.
|
||||
* Copyright (C) 2013 Icinga Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
||||
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||
* @author Icinga Development Team <info@icinga.org>
|
||||
*/
|
||||
// {{{ICINGA_LICENSE_HEADER}}}}
|
||||
|
||||
namespace Icinga\Authentication;
|
||||
|
||||
/**
|
||||
* Api behaviour for a group backend
|
||||
*
|
||||
* @TODO(mh): Groups not implemented at present, re-implement if needed (#4624)
|
||||
*/
|
||||
interface GroupBackend
|
||||
{
|
||||
/**
|
||||
* Name of the backend
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
}
|
|
@ -28,17 +28,20 @@
|
|||
|
||||
namespace Icinga\Authentication;
|
||||
|
||||
use \Exception;
|
||||
use \Zend_Config;
|
||||
use \Icinga\Application\Logger;
|
||||
use \Icinga\Application\Config as IcingaConfig;
|
||||
use \Icinga\Application\DbAdapterFactory;
|
||||
use \Icinga\Exception\ConfigurationError as ConfigError;
|
||||
use \Icinga\User;
|
||||
use \Icinga\Exception\ConfigurationError;
|
||||
|
||||
/**
|
||||
* The authentication manager allows to identify users and
|
||||
* to persist authentication information in a session.
|
||||
*
|
||||
* Direct instanciation is not permitted, the Authencation manager
|
||||
* Direct instantiation is not permitted, the AuthenticationManager
|
||||
* must be created using the getInstance method. Subsequent getInstance
|
||||
* calls return the same object and ignore any additional configuration
|
||||
*
|
||||
|
@ -46,37 +49,57 @@ use \Icinga\User;
|
|||
* you have to decide whether you want to modify the session on the first
|
||||
* initialization and provide the 'writeSession' option if so, otherwise
|
||||
* session changes won't be written to disk. This is done to prevent PHP
|
||||
* from blockung concurrent requests
|
||||
* from blocking concurrent requests
|
||||
*
|
||||
* @TODO: Group support is not implemented yet
|
||||
* @TODO(mh): Group support is not implemented yet (#4624)
|
||||
**/
|
||||
class Manager
|
||||
{
|
||||
const BACKEND_TYPE_USER = "User";
|
||||
const BACKEND_TYPE_GROUP = "Group";
|
||||
/**
|
||||
* Backend type user
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const BACKEND_TYPE_USER = 'user';
|
||||
|
||||
/**
|
||||
* @var Manager
|
||||
**/
|
||||
* Backend type group
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const BACKEND_TYPE_GROUP = 'group';
|
||||
|
||||
/**
|
||||
* Singleton instance
|
||||
*
|
||||
* @var self
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Instance of authenticated user
|
||||
*
|
||||
* @var User
|
||||
**/
|
||||
private $user = null;
|
||||
private $groups = array();
|
||||
|
||||
/**
|
||||
* @var UserBackend
|
||||
* Array of user backends
|
||||
*
|
||||
* @var UserBackend[]
|
||||
**/
|
||||
private $userBackend = null;
|
||||
private $userBackends = array();
|
||||
|
||||
/**
|
||||
* @var GroupBackend
|
||||
* Array of group backends
|
||||
*
|
||||
* @var array
|
||||
**/
|
||||
private $groupBackend = null;
|
||||
private $groupBackends = array();
|
||||
|
||||
/**
|
||||
* Session
|
||||
*
|
||||
* @var Session
|
||||
**/
|
||||
private $session = null;
|
||||
|
@ -86,42 +109,31 @@ class Manager
|
|||
* configuration provided in the authentication.ini if no config is given)
|
||||
* and with the given options.
|
||||
*
|
||||
* @param IcingaConfig $config The configuration to use for authentication
|
||||
* instead of the authentication.ini
|
||||
* @param Array $options Additional options that affect the managers behaviour.
|
||||
* Supported values:
|
||||
* * writeSession : Whether the session should be writable
|
||||
* * userBackendClass : Allows to provide an own user backend class
|
||||
* (used for testing)
|
||||
* * groupBackendClass : Allows to provide an own group backend class
|
||||
* (used for testing)
|
||||
* * sessionClass : Allows to provide a different session implementation)
|
||||
* @param Zend_Config $config The configuration to use for authentication
|
||||
* instead of the authentication.ini
|
||||
* @param array $options Additional options that affect the managers behaviour.
|
||||
* Supported values:
|
||||
* * writeSession: Whether the session should be writable
|
||||
* * sessionClass: Allows to provide a different session implementation)
|
||||
* * noDefaultConfig: Disable default configuration from authentication.ini
|
||||
**/
|
||||
private function __construct($config = null, array $options = array())
|
||||
private function __construct(Zend_Config $config = null, array $options = array())
|
||||
{
|
||||
if ($config === null) {
|
||||
$config = IcingaConfig::app('authentication');
|
||||
}
|
||||
if (isset($options["userBackendClass"])) {
|
||||
$this->userBackend = $options["userBackendClass"];
|
||||
} else {
|
||||
$this->userBackend = $this->initBestBackend(self::BACKEND_TYPE_USER, $config);
|
||||
if ($config === null && !(isset($options['noDefaultConfig']) && $options['noDefaultConfig'] == true)) {
|
||||
$config = IcingaConfig::app('authentication');
|
||||
}
|
||||
|
||||
if (isset($options["groupBackendClass"])) {
|
||||
$this->groupBackend = $options["groupBackendClass"];
|
||||
} else {
|
||||
// @TODO(mh): Re-enable when ready (#4624)
|
||||
// Deactivated, logging error messages breaks bootstrap
|
||||
// $this->groupBackend = $this->initBestBackend(self::BACKEND_TYPE_GROUP, $config);
|
||||
if ($config !== null) {
|
||||
$this->setupBackends($config);
|
||||
}
|
||||
|
||||
if (!isset($options["sessionClass"])) {
|
||||
if (!isset($options['sessionClass'])) {
|
||||
$this->session = new PhpSession($config->session);
|
||||
} else {
|
||||
$this->session = $options["sessionClass"];
|
||||
$this->session = $options['sessionClass'];
|
||||
}
|
||||
if (isset($options["writeSession"]) && $options["writeSession"] === true) {
|
||||
|
||||
if (isset($options['writeSession']) && $options['writeSession'] === true) {
|
||||
$this->session->read(true);
|
||||
} else {
|
||||
$this->session->read();
|
||||
|
@ -129,9 +141,15 @@ class Manager
|
|||
}
|
||||
|
||||
/**
|
||||
* @see Manager:__construct()
|
||||
**/
|
||||
public static function getInstance($config = null, array $options = array())
|
||||
* Get a singleton instance of our self
|
||||
*
|
||||
* @param Zend_Config $config
|
||||
* @param array $options
|
||||
*
|
||||
* @return self
|
||||
* @see Manager:__construct
|
||||
*/
|
||||
public static function getInstance(Zend_Config $config = null, array $options = array())
|
||||
{
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new Manager($config, $options);
|
||||
|
@ -140,100 +158,203 @@ class Manager
|
|||
}
|
||||
|
||||
/**
|
||||
* Clear the instance (this is mostly needed for testing and shouldn't be called otherwise)
|
||||
**/
|
||||
public static function clearInstance()
|
||||
* Initialize multiple backends from Zend Config
|
||||
*/
|
||||
private function setupBackends(Zend_Config $config)
|
||||
{
|
||||
self::$instance = null;
|
||||
foreach ($config as $name => $backendConfig) {
|
||||
if ($backendConfig->name === null) {
|
||||
$backendConfig->name = $name;
|
||||
}
|
||||
|
||||
$backend = $this->createBackend($backendConfig);
|
||||
|
||||
if ($backend instanceof UserBackend) {
|
||||
$this->userBackends[$backend->getName()] = $backend;
|
||||
} elseif ($backend instanceof GroupBackend) {
|
||||
$this->groupBackends[$backend->getName()] = $backend;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a connection to the best available backend
|
||||
* Create a single backend from Zend Config
|
||||
*
|
||||
* @param String $target "User" or "Group", depending on what
|
||||
* authentication information the backend should provide
|
||||
* @param Mixed $backends The configuration containing all backend configurations
|
||||
* in falling priority
|
||||
* @param Zend_Config $backendConfig
|
||||
*
|
||||
* @return (null|UserBackend|GroupBackend)
|
||||
* @return null|UserBackend
|
||||
*/
|
||||
private function initBestBackend($target, $backends)
|
||||
private function createBackend(Zend_Config $backendConfig)
|
||||
{
|
||||
foreach ($backends as $key => $backend) {
|
||||
if (strtolower($target) === strtolower($backend->target)) {
|
||||
$db = $this->tryToInitBackend($target, $backend);
|
||||
if (isset($db)) {
|
||||
return $db;
|
||||
}
|
||||
$type = ucwords(strtolower($backendConfig->backend));
|
||||
$target = ucwords(strtolower($backendConfig->target));
|
||||
$name = $backendConfig->name;
|
||||
|
||||
if (!$type && !$backendConfig->class) {
|
||||
Logger::warn('AuthManager: Backend "%s" has no backend type configuration. (e.g. backend=ldap)', $name);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$target && !$backendConfig->class) {
|
||||
Logger::warn('AuthManager: Backend "%s" has no target configuration. (e.g. target=user|group)', $name);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Allow vendor and test classes in configuration
|
||||
if ($backendConfig->class) {
|
||||
$class = $backendConfig->class;
|
||||
} else {
|
||||
$class = '\\Icinga\\Authentication\\Backend\\' . $type . $target . 'Backend';
|
||||
}
|
||||
|
||||
if (!class_exists($class)) {
|
||||
Logger::error('AuthManager: Class not found (%s) for backend %s', $class, $name);
|
||||
return null;
|
||||
} else {
|
||||
return new $class($backendConfig);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Logger::warn('AuthManager: Not able to create backend. Exception was thrown: %s', $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user backend to stack
|
||||
*
|
||||
* @param UserBackend $userBackend
|
||||
*/
|
||||
public function addUserBackend(UserBackend $userBackend)
|
||||
{
|
||||
$this->userBackends[$userBackend->getName()] = $userBackend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user backend by name
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return UserBackend|null
|
||||
*/
|
||||
public function getUserBackend($name)
|
||||
{
|
||||
return (isset($this->userBackends[$name])) ?
|
||||
$this->userBackends[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a group backend to stack
|
||||
*
|
||||
* @param GroupBackend $groupBackend
|
||||
*/
|
||||
public function addGroupBackend(GroupBackend $groupBackend)
|
||||
{
|
||||
$this->groupBackends[$groupBackend->getName()] = $groupBackend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a group backend by name
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return GroupBackend|null
|
||||
*/
|
||||
public function getGroupBackend($name)
|
||||
{
|
||||
return (isset($this->groupBackends[$name])) ?
|
||||
$this->groupBackends[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a backend for a credential
|
||||
*
|
||||
* @param Credential $credentials
|
||||
*
|
||||
* @return UserBackend|null
|
||||
* @throws ConfigurationError
|
||||
*/
|
||||
private function getBackendForCredential(Credential $credentials)
|
||||
{
|
||||
$authErrors = 0;
|
||||
|
||||
foreach ($this->userBackends as $userBackend) {
|
||||
|
||||
$flag = false;
|
||||
|
||||
try {
|
||||
Logger::debug(
|
||||
'AuthManager: Try backend %s for user %s',
|
||||
$userBackend->getName(),
|
||||
$credentials->getUsername()
|
||||
);
|
||||
$flag = $userBackend->hasUsername($credentials);
|
||||
} catch (Exception $e) {
|
||||
Logger::error(
|
||||
'AuthManager: Backend "%s" has errors. Exception was thrown: %s',
|
||||
$userBackend->getName(),
|
||||
$e->getMessage()
|
||||
);
|
||||
|
||||
$authErrors++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($flag === true) {
|
||||
Logger::debug(
|
||||
'AuthManager: Backend %s has user %s',
|
||||
$userBackend->getName(),
|
||||
$credentials->getUsername()
|
||||
);
|
||||
return $userBackend;
|
||||
}
|
||||
}
|
||||
Logger::error(
|
||||
'Failed to create any authentication backend '
|
||||
. 'for the target "' . $target . '". Entities belonging to this target'
|
||||
. ' will not be able to authenticate.'
|
||||
);
|
||||
|
||||
if ($authErrors >= count($this->userBackends)) {
|
||||
Logger::fatal('AuthManager: No working backend found, unable to authenticate any user');
|
||||
throw new ConfigurationError(
|
||||
'No working backend found. Unable to authenticate any user.'
|
||||
. "\n"
|
||||
. 'Please examine the logs for more information.'
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create the backend with the given configuration
|
||||
* Try to authenticate the current user with the Credential (@see Credential).
|
||||
*
|
||||
* @param String $target "User" or "Group", depending on what
|
||||
* authentication information the backend should provide
|
||||
* @param $backendConfig The configuration containing backend description
|
||||
*
|
||||
* @return UserBackend|null Return the created backend or null
|
||||
*/
|
||||
private function tryToInitBackend($target, $backendConfig)
|
||||
{
|
||||
$type = ucwords(strtolower($backendConfig->backend));
|
||||
if (!$type) {
|
||||
Logger::warn('Backend has no type configured. (e.g. backend=ldap)');
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if ($backendConfig->backend === 'db') {
|
||||
$resource = DbAdapterFactory::getDbAdapter($backendConfig->resource);
|
||||
} else {
|
||||
$resource = $backendConfig;
|
||||
}
|
||||
$class = '\\Icinga\\Authentication\\Backend\\' . $type . $target. 'Backend';
|
||||
return new $class($resource);
|
||||
} catch (\Exception $e) {
|
||||
$msg = 'Not able to create backend. Exception: ' . $e->getMessage();
|
||||
Logger::warn($msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to authenticate the current user with the Credentials (@see Credentials).
|
||||
*
|
||||
* @param Credentials $credentials The credentials to use for authentication
|
||||
* @param Credential $credentials The credentials to use for authentication
|
||||
* @param Boolean $persist Whether to persist the authentication result
|
||||
* in the current session
|
||||
*
|
||||
* @return Boolean true on success, otherwise false
|
||||
* @throws ConfigError
|
||||
*/
|
||||
public function authenticate(Credentials $credentials, $persist = true)
|
||||
public function authenticate(Credential $credentials, $persist = true)
|
||||
{
|
||||
if (!$this->userBackend) {
|
||||
Logger::error("No authentication backend provided, your users will never be able to login.");
|
||||
if (count($this->userBackends) === 0) {
|
||||
Logger::error('AuthManager: No authentication backend provided, your users will never be able to login.');
|
||||
throw new ConfigError(
|
||||
"No authentication backend set - login will never succeed as icinga-web ".
|
||||
"doesn't know how to determine your user. \n".
|
||||
"To fix this error, setup your authentication.ini with a valid authentication backend."
|
||||
'No authentication backend set - login will never succeed as icinga-web '
|
||||
. 'doesn\'t know how to determine your user. ' . "\n"
|
||||
. 'To fix this error, setup your authentication.ini with at least one valid authentication backend.'
|
||||
);
|
||||
}
|
||||
|
||||
$userBackend = $this->getBackendForCredential($credentials);
|
||||
|
||||
if ($userBackend === null) {
|
||||
Logger::info('AuthManager: Unknown user %s tried to log in', $credentials->getUsername());
|
||||
return false;
|
||||
}
|
||||
if (!$this->userBackend->hasUsername($credentials)) {
|
||||
Logger::info("Unknown user %s tried to log in", $credentials->getUsername());
|
||||
return false;
|
||||
}
|
||||
$this->user = $this->userBackend->authenticate($credentials);
|
||||
|
||||
$this->user = $userBackend->authenticate($credentials);
|
||||
|
||||
if ($this->user == null) {
|
||||
Logger::info("Invalid credentials for user %s provided", $credentials->getUsername());
|
||||
Logger::info('AuthManager: Invalid credentials for user %s provided', $credentials->getUsername());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -241,6 +362,9 @@ class Manager
|
|||
$this->persistCurrentUser();
|
||||
$this->session->write();
|
||||
}
|
||||
|
||||
Logger::info('AuthManager: User successfully logged in: %s', $credentials->getUsername());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -250,7 +374,7 @@ class Manager
|
|||
**/
|
||||
public function persistCurrentUser()
|
||||
{
|
||||
$this->session->set("user", $this->user);
|
||||
$this->session->set('user', $this->user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +382,7 @@ class Manager
|
|||
**/
|
||||
public function authenticateFromSession()
|
||||
{
|
||||
$this->user = $this->session->get("user", null);
|
||||
$this->user = $this->session->get('user', null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -266,8 +390,8 @@ class Manager
|
|||
*
|
||||
* @param Boolean $ignoreSession Set to true to prevent authentication by session
|
||||
*
|
||||
* @param Boolean
|
||||
**/
|
||||
* @return bool
|
||||
*/
|
||||
public function isAuthenticated($ignoreSession = false)
|
||||
{
|
||||
if ($this->user === null && !$ignoreSession) {
|
||||
|
@ -296,13 +420,21 @@ class Manager
|
|||
}
|
||||
|
||||
/**
|
||||
* @see User::getGroups
|
||||
* Getter for groups belong authenticated user
|
||||
*
|
||||
* @return array
|
||||
* @see User::getGroups
|
||||
**/
|
||||
public function getGroups()
|
||||
{
|
||||
return $this->user->getGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for session
|
||||
*
|
||||
* @return Session
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
|
|
|
@ -28,10 +28,11 @@
|
|||
|
||||
namespace Icinga\Authentication;
|
||||
|
||||
use Icinga\Application\Logger as Logger;
|
||||
use Icinga\Application\Logger;
|
||||
use \Icinga\Exception\ConfigurationError;
|
||||
|
||||
/**
|
||||
* Class PhpSession
|
||||
* Session implementation in PHP
|
||||
*
|
||||
* Standard PHP Session handling
|
||||
* You have to call read() first in order to start the session. If
|
||||
|
@ -44,97 +45,121 @@ use Icinga\Application\Logger as Logger;
|
|||
*/
|
||||
class PhpSession extends Session
|
||||
{
|
||||
const SESSION_NAME = "Icinga2Web";
|
||||
private $isOpen = false;
|
||||
private $isFlushed = false;
|
||||
|
||||
private static $DEFAULT_COOKIEOPTIONS = array(
|
||||
'use_trans_sid' => false,
|
||||
'use_cookies' => true,
|
||||
'cookie_httponly' => true,
|
||||
'use_only_cookies' => true,
|
||||
'hash_function' => true,
|
||||
'hash_bits_per_character' => 5,
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a new PHPSession object using the provided options (if any)
|
||||
*
|
||||
* @param Array $options An optional array of ini options to set,
|
||||
* @see http://php.net/manual/en/session.configuration.php
|
||||
**/
|
||||
* Name of the session
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const SESSION_NAME = 'Icinga2Web';
|
||||
|
||||
/**
|
||||
* Flag if session is open
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isOpen = false;
|
||||
|
||||
/**
|
||||
* Flag if session is flushed
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isFlushed = false;
|
||||
|
||||
/**
|
||||
* Configuration for cookie options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $defaultCookieOptions = array(
|
||||
'use_trans_sid' => false,
|
||||
'use_cookies' => true,
|
||||
'cookie_httponly' => true,
|
||||
'use_only_cookies' => true,
|
||||
'hash_function' => true,
|
||||
'hash_bits_per_character' => 5,
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new PHPSession object using the provided options (if any)
|
||||
*
|
||||
* @param array $options An optional array of ini options to set,
|
||||
*
|
||||
* @throws ConfigurationError
|
||||
* @see http://php.net/manual/en/session.configuration.php
|
||||
*/
|
||||
public function __construct(array $options = null)
|
||||
{
|
||||
if ($options !== null) {
|
||||
$options = array_merge(PhpSession::$DEFAULT_COOKIEOPTIONS, $options);
|
||||
$options = array_merge(PhpSession::$defaultCookieOptions, $options);
|
||||
} else {
|
||||
$options = PhpSession::$DEFAULT_COOKIEOPTIONS;
|
||||
$options = PhpSession::$defaultCookieOptions;
|
||||
}
|
||||
foreach ($options as $sessionVar => $value) {
|
||||
if (ini_set("session.".$sessionVar, $value) === false) {
|
||||
Logger::warn(
|
||||
"Could not set php.ini setting %s = %s. This might affect your sessions behaviour.",
|
||||
'Could not set php.ini setting %s = %s. This might affect your sessions behaviour.',
|
||||
$sessionVar,
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!is_writable(session_save_path())) {
|
||||
throw new \Icinga\Exception\ConfigurationError("Can't save session");
|
||||
throw new ConfigurationError('Can\'t save session');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the session has not yet been closed
|
||||
*
|
||||
* @return Boolean
|
||||
**/
|
||||
* Return true when the session has not yet been closed
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function sessionCanBeChanged()
|
||||
{
|
||||
if ($this->isFlushed) {
|
||||
Logger::error("Tried to work on a closed session, session changes will be ignored");
|
||||
Logger::error('Tried to work on a closed session, session changes will be ignored');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true when the session has not yet been opened
|
||||
*
|
||||
* @return Boolean
|
||||
**/
|
||||
* Return true when the session has not yet been opened
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function sessionCanBeOpened()
|
||||
{
|
||||
if ($this->isOpen) {
|
||||
Logger::warn("Tried to open a session more than once");
|
||||
Logger::warn('Tried to open a session more than once');
|
||||
return false;
|
||||
}
|
||||
return $this->sessionCanBeChanged();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens a PHP session when possible
|
||||
*
|
||||
* @return Boolean True on success
|
||||
**/
|
||||
* Open a PHP session when possible
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function open()
|
||||
{
|
||||
if (!$this->sessionCanBeOpened()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
session_name(PhpSession::SESSION_NAME);
|
||||
session_name(self::SESSION_NAME);
|
||||
session_start();
|
||||
$this->isOpen = true;
|
||||
$this->setAll($_SESSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures that the session is open modifyable
|
||||
*
|
||||
* @return Boolean True on success
|
||||
**/
|
||||
* Ensure that the session is open modifiable
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
private function ensureOpen()
|
||||
{
|
||||
// try to open first
|
||||
|
@ -145,16 +170,16 @@ class PhpSession extends Session
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads all values written to the underyling session and
|
||||
* makes them accessible. if keepOpen is not set, the session
|
||||
* is immediately closed again
|
||||
*
|
||||
* @param Boolean $keepOpen Set to true when modifying the session
|
||||
*
|
||||
* @return Boolean True on success
|
||||
**/
|
||||
* Read all values written to the underling session and
|
||||
* makes them accessible. if keepOpen is not set, the session
|
||||
* is immediately closed again
|
||||
*
|
||||
* @param bool $keepOpen Set to true when modifying the session
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function read($keepOpen = false)
|
||||
{
|
||||
if (!$this->ensureOpen()) {
|
||||
|
@ -166,15 +191,16 @@ class PhpSession extends Session
|
|||
$this->close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes all values of this session opbject to the underyling session implementation
|
||||
* If keepOpen is not set, the session is closed
|
||||
*
|
||||
* @param Boolean $keepOpen Set to true when modifying the session further
|
||||
*
|
||||
* @return Boolean True on success
|
||||
**/
|
||||
* Write all values of this session object to the underlying session implementation
|
||||
*
|
||||
* If keepOpen is not set, the session is closed
|
||||
*
|
||||
* @param bool $keepOpen Set to true when modifying the session further
|
||||
*
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function write($keepOpen = false)
|
||||
{
|
||||
if (!$this->ensureOpen()) {
|
||||
|
@ -190,12 +216,14 @@ class PhpSession extends Session
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes and writes the session. Call @see PHPSession::write in order to persist changes
|
||||
* and only call this if you want the session to be closed without any changes
|
||||
*
|
||||
**/
|
||||
* Close and writes the session
|
||||
*
|
||||
* Only call this if you want the session to be closed without any changes.
|
||||
*
|
||||
* @see PHPSession::write
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (!$this->isFlushed) {
|
||||
|
@ -203,11 +231,10 @@ class PhpSession extends Session
|
|||
}
|
||||
$this->isFlushed = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the current session, causing all session information to be lost
|
||||
*
|
||||
**/
|
||||
* Delete the current session, causing all session information to be lost
|
||||
*/
|
||||
public function purge()
|
||||
{
|
||||
if ($this->ensureOpen()) {
|
||||
|
@ -219,24 +246,22 @@ class PhpSession extends Session
|
|||
}
|
||||
|
||||
/**
|
||||
* Removes session cookies
|
||||
*
|
||||
**/
|
||||
* Remove session cookies
|
||||
*/
|
||||
private function clearCookies()
|
||||
{
|
||||
if (ini_get("session.use_cookies")) {
|
||||
Logger::debug("Clearing cookies");
|
||||
if (ini_get('session.use_cookies')) {
|
||||
Logger::debug('Clear session cookie');
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(
|
||||
session_name(),
|
||||
'',
|
||||
time() - 42000,
|
||||
$params["path"],
|
||||
$params["domain"],
|
||||
$params["secure"],
|
||||
$params["httponly"]
|
||||
$params['path'],
|
||||
$params['domain'],
|
||||
$params['secure'],
|
||||
$params['httponly']
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,58 +29,71 @@
|
|||
namespace Icinga\Authentication;
|
||||
|
||||
/**
|
||||
* Base class for session, providing getter, setters and required
|
||||
* interface methods
|
||||
*
|
||||
**/
|
||||
* Base class for handling sessions
|
||||
*/
|
||||
abstract class Session
|
||||
{
|
||||
/**
|
||||
* Container for session values
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $sessionValues = array();
|
||||
|
||||
/**
|
||||
* Opens a session or creates a new one if not exists
|
||||
*
|
||||
**/
|
||||
* Open a session or creates a new one if not exists
|
||||
*/
|
||||
abstract public function open();
|
||||
|
||||
/**
|
||||
* Reads all values from the underyling session implementation
|
||||
*
|
||||
* @param Boolean $keepOpen True to keep the session open (depends on implementaiton)
|
||||
**/
|
||||
* Read all values from the underlying session implementation
|
||||
*
|
||||
* @param bool $keepOpen True to keep the session open
|
||||
*/
|
||||
abstract public function read($keepOpen = false);
|
||||
|
||||
|
||||
/**
|
||||
* Persists changes to the underlying session implementation
|
||||
*
|
||||
* @param Boolean $keepOpen True to keep the session open (depends on implementaiton)
|
||||
**/
|
||||
* Persists changes to the underlying session implementation
|
||||
*
|
||||
* @param bool $keepOpen True to keep the session open
|
||||
*/
|
||||
abstract public function write($keepOpen = false);
|
||||
|
||||
/**
|
||||
* Close session
|
||||
*/
|
||||
abstract public function close();
|
||||
|
||||
/**
|
||||
* Purge session
|
||||
*/
|
||||
abstract public function purge();
|
||||
|
||||
/**
|
||||
* Sets a $value under the provided key in the internal session data array
|
||||
* Does not persist those changes, use @see Session::write in order to persist the changes
|
||||
* made here.
|
||||
*
|
||||
* @param String $key
|
||||
* @param mixed $value
|
||||
**/
|
||||
* Setter for session values
|
||||
*
|
||||
* You have to persist values manually
|
||||
*
|
||||
* @see self::persist
|
||||
* @param string $key Name of value
|
||||
* @param mixed $value Value
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->sessionValues[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session value stored under $key or $defaultValue if not found.
|
||||
* call @see Session:read in order to populate this array with the underyling session implementation
|
||||
*
|
||||
* @param String $key
|
||||
* @param mixed $defaultValue
|
||||
*
|
||||
* @return mixed
|
||||
**/
|
||||
* Getter fpr session values
|
||||
*
|
||||
* Values are available after populate session with method read.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $defaultValue
|
||||
*
|
||||
* @return mixed
|
||||
* @see self::read
|
||||
*/
|
||||
public function get($key, $defaultValue = null)
|
||||
{
|
||||
return isset($this->sessionValues[$key]) ?
|
||||
|
@ -88,22 +101,23 @@ abstract class Session
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the current session value state (also dirty changes not yet written to the session)
|
||||
*
|
||||
* @return Array
|
||||
**/
|
||||
* Getter for all session values
|
||||
*
|
||||
* This are also dirty, unwritten values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
return $this->sessionValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all values provided in the key=>value array to the internal session value state.
|
||||
* In order to persist these chages, call @see Session:write
|
||||
*
|
||||
* @param Array $values
|
||||
* @param Boolean $overwrite Whether to overwrite already set values
|
||||
**/
|
||||
* Put an array into session
|
||||
*
|
||||
* @param array $values
|
||||
* @param bool $overwrite Overwrite existing values
|
||||
*/
|
||||
public function setAll(array $values, $overwrite = false)
|
||||
{
|
||||
if ($overwrite) {
|
||||
|
@ -116,11 +130,10 @@ abstract class Session
|
|||
$this->sessionValues[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears all values from the session cache
|
||||
*
|
||||
**/
|
||||
* Clear all values from the session cache
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->sessionValues = array();
|
||||
|
|
|
@ -28,33 +28,46 @@
|
|||
|
||||
namespace Icinga\Authentication;
|
||||
|
||||
use \Zend_Config;
|
||||
use \Icinga\User;
|
||||
use Icinga\Authentication\Credential;
|
||||
|
||||
/**
|
||||
* Interface for backends that authenticate users
|
||||
* Public api for an user backend object
|
||||
*/
|
||||
interface UserBackend
|
||||
{
|
||||
/**
|
||||
* Create a userbackend from the given configuration or resource
|
||||
* Create a new object
|
||||
*
|
||||
* @param $config
|
||||
* @param Zend_Config $config Object to configure instance
|
||||
*/
|
||||
public function __construct($config);
|
||||
public function __construct(Zend_Config $config);
|
||||
|
||||
/**
|
||||
* Test if the username exists
|
||||
*
|
||||
* @param Credentials $credentials
|
||||
* @return boolean
|
||||
* @param Credential $credentials
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasUsername(Credentials $credentials);
|
||||
public function hasUsername(Credential $credentials);
|
||||
|
||||
/**
|
||||
* Authenticate
|
||||
*
|
||||
* @param Credentials $credentials
|
||||
* @return User
|
||||
* @param Credential $credentials
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function authenticate(Credentials $credentials);
|
||||
public function authenticate(Credential $credentials);
|
||||
|
||||
/**
|
||||
* Name of the backend
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Get the number of users available through this backend
|
||||
|
|
|
@ -4,33 +4,52 @@
|
|||
|
||||
namespace Tests\Icinga\Authentication;
|
||||
|
||||
require_once __DIR__. '/../../../../../library/Icinga/Authentication/Credentials.php';
|
||||
require_once __DIR__. '/../../../../../library/Icinga/Authentication/UserBackend.php';
|
||||
require_once __DIR__. '/../../../../../library/Icinga/User.php';
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once realpath(__DIR__ . '/../../../../../library/Icinga/Test/BaseTestCase.php');
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use Icinga\Authentication\Credentials as Credentials;
|
||||
use Icinga\Authentication\UserBackend as UserBackend;
|
||||
use Icinga\User;
|
||||
use Icinga\Test\BaseTestCase;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once 'Zend/Config.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Credential.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/UserBackend.php';
|
||||
require_once BaseTestCase::$libDir . '/User.php';
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use \Zend_Config;
|
||||
use \Icinga\Authentication\Credential;
|
||||
use \Icinga\Authentication\UserBackend as UserBackend;
|
||||
use \Icinga\User;
|
||||
|
||||
/**
|
||||
* Simple backend mock that takes an config object
|
||||
* with the property "credentials", which is an array
|
||||
* of Credentials this backend authenticates
|
||||
* of Credential this backend authenticates
|
||||
**/
|
||||
class BackendMock implements UserBackend
|
||||
{
|
||||
public $allowedCredentials = array();
|
||||
public function __construct($config = null)
|
||||
public $name;
|
||||
|
||||
public function __construct(Zend_Config $config = null)
|
||||
{
|
||||
if ($config === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset ($config->credentials)) {
|
||||
$this->allowedCredentials = $config->credentials;
|
||||
}
|
||||
|
||||
if ($config->name) {
|
||||
$this->name = $config->name;
|
||||
} else {
|
||||
$this->name = 'TestBackendMock-' . uniqid();
|
||||
}
|
||||
}
|
||||
|
||||
public function hasUsername(Credentials $userCredentials)
|
||||
public function hasUsername(Credential $userCredentials)
|
||||
{
|
||||
foreach ($this->allowedCredentials as $credential) {
|
||||
if ($credential->getUsername() == $userCredentials->getUsername()) {
|
||||
|
@ -39,26 +58,43 @@ class BackendMock implements UserBackend
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Name of the backend
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
public static function getDummyUser()
|
||||
{
|
||||
return new User(
|
||||
"Username",
|
||||
"Firstname",
|
||||
"Lastname",
|
||||
"user@test.local"
|
||||
'Username',
|
||||
'Firstname',
|
||||
'Lastname',
|
||||
'user@test.local'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function getUserCount() {
|
||||
return count($this->allowedCredentials);
|
||||
}
|
||||
|
||||
public function authenticate(Credentials $credentials)
|
||||
|
||||
public function authenticate(Credential $credentials)
|
||||
{
|
||||
if (!in_array($credentials, $this->allowedCredentials)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::getDummyUser();
|
||||
}
|
||||
|
||||
public function setCredentials(array $credentials)
|
||||
{
|
||||
$this->allowedCredentials = $credentials;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<?php
|
||||
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/**
|
||||
* This file is part of Icinga 2 Web.
|
||||
|
@ -41,12 +40,13 @@ require_once 'Zend/Config/Ini.php';
|
|||
require_once 'Zend/Db/Adapter/Abstract.php';
|
||||
require_once 'Zend/Db.php';
|
||||
require_once 'Zend/Log.php';
|
||||
require_once BaseTestCase::$libDir . '/Exception/ProgrammingError.php';
|
||||
require_once BaseTestCase::$libDir . '/Util/ConfigAwareFactory.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/UserBackend.php';
|
||||
require_once BaseTestCase::$libDir . '/Protocol/Ldap/Exception.php';
|
||||
require_once BaseTestCase::$libDir . '/Application/DbAdapterFactory.php';
|
||||
require_once BaseTestCase::$libDir . '/Application/Config.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Credentials.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Credential.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Backend/DbUserBackend.php';
|
||||
require_once BaseTestCase::$libDir . '/User.php';
|
||||
require_once BaseTestCase::$libDir . '/Application/Logger.php';
|
||||
|
@ -57,7 +57,7 @@ use \Zend_Db_Adapter_Pdo_Abstract;
|
|||
use \Zend_Config;
|
||||
use \Icinga\Authentication\Backend\DbUserBackend;
|
||||
use \Icinga\Application\DbAdapterFactory;
|
||||
use \Icinga\Authentication\Credentials;
|
||||
use \Icinga\Authentication\Credential;
|
||||
use \Icinga\User;
|
||||
use \Icinga\Application\Config;
|
||||
|
||||
|
@ -107,6 +107,22 @@ class DbUserBackendTest extends BaseTestCase
|
|||
)
|
||||
);
|
||||
|
||||
private function createDbBackendConfig($resource, $name = null)
|
||||
{
|
||||
if ($name === null) {
|
||||
$name = 'TestDbUserBackend-' . uniqid();
|
||||
}
|
||||
|
||||
$config = new Zend_Config(
|
||||
array(
|
||||
'name' => $name,
|
||||
'resource' => $resource
|
||||
)
|
||||
);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the authentication functions of the DbUserBackend using PostgreSQL as backend.
|
||||
*
|
||||
|
@ -115,7 +131,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
public function testCorrectUserLoginForPgsql($db)
|
||||
{
|
||||
$this->setupDbProvider($db);
|
||||
$backend = new DbUserBackend($db);
|
||||
$backend = new DbUserBackend($this->createDbBackendConfig($db));
|
||||
$this->runBackendAuthentication($backend);
|
||||
$this->runBackendUsername($backend);
|
||||
}
|
||||
|
@ -128,7 +144,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
public function testCorrectUserLoginForMySQL($db)
|
||||
{
|
||||
$this->setupDbProvider($db);
|
||||
$backend = new DbUserBackend($db);
|
||||
$backend = new DbUserBackend($this->createDbBackendConfig($db));
|
||||
$this->runBackendAuthentication($backend);
|
||||
$this->runBackendUsername($backend);
|
||||
}
|
||||
|
@ -157,7 +173,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
$usr[self::SALT_COLUMN],
|
||||
$usr[self::PASSWORD_COLUMN]
|
||||
),
|
||||
self::ACTIVE_COLUMN => $usr[self::ACTIVE_COLUMN],
|
||||
self::ACTIVE_COLUMN => $usr[self::ACTIVE_COLUMN],
|
||||
self::SALT_COLUMN => $usr[self::SALT_COLUMN]
|
||||
);
|
||||
$resource->insert($this->testTable, $data);
|
||||
|
@ -174,7 +190,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
// Known user
|
||||
$this->assertTrue(
|
||||
$backend->hasUsername(
|
||||
new Credentials(
|
||||
new Credential(
|
||||
$this->userData[0][self::USER_NAME_COLUMN],
|
||||
$this->userData[0][self::PASSWORD_COLUMN]
|
||||
)
|
||||
|
@ -185,7 +201,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
// Unknown user
|
||||
$this->assertFalse(
|
||||
$backend->hasUsername(
|
||||
new Credentials(
|
||||
new Credential(
|
||||
'unknown user',
|
||||
'secret'
|
||||
)
|
||||
|
@ -196,7 +212,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
// Inactive user
|
||||
$this->assertFalse(
|
||||
$backend->hasUsername(
|
||||
new Credentials(
|
||||
new Credential(
|
||||
$this->userData[2][self::USER_NAME_COLUMN],
|
||||
$this->userData[2][self::PASSWORD_COLUMN]
|
||||
)
|
||||
|
@ -215,7 +231,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
// Known user
|
||||
$this->assertNotNull(
|
||||
$backend->authenticate(
|
||||
new Credentials(
|
||||
new Credential(
|
||||
$this->userData[0][self::USER_NAME_COLUMN],
|
||||
$this->userData[0][self::PASSWORD_COLUMN]
|
||||
)
|
||||
|
@ -226,7 +242,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
// Wrong password
|
||||
$this->assertNull(
|
||||
$backend->authenticate(
|
||||
new Credentials(
|
||||
new Credential(
|
||||
$this->userData[1][self::USER_NAME_COLUMN],
|
||||
'wrongpassword'
|
||||
)
|
||||
|
@ -237,7 +253,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
// Nonexisting user
|
||||
$this->assertNull(
|
||||
$backend->authenticate(
|
||||
new Credentials(
|
||||
new Credential(
|
||||
'nonexisting user',
|
||||
$this->userData[1][self::PASSWORD_COLUMN]
|
||||
)
|
||||
|
@ -248,7 +264,7 @@ class DbUserBackendTest extends BaseTestCase
|
|||
// Inactive user
|
||||
$this->assertNull(
|
||||
$backend->authenticate(
|
||||
new Credentials(
|
||||
new Credential(
|
||||
$this->userData[2][self::USER_NAME_COLUMN],
|
||||
$this->userData[2][self::PASSWORD_COLUMN]
|
||||
)
|
||||
|
@ -256,4 +272,43 @@ class DbUserBackendTest extends BaseTestCase
|
|||
'Assert that an inactive user cannot authenticate.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider mysqlDb
|
||||
*/
|
||||
public function testBackendNameAssignment($db)
|
||||
{
|
||||
$this->setupDbProvider($db);
|
||||
|
||||
$testName = 'test-name-123123';
|
||||
$backend = new DbUserBackend($this->createDbBackendConfig($db, $testName));
|
||||
|
||||
$this->assertSame($testName, $backend->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider mysqlDb
|
||||
*/
|
||||
public function testCountUsersMySql($db)
|
||||
{
|
||||
$this->setupDbProvider($db);
|
||||
$testName = 'test-name-123123';
|
||||
$backend = new DbUserBackend($this->createDbBackendConfig($db, $testName));
|
||||
|
||||
$this->assertGreaterThan(0, $backend->getUserCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider pgsqlDb
|
||||
*/
|
||||
public function testCountUsersPgSql($db)
|
||||
{
|
||||
$this->setupDbProvider($db);
|
||||
$testName = 'test-name-123123';
|
||||
$backend = new DbUserBackend($this->createDbBackendConfig($db, $testName));
|
||||
|
||||
$this->assertGreaterThan(0, $backend->getUserCount());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Tests\Icinga\Authentication;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once realpath(__DIR__ . '/../../../../../library/Icinga/Test/BaseTestCase.php');
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use Icinga\Test\BaseTestCase;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once 'Zend/Config.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Credential.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/UserBackend.php';
|
||||
require_once BaseTestCase::$libDir . '/User.php';
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use \Exception;
|
||||
use \Zend_Config;
|
||||
use \Icinga\Authentication\Credential;
|
||||
use \Icinga\Authentication\UserBackend as UserBackend;
|
||||
use \Icinga\User;
|
||||
|
||||
/**
|
||||
* Simple backend mock that takes an config object
|
||||
* with the property "credentials", which is an array
|
||||
* of Credential this backend authenticates
|
||||
**/
|
||||
class ErrorProneBackendMock implements UserBackend
|
||||
{
|
||||
public static $throwOnCreate = false;
|
||||
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Creates a new object
|
||||
*
|
||||
* @param Zend_Config $config
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(Zend_Config $config)
|
||||
{
|
||||
if (self::$throwOnCreate === true) {
|
||||
throw new Exception('__construct error: Could not create');
|
||||
}
|
||||
|
||||
if ($config->name) {
|
||||
$this->name = $config->name;
|
||||
} else {
|
||||
$this->name = 'TestBackendErrorProneMock-' . uniqid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the username exists
|
||||
*
|
||||
* @param Credential $credentials
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function hasUsername(Credential $credentials)
|
||||
{
|
||||
throw new Exception('hasUsername error: ' . $credentials->getUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate
|
||||
*
|
||||
* @param Credential $credentials
|
||||
*
|
||||
* @return User
|
||||
* @throws Exception
|
||||
*/
|
||||
public function authenticate(Credential $credentials)
|
||||
{
|
||||
throw new Exception('authenticate error: ' . $credentials->getUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the backend
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of users available through this backend
|
||||
*
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getUserCount()
|
||||
{
|
||||
throw new Exception('getUserCount error: No users in this error prone backend');
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,53 +1,106 @@
|
|||
<?php
|
||||
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/**
|
||||
* This file is part of Icinga 2 Web.
|
||||
*
|
||||
* Icinga 2 Web - Head for multiple monitoring backends.
|
||||
* Copyright (C) 2013 Icinga Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
||||
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||
* @author Icinga Development Team <info@icinga.org>
|
||||
*/
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Tests\Icinga\Authentication;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once realpath(__DIR__ . '/../../../../../library/Icinga/Test/BaseTestCase.php');
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use Icinga\Authentication\Credential;
|
||||
use \Icinga\Test\BaseTestCase;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once 'Zend/Config.php';
|
||||
require_once BaseTestCase::$libDir . '/Protocol/Ldap/Connection.php';
|
||||
require_once BaseTestCase::$libDir . '/Protocol/Ldap/Query.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Credential.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/UserBackend.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Backend/LdapUserBackend.php';
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use \Exception;
|
||||
use \Zend_Config;
|
||||
use Icinga\Authentication\Backend\LdapUserBackend;
|
||||
|
||||
/**
|
||||
*
|
||||
* Test class for Ldapuserbackend
|
||||
* Created Mon, 10 Jun 2013 07:54:34 +0000
|
||||
*
|
||||
**/
|
||||
class LdapuserbackendTest extends \PHPUnit_Framework_TestCase
|
||||
class LdapUserBackendTest extends BaseTestCase
|
||||
{
|
||||
// Change this according to your ldap test server
|
||||
const ADMIN_DN = "cn=admin,dc=icinga,dc=org";
|
||||
const ADMIN_PASS = "admin";
|
||||
const ADMIN_DN = 'cn=admin,dc=icinga,dc=org';
|
||||
const ADMIN_PASS = 'admin';
|
||||
|
||||
private $users = array(
|
||||
"cn=John Doe, dc=icinga, dc=org" => array(
|
||||
"cn" => "John Doe",
|
||||
"sn" => "Doe",
|
||||
"objectclass" => "inetOrgPerson",
|
||||
"givenName" => "John",
|
||||
"mail" => "john@doe.local"
|
||||
'cn=Richard Miles,ou=icinga-unittest,dc=icinga,dc=org' => array(
|
||||
'cn' => 'Richard Miles',
|
||||
'sn' => 'Miles',
|
||||
'objectclass' => 'inetOrgPerson',
|
||||
'givenName' => 'Richard',
|
||||
'mail' => 'richard@doe.local',
|
||||
'uid' => 'rmiles',
|
||||
'userPassword' => 'passrmiles'
|
||||
),
|
||||
"cn=Jane Woe, dc=icinga, dc=org" => array(
|
||||
"cn" => "Jane Woe",
|
||||
"sn" => "Woe",
|
||||
"objectclass" => "inetOrgPerson",
|
||||
"givenName" => "Jane",
|
||||
"mail" => "jane@woe.local"
|
||||
'cn=Jane Woe,ou=icinga-unittest,dc=icinga,dc=org' => array(
|
||||
'cn' => 'Jane Woe',
|
||||
'sn' => 'Woe',
|
||||
'objectclass' => 'inetOrgPerson',
|
||||
'givenName' => 'Jane',
|
||||
'mail' => 'jane@woe.local',
|
||||
'uid' => 'jwoe',
|
||||
'userPassword' => 'passjwoe'
|
||||
)
|
||||
);
|
||||
|
||||
private $baseOu = array(
|
||||
'ou=icinga-unittest,dc=icinga,dc=org' => array(
|
||||
'objectclass' => 'organizationalUnit',
|
||||
'ou' => 'icinga-unittest'
|
||||
)
|
||||
);
|
||||
|
||||
private function getLDAPConnection()
|
||||
{
|
||||
$this->markTestSkipped("LDAP User Backend is currently not testable, as it would require to Boostrap most of the application (see Protocol\Ldap\Connection)");
|
||||
return;
|
||||
$ldapConn = ldap_connect("localhost", 389);
|
||||
$ldapConn = ldap_connect('localhost', 389);
|
||||
|
||||
if (!$ldapConn) {
|
||||
$this->markTestSkipped("Could not connect to test-ldap server, skipping test");
|
||||
return null;
|
||||
$this->markTestSkipped('Could not connect to test-ldap server, skipping test');
|
||||
}
|
||||
$bind = ldap_bind($ldapConn, self::ADMIN_DN, self::ADMIN_PASS);
|
||||
$bind = @ldap_bind($ldapConn, self::ADMIN_DN, self::ADMIN_PASS);
|
||||
|
||||
if (!$bind) {
|
||||
$this->markTestSkipped("Could not bind to test-ldap server, skipping test");
|
||||
return null;
|
||||
$this->markTestSkipped('Could not bind to test-ldap server, skipping test');
|
||||
}
|
||||
|
||||
return $ldapConn;
|
||||
}
|
||||
|
||||
|
@ -56,62 +109,114 @@ class LdapuserbackendTest extends \PHPUnit_Framework_TestCase
|
|||
foreach ($this->users as $ou => $info) {
|
||||
@ldap_delete($connection, $ou);
|
||||
}
|
||||
|
||||
foreach ($this->baseOu as $ou => $info) {
|
||||
@ldap_delete($connection, $ou);
|
||||
}
|
||||
}
|
||||
|
||||
private function insertTestdata($connection)
|
||||
{
|
||||
foreach ($this->users as $ou => $info) {
|
||||
foreach ($this->baseOu as $ou => $info) {
|
||||
if (ldap_add($connection, $ou, $info) === false) {
|
||||
$this->markTestSkipped("Couldn't set up test-ldap users, skipping test");
|
||||
$this->markTestSkipped('Couldn\'t set up test-ldap users, skipping test');
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->users as $ou => $info) {
|
||||
if (ldap_add($connection, $ou, $info) === false) {
|
||||
$this->markTestSkipped('Couldn\'t set up test-ldap users, skipping test');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$conn = $this->getLDAPConnection();
|
||||
if ($conn == null) {
|
||||
return;
|
||||
}
|
||||
$this->clearTestData($conn);
|
||||
$this->insertTestData($conn);
|
||||
$result = ldap_list($conn, "dc=icinga, dc=org", "(cn=John Doe)");
|
||||
|
||||
$result = ldap_list($conn, 'ou=icinga-unittest, dc=icinga, dc=org', '(cn=Richard Miles)');
|
||||
|
||||
if (ldap_count_entries($conn, $result) < 1) {
|
||||
$this->markTestSkipped("Couldn't set up test users, skipping test");
|
||||
$this->markTestSkipped('Couldn\'t set up test users, skipping test');
|
||||
}
|
||||
$result = ldap_list($conn, "dc=icinga, dc=org", "(cn=Jane Woe)");
|
||||
|
||||
$result = ldap_list($conn, 'ou=icinga-unittest, dc=icinga, dc=org', '(cn=Jane Woe)');
|
||||
|
||||
if (ldap_count_entries($conn, $result) < 1) {
|
||||
$this->markTestSkipped("Couldn't set up test users, skipping test");
|
||||
$this->markTestSkipped('Couldn\'t set up test users, skipping test');
|
||||
}
|
||||
|
||||
ldap_close($conn);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$conn = $this->getLDAPConnection();
|
||||
if ($conn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->clearTestData($conn);
|
||||
// $this->clearTestData($conn);
|
||||
ldap_close($conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for LdapUserBackend::HasUsername()
|
||||
*
|
||||
**/
|
||||
public function testHasUsername()
|
||||
private function createBackendConfig()
|
||||
{
|
||||
$config = new Zend_Config(
|
||||
array(
|
||||
'backend' => 'ldap',
|
||||
'target' => 'user',
|
||||
'hostname' => 'localhost',
|
||||
'root_dn' => 'ou=icinga-unittest,dc=icinga,dc=org',
|
||||
'bind_dn' => 'cn=admin,cn=config',
|
||||
'bind_pw' => 'admin',
|
||||
'user_class' => 'inetOrgPerson',
|
||||
'user_name_attribute' => 'uid'
|
||||
)
|
||||
);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for LdapUserBackend::Authenticate()
|
||||
*
|
||||
**/
|
||||
* Test for LdapUserBackend::HasUsername()
|
||||
**/
|
||||
public function testHasUsername()
|
||||
{
|
||||
$backend = new LdapUserBackend($this->createBackendConfig());
|
||||
$this->assertTrue($backend->hasUsername(new Credential('jwoe')));
|
||||
$this->assertTrue($backend->hasUsername(new Credential('rmiles')));
|
||||
$this->assertFalse($backend->hasUsername(new Credential('DoesNotExist')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for LdapUserBackend::Authenticate()
|
||||
*/
|
||||
public function testAuthenticate()
|
||||
{
|
||||
$this->markTestIncomplete('testAuthenticate is not implemented yet');
|
||||
$backend = new LdapUserBackend($this->createBackendConfig());
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'\Icinga\User',
|
||||
$backend->authenticate(new Credential('jwoe', 'passjwoe'))
|
||||
);
|
||||
|
||||
$this->assertFalse($backend->authenticate(new Credential('jwoe', 'passjwoe22')));
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'\Icinga\User',
|
||||
$backend->authenticate(new Credential('rmiles', 'passrmiles'))
|
||||
);
|
||||
|
||||
$this->assertFalse($backend->authenticate(new Credential('rmiles', 'passrmiles33')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Exception
|
||||
* @expectedExceptionMessage Cannot fetch single DN for
|
||||
*/
|
||||
public function testAuthenticateUnknownUser()
|
||||
{
|
||||
$backend = new LdapUserBackend($this->createBackendConfig());
|
||||
$this->assertFalse($backend->authenticate(new Credential('unknown123', 'passunknown123')));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,106 +1,175 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/**
|
||||
* This file is part of Icinga 2 Web.
|
||||
*
|
||||
* Icinga 2 Web - Head for multiple monitoring backends.
|
||||
* Copyright (C) 2013 Icinga Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
||||
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||
* @author Icinga Development Team <info@icinga.org>
|
||||
*/
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Tests\Icinga\Authentication;
|
||||
|
||||
require_once("../../library/Icinga/Application/Logger.php");
|
||||
require_once("../../library/Icinga/Authentication/Manager.php");
|
||||
require_once("../../library/Icinga/Authentication/Credentials.php");
|
||||
require_once("Zend/Log.php");
|
||||
require_once("BackendMock.php");
|
||||
require_once("SessionMock.php");
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once realpath(__DIR__ . '/../../../../../library/Icinga/Test/BaseTestCase.php');
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use Icinga\Authentication\Manager as AuthManager;
|
||||
use Icinga\Authentication\Credentials as Credentials;
|
||||
use Icinga\Application\Logger;
|
||||
use \Icinga\Test\BaseTestCase;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once 'Zend/Log.php';
|
||||
require_once 'Zend/Config.php';
|
||||
require_once BaseTestCase::$libDir . '/Application/Logger.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Manager.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Credential.php';
|
||||
require_once BaseTestCase::$libDir . '/Exception/ConfigurationError.php';
|
||||
require_once 'BackendMock.php';
|
||||
require_once 'ErrorProneBackendMock.php';
|
||||
require_once 'SessionMock.php';
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use \Zend_Config;
|
||||
use \Icinga\Authentication\Manager as AuthManager;
|
||||
use \Icinga\Authentication\Credential;
|
||||
use \Icinga\Exception\ConfigurationError;
|
||||
|
||||
/**
|
||||
*
|
||||
* Test class for Manager
|
||||
* Created Mon, 10 Jun 2013 07:54:34 +0000
|
||||
*
|
||||
**/
|
||||
class ManagerTest extends \PHPUnit_Framework_TestCase
|
||||
* @backupStaticAttributes enabled
|
||||
*/
|
||||
class ManagerTest extends BaseTestCase
|
||||
{
|
||||
public function getTestCredentials()
|
||||
{
|
||||
return (object) array("credentials" => array(
|
||||
new Credentials("jdoe", "passjdoe"),
|
||||
new Credentials("root", "passroot"),
|
||||
new Credentials("test", "passtest")
|
||||
));
|
||||
return array(
|
||||
new Credential("jdoe", "passjdoe"),
|
||||
new Credential("root", "passroot"),
|
||||
new Credential("test", "passtest")
|
||||
);
|
||||
}
|
||||
|
||||
public function getManagerInstance(&$session = null, $write = false)
|
||||
{
|
||||
public function getManagerInstance(
|
||||
&$session = null,
|
||||
$write = false,
|
||||
$nobackend = false,
|
||||
Zend_Config $managerConfig = null
|
||||
) {
|
||||
if ($session == null) {
|
||||
$session = new SessionMock();
|
||||
}
|
||||
return AuthManager::getInstance(
|
||||
(object) array(),
|
||||
array(
|
||||
"userBackendClass" => new BackendMock(
|
||||
$this->getTestCredentials()
|
||||
),
|
||||
"groupBackendClass" => new BackendMock(),
|
||||
"sessionClass" => $session,
|
||||
"writeSession" => $write
|
||||
)
|
||||
|
||||
if ($managerConfig === null) {
|
||||
$managerConfig = new Zend_Config(array());
|
||||
}
|
||||
|
||||
$managerOptions = array(
|
||||
'sessionClass' => $session,
|
||||
'writeSession' => $write,
|
||||
'noDefaultConfig' => true
|
||||
);
|
||||
|
||||
$manager = AuthManager::getInstance($managerConfig, $managerOptions);
|
||||
|
||||
if ($nobackend === false) {
|
||||
$backend = new BackendMock();
|
||||
$backend->allowedCredentials = $this->getTestCredentials();
|
||||
$manager->addUserBackend($backend);
|
||||
}
|
||||
|
||||
return $manager;
|
||||
}
|
||||
|
||||
public function testManagerInstanciation()
|
||||
{
|
||||
AuthManager::clearInstance();
|
||||
$this->setPreserveGlobalState(false);
|
||||
$authMgr = $this->getManagerInstance();
|
||||
$auth = $this->assertEquals($authMgr, AuthManager::getInstance());
|
||||
AuthManager::clearInstance();
|
||||
$this->assertSame($authMgr, AuthManager::getInstance());
|
||||
}
|
||||
|
||||
public function testManagerProducingDependencies()
|
||||
{
|
||||
$authMgr = $this->getManagerInstance($session, true);
|
||||
$this->assertSame($authMgr, AuthManager::getInstance());
|
||||
|
||||
$backend = new BackendMock();
|
||||
$backend->setCredentials($this->getTestCredentials());
|
||||
|
||||
$authMgr->addUserBackend($backend);
|
||||
|
||||
$this->assertTrue(
|
||||
$authMgr->authenticate(
|
||||
new Credential('jdoe', 'passjdoe')
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertInstanceOf('Icinga\User', $authMgr->getUser());
|
||||
$this->assertSame('Username', $authMgr->getUser()->getUsername());
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'Tests\Icinga\Authentication\SessionMock',
|
||||
$authMgr->getSession()
|
||||
);
|
||||
|
||||
$authMgr->removeAuthorization();
|
||||
|
||||
$this->assertNull($authMgr->getUser());
|
||||
}
|
||||
|
||||
|
||||
public function testAuthentication()
|
||||
{
|
||||
AuthManager::clearInstance();
|
||||
$auth = $this->getManagerInstance();
|
||||
$this->assertFalse(
|
||||
$auth->authenticate(
|
||||
new Credentials("jhoe", "passjdoe"),
|
||||
new Credential("jhoe", "passjdoe"),
|
||||
false
|
||||
)
|
||||
);
|
||||
$this->assertFalse(
|
||||
$auth->authenticate(
|
||||
new Credentials("joe", "passjhoe"),
|
||||
new Credential("joe", "passjhoe"),
|
||||
false
|
||||
)
|
||||
);
|
||||
$this->assertTrue(
|
||||
$auth->authenticate(
|
||||
new Credentials("jdoe", "passjdoe"),
|
||||
new Credential("jdoe", "passjdoe"),
|
||||
false
|
||||
)
|
||||
);
|
||||
AuthManager::clearInstance();
|
||||
}
|
||||
|
||||
public function testPersistAuthInSession()
|
||||
{
|
||||
AuthManager::clearInstance();
|
||||
$session = new SessionMock();
|
||||
$auth = $this->getManagerInstance($session, true);
|
||||
$this->assertFalse($auth->isAuthenticated(true));
|
||||
$auth->authenticate(new Credentials("jdoe", "passjdoe"));
|
||||
$auth->authenticate(new Credential("jdoe", "passjdoe"));
|
||||
$this->assertNotEquals(null, $session->get("user"));
|
||||
$user = $session->get("user");
|
||||
$this->assertEquals("Username", $user->getUsername());
|
||||
$this->assertTrue($auth->isAuthenticated(true));
|
||||
AuthManager::clearInstance();
|
||||
}
|
||||
|
||||
public function testAuthenticateFromSession()
|
||||
{
|
||||
AuthManager::clearInstance();
|
||||
$session = new SessionMock();
|
||||
$session->set("user", BackendMock::getDummyUser());
|
||||
$auth = $this->getManagerInstance($session, false);
|
||||
|
@ -110,18 +179,195 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
* @expectedException Exception
|
||||
* @expectedExceptionMessage Session write after close
|
||||
*/
|
||||
public function testWriteSessionTwice()
|
||||
{
|
||||
$exception = false;
|
||||
try {
|
||||
$auth = $this->getManagerInstance($session, false);
|
||||
$this->assertFalse($auth->isAuthenticated(true));
|
||||
$auth->authenticate(new Credentials("jdoe", "passjdoe"));
|
||||
} catch (\Exception $e) {
|
||||
$exception = true;
|
||||
}
|
||||
$this->assertTrue($exception);
|
||||
$auth = $this->getManagerInstance($session, false);
|
||||
$this->assertFalse($auth->isAuthenticated(true));
|
||||
$auth->authenticate(new Credential("jdoe", "passjdoe"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Icinga\Exception\ConfigurationError
|
||||
* @expectedExceptionMessage No authentication backend set
|
||||
*/
|
||||
public function testErrorProneBackendsFromConfigurationWhenInitiate()
|
||||
{
|
||||
$managerConfig = new Zend_Config(
|
||||
array(
|
||||
'provider1' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\ErrorProneBackendMock'
|
||||
)
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
ErrorProneBackendMock::$throwOnCreate = true;
|
||||
|
||||
$authManager = $this->getManagerInstance($session, true, true, $managerConfig);
|
||||
|
||||
$this->assertNull(
|
||||
$authManager->getUserBackend('provider1')
|
||||
);
|
||||
|
||||
$authManager->authenticate(
|
||||
new Credential('jdoe', 'passjdoe')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Icinga\Exception\ConfigurationError
|
||||
* @expectedExceptionMessage No working backend found. Unable to authenticate any
|
||||
*/
|
||||
public function testErrorProneBackendsFromConfigurationWhenAuthenticate()
|
||||
{
|
||||
$managerConfig = new Zend_Config(
|
||||
array(
|
||||
'provider1' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\ErrorProneBackendMock'
|
||||
),
|
||||
'provider2' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\ErrorProneBackendMock'
|
||||
)
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
ErrorProneBackendMock::$throwOnCreate = false;
|
||||
|
||||
$authManager = $this->getManagerInstance($session, false, true, $managerConfig);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'Tests\Icinga\Authentication\ErrorProneBackendMock',
|
||||
$authManager->getUserBackend('provider1')
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'Tests\Icinga\Authentication\ErrorProneBackendMock',
|
||||
$authManager->getUserBackend('provider2')
|
||||
);
|
||||
|
||||
$authManager->authenticate(
|
||||
new Credential('jdoe', 'passjdoe')
|
||||
);
|
||||
}
|
||||
|
||||
public function testAuthenticationChainWithGoodProviders()
|
||||
{
|
||||
$managerConfig = new Zend_Config(
|
||||
array(
|
||||
'provider1' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\BackendMock'
|
||||
),
|
||||
'provider2' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\BackendMock'
|
||||
)
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$authManager = $this->getManagerInstance($session, true, true, $managerConfig);
|
||||
|
||||
$authManager->getUserBackend('provider1')->setCredentials(
|
||||
array(
|
||||
new Credential('p1-user1', 'p1-passwd1'),
|
||||
new Credential('p1-user2', 'p1-passwd2')
|
||||
)
|
||||
);
|
||||
|
||||
$authManager->getUserBackend('provider2')->setCredentials(
|
||||
array(
|
||||
new Credential('p2-user1', 'p2-passwd1'),
|
||||
new Credential('p2-user2', 'p2-passwd2')
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
$authManager->authenticate(new Credential('p2-user2', 'p2-passwd2'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testAuthenticationChainWithBadProviders()
|
||||
{
|
||||
$managerConfig = new Zend_Config(
|
||||
array(
|
||||
'provider1' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\ErrorProneBackendMock'
|
||||
),
|
||||
'provider2' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\ErrorProneBackendMock'
|
||||
),
|
||||
'provider3' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\ErrorProneBackendMock'
|
||||
),
|
||||
'provider4' => array(
|
||||
'class' => 'Tests\Icinga\Authentication\BackendMock'
|
||||
)
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$authManager = $this->getManagerInstance($session, false, true, $managerConfig);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'Tests\Icinga\Authentication\ErrorProneBackendMock',
|
||||
$authManager->getUserBackend('provider1')
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'Tests\Icinga\Authentication\BackendMock',
|
||||
$authManager->getUserBackend('provider4')
|
||||
);
|
||||
|
||||
$authManager->getUserBackend('provider4')->setCredentials(
|
||||
array(
|
||||
new Credential('p4-user1', 'p4-passwd1'),
|
||||
new Credential('p4-user2', 'p4-passwd2')
|
||||
)
|
||||
);
|
||||
|
||||
$session->isOpen = true;
|
||||
|
||||
$this->assertTrue(
|
||||
$authManager->authenticate(new Credential('p4-user2', 'p4-passwd2'))
|
||||
);
|
||||
|
||||
$session->isOpen = true;
|
||||
|
||||
$this->assertTrue(
|
||||
$authManager->authenticate(new Credential('p4-user1', 'p4-passwd1'))
|
||||
);
|
||||
|
||||
$session->isOpen = true;
|
||||
|
||||
$this->assertFalse(
|
||||
$authManager->authenticate(new Credential('p4-user2', 'p4-passwd1-WRONG123123'))
|
||||
);
|
||||
}
|
||||
|
||||
public function testErrorConditionsInConfiguration()
|
||||
{
|
||||
$managerConfig = new Zend_Config(
|
||||
array(
|
||||
'provider1' => array(
|
||||
'backend' => 'db'
|
||||
),
|
||||
'provider2' => array(
|
||||
'target' => 'user'
|
||||
),
|
||||
'provider3' => array(
|
||||
'class' => 'Uhh\Ahh\WeDoNotCare123'
|
||||
)
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$authManager = $this->getManagerInstance($session, true, true, $managerConfig);
|
||||
|
||||
$this->assertNull($authManager->getUserBackend('provider1'));
|
||||
$this->assertNull($authManager->getUserBackend('provider2'));
|
||||
$this->assertNull($authManager->getUserBackend('provider3'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,63 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/**
|
||||
* This file is part of Icinga 2 Web.
|
||||
*
|
||||
* Icinga 2 Web - Head for multiple monitoring backends.
|
||||
* Copyright (C) 2013 Icinga Development Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
||||
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||
* @author Icinga Development Team <info@icinga.org>
|
||||
*/
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Tests\Icinga\Authentication;
|
||||
|
||||
require_once('../../library/Icinga/Authentication/Session.php');
|
||||
require_once('../../library/Icinga/Authentication/PhpSession.php');
|
||||
require_once('../../library/Icinga/Application/Logger.php');
|
||||
require_once('../../library/Icinga/Exception/ConfigurationError.php');
|
||||
require_once('Zend/Log.php');
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once realpath(__DIR__ . '/../../../../../library/Icinga/Test/BaseTestCase.php');
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use Icinga\Authentication\PhpSession as PhpSession;
|
||||
use Icinga\Test\BaseTestCase;
|
||||
|
||||
class PHPSessionTest extends \PHPUnit_Framework_TestCase
|
||||
// @codingStandardsIgnoreStart
|
||||
require_once BaseTestCase::$libDir . '/Authentication/Session.php';
|
||||
require_once BaseTestCase::$libDir . '/Authentication/PhpSession.php';
|
||||
require_once BaseTestCase::$libDir . '/Application/Logger.php';
|
||||
require_once BaseTestCase::$libDir . '/Exception/ConfigurationError.php';
|
||||
require_once 'Zend/Log.php';
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
use Icinga\Authentication\PhpSession;
|
||||
|
||||
class PhpSessionTest extends BaseTestCase
|
||||
{
|
||||
|
||||
private function getSession()
|
||||
{
|
||||
|
||||
if (!is_writable('/tmp')) {
|
||||
$this->markTestSkipped('Could not write to session directory');
|
||||
return;
|
||||
}
|
||||
return new PhpSession(array(
|
||||
'use_cookies' => false,
|
||||
'save_path' => '/tmp'
|
||||
));
|
||||
return new PhpSession(
|
||||
array(
|
||||
'use_cookies' => false,
|
||||
'save_path' => '/tmp'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
/**
|
||||
|
@ -62,7 +94,7 @@ class PHPSessionTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals(session_id(), '', 'Asserting test precondition: session not being setup yet ');
|
||||
$session = $this->getSession();
|
||||
$session->open();
|
||||
$this->assertNotEquals(session_id(), '', 'Asserting a Session ID being available after PhpSession::open()');
|
||||
$this->assertNotEquals(session_id(), '', 'Asserting a Session ID being available after PhpSession::open()');
|
||||
$session->close();
|
||||
}
|
||||
|
||||
|
@ -76,8 +108,8 @@ class PHPSessionTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals(session_id(), '', 'Asserting test precondition: session not being setup yet ');
|
||||
$session = $this->getSession();
|
||||
$session->open();
|
||||
$this->assertNotEquals(session_id(), '', 'Asserting a Session ID being available after PhpSession::open()');
|
||||
$this->assertNotEquals(session_id(), '', 'Asserting a Session ID being available after PhpSession::open()');
|
||||
$session->purge();
|
||||
$this->assertEquals(session_id(), '', 'Asserting no Session ID being available after PhpSession::purge()');
|
||||
$this->assertEquals(session_id(), '', 'Asserting no Session ID being available after PhpSession::purge()');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ class SessionMock extends Session
|
|||
|
||||
public function write($keepOpen = false)
|
||||
{
|
||||
|
||||
$this->open();
|
||||
if (!$keepOpen) {
|
||||
$this->close();
|
||||
|
|
Loading…
Reference in New Issue