LaminasAclProvisioner   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 80
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 41
c 1
b 0
f 0
dl 0
loc 80
ccs 0
cts 37
cp 0
rs 10
wmc 11

5 Methods

Rating   Name   Duplication   Size   Complexity  
A provision() 0 27 2
A registerRules() 0 8 3
A resolveOperandValue() 0 6 2
A buildAssertions() 0 5 1
A buildAssertion() 0 15 3
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/security-interop project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\Security\Authorization;
10
11
use Auryn\Injector;
12
use Daikon\Boot\Service\ServiceDefinitionInterface;
13
use Daikon\Boot\Service\Provisioner\ProvisionerInterface;
14
use Daikon\Config\ConfigProviderInterface;
15
use Laminas\Permissions\Acl\Acl;
16
use Laminas\Permissions\Acl\Assertion\AssertionInterface;
17
use Laminas\Permissions\Acl\Assertion\ExpressionAssertion;
18
19
final class LaminasAclProvisioner implements ProvisionerInterface
20
{
21
    public function provision(
22
        Injector $injector,
23
        ConfigProviderInterface $configProvider,
24
        ServiceDefinitionInterface $serviceDefinition
25
    ): void {
26
        $className = $serviceDefinition->getServiceClass();
27
        $settings = $serviceDefinition->getSettings();
28
        $roles = $settings['roles'] ?? [];
29
        $resources = $settings['resources'] ?? [];
30
31
        $injector
32
            ->alias(AuthorizationServiceInterface::class, $className)
33
            ->share($className)
34
            ->delegate(
35
                $className,
36
                function () use ($className, $roles, $resources): AuthorizationServiceInterface {
37
                    $acl = new Acl;
38
                    array_map([$acl, 'addRole'], array_keys($roles), $roles);
39
                    array_map([$acl, 'addResource'], array_keys($resources));
40
                    foreach ($resources as $resource => $rules) {
41
                        $allows = $rules['allow'] ?? [];
42
                        $denies = $rules['deny'] ?? [];
43
                        //@todo support registration order for rule types
44
                        $this->registerRules($acl, Acl::TYPE_ALLOW, $allows, $roles, $resource);
45
                        $this->registerRules($acl, Acl::TYPE_DENY, $denies, $roles, $resource);
46
                    }
47
                    return new $className($acl);
48
                }
49
            );
50
    }
51
52
    private function registerRules(Acl &$acl, string $type, array $rules, array $roles, string $resource = null): void
53
    {
54
        foreach ($rules as $rule) {
55
            $ruleRoles = (array)($rule['roles'] ?? array_keys($roles));
56
            $assertions = (array)($rule['asserts'] ?? [null]);
57
            $privileges = $rule['privileges'] ?? null;
58
            foreach ($this->buildAssertions($assertions) as $assertion) {
59
                $acl->setRule(Acl::OP_ADD, $type, $ruleRoles, $resource, $privileges, $assertion);
60
            }
61
        }
62
    }
63
64
    private function buildAssertions(array $asserts): array
65
    {
66
        $assertions = [];
67
        array_push($assertions, ...array_map([$this, 'buildAssertion'], $asserts));
68
        return $assertions;
69
    }
70
71
    /** @param mixed $assert */
72
    private function buildAssertion($assert = null): ?AssertionInterface
73
    {
74
        $assertion = null;
75
        if (is_string($assert)) {
76
            /** @var AssertionInterface $assertion */
77
            $assertion = new $assert;
78
        } elseif (is_array($assert)) {
79
            /** @var AssertionInterface $assertion */
80
            $assertion = ExpressionAssertion::fromProperties(
81
                [ExpressionAssertion::OPERAND_CONTEXT_PROPERTY => $assert[0]],
82
                $assert[1],
83
                $this->resolveOperandValue($assert[2])
84
            );
85
        }
86
        return $assertion;
87
    }
88
89
    /**
90
     * @param mixed|array $operand
91
     * @return mixed
92
     */
93
    private function resolveOperandValue($operand)
94
    {
95
        if (is_callable($operand) === true) {
96
            return $operand();
97
        }
98
        return $operand;
99
    }
100
}
101