From e87490aad82bd78a64621ee5566bd74497d665a2 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 24 Jun 2020 16:54:52 +0300 Subject: [PATCH] acl changes --- application/Espo/Core/Acl.php | 40 ++++----- application/Espo/Core/Acl/Acl.php | 2 +- application/Espo/Core/Acl/EntityAcl.php | 38 ++++++++ application/Espo/Core/Acl/ScopeAcl.php | 38 ++++++++ application/Espo/Core/Acl/Table.php | 1 - application/Espo/Core/AclManager.php | 88 ++++++++++--------- application/Espo/Core/AclPortal/Acl.php | 2 +- application/Espo/Core/AclPortal/Base.php | 2 +- .../Espo/Core/AclPortal/PortalScopeAcl.php | 35 ++++++++ application/Espo/Core/Portal/Acl.php | 13 ++- application/Espo/Core/Portal/AclManager.php | 75 ++++++++++------ 11 files changed, 234 insertions(+), 100 deletions(-) create mode 100644 application/Espo/Core/Acl/EntityAcl.php create mode 100644 application/Espo/Core/Acl/ScopeAcl.php create mode 100644 application/Espo/Core/AclPortal/PortalScopeAcl.php diff --git a/application/Espo/Core/Acl.php b/application/Espo/Core/Acl.php index 087fdb6950..a408c17dba 100644 --- a/application/Espo/Core/Acl.php +++ b/application/Espo/Core/Acl.php @@ -57,102 +57,102 @@ class Acl return $this->user; } - public function getMap() + public function getMap() : object { return $this->getAclManager()->getMap($this->getUser()); } - public function getLevel($scope, $action) + public function getLevel(string $scope, string $action) : string { return $this->getAclManager()->getLevel($this->getUser(), $scope, $action); } - public function get($permission) + public function get(string $permission) : ?string { return $this->getAclManager()->get($this->getUser(), $permission); } - public function checkReadNo($scope) + public function checkReadNo(string $scope) : bool { return $this->getAclManager()->checkReadNo($this->getUser(), $scope); } - public function checkReadOnlyTeam($scope) + public function checkReadOnlyTeam(string $scope) : bool { return $this->getAclManager()->checkReadOnlyTeam($this->getUser(), $scope); } - public function checkReadOnlyOwn($scope) + public function checkReadOnlyOwn(string $scope) : bool { return $this->getAclManager()->checkReadOnlyOwn($this->getUser(), $scope); } - public function check($subject, $action = null) + public function check($subject, ?string $action = null) : bool { return $this->getAclManager()->check($this->getUser(), $subject, $action); } - public function checkScope($scope, $action = null) + public function checkScope(string $scope, ?string $action = null) : bool { return $this->getAclManager()->checkScope($this->getUser(), $scope, $action); } - public function checkEntity(Entity $entity, $action = 'read') + public function checkEntity(Entity $entity, string $action = 'read') : bool { return $this->getAclManager()->checkEntity($this->getUser(), $entity, $action); } - public function checkUser($permission, User $entity) + public function checkUser(string $permission, User $entity) : bool { return $this->getAclManager()->checkUser($this->getUser(), $permission, $entity); } - public function checkIsOwner(Entity $entity) + public function checkIsOwner(Entity $entity) : bool { return $this->getAclManager()->checkIsOwner($this->getUser(), $entity); } - public function checkInTeam(Entity $entity) + public function checkInTeam(Entity $entity) : bool { return $this->getAclManager()->checkInTeam($this->getUser(), $entity); } - public function getScopeForbiddenAttributeList($scope, $action = 'read', $thresholdLevel = 'no') + public function getScopeForbiddenAttributeList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array { return $this->getAclManager()->getScopeForbiddenAttributeList($this->getUser(), $scope, $action, $thresholdLevel); } - public function getScopeForbiddenFieldList($scope, $action = 'read', $thresholdLevel = 'no') + public function getScopeForbiddenFieldList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array { return $this->getAclManager()->getScopeForbiddenFieldList($this->getUser(), $scope, $action, $thresholdLevel); } - public function getScopeForbiddenLinkList($scope, $action = 'read', $thresholdLevel = 'no') + public function getScopeForbiddenLinkList(string $scope, string $action = 'read', string $thresholdLevel = 'no') : array { return $this->getAclManager()->getScopeForbiddenLinkList($this->getUser(), $scope, $action, $thresholdLevel); } - public function checkUserPermission($target, $permissionType = 'userPermission') + public function checkUserPermission($target, string $permissionType = 'userPermission') : bool { return $this->getAclManager()->checkUserPermission($this->getUser(), $target, $permissionType); } - public function checkAssignmentPermission($target) + public function checkAssignmentPermission($target) : bool { return $this->getAclManager()->checkAssignmentPermission($this->getUser(), $target); } - public function getScopeRestrictedFieldList($scope, $type) + public function getScopeRestrictedFieldList(string $scope, $type) : array { return $this->getAclManager()->getScopeRestrictedFieldList($scope, $type); } - public function getScopeRestrictedAttributeList($scope, $type) + public function getScopeRestrictedAttributeList(string $scope, $type) : array { return $this->getAclManager()->getScopeRestrictedAttributeList($scope, $type); } - public function getScopeRestrictedLinkList($scope, $type) + public function getScopeRestrictedLinkList(string $scope, $type) : array { return $this->getAclManager()->getScopeRestrictedLinkList($scope, $type); } diff --git a/application/Espo/Core/Acl/Acl.php b/application/Espo/Core/Acl/Acl.php index 32897f4f18..9f914cb25c 100644 --- a/application/Espo/Core/Acl/Acl.php +++ b/application/Espo/Core/Acl/Acl.php @@ -38,7 +38,7 @@ use Espo\Core\{ Utils\Config, }; -class Acl +class Acl implements ScopeAcl, EntityAcl { protected $scope; diff --git a/application/Espo/Core/Acl/EntityAcl.php b/application/Espo/Core/Acl/EntityAcl.php new file mode 100644 index 0000000000..01a9ce2768 --- /dev/null +++ b/application/Espo/Core/Acl/EntityAcl.php @@ -0,0 +1,38 @@ +fileManager->putPhpContents($this->cacheFilePath, $this->data, true); } - } diff --git a/application/Espo/Core/AclManager.php b/application/Espo/Core/AclManager.php index 7dee2d3295..77d8f9c911 100644 --- a/application/Espo/Core/AclManager.php +++ b/application/Espo/Core/AclManager.php @@ -33,14 +33,17 @@ use Espo\Core\Exceptions\Error; use Espo\ORM\Entity; use Espo\Entities\User; -use Espo\Core\Utils\Util; - -use Espo\Core\Acl\GlobalRestricton; use Espo\Core\{ Utils\ClassFinder, Utils\Config, ORM\EntityManager, + Acl\Acl as BaseAcl, + Acl\ScopeAcl, + Acl\GlobalRestricton, + Acl as UserAclWrapper, + Acl\Table as AclTable, + Utils\Util, }; /** @@ -52,11 +55,11 @@ class AclManager private $tableHashMap = []; - protected $tableClassName = 'Espo\\Core\\Acl\\Table'; + protected $tableClassName = AclTable::class; - protected $userAclClassName = 'Espo\\Core\\Acl'; + protected $userAclClassName = UserAclWrapper::class; - protected $baseImplementationClassName = 'Espo\\Core\\Acl\\Base'; + protected $baseImplementationClassName = BaseAcl::class; protected $globalRestricton; @@ -78,7 +81,7 @@ class AclManager ]); } - public function getImplementation(string $scope) + public function getImplementation(string $scope) : ScopeAcl { if (empty($this->implementationHashMap[$scope])) { $className = $this->classFinder->find('Acl', $scope); @@ -117,12 +120,12 @@ class AclManager return $this->tableHashMap[$key]; } - public function getMap(User $user) + public function getMap(User $user) : object { return $this->getTable($user)->getMap(); } - public function getLevel(User $user, $scope, $action) + public function getLevel(User $user, string $scope, string $action) : string { if ($user->isAdmin()) { return $this->getTable($user)->getHighestLevel($scope, $action); @@ -130,39 +133,39 @@ class AclManager return $this->getTable($user)->getLevel($scope, $action); } - public function get(User $user, $permission) + public function get(User $user, string $permission) : ?string { return $this->getTable($user)->get($permission); } - public function checkReadNo(User $user, $scope) + public function checkReadNo(User $user, string $scope) : bool { if ($user->isAdmin()) { return false; } $data = $this->getTable($user)->getScopeData($scope); - return $this->getImplementation($scope)->checkReadNo($user, $data); + return (bool) $this->getImplementation($scope)->checkReadNo($user, $data); } - public function checkReadOnlyTeam(User $user, $scope) + public function checkReadOnlyTeam(User $user, string $scope) : bool { if ($user->isAdmin()) { return false; } $data = $this->getTable($user)->getScopeData($scope); - return $this->getImplementation($scope)->checkReadOnlyTeam($user, $data); + return (bool) $this->getImplementation($scope)->checkReadOnlyTeam($user, $data); } - public function checkReadOnlyOwn(User $user, $scope) + public function checkReadOnlyOwn(User $user, string $scope) : bool { if ($user->isAdmin()) { return false; } $data = $this->getTable($user)->getScopeData($scope); - return $this->getImplementation($scope)->checkReadOnlyOwn($user, $data); + return (bool) $this->getImplementation($scope)->checkReadOnlyOwn($user, $data); } - public function check(User $user, $subject, $action = null) + public function check(User $user, $subject, ?string $action = null) : bool { if (is_string($subject)) { return $this->checkScope($user, $subject, $action); @@ -172,9 +175,11 @@ class AclManager return $this->checkEntity($user, $entity, $action); } } + + return false; } - public function checkEntity(User $user, Entity $entity, $action = 'read') + public function checkEntity(User $user, Entity $entity, string $action = 'read') : bool { $scope = $entity->getEntityType(); @@ -189,30 +194,30 @@ class AclManager if ($action) { $methodName = 'checkEntity' . ucfirst($action); if (method_exists($impl, $methodName)) { - return $impl->$methodName($user, $entity, $data); + return (bool) $impl->$methodName($user, $entity, $data); } } - return $impl->checkEntity($user, $entity, $data, $action); + return (bool) $impl->checkEntity($user, $entity, $data, $action); } - public function checkIsOwner(User $user, Entity $entity) + public function checkIsOwner(User $user, Entity $entity) : bool { - return $this->getImplementation($entity->getEntityType())->checkIsOwner($user, $entity); + return (bool) $this->getImplementation($entity->getEntityType())->checkIsOwner($user, $entity); } - public function checkInTeam(User $user, Entity $entity) + public function checkInTeam(User $user, Entity $entity) : bool { - return $this->getImplementation($entity->getEntityType())->checkInTeam($user, $entity); + return (bool) $this->getImplementation($entity->getEntityType())->checkInTeam($user, $entity); } - public function checkScope(User $user, $scope, $action = null) + public function checkScope(User $user, string $scope, ?string $action = null) : bool { $data = $this->getTable($user)->getScopeData($scope); - return $this->getImplementation($scope)->checkScope($user, $data, $action); + return (bool) $this->getImplementation($scope)->checkScope($user, $data, $action); } - public function checkUser(User $user, $permission, User $entity) + public function checkUser(User $user, string $permission, User $entity) : bool { if ($user->isAdmin()) { return true; @@ -241,7 +246,7 @@ class AclManager return true; } - protected function getGlobalRestrictionTypeList(User $user, $action = 'read') + protected function getGlobalRestrictionTypeList(User $user, string $action = 'read') : array { $typeList = ['forbidden']; @@ -263,8 +268,9 @@ class AclManager return $typeList; } - public function getScopeForbiddenAttributeList(User $user, $scope, $action = 'read', $thresholdLevel = 'no') - { + public function getScopeForbiddenAttributeList( + User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no' + ) : array { $list = []; if (!$user->isAdmin()) { @@ -282,8 +288,9 @@ class AclManager return $list; } - public function getScopeForbiddenFieldList(User $user, $scope, $action = 'read', $thresholdLevel = 'no') - { + public function getScopeForbiddenFieldList( + User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no' + ) : array { $list = []; if (!$user->isAdmin()) { @@ -302,8 +309,9 @@ class AclManager } - public function getScopeForbiddenLinkList(User $user, $scope, $action = 'read', $thresholdLevel = 'no') - { + public function getScopeForbiddenLinkList( + User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no' + ) : array { $list = []; if ($thresholdLevel === 'no') { @@ -317,7 +325,7 @@ class AclManager return $list; } - public function checkUserPermission(User $user, $target, $permissionType = 'userPermission') + public function checkUserPermission(User $user, $target, string $permissionType = 'userPermission') : bool { $permission = $this->get($user, $permissionType); @@ -347,19 +355,19 @@ class AclManager return true; } - public function checkAssignmentPermission(User $user, $target) + public function checkAssignmentPermission(User $user, $target) : bool { return $this->checkUserPermission($user, $target, 'assignmentPermission'); } - public function createUserAcl(User $user) + public function createUserAcl(User $user) : UserAclWrapper { $className = $this->userAclClassName; $acl = new $className($this, $user); return $acl; } - public function getScopeRestrictedFieldList($scope, $type) + public function getScopeRestrictedFieldList(string $scope, $type) : array { if (is_array($type)) { $typeList = $type; @@ -373,7 +381,7 @@ class AclManager return $this->globalRestricton->getScopeRestrictedFieldList($scope, $type); } - public function getScopeRestrictedAttributeList($scope, $type) + public function getScopeRestrictedAttributeList(string $scope, $type) : array { if (is_array($type)) { $typeList = $type; @@ -387,7 +395,7 @@ class AclManager return $this->globalRestricton->getScopeRestrictedAttributeList($scope, $type); } - public function getScopeRestrictedLinkList($scope, $type) + public function getScopeRestrictedLinkList(string $scope, $type) : array { if (is_array($type)) { $typeList = $type; diff --git a/application/Espo/Core/AclPortal/Acl.php b/application/Espo/Core/AclPortal/Acl.php index 9f2ae3ae88..bef46c5a8e 100644 --- a/application/Espo/Core/AclPortal/Acl.php +++ b/application/Espo/Core/AclPortal/Acl.php @@ -31,7 +31,7 @@ namespace Espo\Core\AclPortal; use Espo\Core\Acl\Acl as BaseAcl; -class Acl extends BaseAcl +class Acl extends BaseAcl implements PortalScopeAcl { use Portal; } diff --git a/application/Espo/Core/AclPortal/Base.php b/application/Espo/Core/AclPortal/Base.php index 16cab5886f..11b43092eb 100644 --- a/application/Espo/Core/AclPortal/Base.php +++ b/application/Espo/Core/AclPortal/Base.php @@ -31,7 +31,7 @@ namespace Espo\Core\AclPortal; /** Deprecated */ -class Base extends \Espo\Core\Acl\Base +class Base extends \Espo\Core\Acl\Base implements PortalScopeAcl { use Portal; } diff --git a/application/Espo/Core/AclPortal/PortalScopeAcl.php b/application/Espo/Core/AclPortal/PortalScopeAcl.php new file mode 100644 index 0000000000..0da075fd46 --- /dev/null +++ b/application/Espo/Core/AclPortal/PortalScopeAcl.php @@ -0,0 +1,35 @@ +getAclManager()->checkReadOnlyAccount($this->getUser(), $scope); } - public function checkReadOnlyContact($scope) + public function checkReadOnlyContact(string $scope) : bool { return $this->getAclManager()->checkReadOnlyContact($this->getUser(), $scope); } - public function checkInAccount(Entity $entity) + public function checkInAccount(Entity $entity) : bool { return $this->getAclManager()->checkInAccount($this->getUser(), $entity); } - public function checkIsOwnContact(Entity $entity) + public function checkIsOwnContact(Entity $entity) : bool { return $this->getAclManager()->checkIsOwnContact($this->getUser(), $entity); } } - diff --git a/application/Espo/Core/Portal/AclManager.php b/application/Espo/Core/Portal/AclManager.php index 19bcc7b1ef..6238ac16dd 100644 --- a/application/Espo/Core/Portal/AclManager.php +++ b/application/Espo/Core/Portal/AclManager.php @@ -35,19 +35,30 @@ use Espo\Core\Utils\Util; use Espo\Entities\Portal; -class AclManager extends \Espo\Core\AclManager +use Espo\Core\{ + AclPortal\Table as AclPortalTable, + AclPortal\Acl as BasePortalAcl, + AclPortal\PortalScopeAcl, + Acl\ScopeAcl, + Portal\Acl as UserAclWrapper, + AclManager as BaseAclManager, +}; + +use Espo\Core\Exceptions\Error; + +class AclManager extends BaseAclManager { - protected $tableClassName = 'Espo\\Core\\AclPortal\\Table'; + protected $tableClassName = AclPortalTable::class; private $mainManager = null; private $portal = null; - protected $userAclClassName = 'Espo\\Core\\Portal\\Acl'; + protected $userAclClassName = UserAclWrapper::class; - protected $baseImplementationClassName = 'Espo\\Core\\AclPortal\\Base'; + protected $baseImplementationClassName = BasePortalAcl::class; - public function getImplementation(string $scope) + public function getImplementation(string $scope) : ScopeAcl { if (empty($this->implementationHashMap[$scope])) { $className = $this->classFinder->find('AclPortal', $scope); @@ -65,12 +76,16 @@ class AclManager extends \Espo\Core\AclManager ]); $this->implementationHashMap[$scope] = $acl; + + if (!$acl instanceof PortalScopeAcl) { + throw new Error("Portal\AclManager: Implementation should be instance of PortalScopeAcl."); + } } return $this->implementationHashMap[$scope]; } - public function setMainManager($mainManager) + public function setMainManager(BaseAclManager $mainManager) { $this->mainManager = $mainManager; } @@ -107,7 +122,7 @@ class AclManager extends \Espo\Core\AclManager return $this->tableHashMap[$key]; } - public function checkReadOnlyAccount(User $user, $scope) + public function checkReadOnlyAccount(User $user, string $scope) : bool { if ($user->isAdmin()) { return false; @@ -116,7 +131,7 @@ class AclManager extends \Espo\Core\AclManager return $this->getImplementation($scope)->checkReadOnlyAccount($user, $data); } - public function checkReadOnlyContact(User $user, $scope) + public function checkReadOnlyContact(User $user, string $scope) : bool { if ($user->isAdmin()) { return false; @@ -125,17 +140,17 @@ class AclManager extends \Espo\Core\AclManager return $this->getImplementation($scope)->checkReadOnlyContact($user, $data); } - public function checkInAccount(User $user, Entity $entity, $action) + public function checkInAccount(User $user, Entity $entity) : bool { - return $this->getImplementation($entity->getEntityType())->checkInAccount($user, $entity); + return (bool) $this->getImplementation($entity->getEntityType())->checkInAccount($user, $entity); } - public function checkIsOwnContact(User $user, Entity $entity, $action) + public function checkIsOwnContact(User $user, Entity $entity) : bool { - return $this->getImplementation($entity->getEntityType())->checkIsOwnContact($user, $entity); + return (bool) $this->getImplementation($entity->getEntityType())->checkIsOwnContact($user, $entity); } - public function getMap(User $user) + public function getMap(User $user) : object { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->getMap($user); @@ -143,7 +158,7 @@ class AclManager extends \Espo\Core\AclManager return parent::getMap($user); } - public function getLevel(User $user, $scope, $action) + public function getLevel(User $user, string $scope, string $action) : string { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->getLevel($user, $scope, $action); @@ -151,7 +166,7 @@ class AclManager extends \Espo\Core\AclManager return parent::getLevel($user, $scope, $action); } - public function get(User $user, $permission) + public function get(User $user, string $permission) : ?string { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->get($user, $permission); @@ -159,7 +174,7 @@ class AclManager extends \Espo\Core\AclManager return parent::get($user, $permission); } - public function checkReadOnlyTeam(User $user, $scope) + public function checkReadOnlyTeam(User $user, string $scope) : bool { if ($this->checkUserIsNotPortal($user)) { $data = $this->getTable($user)->getScopeData($scope); @@ -168,7 +183,7 @@ class AclManager extends \Espo\Core\AclManager return parent::checkReadOnlyTeam($user, $scope); } - public function checkReadNo(User $user, $scope) + public function checkReadNo(User $user, string $scope) : bool { if ($this->checkUserIsNotPortal($user)) { $data = $this->getTable($user)->getScopeData($scope); @@ -177,7 +192,7 @@ class AclManager extends \Espo\Core\AclManager return parent::checkReadNo($user, $scope); } - public function checkReadOnlyOwn(User $user, $scope) + public function checkReadOnlyOwn(User $user, string $scope) : bool { if ($this->checkUserIsNotPortal($user)) { $data = $this->getTable($user)->getScopeData($scope); @@ -186,7 +201,7 @@ class AclManager extends \Espo\Core\AclManager return parent::checkReadOnlyOwn($user, $scope); } - public function check(User $user, $subject, $action = null) + public function check(User $user, $subject, ?string $action = null) : bool { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->check($user, $subject, $action); @@ -194,7 +209,7 @@ class AclManager extends \Espo\Core\AclManager return parent::check($user, $subject, $action); } - public function checkEntity(User $user, Entity $entity, $action = 'read') + public function checkEntity(User $user, Entity $entity, string $action = 'read') : bool { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->checkEntity($user, $entity, $action); @@ -202,7 +217,7 @@ class AclManager extends \Espo\Core\AclManager return parent::checkEntity($user, $entity, $action); } - public function checkIsOwner(User $user, Entity $entity) + public function checkIsOwner(User $user, Entity $entity) : bool { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->checkIsOwner($user, $entity); @@ -210,7 +225,7 @@ class AclManager extends \Espo\Core\AclManager return parent::checkIsOwner($user, $entity); } - public function checkInTeam(User $user, Entity $entity) + public function checkInTeam(User $user, Entity $entity) : bool { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->checkInTeam($user, $entity); @@ -218,7 +233,7 @@ class AclManager extends \Espo\Core\AclManager return parent::checkInTeam($user, $entity); } - public function checkScope(User $user, $scope, $action = null) + public function checkScope(User $user, string $scope, ?string $action = null) : bool { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->checkScope($user, $scope, $action); @@ -226,7 +241,7 @@ class AclManager extends \Espo\Core\AclManager return parent::checkScope($user, $scope, $action); } - public function checkUser(User $user, $permission, User $entity) + public function checkUser(User $user, string $permission, User $entity) : bool { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->checkUser($user, $permission, $entity); @@ -234,23 +249,25 @@ class AclManager extends \Espo\Core\AclManager return parent::checkUser($user, $permission, $entity); } - public function getScopeForbiddenAttributeList(User $user, $scope, $action = 'read', $thresholdLevel = 'no') - { + public function getScopeForbiddenAttributeList( + User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no' + ) : array { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->getScopeForbiddenAttributeList($user, $scope, $action, $thresholdLevel); } return parent::getScopeForbiddenAttributeList($user, $scope, $action, $thresholdLevel); } - public function getScopeForbiddenFieldList(User $user, $scope, $action = 'read', $thresholdLevel = 'no') - { + public function getScopeForbiddenFieldList( + User $user, string $scope, string $action = 'read', string $thresholdLevel = 'no' + ) : array { if ($this->checkUserIsNotPortal($user)) { return $this->getMainManager()->getScopeForbiddenFieldList($user, $scope, $action, $thresholdLevel); } return parent::getScopeForbiddenFieldList($user, $scope, $action, $thresholdLevel); } - protected function checkUserIsNotPortal($user) + protected function checkUserIsNotPortal(User $user) : bool { return !$user->isPortal(); }