Passed
Push — master ( a5c111...9b63e5 )
by Gabor
05:21
created

Acl::isAllowed()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 3
nop 3
crap 3
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 7.1
6
 *
7
 * @copyright 2012 - 2017 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
declare(strict_types = 1);
13
14
namespace WebHemi\Acl;
15
16
use WebHemi\Adapter\Acl\AclAdapterInterface;
17
use WebHemi\Data\Coupler\UserGroupToPolicyCoupler;
18
use WebHemi\Data\Coupler\UserToGroupCoupler;
19
use WebHemi\Data\Coupler\UserToPolicyCoupler;
20
use WebHemi\Data\Entity\AccessManagement\PolicyEntity;
21
use WebHemi\Data\Entity\AccessManagement\ResourceEntity;
22
use WebHemi\Data\Entity\ApplicationEntity;
23
use WebHemi\Data\Entity\User\UserEntity;
24
25
/**
26
 * Class Acl
27
 */
28
class Acl implements AclAdapterInterface
29
{
30
    /** @var UserToPolicyCoupler */
31
    private $userToPolicyCoupler;
32
    /** @var UserToGroupCoupler */
33
    private $userToGroupCoupler;
34
    /** @var UserGroupToPolicyCoupler */
35
    private $userGroupToPolicyCoupler;
36
37
    /**
38
     * Acl constructor.
39
     *
40
     * @param UserToPolicyCoupler $userToPolicyCoupler
41
     * @param UserToGroupCoupler $userToGroupCoupler
42
     * @param UserGroupToPolicyCoupler $userGroupToPolicyCoupler
43
     */
44 2
    public function __construct(
45
        UserToPolicyCoupler $userToPolicyCoupler,
46
        UserToGroupCoupler $userToGroupCoupler,
47
        UserGroupToPolicyCoupler $userGroupToPolicyCoupler
48
    ) {
49 2
        $this->userToPolicyCoupler = $userToPolicyCoupler;
50 2
        $this->userToGroupCoupler = $userToGroupCoupler;
51 2
        $this->userGroupToPolicyCoupler = $userGroupToPolicyCoupler;
52 2
    }
53
54
    /**
55
     * Checks if a User can access to a Resource in an Application
56
     *
57
     * @param UserEntity             $userEntity
58
     * @param ResourceEntity|null    $resourceEntity
59
     * @param ApplicationEntity|null $applicationEntity
60
     * @return bool
61
     */
62 1
    public function isAllowed(
63
        UserEntity $userEntity,
64
        ?ResourceEntity $resourceEntity = null,
65
        ?ApplicationEntity $applicationEntity = null
66
    ) : bool {
67
        // We assume the best case: the user has access
68 1
        $allowed = false;
69
70
        /** @var array<PolicyEntity> $policies */
71 1
        $policies = array_merge($this->getUserPolicies($userEntity), $this->getUserGroupPolicies($userEntity));
72
73 1
        foreach ($policies as $policyEntity) {
74 1
            $allowed = $allowed || $this->checkPolicy($policyEntity, $resourceEntity, $applicationEntity);
75
        }
76
77 1
        return $allowed;
78
    }
79
80
    /**
81
     * Gets the policies assigned to the user.
82
     *
83
     * @param UserEntity $userEntity
84
     * @return array<PolicyEntity>
85
     */
86 1
    private function getUserPolicies(UserEntity $userEntity) : array
87
    {
88
        /** @var array<PolicyEntity> $userPolicies */
89 1
        return $this->userToPolicyCoupler->getEntityDependencies($userEntity);
90
    }
91
92
    /**
93
     * Gets the policies assigned to the group in which the user is.
94
     *
95
     * @param UserEntity $userEntity
96
     * @return array<PolicyEntity>
97
     */
98 1
    private function getUserGroupPolicies(UserEntity $userEntity) : array
99
    {
100
        /** @var array<PolicyEntity> $userGroupPolicies */
101 1
        $userGroupPolicies = [];
102
        /** @var array<UserGroupEntity> $userGroups */
103 1
        $userGroups = $this->userToGroupCoupler->getEntityDependencies($userEntity);
104
105 1
        foreach ($userGroups as $userGroupEntity) {
106
            /** @var array<PolicyEntity> $groupPolicies */
107 1
            $groupPolicies = $this->userGroupToPolicyCoupler->getEntityDependencies($userGroupEntity);
108 1
            $userGroupPolicies = array_merge($userGroupPolicies, $groupPolicies);
109
        }
110
111 1
        return $userGroupPolicies;
112
    }
113
114
    /**
115
     * Check a concrete policy.
116
     *
117
     * The user has access when:
118
     *  - user/user's group has a policy that connected to the current application OR any application AND
119
     *  - user/user's group has a policy that connected to the current resource OR any resource
120
     *
121
     * @param PolicyEntity           $policyEntity
122
     * @param ResourceEntity|null    $resourceEntity
123
     * @param ApplicationEntity|null $applicationEntity
124
     * @return bool
125
     */
126 1
    private function checkPolicy(
127
        PolicyEntity $policyEntity,
128
        ?ResourceEntity $resourceEntity = null,
129
        ?ApplicationEntity $applicationEntity = null
130
    ) : bool {
131 1
        $policyResourceId = $policyEntity->getResourceId();
132 1
        $policyApplicationId = $policyEntity->getApplicationId();
133
134 1
        $resourceId = $resourceEntity ? $resourceEntity->getResourceId() : null;
135 1
        $applicationId = $applicationEntity ? $applicationEntity->getApplicationId() : null;
136
137 1
        $allowResurce = is_null($policyResourceId) || $policyResourceId === $resourceId;
138 1
        $allowApplication = is_null($policyApplicationId) || $policyApplicationId === $applicationId;
139
140 1
        if ($allowResurce && $allowApplication) {
141 1
            return $policyEntity->getAllowed();
142
        }
143
144 1
        return false;
145
    }
146
}
147