diff options
author | Frederic Guillot <fred@kanboard.net> | 2015-11-27 16:24:21 -0500 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2015-11-27 16:24:21 -0500 |
commit | 91bdf6aaf3cda52a43c35ce22f5e25537684cb56 (patch) | |
tree | 567631b186191508d7cc40f914ffe83740f0d355 | |
parent | 19706944dc94c4fe1784af434f5f2e27a3c8130c (diff) |
Add generic authorization class
-rw-r--r-- | app/Auth/Database.php | 49 | ||||
-rw-r--r-- | app/Core/Security/AccessMap.php | 92 | ||||
-rw-r--r-- | app/Core/Security/Authorization.php | 46 | ||||
-rw-r--r-- | app/Core/Security/Role.php | 21 | ||||
-rw-r--r-- | tests/units/Core/Security/AccessMapTest.php | 22 | ||||
-rw-r--r-- | tests/units/Core/Security/AuthorizationTest.php | 28 |
6 files changed, 209 insertions, 49 deletions
diff --git a/app/Auth/Database.php b/app/Auth/Database.php deleted file mode 100644 index c2041d4d..00000000 --- a/app/Auth/Database.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -namespace Kanboard\Auth; - -use Kanboard\Core\Base; -use Kanboard\Model\User; -use Kanboard\Event\AuthEvent; - -/** - * Database authentication - * - * @package auth - * @author Frederic Guillot - */ -class Database extends Base -{ - /** - * Backend name - * - * @var string - */ - const AUTH_NAME = 'Database'; - - /** - * Authenticate a user - * - * @access public - * @param string $username Username - * @param string $password Password - * @return boolean - */ - public function authenticate($username, $password) - { - $user = $this->db - ->table(User::TABLE) - ->eq('username', $username) - ->eq('disable_login_form', 0) - ->eq('is_ldap_user', 0) - ->findOne(); - - if (is_array($user) && password_verify($password, $user['password'])) { - $this->userSession->initialize($user); - $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id'])); - return true; - } - - return false; - } -} diff --git a/app/Core/Security/AccessMap.php b/app/Core/Security/AccessMap.php new file mode 100644 index 00000000..10a29e1f --- /dev/null +++ b/app/Core/Security/AccessMap.php @@ -0,0 +1,92 @@ +<?php + +namespace Kanboard\Core\Security; + +/** + * Access Map Definition + * + * @package security + * @author Frederic Guillot + */ +class AccessMap +{ + /** + * Default role + * + * @access private + * @var string + */ + private $defaultRole = ''; + + /** + * Access map + * + * @access private + * @var array + */ + private $map = array(); + + /** + * Define the default role when nothing match + * + * @access public + * @param string $role + * @return Acl + */ + public function setDefaultRole($role) + { + $this->defaultRole = $role; + return $this; + } + + /** + * Add new access rules + * + * @access public + * @param string $controller + * @param string $method + * @param array $roles + * @return Acl + */ + public function add($controller, $method, array $roles) + { + $controller = strtolower($controller); + $method = strtolower($method); + + if (! isset($this->map[$controller])) { + $this->map[$controller] = array(); + } + + if (! isset($this->map[$controller][$method])) { + $this->map[$controller][$method] = array(); + } + + $this->map[$controller][$method] = $roles; + + return $this; + } + + /** + * Get roles that match the given controller/method + * + * @access public + * @param string $controller + * @param string $method + * @return boolean + */ + public function getRoles($controller, $method) + { + $controller = strtolower($controller); + $method = strtolower($method); + + if (isset($this->map[$controller][$method])) { + return $this->map[$controller][$method]; + } + + if (isset($this->map[$controller]['*'])) { + return $this->map[$controller]['*']; + } + + return array($this->defaultRole); + } +} diff --git a/app/Core/Security/Authorization.php b/app/Core/Security/Authorization.php new file mode 100644 index 00000000..a04b3720 --- /dev/null +++ b/app/Core/Security/Authorization.php @@ -0,0 +1,46 @@ +<?php + +namespace Kanboard\Core\Security; + +/** + * Authorization Handler + * + * @package security + * @author Frederic Guillot + */ +class Authorization +{ + /** + * Access Map + * + * @access private + * @var AccessMap + */ + private $acl; + + /** + * Constructor + * + * @access public + * @param AccessMap $acl + */ + public function __construct(AccessMap $acl) + { + $this->acl = $acl; + } + + /** + * Check if the given role is allowed to access to the specified resource + * + * @access public + * @param string $controller + * @param string $method + * @param string $role + * @return boolean + */ + public function isAllowed($controller, $method, $role) + { + $roles = $this->acl->getRoles($controller, $method); + return in_array($role, $roles); + } +} diff --git a/app/Core/Security/Role.php b/app/Core/Security/Role.php new file mode 100644 index 00000000..079ce14b --- /dev/null +++ b/app/Core/Security/Role.php @@ -0,0 +1,21 @@ +<?php + +namespace Kanboard\Core\Security; + +/** + * Role Definitions + * + * @package security + * @author Frederic Guillot + */ +class Role +{ + const APP_ADMIN = 'app-admin'; + const APP_MANAGER = 'app-manager'; + const APP_USER = 'app-user'; + const APP_PUBLIC = 'app-public'; + + const PROJECT_MANAGER = 'project-manager'; + const PROJECT_MEMBER = 'project-member'; + const PROJECT_VIEWER = 'project-viewer'; +} diff --git a/tests/units/Core/Security/AccessMapTest.php b/tests/units/Core/Security/AccessMapTest.php new file mode 100644 index 00000000..ab74e036 --- /dev/null +++ b/tests/units/Core/Security/AccessMapTest.php @@ -0,0 +1,22 @@ +<?php + +require_once __DIR__.'/../../Base.php'; + +use Kanboard\Core\Security\AccessMap; + +class AccessMapTest extends Base +{ + public function testGetRoles() + { + $acl = new AccessMap; + $acl->setDefaultRole('role3'); + $acl->add('MyController', 'myAction1', array('role1', 'role2')); + $acl->add('MyController', 'myAction2', array('role1')); + $acl->add('MyAdminController', '*', array('role2')); + + $this->assertEquals(array('role1', 'role2'), $acl->getRoles('mycontroller', 'MyAction1')); + $this->assertEquals(array('role1'), $acl->getRoles('mycontroller', 'MyAction2')); + $this->assertEquals(array('role2'), $acl->getRoles('Myadmincontroller', 'MyAction')); + $this->assertEquals(array('role3'), $acl->getRoles('AnotherController', 'ActionNotFound')); + } +} diff --git a/tests/units/Core/Security/AuthorizationTest.php b/tests/units/Core/Security/AuthorizationTest.php new file mode 100644 index 00000000..ffeb3741 --- /dev/null +++ b/tests/units/Core/Security/AuthorizationTest.php @@ -0,0 +1,28 @@ +<?php + +require_once __DIR__.'/../../Base.php'; + +use Kanboard\Core\Security\Role; +use Kanboard\Core\Security\AccessMap; +use Kanboard\Core\Security\Authorization; + +class AuthorizationTest extends Base +{ + public function testIsAllowed() + { + $acl = new AccessMap; + $acl->setDefaultRole(Role::APP_USER); + $acl->add('MyController', 'myAction1', array(Role::APP_ADMIN, Role::APP_MANAGER)); + $acl->add('MyController', 'myAction2', array(Role::APP_ADMIN)); + $acl->add('MyAdminController', '*', array(Role::APP_MANAGER)); + + $authorization = new Authorization($acl); + $this->assertTrue($authorization->isAllowed('myController', 'myAction1', Role::APP_ADMIN)); + $this->assertTrue($authorization->isAllowed('myController', 'myAction1', Role::APP_MANAGER)); + $this->assertFalse($authorization->isAllowed('myController', 'myAction1', Role::APP_USER)); + $this->assertTrue($authorization->isAllowed('anotherController', 'anotherAction', Role::APP_USER)); + $this->assertTrue($authorization->isAllowed('MyAdminController', 'myAction', Role::APP_MANAGER)); + $this->assertFalse($authorization->isAllowed('MyAdminController', 'myAction', Role::APP_ADMIN)); + $this->assertFalse($authorization->isAllowed('MyAdminController', 'myAction', 'something else')); + } +} |