diff --git a/src/Authorization/AbstractAuthorizationService.php b/src/Authorization/AbstractAuthorizationService.php index 4944f0ad5ca24379aab25f60d60443b2d1dc1562..20dec23e44ca6c45c65eeca0b6bab3249dbfe497 100644 --- a/src/Authorization/AbstractAuthorizationService.php +++ b/src/Authorization/AbstractAuthorizationService.php @@ -6,9 +6,6 @@ namespace Dbp\Relay\CoreBundle\Authorization; use Dbp\Relay\CoreBundle\API\UserSessionInterface; use Dbp\Relay\CoreBundle\Exception\ApiError; -use Dbp\Relay\CoreBundle\Helpers\Tools; -use Symfony\Component\Config\Definition\Builder\NodeDefinition; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; @@ -18,21 +15,7 @@ abstract class AbstractAuthorizationService implements ContextAwareNormalizerInt { use NormalizerAwareTrait; - /* config array keys */ - private const AUTHORIZATION_ROOT_CONFIG_NODE = 'authorization'; - private const ROLES_CONFIG_NODE = 'roles'; - private const ATTRIBUTES_CONFIG_NODE = 'attributes'; - private const ENTITIES_CONFIG_NODE = 'entities'; - private const ENTITY_READ_ACCESS_CONFIG_NODE = 'read_access'; - private const ENTITY_WRITE_ACCESS_CONFIG_NODE = 'write_access'; - private const ENTITY_CLASS_NAME_CONFIG_NODE = 'class_name'; - /* internal array keys */ - private const ROLES_KEY = 'roles'; - private const ATTRIBUTES_KEY = 'attributes'; - private const ENTITIES_KEY = 'entities'; - private const ENTITY_READ_ACCESS_KEY = 'read_access'; - private const ENTITY_WRITE_ACCESS_KEY = 'write_access'; private const ENTITY_SHORT_NAME_KEY = 'short_name'; private const ENTITY_CLASS_NAME_KEY = 'class_name'; @@ -69,15 +52,15 @@ abstract class AbstractAuthorizationService implements ContextAwareNormalizerInt public function setConfig(array $config) { - $this->config = $config[self::AUTHORIZATION_ROOT_CONFIG_NODE] ?? []; + $this->config = $config[AuthorizationConfigDefinition::AUTHORIZATION_CONFIG_NODE] ?? []; $this->loadConfig(); } public function configure(array $roleMapping = [], array $attributeMapping = []): void { $this->config = [ - self::ROLES_CONFIG_NODE => $roleMapping, - self::ATTRIBUTES_CONFIG_NODE => $attributeMapping, + AuthorizationConfigDefinition::ROLES_CONFIG_NODE => $roleMapping, + AuthorizationConfigDefinition::ATTRIBUTES_CONFIG_NODE => $attributeMapping, ]; $this->loadConfig(); } @@ -155,11 +138,11 @@ abstract class AbstractAuthorizationService implements ContextAwareNormalizerInt private function loadConfig() { if ($this->userAuthorizationChecker !== null && $this->config !== null) { - $roleExpressions = $this->config[self::ROLES_CONFIG_NODE] ?? []; - $attributeExpressions = $this->config[self::ATTRIBUTES_CONFIG_NODE] ?? []; + $roleExpressions = $this->config[AuthorizationConfigDefinition::ROLES_CONFIG_NODE] ?? []; + $attributeExpressions = $this->config[AuthorizationConfigDefinition::ATTRIBUTES_CONFIG_NODE] ?? []; - if (isset($this->config[self::ENTITIES_CONFIG_NODE])) { - $entitiesRoleExpressions = $this->loadEntityConfig($this->config[self::ENTITIES_CONFIG_NODE]); + if (isset($this->config[AuthorizationConfigDefinition::ENTITIES_CONFIG_NODE])) { + $entitiesRoleExpressions = $this->loadEntityConfig($this->config[AuthorizationConfigDefinition::ENTITIES_CONFIG_NODE]); $roleExpressions = array_merge($roleExpressions, $entitiesRoleExpressions); } @@ -171,9 +154,9 @@ abstract class AbstractAuthorizationService implements ContextAwareNormalizerInt { $roleExpressions = []; foreach ($entitiesConfigNode as $entityShortName => $entityNode) { - $entityClassName = $entityNode[self::ENTITY_CLASS_NAME_CONFIG_NODE]; + $entityClassName = $entityNode[AuthorizationConfigDefinition::ENTITY_CLASS_NAME_CONFIG_NODE]; $attributeNames = []; - foreach ($entityNode[self::ENTITY_READ_ACCESS_CONFIG_NODE] ?? [] as $attributeName => $attributeAuthorizationExpression) { + foreach ($entityNode[AuthorizationConfigDefinition::ENTITY_READ_ACCESS_CONFIG_NODE] ?? [] as $attributeName => $attributeAuthorizationExpression) { $roleExpressions[self::toAttributeId($entityShortName, $attributeName)] = $attributeAuthorizationExpression; $attributeNames[] = $attributeName; } @@ -199,95 +182,6 @@ abstract class AbstractAuthorizationService implements ContextAwareNormalizerInt return $this->userAuthorizationChecker->isGranted($this->currentAuthorizationUser, $rightName, $object, $objectAlias); } - /** - * Create the 'authorization' config node definition with the given config definition. - */ - public static function getAuthorizationConfigNodeDefinition(array $configDefinition): NodeDefinition - { - $treeBuilder = new TreeBuilder(self::AUTHORIZATION_ROOT_CONFIG_NODE); - - $rightsNodeChildBuilder = $treeBuilder->getRootNode()->children()->arrayNode(self::ROLES_CONFIG_NODE) - ->addDefaultsIfNotSet() - ->children(); - foreach ($configDefinition[self::ROLES_KEY] ?? [] as $roleDefinition) { - $rightsNodeChildBuilder->scalarNode($roleDefinition[0]) - ->defaultValue($roleDefinition[1] ?? 'false') - ->info($roleDefinition[2] ?? '') - ->end(); - } - - $attributesNodeChildBuilder = $treeBuilder->getRootNode()->children()->arrayNode(self::ATTRIBUTES_CONFIG_NODE) - ->addDefaultsIfNotSet() - ->children(); - foreach ($configDefinition[self::ATTRIBUTES_KEY] ?? [] as $attributeDefinition) { - $attributesNodeChildBuilder->scalarNode($attributeDefinition[0]) - ->defaultValue($attributeDefinition[1] ?? 'null') - ->info($attributeDefinition[2] ?? '') - ->end(); - } - - $entitiesNodeChildBuilder = $treeBuilder->getRootNode()->children()->arrayNode(self::ENTITIES_CONFIG_NODE) - ->children(); - foreach ($configDefinition[self::ENTITIES_KEY] ?? [] as $entityDefinition) { - $entityChildBuilder = $entitiesNodeChildBuilder->arrayNode($entityDefinition[self::ENTITY_SHORT_NAME_KEY]) - ->children(); - $entityChildBuilder->scalarNode(self::ENTITY_CLASS_NAME_CONFIG_NODE) - ->defaultValue($entityDefinition[self::ENTITY_CLASS_NAME_KEY]) - ->info('The entity class name. There is no need to change the default value.') - ->end(); - $entityReadAccessChildBuilder = $entityChildBuilder->arrayNode(self::ENTITY_READ_ACCESS_CONFIG_NODE) - ->children(); - foreach ($entityDefinition[self::ENTITY_READ_ACCESS_KEY] ?? [] as $attributeName) { - $entityReadAccessChildBuilder->scalarNode($attributeName) - ->defaultValue('false') - ->info(sprintf('The conditional reader role expression for attribute \'%s\'.', $attributeName)) - ->end(); - } - - $entityWriteAccessChildBuilder = $entitiesNodeChildBuilder->arrayNode(self::ENTITY_WRITE_ACCESS_CONFIG_NODE) - ->children(); - foreach ($entityDefinition[self::ENTITY_WRITE_ACCESS_KEY] ?? [] as $attributeName) { - $entityWriteAccessChildBuilder->scalarNode($attributeName) - ->defaultValue('false') - ->info(sprintf('The conditional writer role expression for attribute \'%s\'.', $attributeName)) - ->end(); - } - } - - return $treeBuilder->getRootNode(); - } - - public static function configDefinitionCreate(): array - { - return []; - } - - public static function configDefinitionAddRole(array &$configDefinition, string $roleName, string $defaultExpression = 'false', string $info = ''): array - { - Tools::pushToSubarray($configDefinition, self::ROLES_KEY, [$roleName, $defaultExpression, $info]); - - return $configDefinition; - } - - public static function configDefinitionAddAttribute(array &$configDefinition, string $attributeName, string $defaultExpression = 'false', string $info = ''): array - { - Tools::pushToSubarray($configDefinition, self::ATTRIBUTES_KEY, [$attributeName, $defaultExpression, $info]); - - return $configDefinition; - } - - public static function configDefinitionAddEntity(array &$configDefinition, string $entityShortName, string $entityClassName, array $readAttributes = [], array $writeAttributes = []): array - { - Tools::pushToSubarray($configDefinition, self::ENTITIES_KEY, [ - self::ENTITY_SHORT_NAME_KEY => $entityShortName, - self::ENTITY_CLASS_NAME_KEY => $entityClassName, - self::ENTITY_READ_ACCESS_KEY => $readAttributes, - self::ENTITY_WRITE_ACCESS_KEY => $writeAttributes, - ]); - - return $configDefinition; - } - private static function toAttributeId(string $entityShortName, string $attributeName): string { return $entityShortName.':'.$attributeName; diff --git a/src/Authorization/AuthorizationConfigDefinition.php b/src/Authorization/AuthorizationConfigDefinition.php new file mode 100644 index 0000000000000000000000000000000000000000..25599e466d33e8db306acb888a34c2008466449c --- /dev/null +++ b/src/Authorization/AuthorizationConfigDefinition.php @@ -0,0 +1,123 @@ +<?php + +declare(strict_types=1); + +namespace Dbp\Relay\CoreBundle\Authorization; + +use Dbp\Relay\CoreBundle\Helpers\Tools; +use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\Config\Definition\Builder\TreeBuilder; + +class AuthorizationConfigDefinition +{ + /* config array keys */ + public const AUTHORIZATION_CONFIG_NODE = 'authorization'; + public const ROLES_CONFIG_NODE = 'roles'; + public const ATTRIBUTES_CONFIG_NODE = 'attributes'; + public const ENTITIES_CONFIG_NODE = 'entities'; + public const ENTITY_READ_ACCESS_CONFIG_NODE = 'read_access'; + public const ENTITY_WRITE_ACCESS_CONFIG_NODE = 'write_access'; + public const ENTITY_CLASS_NAME_CONFIG_NODE = 'class_name'; + + private const ROLES_KEY = 'roles'; + private const ATTRIBUTES_KEY = 'attributes'; + private const ENTITIES_KEY = 'entities'; + private const ENTITY_READ_ACCESS_KEY = 'read_access'; + private const ENTITY_WRITE_ACCESS_KEY = 'write_access'; + private const ENTITY_SHORT_NAME_KEY = 'short_name'; + private const ENTITY_CLASS_NAME_KEY = 'class_name'; + + /** @var array */ + private $configDefinition; + + public static function create(): AuthorizationConfigDefinition + { + return new AuthorizationConfigDefinition(); + } + + public function __construct() + { + $this->configDefinition = []; + } + + public function addRole(string $roleName, string $defaultExpression = 'false', string $info = ''): AuthorizationConfigDefinition + { + Tools::pushToSubarray($this->configDefinition, self::ROLES_KEY, [$roleName, $defaultExpression, $info]); + + return $this; + } + + public function addAttribute(string $attributeName, string $defaultExpression = 'false', string $info = ''): AuthorizationConfigDefinition + { + Tools::pushToSubarray($this->configDefinition, self::ATTRIBUTES_KEY, [$attributeName, $defaultExpression, $info]); + + return $this; + } + + public function addEntity(string $entityShortName, string $entityClassName, array $readAttributes = [], array $writeAttributes = []): AuthorizationConfigDefinition + { + Tools::pushToSubarray($this->configDefinition, self::ENTITIES_KEY, [ + self::ENTITY_SHORT_NAME_KEY => $entityShortName, + self::ENTITY_CLASS_NAME_KEY => $entityClassName, + self::ENTITY_READ_ACCESS_KEY => $readAttributes, + self::ENTITY_WRITE_ACCESS_KEY => $writeAttributes, + ]); + + return $this; + } + + public function getNodeDefinition(): NodeDefinition + { + $treeBuilder = new TreeBuilder(self::AUTHORIZATION_CONFIG_NODE); + + $rightsNodeChildBuilder = $treeBuilder->getRootNode()->children()->arrayNode(self::ROLES_CONFIG_NODE) + ->addDefaultsIfNotSet() + ->children(); + foreach ($this->configDefinition[self::ROLES_KEY] ?? [] as $roleDefinition) { + $rightsNodeChildBuilder->scalarNode($roleDefinition[0]) + ->defaultValue($roleDefinition[1] ?? 'false') + ->info($roleDefinition[2] ?? '') + ->end(); + } + + $attributesNodeChildBuilder = $treeBuilder->getRootNode()->children()->arrayNode(self::ATTRIBUTES_CONFIG_NODE) + ->addDefaultsIfNotSet() + ->children(); + foreach ($this->configDefinition[self::ATTRIBUTES_KEY] ?? [] as $attributeDefinition) { + $attributesNodeChildBuilder->scalarNode($attributeDefinition[0]) + ->defaultValue($attributeDefinition[1] ?? 'null') + ->info($attributeDefinition[2] ?? '') + ->end(); + } + + $entitiesNodeChildBuilder = $treeBuilder->getRootNode()->children()->arrayNode(self::ENTITIES_CONFIG_NODE) + ->children(); + foreach ($this->configDefinition[self::ENTITIES_KEY] ?? [] as $entityDefinition) { + $entityChildBuilder = $entitiesNodeChildBuilder->arrayNode($entityDefinition[self::ENTITY_SHORT_NAME_KEY]) + ->children(); + $entityChildBuilder->scalarNode(self::ENTITY_CLASS_NAME_CONFIG_NODE) + ->defaultValue($entityDefinition[self::ENTITY_CLASS_NAME_KEY]) + ->info('The entity class name. There is no need to change the default value.') + ->end(); + $entityReadAccessChildBuilder = $entityChildBuilder->arrayNode(self::ENTITY_READ_ACCESS_CONFIG_NODE) + ->children(); + foreach ($entityDefinition[self::ENTITY_READ_ACCESS_KEY] ?? [] as $attributeName) { + $entityReadAccessChildBuilder->scalarNode($attributeName) + ->defaultValue('false') + ->info(sprintf('The conditional reader role expression for attribute \'%s\'.', $attributeName)) + ->end(); + } + + $entityWriteAccessChildBuilder = $entitiesNodeChildBuilder->arrayNode(self::ENTITY_WRITE_ACCESS_CONFIG_NODE) + ->children(); + foreach ($entityDefinition[self::ENTITY_WRITE_ACCESS_KEY] ?? [] as $attributeName) { + $entityWriteAccessChildBuilder->scalarNode($attributeName) + ->defaultValue('false') + ->info(sprintf('The conditional writer role expression for attribute \'%s\'.', $attributeName)) + ->end(); + } + } + + return $treeBuilder->getRootNode(); + } +}