Skip to content

Commit

Permalink
Fix EZP-24955: Dynamically inject limitation map into RoleService
Browse files Browse the repository at this point in the history
> https://jira.ez.no/browse/EZP-24955

This PR just injects policies that are being provided by policy providers into the Repository.
Tests have been updated accordingly.
  • Loading branch information
lolautruche committed Oct 13, 2015
1 parent acf8d12 commit 6a49656
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 23 deletions.
2 changes: 2 additions & 0 deletions doc/bc/changes-6.0.md
Expand Up @@ -171,6 +171,8 @@ Changes affecting version compatibility with former or future versions.
whole User object. User API abstract object has been changed to implement this so there is no BC
break for API use, only for custom API implementations.
Also new `getCurrentUserReference()` method has been added on Repository to get this object.

* Internal `limitationMap` repository service setting (for `RoleService`) has been renamed to `policyMap`.

## Deprecations

Expand Down
Expand Up @@ -21,7 +21,26 @@ A `PolicyProvider` is an object providing a hash containing declared modules, fu
* Each module can provide *functions* (e.g. "content/read": "content" is the module, "read" is the function)
* Each function can provide a collection of limitations.

Limitations need to be implemented as *limitation types* and declared as services identified with `ezpublish.limitationType` tag.
Policies configuration hash contains declared these modules, functions and limitations.
First level key is the module name, value is a hash of available functions, with function name as key.
Function value is an array of available limitations, identified by the alias declared in LimitationType service tag.
If no limitation is provided, value can be null or an empty array.

```php
[
"content" => [
"read" => ["Class", "ParentClass", "Node", "Language"],
"edit" => ["Class", "ParentClass", "Language"]
],
"custom_module" => [
"custom_function_1" => null,
"custom_function_2" => ["CustomLimitation"]
],
]
```

> Limitations need to be implemented as *limitation types* and declared as services identified with `ezpublish.limitationType` tag.
> Name provided in the hash for each limitation is the same value set in `alias` attribute in the service tag.
### Example

Expand Down
10 changes: 9 additions & 1 deletion eZ/Bundle/EzPublishCoreBundle/ApiLoader/RepositoryFactory.php
Expand Up @@ -46,14 +46,21 @@ class RepositoryFactory extends ContainerAware
*/
protected $roleLimitations = array();

/**
* @var array
*/
private $policyMap;

public function __construct(
ConfigResolverInterface $configResolver,
FieldTypeCollectionFactory $fieldTypeCollectionFactory,
$repositoryClass
$repositoryClass,
array $policyMap
) {
$this->configResolver = $configResolver;
$this->fieldTypeCollectionFactory = $fieldTypeCollectionFactory;
$this->repositoryClass = $repositoryClass;
$this->policyMap = $policyMap;
}

/**
Expand All @@ -76,6 +83,7 @@ public function buildRepository(PersistenceHandler $persistenceHandler, SearchHa
'fieldType' => $this->fieldTypeCollectionFactory->getFieldTypes(),
'role' => array(
'limitationTypes' => $this->roleLimitations,
'policyMap' => $this->policyMap,
),
'languages' => $this->configResolver->getParameter('languages'),
),
Expand Down
Expand Up @@ -16,13 +16,22 @@ class PoliciesConfigBuilder extends ContainerConfigBuilder
public function addConfig(array $config)
{
$policyMap = [];
$previousPolicyMap = [];

// We receive limitations as values, but we want them as keys to be used by isset().
foreach ($config as $module => $functionArray) {
foreach ($functionArray as $function => $limitationCollection) {
$policyMap[$module][$function] = array_fill_keys((array)$limitationCollection, true);
}
}

if ($this->containerBuilder->hasParameter('ezpublish.api.role.policy_map')) {
$policyMap = $this->containerBuilder->getParameter('ezpublish.api.role.policy_map');
$previousPolicyMap = $this->containerBuilder->getParameter('ezpublish.api.role.policy_map');
}

$this->containerBuilder->setParameter(
'ezpublish.api.role.policy_map',
array_merge_recursive($policyMap, $config)
array_merge_recursive($previousPolicyMap, $policyMap)
);
}

Expand Down
1 change: 1 addition & 0 deletions eZ/Bundle/EzPublishCoreBundle/Resources/config/papi.yml
Expand Up @@ -26,6 +26,7 @@ services:
- @ezpublish.config.resolver
- @ezpublish.field_type_collection.factory
- %ezpublish.api.inner_repository.class%
- %ezpublish.api.role.policy_map%
calls:
- [setContainer, [@service_container]]

Expand Down
Expand Up @@ -620,17 +620,17 @@ public function testRegisteredPolicies()

$expectedPolicies = [
'custom_module' => [
'custom_function_1' => null,
'custom_function_2' => ['CustomLimitation'],
'custom_function_1' => [],
'custom_function_2' => ['CustomLimitation' => true],
],
'helloworld' => [
'foo' => ['bar', 'additional_limitation'],
'baz' => null,
'some' => ['thingy', 'thing', 'but', 'wait'],
'foo' => ['bar' => true, 'additional_limitation' => true],
'baz' => [],
'some' => ['thingy' => true, 'thing' => true, 'but' => true, 'wait' => true],
],
'custom_module2' => [
'custom_function_3' => null,
'custom_function_4' => ['CustomLimitation2', 'CustomLimitation3'],
'custom_function_3' => [],
'custom_function_4' => ['CustomLimitation2' => true, 'CustomLimitation3' => true],
],
];

Expand Down
Expand Up @@ -23,8 +23,8 @@ public function testAddConfig()
$config1 = ['foo' => ['bar' => null]];
$config2 = ['some' => ['thing' => ['limitation']]];
$expected = [
'foo' => ['bar' => null],
'some' => ['thing' => ['limitation']],
'foo' => ['bar' => []],
'some' => ['thing' => ['limitation' => true]],
];
$configBuilder->addConfig($config1);
$configBuilder->addConfig($config2);
Expand Down
2 changes: 1 addition & 1 deletion eZ/Publish/Core/Repository/Repository.php
Expand Up @@ -524,7 +524,7 @@ public function canUser($module, $function, ValueObject $object, $targets = null
* For policy limitation atm only support ACCESS_GRANTED
*
* Reasoning: Right now, use of a policy limitation not valid for a policy is per definition a
* BadState. To reach this you would have to configure the "limitationMap" wrongly, like using
* BadState. To reach this you would have to configure the "policyMap" wrongly, like using
* Node (Location) limitation on state/assign. So in this case Role Limitations will return
* ACCESS_ABSTAIN (== no access here), and other limitations will throw InvalidArgument above,
* both cases forcing dev to investigate to find miss configuration. This might be relaxed in
Expand Down
11 changes: 5 additions & 6 deletions eZ/Publish/Core/Repository/RoleService.php
Expand Up @@ -95,8 +95,7 @@ public function __construct(
$this->roleDomainMapper = $roleDomainMapper;
// Union makes sure default settings are ignored if provided in argument
$this->settings = $settings + array(
'limitationMap' => array(
// @todo Inject these dynamically by activated eZ Controllers, see PR #252
'policyMap' => array(
'content' => array(
'read' => array('Class' => true, 'Section' => true, 'Owner' => true, 'Group' => true, 'Node' => true, 'Subtree' => true, 'State' => true),
'diff' => array('Class' => true, 'Section' => true, 'Owner' => true, 'Node' => true, 'Subtree' => true),
Expand Down Expand Up @@ -1253,19 +1252,19 @@ public function getLimitationType($identifier)
*/
public function getLimitationTypesByModuleFunction($module, $function)
{
if (empty($this->settings['limitationMap'][$module][$function])) {
if (empty($this->settings['policyMap'][$module][$function])) {
return array();
}

$types = array();
try {
foreach (array_keys($this->settings['limitationMap'][$module][$function]) as $identifier) {
foreach (array_keys($this->settings['policyMap'][$module][$function]) as $identifier) {
$types[$identifier] = $this->limitationService->getLimitationType($identifier);
}
} catch (LimitationNotFoundException $e) {
throw new BadStateException(
"{$module}/{$function}",
"limitationMap configuration is referring to non existing identifier: {$identifier}",
"policyMap configuration is referring to non existing identifier: {$identifier}",
$e
);
}
Expand Down Expand Up @@ -1324,7 +1323,7 @@ protected function validatePolicy($module, $function, array $limitations)
);
}

if (!isset($this->settings['limitationMap'][$module][$function][$limitation->getIdentifier()])) {
if (!isset($this->settings['policyMap'][$module][$function][$limitation->getIdentifier()])) {
throw new InvalidArgumentException(
'policy',
"The limitation '{$limitation->getIdentifier()}' is not applicable on '{$module}/{$function}'"
Expand Down
6 changes: 3 additions & 3 deletions eZ/Publish/Core/Repository/Tests/Service/Mock/RoleTest.php
Expand Up @@ -47,7 +47,7 @@ public function testCreateRoleThrowsLimitationValidationException()
->will($this->returnValue(array(42)));

$settings = array(
'limitationMap' => array('mockModule' => array('mockFunction' => array('mockIdentifier' => true))),
'policyMap' => array('mockModule' => array('mockFunction' => array('mockIdentifier' => true))),
'limitationTypes' => array('mockIdentifier' => $limitationTypeMock),
);

Expand Down Expand Up @@ -114,7 +114,7 @@ public function testAddPolicyThrowsLimitationValidationException()
->will($this->returnValue('mockIdentifier'));

$settings = array(
'limitationMap' => array('mockModule' => array('mockFunction' => array('mockIdentifier' => true))),
'policyMap' => array('mockModule' => array('mockFunction' => array('mockIdentifier' => true))),
'limitationTypes' => array('mockIdentifier' => $limitationTypeMock),
);

Expand Down Expand Up @@ -180,7 +180,7 @@ public function testUpdatePolicyThrowsLimitationValidationException()
->will($this->returnValue('mockIdentifier'));

$settings = array(
'limitationMap' => array('mockModule' => array('mockFunction' => array('mockIdentifier' => true))),
'policyMap' => array('mockModule' => array('mockFunction' => array('mockIdentifier' => true))),
'limitationTypes' => array('mockIdentifier' => $limitationTypeMock),
);

Expand Down

0 comments on commit 6a49656

Please sign in to comment.