mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-04-08 17:15:08 +02:00
Update and test Auth/Manager implementation
- remove Storable inheritance from User and make it a plain DAO - remove Authorization methods from User refs #4265 refs #4250
This commit is contained in:
parent
06b7b9ee2e
commit
db61cfafe1
49
library/Icinga/Authentication/Credentials.php
Normal file
49
library/Icinga/Authentication/Credentials.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Authentication;
|
||||||
|
|
||||||
|
|
||||||
|
class Credentials
|
||||||
|
{
|
||||||
|
protected $username;
|
||||||
|
protected $password;
|
||||||
|
protected $domain;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($username = "", $password = null, $domain = null)
|
||||||
|
{
|
||||||
|
$this->username = $username;
|
||||||
|
$this->password = $password;
|
||||||
|
$this->domain = $domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUsername()
|
||||||
|
{
|
||||||
|
return $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUsername($username)
|
||||||
|
{
|
||||||
|
return $this->username = $username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPassword()
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPassword($password)
|
||||||
|
{
|
||||||
|
return $this->password = $password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDomain()
|
||||||
|
{
|
||||||
|
return $this->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDomain($domain)
|
||||||
|
{
|
||||||
|
return $this->domain = $domain;
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,8 @@ class Manager
|
|||||||
const BACKEND_TYPE_USER = "User";
|
const BACKEND_TYPE_USER = "User";
|
||||||
const BACKEND_TYPE_GROUP = "Group";
|
const BACKEND_TYPE_GROUP = "Group";
|
||||||
|
|
||||||
|
private static $instance = null;
|
||||||
|
|
||||||
private $user = null;
|
private $user = null;
|
||||||
private $groups = array();
|
private $groups = array();
|
||||||
private $userBackend = null;
|
private $userBackend = null;
|
||||||
@ -29,7 +31,7 @@ class Manager
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options["groupBackendClass"])) {
|
if (isset($options["groupBackendClass"])) {
|
||||||
$this->userBackend = $options["groupBackendClass"];
|
$this->groupBackend = $options["groupBackendClass"];
|
||||||
} elseif ($config->groups != null) {
|
} elseif ($config->groups != null) {
|
||||||
$this->groupBackend = initBackend(BACKEND_TYPE_GROUP, $config->groups);
|
$this->groupBackend = initBackend(BACKEND_TYPE_GROUP, $config->groups);
|
||||||
}
|
}
|
||||||
@ -37,18 +39,28 @@ class Manager
|
|||||||
if (!isset($options["sessionClass"])) {
|
if (!isset($options["sessionClass"])) {
|
||||||
$this->session = new PhpSession($config->session);
|
$this->session = new PhpSession($config->session);
|
||||||
} else {
|
} else {
|
||||||
$options["sessionClass"];
|
$this->session = $options["sessionClass"];
|
||||||
|
}
|
||||||
|
if (isset($options["writeSession"]) && $options["writeSession"] === true) {
|
||||||
|
$this->session->read(true);
|
||||||
|
} else {
|
||||||
|
$this->session->read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getInstance($config = null, array $options = array())
|
public static function getInstance($config = null, array $options = array())
|
||||||
{
|
{
|
||||||
if (self::$instance === null) {
|
if (self::$instance === null) {
|
||||||
self::$instance = new Auth($config, $options);
|
self::$instance = new Manager($config, $options);
|
||||||
}
|
}
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function clearInstance()
|
||||||
|
{
|
||||||
|
self::$instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
private function initBackend($authenticationTarget, $authenticationSource)
|
private function initBackend($authenticationTarget, $authenticationSource)
|
||||||
{
|
{
|
||||||
$userbackend = ucwords(strtolower($authenticationSource->backend));
|
$userbackend = ucwords(strtolower($authenticationSource->backend));
|
||||||
@ -56,7 +68,7 @@ class Manager
|
|||||||
return new $class($authenticationSource);
|
return new $class($authenticationSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authenticate(Credentials $credentials)
|
public function authenticate(Credentials $credentials, $persist = true)
|
||||||
{
|
{
|
||||||
if (!$this->userBackend->hasUsername($credentials)) {
|
if (!$this->userBackend->hasUsername($credentials)) {
|
||||||
Logger::info("Unknown user %s tried to log in", $credentials->getUsername());
|
Logger::info("Unknown user %s tried to log in", $credentials->getUsername());
|
||||||
@ -68,26 +80,29 @@ class Manager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
persistCurrentUser();
|
if ($persist == true) {
|
||||||
|
$this->persistCurrentUser();
|
||||||
|
$this->session->write();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function persistCurrentUser()
|
public function persistCurrentUser()
|
||||||
{
|
{
|
||||||
$this->session->set("user", $this->user->toSession());
|
$this->session->set("user", $this->user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authenticateFromSession()
|
public function authenticateFromSession()
|
||||||
{
|
{
|
||||||
$this->user = User::fromSession($this->session->get("user", null));
|
$this->user = $this->session->get("user", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isAuthenticated()
|
public function isAuthenticated($ignoreSession = false)
|
||||||
{
|
{
|
||||||
if ($this->user === null) {
|
if ($this->user === null && !$ignoreSession) {
|
||||||
$this->authenticateFromSession();
|
$this->authenticateFromSession();
|
||||||
}
|
}
|
||||||
return is_object($this->user) && !empty($this->user->username);
|
return is_object($this->user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removeAuthorization()
|
public function removeAuthorization()
|
||||||
|
@ -28,7 +28,11 @@ class PhpSession extends Session
|
|||||||
}
|
}
|
||||||
foreach ($options as $sessionVar => $value) {
|
foreach ($options as $sessionVar => $value) {
|
||||||
if (ini_set("session.".$sessionVar, $value) === false) {
|
if (ini_set("session.".$sessionVar, $value) === false) {
|
||||||
Logger::warn("Could not set php.ini settint %s = %s", $sessionVar, $value);
|
Logger::warn(
|
||||||
|
"Could not set php.ini setting %s = %s. This might affect your sessions behaviour.",
|
||||||
|
$sessionVar,
|
||||||
|
$value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,61 +10,116 @@ namespace Icinga\Authentication;
|
|||||||
/**
|
/**
|
||||||
* This class represents a user object
|
* This class represents a user object
|
||||||
*
|
*
|
||||||
* TODO: Show some use cases
|
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2013 Icinga-Web Team <info@icinga.org>
|
* @copyright Copyright (c) 2013 Icinga-Web Team <info@icinga.org>
|
||||||
* @author Icinga-Web Team <info@icinga.org>
|
* @author Icinga-Web Team <info@icinga.org>
|
||||||
* @package Icinga\Application
|
* @package Icinga\Application
|
||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
|
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
|
||||||
*/
|
*/
|
||||||
class User extends Storable
|
class User
|
||||||
{
|
{
|
||||||
protected $defaultProps = array(
|
private $username = "";
|
||||||
'username' => null,
|
private $firstname = "";
|
||||||
'password' => null,
|
private $lastname = "";
|
||||||
'first_name' => null,
|
private $email = "";
|
||||||
'last_name' => null,
|
private $domain = "";
|
||||||
'email' => null,
|
private $additionalInformation = array();
|
||||||
);
|
|
||||||
protected $permissions = array();
|
|
||||||
protected $backend;
|
|
||||||
protected $groups;
|
|
||||||
protected $key = 'username';
|
|
||||||
|
|
||||||
public function listGroups()
|
private $permissions = array();
|
||||||
|
private $groups = array();
|
||||||
|
|
||||||
|
public function __construct($username, $firstname, $lastname, $email)
|
||||||
{
|
{
|
||||||
if ($this->groups === null) {
|
$this->setUsername($username);
|
||||||
$this->loadGroups();
|
$this->setFirstname($firstname);
|
||||||
}
|
$this->setLastname($lastname);
|
||||||
|
$this->setEmail($email);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadGroups()
|
public function getGroups()
|
||||||
{
|
{
|
||||||
// Whatever
|
return $this->groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setGroups(array $groups)
|
||||||
|
{
|
||||||
|
$this->groups = $groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isMemberOf(Group $group)
|
public function isMemberOf(Group $group)
|
||||||
{
|
{
|
||||||
|
return in_array($group, $this->groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPermissionList()
|
public function getPermissions()
|
||||||
{
|
{
|
||||||
return $this->permissions;
|
return $this->permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasPermission($uri, $permission)
|
public function getUsername()
|
||||||
{
|
{
|
||||||
|
return $this->username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function grantPermission($uri, $permission)
|
public function setUsername($name)
|
||||||
{
|
{
|
||||||
|
$this->username = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function revokePermission($uri, $permission)
|
public function getFirstname()
|
||||||
{
|
{
|
||||||
|
return $this->firstname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFirstname($name)
|
||||||
|
{
|
||||||
|
$this->firstname = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLastname()
|
||||||
|
{
|
||||||
|
return $this->lastname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLastname($name)
|
||||||
|
{
|
||||||
|
$this->lastname = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmail()
|
||||||
|
{
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEmail($mail)
|
||||||
|
{
|
||||||
|
if (filter_var($mail, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$this->mail = $mail;
|
||||||
|
} else {
|
||||||
|
throw new InvalidArgumentException("Invalid mail given for user $this->username: $mail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDomain($domain)
|
||||||
|
{
|
||||||
|
$this->domain = $domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDomain()
|
||||||
|
{
|
||||||
|
return $this->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAdditional($key, $value)
|
||||||
|
{
|
||||||
|
$this->additionalInformation[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAdditional($key)
|
||||||
|
{
|
||||||
|
if (isset($this->additionalInformation[$key])) {
|
||||||
|
return $this->additionalInformation[$key];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,27 +2,11 @@
|
|||||||
|
|
||||||
namespace Icinga\Authentication;
|
namespace Icinga\Authentication;
|
||||||
|
|
||||||
class UserBackend
|
interface UserBackend
|
||||||
{
|
{
|
||||||
protected $config;
|
public function __construct($config);
|
||||||
|
|
||||||
public function __construct($config)
|
public function hasUsername(Credentials $credentials);
|
||||||
{
|
|
||||||
$this->config = $config;
|
|
||||||
$this->init();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function init()
|
public function authenticate(Credentials $credentials);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasUsername($username)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function authenticate($username, $password = null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
59
test/php/library/Icinga/Authentication/BackendMock.php
Normal file
59
test/php/library/Icinga/Authentication/BackendMock.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Tests\Icinga\Authentication;
|
||||||
|
|
||||||
|
require_once("../../library/Icinga/Authentication/Credentials.php");
|
||||||
|
require_once("../../library/Icinga/Authentication/UserBackend.php");
|
||||||
|
require_once("../../library/Icinga/Authentication/User.php");
|
||||||
|
|
||||||
|
use Icinga\Authentication\Credentials as Credentials;
|
||||||
|
use Icinga\Authentication\UserBackend as UserBackend;
|
||||||
|
use Icinga\Authentication\User as User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple backend mock that takes an config object
|
||||||
|
* with the property "credentials", which is an array
|
||||||
|
* of Credentials this backend authenticates
|
||||||
|
**/
|
||||||
|
class BackendMock implements UserBackend
|
||||||
|
{
|
||||||
|
public $allowedCredentials = array();
|
||||||
|
public function __construct($config = null)
|
||||||
|
{
|
||||||
|
if ($config === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isset ($config->credentials)) {
|
||||||
|
$this->allowedCredentials = $config->credentials;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasUsername(Credentials $userCredentials)
|
||||||
|
{
|
||||||
|
foreach ($this->allowedCredentials as $credential) {
|
||||||
|
if ($credential->getUsername() == $userCredentials->getUsername()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDummyUser()
|
||||||
|
{
|
||||||
|
return new User(
|
||||||
|
"Username",
|
||||||
|
"Firstname",
|
||||||
|
"Lastname",
|
||||||
|
"user@test.local"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authenticate(Credentials $credentials)
|
||||||
|
{
|
||||||
|
if (!in_array($credentials, $this->allowedCredentials)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return self::getDummyUser();
|
||||||
|
}
|
||||||
|
}
|
122
test/php/library/Icinga/Authentication/ManagerTest.php
Normal file
122
test/php/library/Icinga/Authentication/ManagerTest.php
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Tests\Icinga\Authentication;
|
||||||
|
|
||||||
|
require_once("../../library/Icinga/Application/Logger.php");
|
||||||
|
require_once("../../library/Icinga/Authentication/Manager.php");
|
||||||
|
require_once("../../library/Icinga/Authentication/Credentials.php");
|
||||||
|
require_once("Zend/Log.php");
|
||||||
|
require_once("BackendMock.php");
|
||||||
|
require_once("SessionMock.php");
|
||||||
|
|
||||||
|
use Icinga\Authentication\Manager as AuthManager;
|
||||||
|
use Icinga\Authentication\Credentials as Credentials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Test class for Manager
|
||||||
|
* Created Mon, 10 Jun 2013 07:54:34 +0000
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
class ManagerTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function getTestCredentials()
|
||||||
|
{
|
||||||
|
return (object) array("credentials" => array(
|
||||||
|
new Credentials("jdoe", "passjdoe"),
|
||||||
|
new Credentials("root", "passroot"),
|
||||||
|
new Credentials("test", "passtest")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getManagerInstance(&$session = null, $write = false)
|
||||||
|
{
|
||||||
|
if ($session == null) {
|
||||||
|
$session = new SessionMock();
|
||||||
|
}
|
||||||
|
return AuthManager::getInstance(
|
||||||
|
(object) array(),
|
||||||
|
array(
|
||||||
|
"userBackendClass" => new BackendMock(
|
||||||
|
$this->getTestCredentials()
|
||||||
|
),
|
||||||
|
"groupBackendClass" => new BackendMock(),
|
||||||
|
"sessionClass" => $session,
|
||||||
|
"writeSession" => $write
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManagerInstanciation()
|
||||||
|
{
|
||||||
|
AuthManager::clearInstance();
|
||||||
|
$this->setPreserveGlobalState(false);
|
||||||
|
$authMgr = $this->getManagerInstance();
|
||||||
|
$auth = $this->assertEquals($authMgr, AuthManager::getInstance());
|
||||||
|
AuthManager::clearInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testAuthentication()
|
||||||
|
{
|
||||||
|
AuthManager::clearInstance();
|
||||||
|
$auth = $this->getManagerInstance();
|
||||||
|
$this->assertFalse(
|
||||||
|
$auth->authenticate(
|
||||||
|
new Credentials("jhoe", "passjdoe"),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertFalse(
|
||||||
|
$auth->authenticate(
|
||||||
|
new Credentials("joe", "passjhoe"),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->assertTrue(
|
||||||
|
$auth->authenticate(
|
||||||
|
new Credentials("jdoe", "passjdoe"),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
AuthManager::clearInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPersistAuthInSession()
|
||||||
|
{
|
||||||
|
AuthManager::clearInstance();
|
||||||
|
$session = new SessionMock();
|
||||||
|
$auth = $this->getManagerInstance($session, true);
|
||||||
|
$this->assertFalse($auth->isAuthenticated(true));
|
||||||
|
$auth->authenticate(new Credentials("jdoe", "passjdoe"));
|
||||||
|
$this->assertNotEquals(null, $session->get("user"));
|
||||||
|
$user = $session->get("user");
|
||||||
|
$this->assertEquals("Username", $user->getUsername());
|
||||||
|
$this->assertTrue($auth->isAuthenticated(true));
|
||||||
|
AuthManager::clearInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAuthenticateFromSession()
|
||||||
|
{
|
||||||
|
AuthManager::clearInstance();
|
||||||
|
$session = new SessionMock();
|
||||||
|
$session->set("user", BackendMock::getDummyUser());
|
||||||
|
$auth = $this->getManagerInstance($session, false);
|
||||||
|
$this->assertFalse($auth->isAuthenticated(true));
|
||||||
|
$this->assertTrue($auth->isAuthenticated());
|
||||||
|
$this->assertTrue($auth->isAuthenticated());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @expectedException \Exception
|
||||||
|
**/
|
||||||
|
public function testWriteSessionTwice()
|
||||||
|
{
|
||||||
|
$auth = $this->getManagerInstance($session, false);
|
||||||
|
$this->assertFalse($auth->isAuthenticated(true));
|
||||||
|
$auth->authenticate(new Credentials("jdoe", "passjdoe"));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
49
test/php/library/Icinga/Authentication/SessionMock.php
Normal file
49
test/php/library/Icinga/Authentication/SessionMock.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Tests\Icinga\Authentication;
|
||||||
|
|
||||||
|
require_once("../../library/Icinga/Authentication/Session.php");
|
||||||
|
|
||||||
|
use Icinga\Authentication\Session as Session;
|
||||||
|
|
||||||
|
class SessionMock extends Session
|
||||||
|
{
|
||||||
|
public $isOpen = false;
|
||||||
|
public $isWritten = false;
|
||||||
|
|
||||||
|
public function open()
|
||||||
|
{
|
||||||
|
if (!$this->isOpen && $this->isWritten) {
|
||||||
|
throw new \Exception("Session write after close");
|
||||||
|
}
|
||||||
|
$this->isOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read($keepOpen = false)
|
||||||
|
{
|
||||||
|
$this->open();
|
||||||
|
if (!$keepOpen) {
|
||||||
|
$this->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write($keepOpen = false)
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->open();
|
||||||
|
if (!$keepOpen) {
|
||||||
|
$this->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
$this->isOpen = false;
|
||||||
|
$this->isWritten = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function purge()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user