summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2015-11-27 16:24:21 -0500
committerFrederic Guillot <fred@kanboard.net>2015-11-27 16:24:21 -0500
commit91bdf6aaf3cda52a43c35ce22f5e25537684cb56 (patch)
tree567631b186191508d7cc40f914ffe83740f0d355
parent19706944dc94c4fe1784af434f5f2e27a3c8130c (diff)
Add generic authorization class
-rw-r--r--app/Auth/Database.php49
-rw-r--r--app/Core/Security/AccessMap.php92
-rw-r--r--app/Core/Security/Authorization.php46
-rw-r--r--app/Core/Security/Role.php21
-rw-r--r--tests/units/Core/Security/AccessMapTest.php22
-rw-r--r--tests/units/Core/Security/AuthorizationTest.php28
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'));
+ }
+}