diff --git a/vendor/magento/module-authorization/Model/Acl/Loader/Rule.php b/vendor/magento/module-authorization/Model/Acl/Loader/Rule.php index b8fd974c5da..653882f7a28 100644 --- a/vendor/magento/module-authorization/Model/Acl/Loader/Rule.php +++ b/vendor/magento/module-authorization/Model/Acl/Loader/Rule.php @@ -7,6 +7,7 @@ declare(strict_types=1); namespace Magento\Authorization\Model\Acl\Loader; +use Magento\Framework\Acl; use Magento\Framework\Acl\Data\CacheInterface; use Magento\Framework\Acl\LoaderInterface; use Magento\Framework\Acl\RootResource; @@ -21,7 +22,12 @@ class Rule implements LoaderInterface /** * Rules array cache key */ - const ACL_RULE_CACHE_KEY = 'authorization_rule_cached_data'; + public const ACL_RULE_CACHE_KEY = 'authorization_rule_cached_data'; + + /** + * Allow everything resource id + */ + private const ALLOW_EVERYTHING = 'Magento_Backend::all'; /** * @var ResourceConnection @@ -75,27 +81,74 @@ class Rule implements LoaderInterface /** * Populate ACL with rules from external storage * - * @param \Magento\Framework\Acl $acl + * @param Acl $acl * @return void */ - public function populateAcl(\Magento\Framework\Acl $acl) + public function populateAcl(Acl $acl) { + $result = $this->applyPermissionsAccordingToRules($acl); + $this->applyDenyPermissionsForMissingRules($acl, ...$result); + } + + /** + * Apply ACL with rules + * + * @param Acl $acl + * @return array[] + */ + private function applyPermissionsAccordingToRules(Acl $acl): array + { + $foundResources = $foundDeniedRoles = []; foreach ($this->getRulesArray() as $rule) { $role = $rule['role_id']; $resource = $rule['resource_id']; $privileges = !empty($rule['privileges']) ? explode(',', $rule['privileges']) : null; if ($acl->has($resource)) { + $foundResources[$resource] = $resource; if ($rule['permission'] == 'allow') { if ($resource === $this->_rootResource->getId()) { $acl->allow($role, null, $privileges); } $acl->allow($role, $resource, $privileges); } elseif ($rule['permission'] == 'deny') { + $foundDeniedRoles[$role] = $role; $acl->deny($role, $resource, $privileges); } } } + return [$foundResources, $foundDeniedRoles]; + } + + /** + * Apply deny permissions for missing rules + * + * For all rules that were not regenerated in authorization_rule table, + * when adding a new module and without re-saving all roles, + * consider not present rules with deny permissions + * + * @param Acl $acl + * @param array $resources + * @param array $deniedRoles + * @return void + */ + private function applyDenyPermissionsForMissingRules( + Acl $acl, + array $resources, + array $deniedRoles + ) { + if (count($resources) && count($deniedRoles) + //ignore denying missing permission if all are allowed + && !(count($resources) === 1 && isset($resources[static::ALLOW_EVERYTHING])) + ) { + foreach ($acl->getResources() as $resource) { + if (!isset($resources[$resource])) { + foreach ($deniedRoles as $role) { + $acl->deny($role, $resource, null); + } + } + } + } } /**