From dfb7238b81517fc21e60bc7876bc58083c19a340 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Wed, 28 Aug 2013 10:16:18 +0200 Subject: [PATCH] AuthManager: Implement backend chain refs #4641 refs #4590 refs #4593 --- .../Authentication/Backend/DbUserBackend.php | 115 +++++-- .../Backend/LdapUserBackend.php | 83 +++-- library/Icinga/Authentication/Credentials.php | 95 ++++-- .../Icinga/Authentication/GroupBackend.php | 44 +++ library/Icinga/Authentication/Manager.php | 302 ++++++++++++------ library/Icinga/Authentication/PhpSession.php | 187 ++++++----- library/Icinga/Authentication/Session.php | 103 +++--- library/Icinga/Authentication/UserBackend.php | 28 +- 8 files changed, 626 insertions(+), 331 deletions(-) create mode 100644 library/Icinga/Authentication/GroupBackend.php diff --git a/library/Icinga/Authentication/Backend/DbUserBackend.php b/library/Icinga/Authentication/Backend/DbUserBackend.php index 149621784..d67c5e8bb 100644 --- a/library/Icinga/Authentication/Backend/DbUserBackend.php +++ b/library/Icinga/Authentication/Backend/DbUserBackend.php @@ -1,5 +1,4 @@ db = $database; + $this->name = $config->name; + $this->db = DbAdapterFactory::getDbAdapter($config->resource); - // Test if the connection is available + // 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 Credentials $credential * - * @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) { @@ -105,9 +146,9 @@ class DbUserBackend implements UserBackend /** * Authenticate a user with the given credentials * - * @param Credentials $credentials The login credentials + * @param Credentials $credential * - * @return User|null The authenticated user or Null. + * @return User|null The authenticated user or Null. */ public function authenticate(Credentials $credential) { @@ -118,16 +159,20 @@ class DbUserBackend implements UserBackend $this->db->getConnection(); try { $salt = $this->getUserSalt($credential->getUsername()); - } catch (\Exception $e) { - Logger::error($e->getMessage()); + } catch (Exception $e) { + Logger::error( + 'Could not create salt 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,14 +183,17 @@ 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) { @@ -157,16 +205,16 @@ 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) { @@ -178,15 +226,15 @@ class DbUserBackend implements UserBackend $this->db->getConnection(); $res = $this->db-> select()->from($this->userTable) - ->where(self::USER_NAME_COLUMN.' = ?', $username) - ->where(self::ACTIVE_COLUMN.' = ?', true) + ->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()); + Logger::error('Could not fetch users from db : %s ', $exc->getMessage()); return null; } } @@ -194,11 +242,11 @@ class DbUserBackend implements UserBackend /** * Create a new instance of User from a query result * - * @param $result The query result containing the user row + * @param stdClass $resultRow * - * @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} @@ -206,6 +254,7 @@ class DbUserBackend implements UserBackend return $usr; } + /** * Return the number of users in this database connection * diff --git a/library/Icinga/Authentication/Backend/LdapUserBackend.php b/library/Icinga/Authentication/Backend/LdapUserBackend.php index ac5c3d07f..4bfdf9033 100644 --- a/library/Icinga/Authentication/Backend/LdapUserBackend.php +++ b/library/Icinga/Authentication/Backend/LdapUserBackend.php @@ -28,49 +28,70 @@ 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\Credentials; +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 + */ + public function __construct(Zend_Config $config) { $this->connection = new Ldap\Connection($config); $this->config = $config; + $this->name = $config->name; } /** - * @see Icinga\Authentication\UserBackend::hasUsername - **/ + * Name of the backend + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Test if the username exists + * + * @param Credentials $credential + * + * @return bool + */ public function hasUsername(Credentials $credential) { return $this->connection->fetchOne( @@ -79,11 +100,11 @@ class LdapUserBackend implements UserBackend } /** - * Removes the '*' characted from $string + * Removes the '*' character from $string * - * @param String $string + * @param string $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,8 +134,12 @@ class LdapUserBackend implements UserBackend } /** - * @see Icinga\Authentication\UserBackend::authenticate - **/ + * Authenticate + * + * @param Credentials $credentials + * + * @return User + */ public function authenticate(Credentials $credentials) { if (!$this->connection->testCredentials( diff --git a/library/Icinga/Authentication/Credentials.php b/library/Icinga/Authentication/Credentials.php index 8b5cbda0c..df20f6d36 100644 --- a/library/Icinga/Authentication/Credentials.php +++ b/library/Icinga/Authentication/Credentials.php @@ -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 -**/ + * 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 { - 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; } } diff --git a/library/Icinga/Authentication/GroupBackend.php b/library/Icinga/Authentication/GroupBackend.php new file mode 100644 index 000000000..621961ebb --- /dev/null +++ b/library/Icinga/Authentication/GroupBackend.php @@ -0,0 +1,44 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{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(); +} diff --git a/library/Icinga/Authentication/Manager.php b/library/Icinga/Authentication/Manager.php index ec3be7404..e491a984c 100644 --- a/library/Icinga/Authentication/Manager.php +++ b/library/Icinga/Authentication/Manager.php @@ -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,72 +158,139 @@ class Manager } /** - * Clear the instance (this is mostly needed for testing and shouldn't be called otherwise) - **/ - public static function clearInstance() - { - self::$instance = null; - } - - /** - * 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) + * Initialize multiple backends from Zend Config */ - private function initBestBackend($target, $backends) + private function setupBackends(Zend_Config $config) { - foreach ($backends as $key => $backend) { - if (strtolower($target) === strtolower($backend->target)) { - $db = $this->tryToInitBackend($target, $backend); - if (isset($db)) { - return $db; - } + 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; } } - 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 + * Create a single backend from Zend Config * - * @param String $target "User" or "Group", depending on what - * authentication information the backend should provide - * @param $backendConfig The configuration containing backend description + * @param Zend_Config $backendConfig * - * @return UserBackend|null Return the created backend or null + * @return null|UserBackend */ - private function tryToInitBackend($target, $backendConfig) + private function createBackend(Zend_Config $backendConfig) { $type = ucwords(strtolower($backendConfig->backend)); + $target = ucwords(strtolower($backendConfig->target)); + $name = $backendConfig->name; + if (!$type) { - Logger::warn('Backend has no type configured. (e.g. backend=ldap)'); + Logger::warn('AuthManager: Backend "%s" has no type configured. (e.g. backend=ldap)', $name); return null; } + + if (!$target) { + Logger::warn('AuthManager: Backend "%s" has no target configured. (e.g. target=user|group)', $name); + return null; + } + try { - if ($backendConfig->backend === 'db') { - $resource = DbAdapterFactory::getDbAdapter($backendConfig->resource); + $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 { - $resource = $backendConfig; + return new $class($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); + 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; + } + + /** + * Add a group backend to stack + * + * @param $groupBackend + */ + public function addGroupBackend($groupBackend) + { + $this->groupBackends[] = $groupBackend; + } + + /** + * Find a backend for a credential + * + * @param Credentials $credentials + * + * @return UserBackend|null + * @throws ConfigurationError + */ + private function getBackendForCredentials(Credentials $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; + } + } + + if (count($this->userBackends) === $authErrors) { + 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 authenticate the current user with the Credentials (@see Credentials). * @@ -218,22 +303,26 @@ class Manager */ public function authenticate(Credentials $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->getBackendForCredentials($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 +330,9 @@ class Manager $this->persistCurrentUser(); $this->session->write(); } + + Logger::info('AuthManager: User successfully logged in: %s', $credentials->getUsername()); + return true; } @@ -250,7 +342,7 @@ class Manager **/ public function persistCurrentUser() { - $this->session->set("user", $this->user); + $this->session->set('user', $this->user); } /** @@ -258,7 +350,7 @@ class Manager **/ public function authenticateFromSession() { - $this->user = $this->session->get("user", null); + $this->user = $this->session->get('user', null); } /** @@ -266,8 +358,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 +388,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; diff --git a/library/Icinga/Authentication/PhpSession.php b/library/Icinga/Authentication/PhpSession.php index bffeead7d..bcb12d05f 100644 --- a/library/Icinga/Authentication/PhpSession.php +++ b/library/Icinga/Authentication/PhpSession.php @@ -28,7 +28,8 @@ namespace Icinga\Authentication; -use Icinga\Application\Logger as Logger; +use Icinga\Application\Logger; +use \Icinga\Exception\ConfigurationError; /** * Class PhpSession @@ -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, + ); + + /** + * Creates 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 - **/ + * Returns 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 - **/ + * Returns 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 - **/ + * Opens 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 - **/ + * Ensures 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 - **/ + * Reads 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 - **/ + * Writes 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 - * - **/ + * Closes 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 - * - **/ + * Deletes 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 - * - **/ + * Removes 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'] ); } - } } diff --git a/library/Icinga/Authentication/Session.php b/library/Icinga/Authentication/Session.php index bf4b75a6a..64a4eb2b0 100644 --- a/library/Icinga/Authentication/Session.php +++ b/library/Icinga/Authentication/Session.php @@ -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 - * - **/ + * Opens 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) - **/ + * Reads 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 - * - **/ + * Clears all values from the session cache + */ public function clear() { $this->sessionValues = array(); diff --git a/library/Icinga/Authentication/UserBackend.php b/library/Icinga/Authentication/UserBackend.php index 1b8a0b652..dafdb8403 100644 --- a/library/Icinga/Authentication/UserBackend.php +++ b/library/Icinga/Authentication/UserBackend.php @@ -28,34 +28,46 @@ namespace Icinga\Authentication; +use \Zend_Config; +use \Icinga\User; + /** - * Interface for backends that authenticate users + * Public api for an user backend object */ interface UserBackend { /** - * Create a userbackend from the given configuration or resource + * Creates a new object * - * @param $config + * @param Zend_Config $config */ - public function __construct($config); + public function __construct(Zend_Config $config); /** * Test if the username exists * - * @param Credentials $credentials - * @return boolean + * @param Credentials $credentials + * + * @return bool */ public function hasUsername(Credentials $credentials); /** * Authenticate * - * @param Credentials $credentials - * @return User + * @param Credentials $credentials + * + * @return User */ public function authenticate(Credentials $credentials); + /** + * Name of the backend + * + * @return string + */ + public function getName(); + /** * Get the number of users available through this backend *