Fix unit tests and add documentation

Add functionality to check if a certain database type like psql or mysql is
available and skip the tests accordingly.

Add documentation for backend authentication.

refs #3769
This commit is contained in:
Matthias Jentsch 2013-07-25 10:05:47 +02:00
parent 2807982f72
commit b013966464
2 changed files with 169 additions and 59 deletions

29
doc/authentication.md Normal file
View File

@ -0,0 +1,29 @@
# Authentication via internal DB
The class DbUserBackend allows
## Configuration
The internal authentication is configured in *config/authentication.ini*. The value
of the configuration key "backend" will determine which UserBackend class to
load. To use the internal backend you will need to specifiy the value "Db"
which will cause the class "DbUserBackend" to be loaded.
There are various configuration keys in "Authentication.ini" and some are only
used by specific backends. The internal DB uses the values
*dbtype*,*table*,*host*,*password*,*user* and *db*, which define the used
connection parameters, the database and the table.
## Database support
The module currently supports these databases:
- mysql (dbtype=mysql)
- PostgreSQL (dbtype=pgsql)
## Authentication
The backend will store the salted hash of the password in the column "password" and the salt in the column "salt".
When a password is checked, the hash is calculated with the function hash_hmac("sha256",salt,password) and compared
to the stored value.

View File

@ -34,6 +34,7 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
private $dbUserBackend;
private $db;
private $testTable = "icinga_users_test";
private $testDatabase = "icinga_unittest";
/*
* Must be identical with the column names defined in DbUserBackend
@ -49,13 +50,52 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
$EMAIL_COLUMN = "email";
private $users;
private $unknownUsers;
private $mysql;
private $pgsql;
private $dbTypeMap = Array(
'mysql' => 'PDO_MYSQL',
'pgsql' => 'PDO_PGSQL'
);
/**
* Create a preset-configuration that can be used to access the database
* with the icinga_unittest account.
* @return \stdClass
*/
private function getBackendConfig()
{
$config = new \stdClass();
$config->host = "127.0.0.1";
$config->user = "icinga_unittest";
$config->password= "icinga_unittest";
$config->table = $this->testTable;
$config->db = $this->testDatabase;
return $config;
}
/**
* Create a backend with the given database type.
* @param $dbType The database type as a string, like "mysql" or "pgsql".
* @return DbUserBackend|null
*/
private function createBackend($dbType){
try{
$config = $this->getBackendConfig();
$config->dbtype = $dbType;
$db = $this->createDb($dbType,$config);
$this->setUpDb($db);
return new DbUserBackend($config);
}
catch(\Exception $e){
echo "CREATE_BACKEND_ERROR:".$e->getMessage();
return null;
}
}
/**
* Create the backends and fill it with sample-data.
*/
protected function setUp()
{
$this->users = Array(
@ -63,67 +103,111 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
$this->USER_NAME_COLUMN => 'user1',
$this->PASSWORD_COLUMN => 'secret1',
$this->SALT_COLUMN => '8a7487a539c5d1d6766639d04d1ed1e6',
$this->ACTIVE_COLUMN => true
$this->ACTIVE_COLUMN => 1
),
1 => Array(
$this->USER_NAME_COLUMN => 'user2',
$this->PASSWORD_COLUMN => 'secret2',
$this->SALT_COLUMN => '04b5521ddd761b5a5b633be83faa494d',
$this->ACTIVE_COLUMN => true
$this->ACTIVE_COLUMN => 1
),
2 => Array(
$this->USER_NAME_COLUMN => 'user3',
$this->PASSWORD_COLUMN => 'secret3',
$this->SALT_COLUMN => '08bb94ba3120338ae56db80ef551d324',
$this->ACTIVE_COLUMN => false
$this->ACTIVE_COLUMN => 0
)
);
$this->mysql = $this->createBackend("mysql");
$this->pgsql = $this->createBackend("pgsql");
}
/*
* TODO: Fetch config folder from somewhere instead of defining it statically, or this test
* will break when the path changes
*/
Config::$configDir = "/vagrant/config";
$config = Config::app('authentication')->users;
$config->table = $this->testTable;
/**
* Test the PostgreSQL backend.
*/
public function testPgsql(){
if(!empty($this->pgsql)){
$this->runBackendAuthentication($this->pgsql);
$this->runBackendUsername($this->pgsql);
}
else{
echo "\nSKIPPING PGSQL TEST...\n";
$this->markTestSkipped();
}
}
$this->db = \Zend_Db::factory($this->dbTypeMap[$config->dbtype],
/**
* Test the MySQL-Backend.
*/
public function testMySQL(){
if(!empty($this->mysql)){
$this->runBackendAuthentication($this->mysql);
$this->runBackendUsername($this->mysql);
}
else{
echo "\nSKIPPING MYSQL TEST...\n";
$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' => $config->db
"dbname" => "icinga_unittest"
));
if($config->dbtype == 'pgsql'){
$this->users[0][$this->ACTIVE_COLUMN] = "TRUE";
$this->users[1][$this->ACTIVE_COLUMN] = "TRUE";
$this->users[2][$this->ACTIVE_COLUMN] = "FALSE";
}
$this->setUpDb($this->db);
$this->dbUserBackend = new DbUserBackend($config);
}
/**
* Try to drop all databases that may eventually be present.
*/
public function tearDown()
{
$this->tearDownDb($this->db);
try{
$db = $this->createDb("mysql",$this->getBackendConfig());
$this->tearDownDb($db);
}
catch(\Exception $e){}
try{
$db = $this->createDb("pgsql",$this->getBackendConfig());
$this->tearDownDb($db);
}
catch(\Exception $e){}
}
/**
* Drop the test database in the given db.
* @param $db
*/
private function tearDownDb($db){
$db->exec('DROP TABLE '.$this->testTable);
}
/**
* Fill the given database with the sample-data provided in users.
* @param $db
*/
private function setUpDb($db){
$db->exec('CREATE TABLE '.$this->testTable.' (
'.$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.')
)');
'.$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++){
$usr = $this->users[$i];
$data = Array(
@ -139,45 +223,41 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
}
}
private function tearDownDb($db){
$db->exec('DROP TABLE '.$this->testTable);
}
/**
* Test for DbUserBackend::HasUsername()
**/
public function testHasUsername(){
* Run the hasUsername test against an instance of DbUserBackend.
* @param $backend The backend that will be tested.
*/
private function runBackendUsername($backend){
// Known user
$this->assertTrue($this->dbUserBackend->hasUsername(
$this->assertTrue($backend->hasUsername(
new Credentials(
$this->users[0][$this->USER_NAME_COLUMN],
$this->users[0][$this->PASSWORD_COLUMN])
));
// Unknown user
$this->assertFalse($this->dbUserBackend->hasUsername(
$this->assertFalse($backend->hasUsername(
new Credentials(
'unkown user',
'secret')
));
// Inactive user
$this->assertFalse($this->dbUserBackend->hasUsername(
$this->assertFalse($backend->hasUsername(
new Credentials(
$this->users[2][$this->USER_NAME_COLUMN],
$this->users[2][$this->PASSWORD_COLUMN])
));
}
/**
* Test for DbUserBackend::Authenticate()
*
**/
public function testAuthenticate(){
* Run the authentication test against an instance of DbUserBackend.
* @param $backend The backend that will be tested.
*/
private function runBackendAuthentication($backend){
// Known user
$this->assertNotNull($this->dbUserBackend->authenticate(
$this->assertNotNull($backend->authenticate(
new Credentials(
$this->users[0][$this->USER_NAME_COLUMN],
$this->users[0][$this->PASSWORD_COLUMN])
@ -185,27 +265,28 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase {
// Wrong password
$this->assertNull(
$this->dbUserBackend->authenticate(
$backend->authenticate(
new Credentials(
$this->users[1][$this->USER_NAME_COLUMN],
'wrongpassword')
)
);
// Nonexistend user
// Nonexisting user
$this->assertNull(
$this->dbUserBackend->authenticate(
$backend->authenticate(
new Credentials(
'nonexistend user',
'nonexisting user',
$this->users[1][$this->PASSWORD_COLUMN])
)
);
// Inactive user
$this->assertNull($this->dbUserBackend->authenticate(
new Credentials(
$this->users[2][$this->USER_NAME_COLUMN],
$this->users[2][$this->PASSWORD_COLUMN])
$this->assertNull(
$backend->authenticate(
new Credentials(
$this->users[2][$this->USER_NAME_COLUMN],
$this->users[2][$this->PASSWORD_COLUMN])
));
}
}