Merge branch 'bugfix/db-user-backend-not-working-4596'

fixes #4577
fixes #4578
fixes #4596
fixes #4599
fixes #4627
This commit is contained in:
Marius Hein 2013-08-26 11:11:44 +02:00
commit 1b63f24b7b
13 changed files with 281 additions and 309 deletions

View File

@ -482,13 +482,13 @@ exec { 'populate-icingweba-pgsql-db-accounts':
} }
exec { 'populate-icingaweb-mysql-db-preferences': exec { 'populate-icingaweb-mysql-db-preferences':
unless => 'mysql -uicingaweb -picinga icingaweb -e "SELECT * FROM preferences;" &> /dev/null', unless => 'mysql -uicingaweb -picinga icingaweb -e "SELECT * FROM preference;" &> /dev/null',
command => 'mysql -uicingaweb -picinga icingaweb < /vagrant/etc/schema/preferences.mysql.sql', command => 'mysql -uicingaweb -picinga icingaweb < /vagrant/etc/schema/preferences.mysql.sql',
require => [ Exec['create-mysql-icingaweb-db'] ] require => [ Exec['create-mysql-icingaweb-db'] ]
} }
exec { 'populate-icingweba-pgsql-db-preferences': exec { 'populate-icingweba-pgsql-db-preferences':
unless => 'psql -U icingaweb -d icingaweb -c "SELECT * FROM preferences;" &> /dev/null', unless => 'psql -U icingaweb -d icingaweb -c "SELECT * FROM preference;" &> /dev/null',
command => 'sudo -u postgres psql -U icingaweb -d icingaweb -f /vagrant/etc/schema/preferences.pgsql.sql', command => 'sudo -u postgres psql -U icingaweb -d icingaweb -f /vagrant/etc/schema/preferences.pgsql.sql',
require => [ Exec['create-pgsql-icingaweb-db'] ] require => [ Exec['create-pgsql-icingaweb-db'] ]
} }

View File

@ -0,0 +1,24 @@
create table account (
`username` varchar(255) COLLATE latin1_general_ci NOT NULL,
`salt` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`active` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*
* user: icingaadmin
* password: icinga
*/
INSERT INTO account (
`username`,
`salt`,
`password`,
`active`
)
VALUES (
'icingaadmin',
'IepKgTTShC',
'52deddb5cc7a5769484fcb0fbc5981a7c62cd9f3ddbb8ff3ddb1b89ea324ad16',
1
);

View File

@ -0,0 +1,28 @@
create table "account" (
"username" character varying(255) NOT NULL,
"salt" character varying(255),
"password" character varying(255) NOT NULL,
"active" boolean
);
ALTER TABLE ONLY "account"
ADD CONSTRAINT account_pkey PRIMARY KEY ("username");
CREATE UNIQUE INDEX username_lower_unique_idx ON "account" USING btree (lower((username)::text));
/*
* user: icingaadmin
* password: icinga
*/
INSERT INTO "account" (
"username",
"salt",
"password",
"active"
)
VALUES (
'icingaadmin',
'IepKgTTShC',
'52deddb5cc7a5769484fcb0fbc5981a7c62cd9f3ddbb8ff3ddb1b89ea324ad16',
true
);

View File

@ -1,7 +1,6 @@
create table `preferences`( create table `preference`(
`username` VARCHAR(255) NOT NULL, `username` VARCHAR(255) COLLATE latin1_general_ci NOT NULL,
`preference` VARCHAR(100) NOT NULL, `key` VARCHAR(100) COLLATE latin1_general_ci NOT NULL,
`value` VARCHAR(255) NOT NULL, `value` VARCHAR(255) NOT NULL,
PRIMARY KEY (`username`, `key`)
PRIMARY KEY(username, preference) ) ENGINE=InnoDB;
);

View File

@ -1,7 +1,10 @@
create table "preferences"( create table "preference"(
"username" VARCHAR(255) NOT NULL, "username" VARCHAR(255) NOT NULL,
"preference" VARCHAR(100) NOT NULL, "key" VARCHAR(100) NOT NULL,
"value" VARCHAR(255) NOT NULL, "value" VARCHAR(255) NOT NULL
PRIMARY KEY(username, preference)
); );
ALTER TABLE ONLY "preference"
ADD CONSTRAINT preference_pkey PRIMARY KEY ("username", "key");
CREATE UNIQUE INDEX username_and_key_lower_unique_idx ON "preference" USING btree (lower((username)::text), lower((key)::text));

View File

@ -1,28 +0,0 @@
create table account (
user_name varchar(255) NOT NULL,
first_name varchar(255),
last_name varchar(255),
email varchar(255),
domain varchar(255),
last_login timestamp,
salt varchar(255),
password varchar(255) NOT NULL,
active BOOL,
PRIMARY KEY (user_name)
);
/*
* user: icingaadmin
* password: icinga
*/
INSERT INTO account (
user_name,
salt,
password,
active)
VALUES (
'icingaadmin',
'IepKgTTShC',
'52deddb5cc7a5769484fcb0fbc5981a7c62cd9f3ddbb8ff3ddb1b89ea324ad16',
true
);

View File

@ -1,28 +0,0 @@
create table "account" (
user_name varchar(255) NOT NULL,
first_name varchar(255),
last_name varchar(255),
email varchar(255),
domain varchar(255),
last_login timestamp,
salt varchar(255),
password varchar(255) NOT NULL,
active BOOL,
PRIMARY KEY (user_name)
);
/*
* user: icingaadmin
* password: icinga
*/
INSERT INTO "account" (
user_name,
salt,
password,
active)
VALUES (
'icingaadmin',
'IepKgTTShC',
'52deddb5cc7a5769484fcb0fbc5981a7c62cd9f3ddbb8ff3ddb1b89ea324ad16',
true
);

View File

@ -54,7 +54,7 @@ class DbAdapterFactory implements ConfigAwareFactory
* *
* @var String * @var String
*/ */
private static $factoryClass; private static $factoryClass = 'Zend_Db';
/** /**
* Resource cache to allow multiple use * Resource cache to allow multiple use
@ -115,7 +115,7 @@ class DbAdapterFactory implements ConfigAwareFactory
public static function resetConfig() public static function resetConfig()
{ {
self::$resources = null; self::$resources = null;
self::$factoryClass = null; self::$factoryClass = 'Zend_Db';
} }
/** /**
@ -150,11 +150,11 @@ class DbAdapterFactory implements ConfigAwareFactory
/** /**
* Get the resource with the given $identifier * Get the resource with the given $identifier
* *
* @throws ConfigurationError
* @throws ProgrammingError
* @param string $identifier The name of the resource * @param string $identifier The name of the resource
* *
* @return Zend_Db_Adapter_Abstract * @return Zend_Db_Adapter_Abstract
* @throws ConfigurationError
* @throws ProgrammingError
*/ */
public static function getDbAdapter($identifier) public static function getDbAdapter($identifier)
{ {
@ -180,6 +180,19 @@ class DbAdapterFactory implements ConfigAwareFactory
} }
} }
/**
* Create a db adapter directly from a configuration instead of a resource identifier
*
* @param Zend_Config $config The resource configuration that will be used.
*
* @return Zend_Db_Adapter_Abstract The created DbAdapter
* @throws ProgrammingError
*/
public static function createDbAdapterFromConfig(Zend_Config $config)
{
return self::createDbAdapter($config);
}
/** /**
* Create the Db_Adapter for the given configuration section * Create the Db_Adapter for the given configuration section
* *
@ -225,21 +238,18 @@ class DbAdapterFactory implements ConfigAwareFactory
* Call the currently set factory class * Call the currently set factory class
* *
* @param string $adapter The name of the used db adapter * @param string $adapter The name of the used db adapter
* @param array $options An array or Zend_Config object with adapter * @param mixed $options An array or Zend_Config object with adapter
* parameters * parameters
* *
* @return Zend_Db_Adapter_Abstract The created adapter * @return Zend_Db_Adapter_Abstract The created adapter
*/ */
private static function callFactory($adapter, array $options) private static function callFactory($adapter, $options)
{ {
$factory = self::$factoryClass; $factory = self::$factoryClass;
$optionModifierCallback = __CLASS__ . '::get' . ucfirst(str_replace('_', '', $adapter)) . 'Options';
$optionModifierCallback = __CLASS__. '::get'. ucfirst(str_replace('_', '', $adapter)). 'Options';
if (is_callable($optionModifierCallback)) { if (is_callable($optionModifierCallback)) {
$options = call_user_func($optionModifierCallback, $options); $options = call_user_func($optionModifierCallback, $options);
} }
return $factory::factory($adapter, $options); return $factory::factory($adapter, $options);
} }

View File

@ -29,6 +29,7 @@
namespace Icinga\Authentication\Backend; namespace Icinga\Authentication\Backend;
use Zend_Db;
use \Icinga\User; use \Icinga\User;
use \Icinga\Authentication\UserBackend; use \Icinga\Authentication\UserBackend;
use \Icinga\Authentication\Credentials; use \Icinga\Authentication\Credentials;
@ -49,13 +50,7 @@ class DbUserBackend implements UserBackend
* Mapping of all table column names * Mapping of all table column names
*/ */
const USER_NAME_COLUMN = 'user_name'; const USER_NAME_COLUMN = 'username';
const FIRST_NAME_COLUMN = 'first_name';
const LAST_NAME_COLUMN = 'last_name';
const LAST_LOGIN_COLUMN = 'last_login';
const SALT_COLUMN = 'salt'; const SALT_COLUMN = 'salt';
@ -63,10 +58,6 @@ class DbUserBackend implements UserBackend
const ACTIVE_COLUMN = 'active'; const ACTIVE_COLUMN = 'active';
const DOMAIN_COLUMN = 'domain';
const EMAIL_COLUMN = 'email';
/** /**
* The database connection that will be used for fetching users * The database connection that will be used for fetching users
* *
@ -80,6 +71,7 @@ class DbUserBackend implements UserBackend
* @var String * @var String
*/ */
private $userTable = "account"; private $userTable = "account";
/** /**
* Create a DbUserBackend * Create a DbUserBackend
* *
@ -109,7 +101,7 @@ class DbUserBackend implements UserBackend
return false; return false;
} }
$user = $this->getUserByName($credential->getUsername()); $user = $this->getUserByName($credential->getUsername());
return !empty($user); return isset($user);
} }
/** /**
@ -126,6 +118,12 @@ class DbUserBackend implements UserBackend
return null; return null;
} }
$this->db->getConnection(); $this->db->getConnection();
try {
$salt = $this->getUserSalt($credential->getUsername());
} catch (\Exception $e) {
Logger::error($e->getMessage());
return null;
}
$res = $this->db $res = $this->db
->select()->from($this->userTable) ->select()->from($this->userTable)
->where(self::USER_NAME_COLUMN.' = ?', $credential->getUsername()) ->where(self::USER_NAME_COLUMN.' = ?', $credential->getUsername())
@ -134,35 +132,16 @@ class DbUserBackend implements UserBackend
self::PASSWORD_COLUMN. ' = ?', self::PASSWORD_COLUMN. ' = ?',
hash_hmac( hash_hmac(
'sha256', 'sha256',
$this->getUserSalt($credential->getUsername()), $salt,
$credential->getPassword() $credential->getPassword()
) )
) )
->query()->fetch(); ->query()->fetch();
if (!empty($res)) { if ($res !== false) {
$this->updateLastLogin($credential->getUsername());
return $this->createUserFromResult($res); return $this->createUserFromResult($res);
} }
} }
/**
* Update the timestamp containing the time of the last login for
* the user with the given username
*
* @param $username The login-name of the user.
*/
private function updateLastLogin($username)
{
$this->db->getConnection();
$this->db->update(
$this->userTable,
array(
self::LAST_LOGIN_COLUMN => new \Zend_Db_Expr('NOW()')
),
self::USER_NAME_COLUMN.' = '.$this->db->quoteInto('?', $username)
);
}
/** /**
* Fetch the users salt from the database * Fetch the users salt from the database
* *
@ -177,7 +156,11 @@ class DbUserBackend implements UserBackend
->from($this->userTable, self::SALT_COLUMN) ->from($this->userTable, self::SALT_COLUMN)
->where(self::USER_NAME_COLUMN.' = ?', $username) ->where(self::USER_NAME_COLUMN.' = ?', $username)
->query()->fetch(); ->query()->fetch();
return $res[self::SALT_COLUMN]; if ($res !== false) {
return $res->{self::SALT_COLUMN};
} else {
throw new \Exception('No Salt found for user "' . $username . '"');
}
} }
/** /**
@ -200,10 +183,10 @@ class DbUserBackend implements UserBackend
->where(self::USER_NAME_COLUMN.' = ?', $username) ->where(self::USER_NAME_COLUMN.' = ?', $username)
->where(self::ACTIVE_COLUMN.' = ?', true) ->where(self::ACTIVE_COLUMN.' = ?', true)
->query()->fetch(); ->query()->fetch();
if (empty($res)) { if ($res !== false) {
return null;
}
return $this->createUserFromResult($res); return $this->createUserFromResult($res);
}
return null;
} catch (\Zend_Db_Statement_Exception $exc) { } catch (\Zend_Db_Statement_Exception $exc) {
Logger::error("Could not fetch users from db : %s ", $exc->getMessage()); Logger::error("Could not fetch users from db : %s ", $exc->getMessage());
return null; return null;
@ -213,19 +196,15 @@ class DbUserBackend implements UserBackend
/** /**
* Create a new instance of User from a query result * Create a new instance of User from a query result
* *
* @param array $result The query result-array containing the column * @param $result The query result containing the user row
* *
* @return User The created instance of User. * @return User The created instance of User.
*/ */
private function createUserFromResult(Array $result) private function createUserFromResult($resultRow)
{ {
$usr = new User( $usr = new User(
$result[self::USER_NAME_COLUMN], $resultRow->{self::USER_NAME_COLUMN}
$result[self::FIRST_NAME_COLUMN],
$result[self::LAST_NAME_COLUMN],
$result[self::EMAIL_COLUMN]
); );
$usr->setDomain($result[self::DOMAIN_COLUMN]);
return $usr; return $usr;
} }
} }

View File

@ -159,21 +159,21 @@ class Manager
*/ */
private function initBestBackend($target, $backends) private function initBestBackend($target, $backends)
{ {
foreach ($backends as $backend) { foreach ($backends as $key => $backend) {
if (strtolower($target) === strtolower($backend->target)) { if (strtolower($target) === strtolower($backend->target)) {
$db = $this->tryToInitBackend($target, $backend); $db = $this->tryToInitBackend($target, $backend);
if (isset($db)) { if (isset($db)) {
break;
}
}
}
if (!isset($db)) {
$msg = 'Failed to create any authentication backend, login will not be possible.';
Logger::error($msg);
return null;
}
return $db; return $db;
} }
}
}
Logger::error(
'Failed to create any authentication backend '
. 'for the target "' . $target . '". Entities belonging to this target'
. ' will not be able to authenticate.'
);
return null;
}
/** /**
* Try to create the backend with the given configuration * Try to create the backend with the given configuration
@ -188,6 +188,7 @@ class Manager
{ {
$type = ucwords(strtolower($backendConfig->backend)); $type = ucwords(strtolower($backendConfig->backend));
if (!$type) { if (!$type) {
Logger::warn('Backend has no type configured. (e.g. backend=ldap)');
return null; return null;
} }
try { try {
@ -199,9 +200,7 @@ class Manager
$class = '\\Icinga\\Authentication\\Backend\\' . $type . $target. 'Backend'; $class = '\\Icinga\\Authentication\\Backend\\' . $type . $target. 'Backend';
return new $class($resource); return new $class($resource);
} catch (\Exception $e) { } catch (\Exception $e) {
$msg = 'Not able to create backend: ' . $msg = 'Not able to create backend. Exception: ' . $e->getMessage();
print_r($backendConfig->backend, true)
. '. Exception: ' . $e->getMessage();
Logger::warn($msg); Logger::warn($msg);
return null; return null;
} }
@ -215,7 +214,8 @@ class Manager
* in the current session * in the current session
* *
* @return Boolean true on success, otherwise false * @return Boolean true on success, otherwise false
**/ * @throws ConfigError
*/
public function authenticate(Credentials $credentials, $persist = true) public function authenticate(Credentials $credentials, $persist = true)
{ {
if (!$this->userBackend) { if (!$this->userBackend) {

View File

@ -47,7 +47,7 @@ class DbStore implements LoadInterface, FlushObserverInterface
/** /**
* Column name for preference * Column name for preference
*/ */
const COLUMN_PREFERENCE = 'preference'; const COLUMN_PREFERENCE = 'key';
/** /**
* Column name for value * Column name for value
@ -66,14 +66,14 @@ class DbStore implements LoadInterface, FlushObserverInterface
* *
* @var Zend_Db_Adapter_Abstract * @var Zend_Db_Adapter_Abstract
*/ */
private $dbAdapter; private $db;
/** /**
* Table name * Table name
* *
* @var string * @var string
*/ */
private $table = 'preferences'; private $table = 'preference';
/** /**
* Setter for user * Setter for user
@ -88,12 +88,11 @@ class DbStore implements LoadInterface, FlushObserverInterface
/** /**
* Setter for db adapter * Setter for db adapter
* *
* @param Zend_Db_Adapter_Abstract $dbAdapter * @param Zend_Db_Adapter_Abstract $db
*/ */
public function setDbAdapter(Zend_Db_Adapter_Abstract $dbAdapter) public function setDbAdapter(Zend_Db_Adapter_Abstract $db)
{ {
$this->dbAdapter = $dbAdapter; $this->db = $db;
$this->dbAdapter->getProfiler()->setEnabled(true);
} }
@ -114,14 +113,14 @@ class DbStore implements LoadInterface, FlushObserverInterface
*/ */
public function load() public function load()
{ {
$res = $this->dbAdapter->select()->from($this->table) $res = $this->db->select()->from($this->table)
->where('username=?', $this->user->getUsername()) ->where('username=?', $this->user->getUsername())
->query(); ->query();
$out = array(); $out = array();
foreach ($res->fetchAll() as $row) { foreach ($res->fetchAll() as $row) {
$out[$row[self::COLUMN_PREFERENCE]] = $row[self::COLUMN_VALUE]; $out[$row->{self::COLUMN_PREFERENCE}] = $row->{self::COLUMN_VALUE};
} }
return $out; return $out;
@ -136,8 +135,8 @@ class DbStore implements LoadInterface, FlushObserverInterface
private function createWhereCondition($preference) private function createWhereCondition($preference)
{ {
return array( return array(
self::COLUMN_USERNAME. '=?' => $this->user->getUsername(), $this->db->quoteIdentifier(self::COLUMN_USERNAME) . '=?' => $this->user->getUsername(),
self::COLUMN_PREFERENCE. '=?' => $preference $this->db->quoteIdentifier(self::COLUMN_PREFERENCE) . '=?' => $preference
); );
} }
@ -150,12 +149,12 @@ class DbStore implements LoadInterface, FlushObserverInterface
*/ */
private function doCreate($preference, $value) private function doCreate($preference, $value)
{ {
return $this->dbAdapter->insert( return $this->db->insert(
$this->table, $this->table,
array( array(
self::COLUMN_USERNAME => $this->user->getUsername(), $this->db->quoteIdentifier(self::COLUMN_USERNAME) => $this->user->getUsername(),
self::COLUMN_PREFERENCE => $preference, $this->db->quoteIdentifier(self::COLUMN_PREFERENCE) => $preference,
self::COLUMN_VALUE => $value $this->db->quoteIdentifier(self::COLUMN_VALUE) => $value
) )
); );
} }
@ -169,7 +168,7 @@ class DbStore implements LoadInterface, FlushObserverInterface
*/ */
private function doUpdate($preference, $value) private function doUpdate($preference, $value)
{ {
return $this->dbAdapter->update( return $this->db->update(
$this->table, $this->table,
array( array(
self::COLUMN_VALUE => $value self::COLUMN_VALUE => $value
@ -186,7 +185,7 @@ class DbStore implements LoadInterface, FlushObserverInterface
*/ */
private function doDelete($preference) private function doDelete($preference)
{ {
return $this->dbAdapter->delete( return $this->db->delete(
$this->table, $this->table,
$this->createWhereCondition($preference) $this->createWhereCondition($preference)
); );

View File

@ -29,29 +29,46 @@
namespace Tests\Icinga\Authentication; namespace Tests\Icinga\Authentication;
require_once('Zend/Config.php');
require_once('Zend/Config/Ini.php'); require_once('Zend/Config/Ini.php');
require_once('Zend/Db/Adapter/Abstract.php');
require_once('Zend/Db.php'); require_once('Zend/Db.php');
require_once('Zend/Log.php');
require_once('../../library/Icinga/Util/ConfigAwareFactory.php');
require_once('../../library/Icinga/Authentication/UserBackend.php'); require_once('../../library/Icinga/Authentication/UserBackend.php');
require_once('../../library/Icinga/Protocol/Ldap/Exception.php'); require_once('../../library/Icinga/Protocol/Ldap/Exception.php');
require_once('../../library/Icinga/Application/DbAdapterFactory.php');
require_once('../../library/Icinga/Application/Config.php'); require_once('../../library/Icinga/Application/Config.php');
require_once('../../library/Icinga/Authentication/Credentials.php'); require_once('../../library/Icinga/Authentication/Credentials.php');
require_once('../../library/Icinga/Authentication/Backend/DbUserBackend.php'); require_once('../../library/Icinga/Authentication/Backend/DbUserBackend.php');
require_once('../../library/Icinga/User.php'); require_once('../../library/Icinga/User.php');
require_once('../../library/Icinga/Application/Logger.php');
use Zend_Config;
use Zend_Db_Adapter_Abstract;
use Icinga\Authentication\Backend\DbUserBackend; use Icinga\Authentication\Backend\DbUserBackend;
use Icinga\Application\DbAdapterFactory;
use Icinga\Util\Crypto; use Icinga\Util\Crypto;
use Icinga\Authentication\Credentials; use Icinga\Authentication\Credentials;
use Icinga\User; use Icinga\User;
use \Icinga\Application\Config; use \Icinga\Application\Config;
/** /**
*
* Test Class fpr DbUserBackend * Test Class fpr DbUserBackend
* Created Wed, 17 Jul 2013 11:52:34 +0000
*
*/ */
class DbUserBackendTest extends \PHPUnit_Framework_TestCase { class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
/*
* Mapping of columns
*/
const USER_NAME_COLUMN = 'username';
const SALT_COLUMN = 'salt';
const PASSWORD_COLUMN = 'password';
const ACTIVE_COLUMN = 'active';
/** /**
* The table that is used to store the authentication data * The table that is used to store the authentication data
* *
@ -66,21 +83,6 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
*/ */
private $testDatabase = 'icinga_unittest'; private $testDatabase = 'icinga_unittest';
/**
* Mapping of columns
*
* @var string
*/
private $USER_NAME_COLUMN = 'user_name',
$FIRST_NAME_COLUMN = 'first_name',
$LAST_NAME_COLUMN = 'last_name',
$LAST_LOGIN_COLUMN = 'last_login',
$SALT_COLUMN = 'salt',
$PASSWORD_COLUMN = 'password',
$ACTIVE_COLUMN = 'active',
$DOMAIN_COLUMN = 'domain',
$EMAIL_COLUMN = 'email';
/** /**
* Example users * Example users
* *
@ -114,36 +116,40 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
); );
/** /**
* Create a preset-configuration that can be used to access the database * Create a preset configuration that can be used to access the database
* with the icinga_unittest account. * with the icinga_unittest account.
* *
* @return \stdClass * @param String $dbType The database type as a string, like 'mysql' or 'pgsql'.
*
* @return Zend_Config The created resource configuration
*/ */
private function getBackendConfig() private function getResourceConfig($dbType)
{ {
$config = new \stdClass(); return new Zend_Config(
$config->host = '127.0.0.1'; array(
$config->user = 'icinga_unittest'; 'type' => 'db',
$config->password= 'icinga_unittest'; 'db' => $dbType,
$config->table = $this->testTable; 'host' => 'localhost',
$config->db = $this->testDatabase; 'username' => 'icinga_unittest',
return $config; 'password' => 'icinga_unittest',
'dbname' => $this->testDatabase,
'table' => $this->testTable
)
);
} }
/** /**
* Create a backend with the given database type * Create a backend with the given database type
* *
* @param $dbType The database type as a string, like 'mysql' or 'pgsql'. * @param String $dbType The database type as a string, like 'mysql' or 'pgsql'.
* *
* @return DbUserBackend|null * @return DbUserBackend|null
*/ */
private function createBackend($dbType) private function createBackend($dbType)
{ {
try { try {
$config = $this->getBackendConfig(); $db = $this->createDb($this->getResourceConfig($dbType));
$config->dbtype = $dbType; $this->setUpDb($db,$dbType);
$db = $this->createDb($dbType,$config);
$this->setUpDb($db);
return new DbUserBackend($db); return new DbUserBackend($db);
} catch(\Exception $e) { } catch(\Exception $e) {
echo 'CREATE_BACKEND_ERROR:'.$e->getMessage(); echo 'CREATE_BACKEND_ERROR:'.$e->getMessage();
@ -151,29 +157,42 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
} }
} }
/**
* Create the db adapter
*
* @param $config The configuration to use
*
* @return Zend_Db_Adapter_Abstract The created adabter
*/
private function createDb($config)
{
return DbAdapterFactory::createDbAdapterFromConfig($config);
}
/** /**
* Create the backends and fill it with sample-data * Create the backends and fill it with sample-data
*/ */
protected function setUp() protected function setUp()
{ {
DbAdapterFactory::resetConfig();
$this->users = Array( $this->users = Array(
0 => Array( 0 => Array(
$this->USER_NAME_COLUMN => 'user1', self::USER_NAME_COLUMN => 'user1',
$this->PASSWORD_COLUMN => 'secret1', self::PASSWORD_COLUMN => 'secret1',
$this->SALT_COLUMN => '8a7487a539c5d1d6766639d04d1ed1e6', self::SALT_COLUMN => '8a7487a539c5d1d6766639d04d1ed1e6',
$this->ACTIVE_COLUMN => 1 self::ACTIVE_COLUMN => 1
), ),
1 => Array( 1 => Array(
$this->USER_NAME_COLUMN => 'user2', self::USER_NAME_COLUMN => 'user2',
$this->PASSWORD_COLUMN => 'secret2', self::PASSWORD_COLUMN => 'secret2',
$this->SALT_COLUMN => '04b5521ddd761b5a5b633be83faa494d', self::SALT_COLUMN => '04b5521ddd761b5a5b633be83faa494d',
$this->ACTIVE_COLUMN => 1 self::ACTIVE_COLUMN => 1
), ),
2 => Array( 2 => Array(
$this->USER_NAME_COLUMN => 'user3', self::USER_NAME_COLUMN => 'user3',
$this->PASSWORD_COLUMN => 'secret3', self::PASSWORD_COLUMN => 'secret3',
$this->SALT_COLUMN => '08bb94ba3120338ae56db80ef551d324', self::SALT_COLUMN => '08bb94ba3120338ae56db80ef551d324',
$this->ACTIVE_COLUMN => 0 self::ACTIVE_COLUMN => 0
) )
); );
$this->mysql = $this->createBackend('mysql'); $this->mysql = $this->createBackend('mysql');
@ -185,12 +204,11 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
*/ */
public function testCorrectUserLoginForPgsql() public function testCorrectUserLoginForPgsql()
{ {
if(!empty($this->pgsql)){ if (!empty($this->pgsql)) {
$this->runBackendAuthentication($this->pgsql); $this->runBackendAuthentication($this->pgsql);
$this->runBackendUsername($this->pgsql); $this->runBackendUsername($this->pgsql);
} }
else{ else {
echo '\nSKIPPING PGSQL TEST...\n';
$this->markTestSkipped(); $this->markTestSkipped();
} }
} }
@ -205,40 +223,21 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
$this->runBackendUsername($this->mysql); $this->runBackendUsername($this->mysql);
} }
else{ else{
echo '\nSKIPPING MYSQL TEST...\n';
$this->markTestSkipped(); $this->markTestSkipped();
} }
} }
/**
* Create a database with the given config and type
*
* @param $dbtype The database type as a string, like 'mysql' or 'pgsql'.
* @param $config The configuration-object.
* @return mixed
*/
private function createDb($dbtype,$config)
{
return \Zend_Db::factory($this->dbTypeMap[$dbtype],
array(
'host' => $config->host,
'username' => $config->user,
'password' => $config->password,
'dbname' => 'icinga_unittest'
));
}
/** /**
* Try to drop all databases that may eventually be present * Try to drop all databases that may eventually be present
*/ */
public function tearDown() public function tearDown()
{ {
try{ try{
$db = $this->createDb('mysql',$this->getBackendConfig()); $db = $this->createDb($this->getResourceConfig('mysql'));
$this->tearDownDb($db); $this->tearDownDb($db);
} catch(\Exception $e) { } } catch(\Exception $e) { }
try { try {
$db = $this->createDb('pgsql',$this->getBackendConfig()); $db = $this->createDb($this->getResourceConfig('pgsql'));
$this->tearDownDb($db); $this->tearDownDb($db);
} catch(\Exception $e) { } } catch(\Exception $e) { }
} }
@ -256,37 +255,28 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
/** /**
* Fill the given database with the sample-data provided in users * Fill the given database with the sample-data provided in users
* *
* @param $db * @param $db Zend_Db_Adapter_Abstract The database to set up
* @param $type String The database type as a string: 'mysql'|'pgsql'
*/ */
private function setUpDb($db) private function setUpDb($db,$type)
{ {
try { try {
$this->tearDownDb($db); $this->tearDownDb($db);
} catch (\Exception $e) { } catch (\Exception $e) {}
// if no database exists, an exception will be thrown
} $setupScript = file_get_contents('../../etc/schema/accounts.' . $type . '.sql');
$db->exec('CREATE TABLE '.$this->testTable.' ( $db->exec($setupScript);
'.$this->USER_NAME_COLUMN.' varchar(255) NOT NULL,
'.$this->FIRST_NAME_COLUMN.' varchar(255),
'.$this->LAST_NAME_COLUMN.' varchar(255),
'.$this->LAST_LOGIN_COLUMN.' timestamp,
'.$this->SALT_COLUMN.' varchar(255),
'.$this->DOMAIN_COLUMN.' varchar(255),
'.$this->EMAIL_COLUMN.' varchar(255),
'.$this->PASSWORD_COLUMN.' varchar(255) NOT NULL,
'.$this->ACTIVE_COLUMN.' BOOL,
PRIMARY KEY ('.$this->USER_NAME_COLUMN.')
)');
for ($i = 0; $i < count($this->users); $i++) { for ($i = 0; $i < count($this->users); $i++) {
$usr = $this->users[$i]; $usr = $this->users[$i];
$data = Array( $data = Array(
$this->USER_NAME_COLUMN => $usr[$this->USER_NAME_COLUMN], self::USER_NAME_COLUMN => $usr[self::USER_NAME_COLUMN],
$this->PASSWORD_COLUMN => hash_hmac('sha256', self::PASSWORD_COLUMN => hash_hmac('sha256',
$usr[$this->SALT_COLUMN], $usr[self::SALT_COLUMN],
$usr[$this->PASSWORD_COLUMN] $usr[self::PASSWORD_COLUMN]
), ),
$this->ACTIVE_COLUMN => $usr[$this->ACTIVE_COLUMN], self::ACTIVE_COLUMN => $usr[self::ACTIVE_COLUMN],
$this->SALT_COLUMN => $usr[$this->SALT_COLUMN] self::SALT_COLUMN => $usr[self::SALT_COLUMN]
); );
$db->insert($this->testTable,$data); $db->insert($this->testTable,$data);
} }
@ -303,23 +293,23 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
// Known user // Known user
$this->assertTrue($backend->hasUsername( $this->assertTrue($backend->hasUsername(
new Credentials( new Credentials(
$this->users[0][$this->USER_NAME_COLUMN], $this->users[0][self::USER_NAME_COLUMN],
$this->users[0][$this->PASSWORD_COLUMN]) $this->users[0][self::PASSWORD_COLUMN])
),'Assert that the user is known by the backend'); ), 'Assert that the user is known by the backend');
// Unknown user // Unknown user
$this->assertFalse($backend->hasUsername( $this->assertFalse($backend->hasUsername(
new Credentials( new Credentials(
'unknown user', 'unknown user',
'secret') 'secret')
),'Assert that the user is not known by the backend'); ), 'Assert that the user is not known by the backend');
// Inactive user // Inactive user
$this->assertFalse($backend->hasUsername( $this->assertFalse($backend->hasUsername(
new Credentials( new Credentials(
$this->users[2][$this->USER_NAME_COLUMN], $this->users[2][self::USER_NAME_COLUMN],
$this->users[2][$this->PASSWORD_COLUMN]) $this->users[2][self::PASSWORD_COLUMN])
),'Assert that the user is inactive and therefore not known by the backend'); ), 'Assert that the user is inactive and therefore not known by the backend');
} }
/** /**
@ -332,17 +322,17 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
// Known user // Known user
$this->assertNotNull($backend->authenticate( $this->assertNotNull($backend->authenticate(
new Credentials( new Credentials(
$this->users[0][$this->USER_NAME_COLUMN], $this->users[0][self::USER_NAME_COLUMN],
$this->users[0][$this->PASSWORD_COLUMN]) $this->users[0][self::PASSWORD_COLUMN])
),'Assert that an existing, active user with the right credentials can authenticate.'); ), 'Assert that an existing, active user with the right credentials can authenticate.');
// Wrong password // Wrong password
$this->assertNull( $this->assertNull(
$backend->authenticate( $backend->authenticate(
new Credentials( new Credentials(
$this->users[1][$this->USER_NAME_COLUMN], $this->users[1][self::USER_NAME_COLUMN],
'wrongpassword') 'wrongpassword')
),'Assert that an existing user with an invalid password cannot authenticate' ), 'Assert that an existing user with an invalid password cannot authenticate'
); );
// Nonexisting user // Nonexisting user
@ -350,16 +340,16 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
$backend->authenticate( $backend->authenticate(
new Credentials( new Credentials(
'nonexisting user', 'nonexisting user',
$this->users[1][$this->PASSWORD_COLUMN]) $this->users[1][self::PASSWORD_COLUMN])
),'Assert that a non-existing user cannot authenticate.' ), 'Assert that a non-existing user cannot authenticate.'
); );
// Inactive user // Inactive user
$this->assertNull( $this->assertNull(
$backend->authenticate( $backend->authenticate(
new Credentials( new Credentials(
$this->users[2][$this->USER_NAME_COLUMN], $this->users[2][self::USER_NAME_COLUMN],
$this->users[2][$this->PASSWORD_COLUMN]) $this->users[2][self::PASSWORD_COLUMN])
),'Assert that an inactive user cannot authenticate.'); ), 'Assert that an inactive user cannot authenticate.');
} }
} }

View File

@ -2,20 +2,26 @@
namespace Tests\Icinga\User\Preferences; namespace Tests\Icinga\User\Preferences;
require_once __DIR__. '/../../../../../../library/Icinga/Exception/ConfigurationError.php'; require_once __DIR__ . '/../../../../../../library/Icinga/Exception/ConfigurationError.php';
require_once __DIR__. '/../../../../../../library/Icinga/User.php'; require_once __DIR__ . '/../../../../../../library/Icinga/Util/ConfigAwareFactory.php';
require_once __DIR__. '/../../../../../../library/Icinga/User/Preferences.php'; require_once __DIR__ . '/../../../../../../library/Icinga/Application/DbAdapterFactory.php';
require_once __DIR__. '/../../../../../../library/Icinga/User/Preferences/LoadInterface.php'; require_once __DIR__ . '/../../../../../../library/Icinga/User.php';
require_once __DIR__. '/../../../../../../library/Icinga/User/Preferences/FlushObserverInterface.php'; require_once __DIR__ . '/../../../../../../library/Icinga/User/Preferences.php';
require_once __DIR__. '/../../../../../../library/Icinga/User/Preferences/DbStore.php'; require_once __DIR__ . '/../../../../../../library/Icinga/User/Preferences/ChangeSet.php';
require_once __DIR__ . '/../../../../../../library/Icinga/User/Preferences/LoadInterface.php';
require_once __DIR__ . '/../../../../../../library/Icinga/User/Preferences/FlushObserverInterface.php';
require_once __DIR__ . '/../../../../../../library/Icinga/User/Preferences/DbStore.php';
require_once 'Zend/Db.php'; require_once 'Zend/Db.php';
require_once 'Zend/Config.php';
require_once 'Zend/Db/Adapter/Abstract.php'; require_once 'Zend/Db/Adapter/Abstract.php';
use Icinga\Application\DbAdapterFactory;
use Icinga\User; use Icinga\User;
use Icinga\User\Preferences\DbStore; use Icinga\User\Preferences\DbStore;
use Icinga\User\Preferences; use Icinga\User\Preferences;
use \PHPUnit_Framework_TestCase; use \PHPUnit_Framework_TestCase;
use \Zend_Config;
use \Zend_Db; use \Zend_Db;
use \Zend_Db_Adapter_Abstract; use \Zend_Db_Adapter_Abstract;
use \PDOException; use \PDOException;
@ -27,11 +33,10 @@ class DbStoreTest extends PHPUnit_Framework_TestCase
const TYPE_PGSQL = 'pgsql'; const TYPE_PGSQL = 'pgsql';
private $database = 'icinga_unittest'; private $table = 'preference';
private $table = 'preferences';
private $databaseConfig = array( private $databaseConfig = array(
'type' => 'db',
'host' => '127.0.0.1', 'host' => '127.0.0.1',
'username' => 'icinga_unittest', 'username' => 'icinga_unittest',
'password' => 'icinga_unittest', 'password' => 'icinga_unittest',
@ -50,26 +55,18 @@ class DbStoreTest extends PHPUnit_Framework_TestCase
private function createDb($type) private function createDb($type)
{ {
$zendType = 'PDO_'. strtoupper($type); $this->databaseConfig['db'] = $type;
$db = DbAdapterFactory::createDbAdapterFromConfig(
if ($type === self::TYPE_MYSQL) { new Zend_Config($this->databaseConfig)
$this->databaseConfig['port'] = 3306;
} elseif ($type === self::TYPE_PGSQL) {
$this->databaseConfig['port'] = 5432;
}
$db = Zend_Db::factory(
$zendType,
$this->databaseConfig
); );
try { try {
$db->getConnection(); $db->getConnection();
$dumpFile = realpath(__DIR__. '/../../../../../../etc/schema/preferences.'. strtolower($type). '.sql'); $dumpFile = realpath(__DIR__ . '/../../../../../../etc/schema/preferences.' . strtolower($type) . '.sql');
if (!$dumpFile) { if (!$dumpFile) {
throw new Exception('Dumpfile for db type not found: '. $type); throw new Exception('Dumpfile for db type not found: ' . $type);
} }
try { try {
@ -96,11 +93,11 @@ class DbStoreTest extends PHPUnit_Framework_TestCase
protected function tearDown() protected function tearDown()
{ {
if ($this->dbMysql) { if ($this->dbMysql) {
$this->dbMysql->getConnection()->exec('DROP TABLE '. $this->table); $this->dbMysql->getConnection()->exec('DROP TABLE ' . $this->table);
} }
if ($this->dbPgsql) { if ($this->dbPgsql) {
$this->dbPgsql->getConnection()->exec('DROP TABLE '. $this->table); $this->dbPgsql->getConnection()->exec('DROP TABLE ' . $this->table);
} }
} }
@ -165,5 +162,4 @@ class DbStoreTest extends PHPUnit_Framework_TestCase
$this->markTestSkipped('PgSQL test environment is not configured'); $this->markTestSkipped('PgSQL test environment is not configured');
} }
} }
} }