Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/tdr 22/declarative funcacl #2510

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
57d9c13
Quick POC for declarative access rights
jbout Apr 21, 2020
c1b5367
Removed unused use statements
jbout Apr 21, 2020
e0c7624
Merge branch 'develop' into poc/funcAcl
jbout Apr 29, 2020
7da8d60
Merge branch 'develop' into poc/funcAcl
jbout May 12, 2020
0be41d1
Merge branch 'develop' into feature/TDR-22/declarative-funcacl
jbout May 13, 2020
b6012f8
Fix first page error bug, use PSR-16
jbout May 13, 2020
758253a
Bump requirements and version to 42.9.0
jbout May 13, 2020
bfd0bed
Reduce complexity
jbout May 14, 2020
68f01d5
Reduce Cognitive Complexity
jbout May 18, 2020
9e37061
Invert parsing logic
jbout May 18, 2020
2a30e48
Removed legacy extension lookup
jbout May 18, 2020
039e3ff
Reduce Complexity
jbout May 18, 2020
8caf7b8
Fix codestyle, merge
jbout Jun 4, 2020
f66a47a
Merge branch 'develop' into feature/TDR-22/declarative-funcacl
jbout Jun 4, 2020
d87c832
Remove unused use satatement
jbout Jun 4, 2020
ac71b2f
Merge branch 'fix/cached-func-acl' into feature/TDR-22/declarative-fu…
jbout Jun 9, 2020
a14d4a5
Merge branch 'develop' into feature/TDR-22/declarative-funcacl
jbout Jun 29, 2020
32fa3f0
Merge branch 'develop' into feature/TDR-22/declarative-funcacl
jbout Jul 29, 2020
ca82769
fix merge
jbout Jul 29, 2020
20eaf34
Code Style fix
jbout Jul 29, 2020
ecb63f1
code beautifulizer
jbout Jul 29, 2020
88300f0
Added minor unit test
jbout Jul 30, 2020
2699b12
Merge branch 'develop' into feature/TDR-22/declarative-funcacl
jbout Aug 10, 2020
7bcc6f9
Added ACL Model test
jbout Aug 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 3 additions & 16 deletions scripts/install/setSimpleAccess.php → config/default/FuncAccessControl.conf.php
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*
*
* Copyright (c) 2020 (original work) Open Assessment Technologies SA;
*/

use oat\tao\model\accessControl\func\AccessRule;
use oat\tao\model\accessControl\func\AclProxy as FuncProxy;
use oat\tao\model\accessControl\data\implementation\FreeAccess;

$impl = new oat\tao\model\accessControl\func\implementation\SimpleAccess();
use oat\tao\model\accessControl\func\implementation\CacheOnly;

$exts = common_ext_ExtensionsManager::singleton()->getInstalledExtensions();
foreach ($exts as $extension) {
foreach ($extension->getManifest()->getAclTable() as $tableEntry) {
$rule = new AccessRule($tableEntry[0], $tableEntry[1], $tableEntry[2]);
$impl->applyRule($rule);
}
}
FuncProxy::setImplementation($impl);
return new CacheOnly();
5 changes: 2 additions & 3 deletions manifest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@
'label' => 'TAO Base',
'description' => 'TAO meta-extension',
'license' => 'GPL-2.0',
'version' => '42.8.0',
'version' => '42.9.0',
'author' => 'Open Assessment Technologies, CRP Henri Tudor',
'requires' => [
'generis' => '>=12.21.0',
'generis' => '>=12.22.0',
],
'models' => [
'http://www.tao.lu/Ontologies/TAO.rdf',
Expand Down Expand Up @@ -104,7 +104,6 @@
],
'php' => [
__DIR__ . '/scripts/install/addFileUploadSource.php',
__DIR__ . '/scripts/install/setSimpleAccess.php',
SetServiceFileStorage::class,
SetServiceState::class,
__DIR__ . '/scripts/install/setJsConfig.php',
Expand Down
109 changes: 105 additions & 4 deletions models/classes/accessControl/func/AccessRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,34 @@ class AccessRule
const GRANT = 'grant';
const DENY = 'deny';

const SCOPE_EXTENSION = 'ext';
const SCOPE_CONTROLLER = 'mod';
const SCOPE_ACTION = 'act';

/** @var string */
private $grantDeny;

/** @var string */
private $role;

/** @var string */
private $mask;

/** @var string */
private $scope;
/** @var string */
private $extension;
/** @var string */
private $controller;
/** @var string */
private $action;

public function __construct($mode, $roleUri, $mask)
{
$this->grantDeny = $mode;
$this->role = new core_kernel_classes_Resource($roleUri);
$this->role = $roleUri;
$this->mask = $mask;
$this->parseMask();
}

/**
Expand All @@ -63,16 +79,101 @@ public function isGrant()
* @return core_kernel_classes_Resource
*/
public function getRole()
{
return new core_kernel_classes_Resource($this->role);
}

public function getRoleId()
{
return $this->role;
}

/**
* Returns the filter of the rule
* @return array
* @deprecated please used the preparsed extension, controller, action
*/
public function getMask()
{
return $this->mask;
}

public function getScope()
{
return $this->scope;
}

public function getAction(): ?string
{
return $this->action;
}

public function getController(): ?string
{
return $this->controller;
}

public function getExtensionId(): ?string
{
return $this->extension;
}

private function parseMask(): void
{
if (is_string($this->mask)) {
$this->parseStringMask($this->mask);
} elseif (is_array($this->mask)) { /// array masks
$this->parseArrayMask($this->mask);
} else {
throw new \common_exception_InconsistentData('Invalid AccessRule mask ' . gettype($this->mask));
}
}

private function parseStringMask(string $mask): void
{
$controller = $mask;
$action = null;
if (strpos($mask, '@') !== false) {
[$controller, $action] = explode('@', $mask, 2);
}
if (class_exists($controller)) {
$this->scope = is_null($action) ? self::SCOPE_CONTROLLER : self::SCOPE_ACTION;
$this->controller = $controller;
$this->action = $action;
} else {
throw new \common_exception_InconsistentData('Invalid AccessRule mask ' . $mask);
}
}

private function parseArrayMask(array $mask): void
{
$legacy = $this->checkLegacyMask($mask);
if (!is_null($legacy)) {
$this->parseStringMask($legacy);
} elseif (isset($mask['act'], $mask['mod'], $mask['ext'])) {
$this->scope = self::SCOPE_ACTION;
$this->controller = FuncHelper::getClassName($mask['ext'], $mask['mod']);
$this->action = $mask['act'];
} elseif (isset($mask['mod'], $mask['ext'])) {
$this->scope = self::SCOPE_CONTROLLER;
$this->controller = FuncHelper::getClassName($mask['ext'], $mask['mod']);
} elseif (isset($mask['ext'])) {
$this->scope = self::SCOPE_EXTENSION;
$this->extension = $mask['ext'];
} else {
throw new \common_exception_InconsistentData('Invalid AccessRule mask ' . implode(',', array_keys($mask)));
}
}

/**
* Legacy notation, should not be used, but we still need to support it
*/
private function checkLegacyMask(array $mask): ?string
{
if (isset($mask['controller'])) {
return $mask['controller'];
} elseif (isset($mask['act']) && !isset($mask['controller']) && strpos($mask['act'], '@') !== false) {
return $mask['act'];
} else {
return null;
}
}
}
2 changes: 0 additions & 2 deletions models/classes/accessControl/func/AclProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
namespace oat\tao\model\accessControl\func;

use oat\tao\model\accessControl\AccessControl;
use common_ext_ExtensionsManager;
use common_Logger;
use oat\oatbox\user\User;
use oat\oatbox\service\ServiceManager;

Expand Down
3 changes: 2 additions & 1 deletion models/classes/accessControl/func/FuncAccessControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
*/
interface FuncAccessControl
{

public const SERVICE_ID = 'tao/FuncAccessControl';

/**
* Returns whenever or not a user has access to a specified call
*
Expand Down
126 changes: 126 additions & 0 deletions models/classes/accessControl/func/implementation/AclModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
jbout marked this conversation as resolved.
Show resolved Hide resolved
*
*/

jbout marked this conversation as resolved.
Show resolved Hide resolved
namespace oat\tao\model\accessControl\func\implementation;

use oat\tao\model\accessControl\func\AccessRule;
use oat\tao\model\accessControl\func\FuncHelper;

/**
* Simple ACL Implementation deciding whenever or not to allow access
* strictly by the BASEUSER role and a whitelist
*
* Not to be used in production, since testtakers cann access the backoffice
*
* @access public
* @author Joel Bout, <[email protected]>
* @package tao

*/
class AclModel
{
private $actionRules = [];
private $controllerRules = [];
private $extensionRules = [];

public function applyRule(AccessRule $rule): void
{
switch ($rule->getScope()) {
case AccessRule::SCOPE_ACTION :
$this->addAction($rule);
break;
case AccessRule::SCOPE_CONTROLLER :
$this->addController($rule);
break;
case AccessRule::SCOPE_EXTENSION :
$this->addExtension($rule);
break;
}
}

public function getControllerAcl(string $controllerName, string $extensionId): ControllerAccessRight
{
$controller = new ControllerAccessRight($controllerName, $extensionId);
$this->applyExtensionRules($controller);
$this->applyControllerRules($controller);
$this->applyActionRules($controller);
return $controller;
}

private function addAction(AccessRule $rule): void
{
$action = $rule->getAction();
$controller = $rule->getController();
if (!isset($this->actionRules[$controller])) {
$this->actionRules[$controller] = [];
}
$this->actionRules[$controller][] = [$rule->getRoleId(), $action];
}

private function addController(AccessRule $rule): void
{
$controller = $rule->getController();
if (!isset($this->controllerRules[$controller])) {
$this->controllerRules[$controller] = [];
}
$this->controllerRules[$controller][] = $rule->getRoleId();
}

private function addExtension(AccessRule $rule): void
{
$extensionName = $rule->getExtensionId();
if (!isset($this->extensionRules[$extensionName])) {
$this->extensionRules[$extensionName] = [];
}
$this->extensionRules[$extensionName][] = $rule->getRoleId();
}

private function applyActionRules(ControllerAccessRight $controller): ControllerAccessRight
{
if (isset($this->actionRules[$controller->getClassName()])) {
foreach ($this->actionRules[$controller->getClassName()] as $pair) {
$controller->addActionAccess($pair[0], $pair[1]);
}
}
return $controller;
}

private function applyControllerRules(ControllerAccessRight $controller): ControllerAccessRight
{
if (isset($this->controllerRules[$controller->getClassName()])) {
foreach ($this->controllerRules[$controller->getClassName()] as $roleId) {
$controller->addFullAccess($roleId);
}
}
return $controller;
}

private function applyExtensionRules(ControllerAccessRight $controller): ControllerAccessRight
{
$extensionId = $controller->getExtensionId();
if (isset($this->extensionRules[$extensionId])) {
foreach ($this->extensionRules[$extensionId] as $roleId) {
$controller->addFullAccess($roleId);
}
}
return $controller;
}
}
Loading