diff --git a/config/authentication.ini b/config/authentication.ini index e07116ca7..7fb51c2ad 100644 --- a/config/authentication.ini +++ b/config/authentication.ini @@ -1,26 +1,32 @@ -[users] -backend=ldap -hostname=localhost -root_dn="ou=people,dc=icinga,dc=org" -bind_dn="cn=admin,cn=config" -bind_pw=admin -user_class=inetOrgPerson -user_name_attribute=uid +; authentication.ini +; +; Each section listed in this configuration represents a single backend +; that can be used to authenticate users or groups. Each databse backend must refer +; to a resource defined in resources.ini, +; +; The order of entries in this configuration is used to determine the fallback +; priority in case of an error. If the resource referenced in the first +; entry is not reachable, the next lower entry will be used for authentication. +; Please be aware that this behaviour is not valid for the authentication itself. +; The authentication will only be done against the one available resource with the highest +; priority. + +[users-ldap] +backend = "ldap" +target = "user" +hostname = "localhost" +root_dn = "ou=people,dc=icinga,dc=org" +bind_dn = "cn=admin,cn=config" +bind_pw = "admin" +user_class = "inetOrgPerson" +user_name_attribute = "uid" [users-mysql] -backend=Db -dbtype=mysql -table=account -host=localhost -password=icinga -user=icingaweb -db=icingaweb +backend = "db" +target = "user" +resource = "icingaweb-mysql" [users-pgsql] -backend=Db -dbtype=pgsql -table=account -host=localhost -password=icinga -user=icingaweb -db=icingaweb \ No newline at end of file +backend = "db" +target = "user" +resource = "icingaweb-pgsql" diff --git a/config/preferences/KEEP.md b/config/preferences/KEEP.md old mode 100644 new mode 100755 diff --git a/config/resources.ini b/config/resources.ini new file mode 100644 index 000000000..b45ef51e6 --- /dev/null +++ b/config/resources.ini @@ -0,0 +1,38 @@ +; resources.ini +; +; The configuration file *resources.ini* contains data sources that +; can be referenced in other configurations. This allows you to manage +; all connections to SQL databases in one single place, avoiding the need +: to edit several different configuration files, when the connection +; information of a resource change. +; +; Each section represents a resource, with the section name being the +; identifier used to reference this certain section. Depending on the +; resource type, each section contains different properties. The property +; *type* defines the resource type and thus how the properties are going to +; be interpreted. Currently only the resource type *db* is available. + + +[icingaweb-pgsql] +type = db +db = pgsql ; PostgreSQL +host = localhost +password = icinga +username = icingaweb +dbname = icingaweb + +[icingaweb-mysql] +type = db +db = mysql ; MySQL +host = localhost +password = icinga +username = icingaweb +dbname = icingaweb + +[ido] +type = db +dbname = mysql +host = localhost +password = icinga +username = icingaweb +db = icingaweb \ No newline at end of file diff --git a/doc/authentication.md b/doc/authentication.md index 70a22f144..2d54c2287 100644 --- a/doc/authentication.md +++ b/doc/authentication.md @@ -1,29 +1,59 @@ -# Authentication via internal DB +# Authentication -The class DbUserBackend allows to handle the user authentication internally in a database. +The authentication manager can use different backend types like LDAP or Databases as data sources. During +the application bootstrap the different available resources are checked for availability and +the resource with the highest priority will be used for authentication. This behaviour is useful for setting +up fallback accounts, that are available when the regular authentication backend is not available. ## Configuration -The internal authentication is configured in *config/authentication.ini*. The value -of the configuration key "backend" will determine which UserBackend class to +The internal authentication is configured in *config/authentication.ini*. + +Each section listed in this configuration represents a single backend +that can be used to authenticate users or groups. + +The order of entries in this configuration is used to determine the fallback +priority in case of an error. If the resource referenced in the first entry (the one at the top if the file) +is not reachable, the next lower entry will be used for authentication. +Please be aware that this behaviour is not valid for the authentication itself. +The authentication will only be done against the one available resource with the highest +priority. + +### Backend + +The value of the configuration key *backend* will determine which UserBackend class to load. To use the internal backend you 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. +Currently these types of backends are allowed: + * ldap + * db -## Database support +#### db -The module currently supports these databases: +The authentication source is a SQL database and points to a resource defined in *resources.ini*, which +contains all the connection information. Every entry should therefore contain a property *resource* +with the name of the assigned resource. For a more detailed description about how to set up resources, +please read the chapter *Resources*. - - mysql (dbtype=mysql) - - PostgreSQL (dbtype=pgsql) +The authentication currently supports the databases MySQL and PostgreSQL. + +#### ldap + +The authentication source is an ldap server. The connection information should be directly present +in the *authentication.ini*, like described in the example configuration. -## Authentication +### target -The backend will store the salted hash of the password in the column "password" and the salt in the column "salt". +The value of the configuration key *target* defines + + +## Technical description + +If an ldap-backend is used, the standard ldap bind will be executed and all user credentials will be managed +directly by the ldap server. + +In case of an SQL-backend, 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. \ No newline at end of file +to the stored value. diff --git a/doc/resources.md b/doc/resources.md new file mode 100644 index 000000000..4873fb1ad --- /dev/null +++ b/doc/resources.md @@ -0,0 +1,22 @@ +# Resources + +The configuration file *config/resources.ini* contains data sources that can be referenced +in other configurations. This allows you to manage all connections to SQL databases in one +single place, avoiding the need to edit several different configuration files, when the +connection information of a resource change. + +## Configuration + +Each section represents a resource, with the section name being the identifier used to +reference this certain section. Depending on the resource type, each section contains different properties. +The property *type* defines the resource type and thus how the properties are going to be interpreted. +Currently only the resource type *db* is available. + +### db + +This resource type represents a SQL database. The property *db* defines the used sql database, which +could be a value like *mysql* or *pgsql*. The other properties like *host*, *password*, *username* and +*dbname* are the connection information for the resource. + + + diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index 651209627..faf5482a9 100755 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -34,6 +34,8 @@ use Zend_Loader_Autoloader; use Icinga\Application\Modules\Manager as ModuleManager; use Icinga\Application\Platform; use \Icinga\Application\Config; +use Icinga\Exception\ProgrammingError; +use Icinga\Application\DbAdapterFactory; use Icinga\Exception\ConfigurationError; use Icinga\Util\DateTimeFactory; @@ -341,7 +343,23 @@ abstract class ApplicationBootstrap } /** +<<<<<<< HEAD * Setup time zone +======= + * Setup factories that provide access to the resources + * + * @return self + */ + protected function setupResourceFactories() + { + $config = Config::app('resources'); + DbAdapterFactory::setConfig($config); + return $this; + } + + /** + * Setup default timezone +>>>>>>> Add the DbAdapterFactory to instanciate database adapters using resource names * * @return self * @throws ConfigurationError if the timezone in config.ini isn't valid diff --git a/library/Icinga/Application/ConfigAwareFactory.php b/library/Icinga/Application/ConfigAwareFactory.php new file mode 100644 index 000000000..855f8a8f5 --- /dev/null +++ b/library/Icinga/Application/ConfigAwareFactory.php @@ -0,0 +1,42 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +namespace Icinga\Application; + +/** + * A factory that is configurable + */ +interface ConfigAwareFactory { + + /** + * Set the factory configuration + * + * @param mixed $config The configuration + */ + public static function setConfig($config); +} \ No newline at end of file diff --git a/library/Icinga/Application/DbAdapterFactory.php b/library/Icinga/Application/DbAdapterFactory.php new file mode 100644 index 000000000..3799ebfe9 --- /dev/null +++ b/library/Icinga/Application/DbAdapterFactory.php @@ -0,0 +1,170 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +namespace Icinga\Application; + +use Zend_Config; +use Zend_Db; +use Icinga\Application\Logger; +use Icinga\Exception\ConfigurationError; +use Icinga\Exception\ProgrammingError; +use Tests\Icinga\Application\ZendDbMock; + +/** + * Create resources using short identifiers referring to configuration entries + */ +class DbAdapterFactory implements ConfigAwareFactory { + + /** + * Resource definitions + * + * @var Zend_Config + */ + private static $resources; + + /** + * The factory class used to create instances of Zend_Db_Adapter + * + * @var String + */ + private static $factoryClass; + + /** + * Resource cache to allow multiple use + * + * @var array + */ + private static $resourceCache = array(); + + /** + * Set the configuration that stores the available resources + * + * @param mixed $config The configuration containing the resources + * + * @param array $options Additional options that affect the factories behaviour: + * * factory : Set the factory class that creates instances + * of Zend_Db_Adapter for the different database types + * (used for testing) + */ + public static function setConfig($config, array $options = null) + { + self::$resources = $config; + if (isset($options['factory'])) { + self::$factoryClass = $options['factory']; + } else { + self::$factoryClass = 'Zend_Db'; + } + } + + /** + * Reset the factory configuration back to the default state + */ + public static function resetConfig() + { + unset(self::$resources); + unset(self::$factoryClass); + } + + /** + * Get the resource with the given $identifier + * + * @param $identifier The name of the resource + */ + public static function getDbAdapter($identifier) + { + if (!isset(self::$resources)) { + $msg = 'Creation of resource ' . $identifier . ' not possible, because there is no configuration present.' + . ' Make shure this factory class was initiated correctly during the application bootstrap.'; + Logger::error($msg); + throw new ProgrammingError($msg); + } + if (!isset(self::$resources->{$identifier})) { + $msg = 'Creation of resource "' + . $identifier + . '" not possible, because there is no matching resource present in the configuration '; + Logger::error($msg); + throw new ConfigurationError($msg); + } + if (array_key_exists($identifier,self::$resourceCache)) { + return self::$resourceCache[$identifier]; + } else { + $res = self::createDbAdapter(self::$resources->{$identifier}); + self::$resourceCache[$identifier] = $res; + return $res; + } + } + + /** + * Create the Db_Adapter for the given configuration section + * + * @param mixed $config The configuration section containing the + * db information + * + * @return \Zend_Db_Adapter_Abstract The created Zend_Db_Adapter + * + * @throws \ConfigurationError When the specified db type is invalid + */ + private static function createDbAdapter($config) + { + if ($config->type !== 'db') { + throw new ConfigurationError( + 'Resource type must be "db" but is "' . $config->type . '"'); + } + $options = array( + 'dbname' => $config->dbname, + 'host' => $config->host, + 'username' => $config->username, + 'password' => $config->password, + ); + switch ($config->db) { + case 'mysql': + return self::callFactory('Pdo_Mysql',$options); + + case 'pgsql': + return self::callFactory('Pdo_Pgsql',$options); + + default: + throw new ConfigurationError('Unsupported db type ' . $config->db . '.'); + } + } + + /** + * Call the currently set factory class + * + * @param $adapter The name of the used db adapter + * @param $options OPTIONAL: an array or Zend_Config object with adapter + * parameters + * + * @return Zend_Db_Adapter_Abstract The created adapter + */ + private static function callFactory($adapter, $options) + { + $factory = self::$factoryClass; + return $factory::factory($adapter,$options); + } +} \ No newline at end of file diff --git a/library/Icinga/Application/Web.php b/library/Icinga/Application/Web.php index de20dca6e..4bba5fb6b 100644 --- a/library/Icinga/Application/Web.php +++ b/library/Icinga/Application/Web.php @@ -93,6 +93,7 @@ class Web extends ApplicationBootstrap return $this->setupConfig() ->setupErrorHandling() ->setupTimezone() + ->setupResourceFactories() ->setupRequest() ->setupZendMvc() ->setupTranslation() diff --git a/library/Icinga/Authentication/Backend/DbUserBackend.php b/library/Icinga/Authentication/Backend/DbUserBackend.php index 4259b63e7..87fc98e38 100644 --- a/library/Icinga/Authentication/Backend/DbUserBackend.php +++ b/library/Icinga/Authentication/Backend/DbUserBackend.php @@ -53,11 +53,11 @@ class DbUserBackend implements UserBackend { private $db = null; /** - * The name of the user table as provided by the configuration + * The name of the user table * * @var String */ - private $userTable; + private $userTable = "account"; /** * Mapping of columns @@ -74,45 +74,19 @@ class DbUserBackend implements UserBackend { $DOMAIN_COLUMN = 'domain', $EMAIL_COLUMN = 'email'; - /** - * Map the configuration dbtypes to the corresponding Zend-PDOs - * - * @var Array - */ - private $dbTypeMap = Array( - 'mysql' => 'PDO_MYSQL', - 'pgsql' => 'PDO_PGSQL' - ); - /** * Create a DbUserBackend * - * @param $config The configuration-object containing the members host,user,password,db + * @param Zend_Db The database that provides the authentication data */ - public function __construct($config) + public function __construct($database) { - $this->dbtype = $config->dbtype; - $this->userTable = $config->table; - try { - $this->db = \Zend_Db::factory( - $this->dbTypeMap[$config->dbtype], - array( - 'host' => $config->host, - 'username' => $config->user, - 'password' => $config->password, - 'dbname' => $config->db - )); + $this->db = $database; - /* - * Test the connection settings - */ - $this->db->getConnection(); - $this->db->select()->from($this->userTable,new \Zend_Db_Expr('TRUE')); - } catch (\Zend_Db_Adapter_Exception $exc) { - Logger::error('Could not authenticate via database : %s ', $exc->getMessage()); - $this->db = null; - - } + /* + * Test if the connection is available + */ + $this->db->getConnection(); } /** @@ -180,6 +154,7 @@ class DbUserBackend implements UserBackend { * Fetch the users salt from the database * * @param $username The user whose salt should be fetched. + * * @return String|null Returns the salt-string or Null, when the user does not exist. */ private function getUserSalt($username) @@ -196,6 +171,7 @@ class DbUserBackend implements UserBackend { * Fetch the user information from the database * * @param $username The name of the user. + * * @return User|null Returns the user object, or null when the user does not exist. */ private function getUserByName($username) diff --git a/library/Icinga/Authentication/Backend/LdapUserBackend.php b/library/Icinga/Authentication/Backend/LdapUserBackend.php index 0161368f8..52fc51704 100644 --- a/library/Icinga/Authentication/Backend/LdapUserBackend.php +++ b/library/Icinga/Authentication/Backend/LdapUserBackend.php @@ -45,24 +45,32 @@ use \Icinga\Application\Config as IcingaConfig; class LdapUserBackend implements UserBackend { /** - * @var Ldap\Connection - **/ + * @var Ldap\Connection + **/ protected $connection; /** - * Creates a new Authentication backend using the - * connection information provided in $config - * - * @param object $config The ldap connection information - **/ + * The ldap connection information + * + * @var object + */ + private $config; + + /** + * Creates a new Authentication backend using the + * connection information provided in $config + * + * @param object $config The ldap connection information + **/ public function __construct($config) { $this->connection = new Ldap\Connection($config); + $this->config = $config; } /** - * @see Icinga\Authentication\UserBackend::hasUsername - **/ + * @see Icinga\Authentication\UserBackend::hasUsername + **/ public function hasUsername(Credentials $credential) { return $this->connection->fetchOne( @@ -71,44 +79,44 @@ class LdapUserBackend implements UserBackend } /** - * Removes the '*' characted from $string - * - * @param String $string - * - * @return String - **/ + * Removes the '*' characted from $string + * + * @param String $string + * + * @return String + **/ protected function stripAsterisks($string) { return str_replace('*', '', $string); } /** - * Tries to fetch the username given in $username from - * the ldap connection, using the configuration parameters - * given in the Authentication configuration - * - * @param String $username The username to select - * - * @return object $result - **/ + * Tries to fetch the username given in $username from + * the ldap connection, using the configuration parameters + * given in the Authentication configuration + * + * @param String $username The username to select + * + * @return object $result + **/ protected function selectUsername($username) { return $this->connection->select() ->from( - IcingaConfig::app('authentication')->users->user_class, + $this->config->user_class, array( - IcingaConfig::app('authentication')->users->user_name_attribute + $this->config->user_name_attribute ) ) ->where( - IcingaConfig::app('authentication')->users->user_name_attribute, + $this->config->user_name_attribute, $this->stripAsterisks($username) ); } /** - * @see Icinga\Authentication\UserBackend::authenticate - **/ + * @see Icinga\Authentication\UserBackend::authenticate + **/ public function authenticate(Credentials $credentials) { if (!$this->connection->testCredentials( diff --git a/library/Icinga/Authentication/Manager.php b/library/Icinga/Authentication/Manager.php index b1e45c3f4..747ab65e7 100644 --- a/library/Icinga/Authentication/Manager.php +++ b/library/Icinga/Authentication/Manager.php @@ -30,72 +30,73 @@ namespace Icinga\Authentication; use Icinga\Application\Logger; use \Icinga\Application\Config as IcingaConfig; +use Icinga\Application\DbAdapterFactory; use Icinga\Exception\ConfigurationError as ConfigError; use Icinga\User; /** -* The authentication manager allows to identify users and -* to persist authentication information in a session. -* -* Direct instanciation is not permitted, the Authencation manager -* must be created using the getInstance method. Subsequent getInstance -* calls return the same object and ignore any additional configuration -* -* When creating the Authentication manager with standard PHP Sessions, -* 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 -* -* @TODO: Group support is not implemented yet -**/ + * The authentication manager allows to identify users and + * to persist authentication information in a session. + * + * Direct instanciation is not permitted, the Authencation manager + * must be created using the getInstance method. Subsequent getInstance + * calls return the same object and ignore any additional configuration + * + * When creating the Authentication manager with standard PHP Sessions, + * 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 + * + * @TODO: Group support is not implemented yet + **/ class Manager { const BACKEND_TYPE_USER = "User"; const BACKEND_TYPE_GROUP = "Group"; /** - * @var Manager - **/ + * @var Manager + **/ private static $instance = null; /** - * @var User - **/ + * @var User + **/ private $user = null; private $groups = array(); /** - * @var UserBackend - **/ + * @var UserBackend + **/ private $userBackend = null; /** - * @var GroupBackend - **/ + * @var GroupBackend + **/ private $groupBackend = null; /** - * @var Session - **/ + * @var Session + **/ private $session = null; /** - * Creates a new authentication manager using the provided config (or the - * 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) - **/ + * Creates a new authentication manager using the provided config (or the + * 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) + **/ private function __construct($config = null, array $options = array()) { if ($config === null) { @@ -103,14 +104,14 @@ class Manager } if (isset($options["userBackendClass"])) { $this->userBackend = $options["userBackendClass"]; - } elseif ($config->users !== null) { - $this->userBackend = $this->initBackend(self::BACKEND_TYPE_USER, $config->users); + } else { + $this->userBackend = $this->initBestBackend(self::BACKEND_TYPE_USER, $config); } if (isset($options["groupBackendClass"])) { $this->groupBackend = $options["groupBackendClass"]; - } elseif ($config->groups != null) { - $this->groupBackend = $this->initBackend(self::BACKEND_TYPE_GROUP, $config->groups); + } else { + $this->groupBackend = $this->initBestBackend(self::BACKEND_TYPE_GROUP, $config); } if (!isset($options["sessionClass"])) { @@ -126,8 +127,8 @@ class Manager } /** - * @see Manager:__construct() - **/ + * @see Manager:__construct() + **/ public static function getInstance($config = null, array $options = array()) { if (self::$instance === null) { @@ -137,50 +138,82 @@ class Manager } /** - * Clears the instance (this is mostly needed for testing and shouldn't be called otherwise) - **/ + * Clear the instance (this is mostly needed for testing and shouldn't be called otherwise) + **/ public static function clearInstance() { self::$instance = null; } /** - * Creates a backend for the the given authenticationTarget (User or Group) and the - * Authenticaiton source. - * - * initBackend("User", "Ldap") would create a UserLdapBackend, - * initBackend("Group", "MySource") would create a GroupMySourceBackend, - * - * Supported backends can be found in the Authentication\Backend folder - * - * @param String $authenticationTarget "User" or "Group", depending on what - * authentication information the backend should - * provide - * @param String $authenticationSource The Source, see the above examples - * - * @return (null|UserBackend|GroupBackend) - **/ - private function initBackend($authenticationTarget, $authenticationSource) + * Create a connection to the best available backend + * + * @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 + * + * @return (null|UserBackend|GroupBackend) + */ + private function initBestBackend($target, $backends) { - $backend = ucwords(strtolower($authenticationSource->backend)); - - if (!$backend) { + foreach ($backends as $backend) { + if (strtolower($target) === strtolower($backend->target)) { + $db = $this->tryToInitBackend($target,$backend); + if (isset($db)) { + break; + } + } + } + if (!isset($db)) { + $msg = 'Failed to create any authentication backend, login will not be possible.'; + Logger::error($msg); return null; } - - $class = '\\Icinga\\Authentication\\Backend\\' . $backend . $authenticationTarget. 'Backend'; - return new $class($authenticationSource); + return $db; } /** - * Tries to authenticate the current user with the Credentials (@see Credentials). - * - * @param Credentials $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 - **/ + * Try to create the backend with the given configuration + * + * @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) { + 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: ' . + print_r($backendConfig->backend,true) + . '. 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 Boolean $persist Whether to persist the authentication result + * in the current session + * + * @return Boolean true on success, otherwise false + **/ public function authenticate(Credentials $credentials, $persist = true) { if (!$this->userBackend) { @@ -211,29 +244,28 @@ class Manager /** - * Writes the current user to the session (only usable when writeSession = true) - * - **/ + * Writes the current user to the session (only usable when writeSession = true) + **/ public function persistCurrentUser() { $this->session->set("user", $this->user); } /** - * Tries to authenticate the user with the current session - **/ + * Tries to authenticate the user with the current session + **/ public function authenticateFromSession() { $this->user = $this->session->get("user", null); } /** - * Returns true when the user is currently authenticated - * - * @param Boolean $ignoreSession Set to true to prevent authentication by session - * - * @param Boolean - **/ + * Returns true when the user is currently authenticated + * + * @param Boolean $ignoreSession Set to true to prevent authentication by session + * + * @param Boolean + **/ public function isAuthenticated($ignoreSession = false) { if ($this->user === null && !$ignoreSession) { @@ -243,9 +275,8 @@ class Manager } /** - * Purges the current authorisation information and deletes the session - * - **/ + * Purges the current authorisation information and deletes the session + **/ public function removeAuthorization() { $this->user = null; @@ -253,18 +284,18 @@ class Manager } /** - * Returns the current user or null if no user is authenticated - * - * @return User - **/ + * Returns the current user or null if no user is authenticated + * + * @return User + **/ public function getUser() { return $this->user; } /** - * @see User::getGroups - **/ + * @see User::getGroups + **/ public function getGroups() { return $this->user->getGroups(); diff --git a/test/php/library/Icinga/Application/DbAdapterFactoryTest.php b/test/php/library/Icinga/Application/DbAdapterFactoryTest.php new file mode 100644 index 000000000..eb8cb750f --- /dev/null +++ b/test/php/library/Icinga/Application/DbAdapterFactoryTest.php @@ -0,0 +1,159 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +namespace Tests\Icinga\Application; + +require_once('Zend/Db.php'); +require_once('Zend/Db/Adapter/Pdo/Mysql.php'); +require_once('Zend/Config.php'); +require_once('Zend/Log.php'); +require_once('Zend/Config.php'); +require_once('../../library/Icinga/Application/Logger.php'); +require_once('library/Icinga/Application/ZendDbMock.php'); +require_once('../../library/Icinga/Exception/ConfigurationError.php'); +require_once('../../library/Icinga/Application/ConfigAwareFactory.php'); +require_once('../../library/Icinga/Application/DbAdapterFactory.php'); + +use Tests\Icinga\Application\ZendDbMock; +use Icinga\Application\DbAdapterFactory; +use Icinga\Exception\ConfigurationError; + +/* + * Unit test for the class DbAdapterFactory + */ +class DbAdapterFactoryTest extends \PHPUnit_Framework_TestCase { + + /** + * The resources used for this test + */ + private $resources; + + /** + * Set up the test fixture + */ + public function setUp() + { + $resources = array( + /* + * PostgreSQL databse + */ + 'resource1' => array( + 'type' => 'db', + 'db' => 'pgsql', + 'dbname' => 'resource1', + 'host' => 'host1', + 'username' => 'username1', + 'password' => 'password1' + ), + /* + * MySQL database + */ + 'resource2' => array( + 'type' => 'db', + 'db' => 'mysql', + 'dbname' => 'resource2', + 'host' => 'host2', + 'username' => 'username2', + 'password' => 'password2' + ), + /* + * Unsupported database type + */ + 'resource3' => array( + 'type' => 'db', + 'db' => 'mssql', + 'dbname' => 'resource3', + 'host' => 'host3', + 'username' => 'username3', + 'password' => 'password3' + ), + /* + * Unsupported resource type + */ + 'resource4' => array( + 'type' => 'ldap', + ), + ); + $this->resources = new \Zend_Config($resources); + DbAdapterFactory::setConfig( + $this->resources, + array( + 'factory' => 'Tests\Icinga\Application\ZendDbMock' + ) + ); + } + + public function testGetValidResource() + { + DbAdapterFactory::getDbAdapter('resource2'); + $this->assertEquals( + 'Pdo_Mysql', + ZendDbMock::getAdapter(), + 'The db adapter name must be Pdo_Mysql.'); + $this->assertEquals( + $this->getOptions($this->resources->{'resource2'}), + ZendDbMock::getConfig(), + 'The options must match the original config file content' + ); + } + + /** + * Test if an exception is thrown, when an invalid database is used. + * + * @expectedException \Exception + */ + public function testGetInvalidDatabase() + { + DbAdapterFactory::getDbAdapter('resource3'); + } + + /** + * Test if an exception is thrown, when an invalid type is used. + * + * @expectedException \Exception + */ + public function testGetInvalidType() + { + DbAdapterFactory::getDbAdapter('resource4'); + } + + /** + * Prepare the options object for assertions + * + * @param Zend_Config $config The configuration to prepare + * + * @return array The prepared options object + */ + private function getOptions($config) + { + $options = array_merge(array(),$config->toArray()); + unset($options['type']); + unset($options['db']); + return $options; + } +} diff --git a/test/php/library/Icinga/Application/ZendDbMock.php b/test/php/library/Icinga/Application/ZendDbMock.php new file mode 100644 index 000000000..3ad99067c --- /dev/null +++ b/test/php/library/Icinga/Application/ZendDbMock.php @@ -0,0 +1,86 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +namespace Tests\Icinga\Application; + +/** + * Partially emulate the functionality of Zend_Db + */ +class ZendDbMock { + + /** + * The config that was used in the last call of the factory function + * + * @var mixed + */ + private static $config; + + /** + * Name of the adapter class that was used in the last call of the factory function + * + * @var mixed + */ + private static $adapter; + + /** + * Mock the factory-method of Zend_Db and save the given parameters + * + * @param $adapter String name of base adapter class, or Zend_Config object + * @param $config mixed OPTIONAL; an array or Zend_Config object with adapter + * parameters + * + * @return stdClass Empty object + */ + public static function factory($adapter, $config) + { + self::$config = $config; + self::$adapter = $adapter; + return new \stdClass(); + } + + /** + * Get the name of the adapter class that was used in the last call + * of the factory function + * + * @return String + */ + public static function getAdapter() + { + return self::$adapter; + } + + /** + * Get the config that was used in the last call of the factory function + * + * @return mixed + */ + public static function getConfig() + { + return self::$config; + } +} diff --git a/test/php/library/Icinga/Authentication/DbUserBackendTest.php b/test/php/library/Icinga/Authentication/DbUserBackendTest.php index 72a8bdecb..904404952 100644 --- a/test/php/library/Icinga/Authentication/DbUserBackendTest.php +++ b/test/php/library/Icinga/Authentication/DbUserBackendTest.php @@ -29,9 +29,6 @@ namespace Tests\Icinga\Authentication; -//use Icinga\Protocol\Ldap\Exception; -//use Zend_Config_Ini; - require_once('Zend/Config/Ini.php'); require_once('Zend/Db.php'); require_once('../../library/Icinga/Authentication/UserBackend.php'); @@ -147,7 +144,7 @@ class DbUserBackendTest extends \PHPUnit_Framework_TestCase { $config->dbtype = $dbType; $db = $this->createDb($dbType,$config); $this->setUpDb($db); - return new DbUserBackend($config); + return new DbUserBackend($db); } catch(\Exception $e) { echo 'CREATE_BACKEND_ERROR:'.$e->getMessage(); return null;