centerResolverManager = $centerResolverManager; $this->logger = $logger; $this->scopeResolverDispatcher = $scopeResolverDispatcher; $this->userACLAwareRepository = $userACLAwareRepository; $this->parentRoleHelper = $parentRoleHelper; } /** * Filter an array of centers, return only center which are reachable. * * @param User $user The user * @param array $centers a list of centers which are going to be filtered * @param string $role */ public function filterReachableCenters(User $user, array $centers, $role): array { $results = []; if ($role instanceof Role) { $role = $role->getRole(); } foreach ($centers as $center) { if ($this->userCanReachCenter($user, $center)) { $results[] = $center; } } return $results; } /** * @deprecated use UserACLAwareRepositoryInterface::findUsersByReachedACL instead * * @param array|Center|Center[] $center * @param array|Scope|Scope[]|null $scope * * @return User[] */ public function findUsersReaching(string $role, $center, $scope = null, bool $onlyEnabled = true): array { return $this->userACLAwareRepository ->findUsersByReachedACL($role, $center, $scope, $onlyEnabled); } /** * Return all the role which give access to the given role. Only the role * which are registered into Chill are taken into account. * * @return string[] the role which give access to the given $role */ public function getParentRoles(string $role): array { trigger_deprecation('Chill\MainBundle', '2.0', 'use ParentRoleHelper::getParentRoles instead'); return $this->parentRoleHelper->getParentRoles($role); } /** * Get reachable Centers for the given user, role, * and optionally Scope. * * @return list
*/ public function getReachableCenters(UserInterface $user, string $role, ?Scope $scope = null): array { if ($role instanceof Role) { $role = $role->getRole(); } /** @var array $centers */ $centers = []; foreach ($user->getGroupCenters() as $groupCenter) { $permissionGroup = $groupCenter->getPermissionsGroup(); //iterate on roleScopes foreach ($permissionGroup->getRoleScopes() as $roleScope) { //check that the role is in the reachable roles if ($this->isRoleReached($role, $roleScope->getRole())) { if (null === $scope) { $centers[spl_object_hash($groupCenter->getCenter())] = $groupCenter->getCenter(); break; } if ($scope->getId() === $roleScope->getScope()->getId()) { $centers[spl_object_hash($groupCenter->getCenter())] = $groupCenter->getCenter(); break; } } } } return array_values($centers); } /** * Return all reachable circle for a given user, center and role. * * @param Role|string $role * @param Center|Center[] $center * * @return Scope[] */ public function getReachableCircles(UserInterface $user, $role, $center) { $scopes = []; if (is_iterable($center)) { foreach ($center as $c) { $scopes = array_merge($scopes, $this->getReachableCircles($user, $role, $c)); } return $scopes; } if ($role instanceof Role) { $role = $role->getRole(); } foreach ($user->getGroupCenters() as $groupCenter) { if ($center->getId() === $groupCenter->getCenter()->getId()) { //iterate on permissionGroup $permissionGroup = $groupCenter->getPermissionsGroup(); //iterate on roleScopes foreach ($permissionGroup->getRoleScopes() as $roleScope) { //check that the role is in the reachable roles if ($this->isRoleReached($role, $roleScope->getRole())) { $scopes[] = $roleScope->getScope(); } } } } return $scopes; } /** * Return all reachable scope for a given user, center and role. * * @param Center|Center[] $center * * @return array|Scope[] */ public function getReachableScopes(UserInterface $user, string $role, Center|array $center): array { if ($role instanceof Role) { $role = $role->getRole(); } return $this->getReachableCircles($user, $role, $center); } /** * Determines if a user is active on this center. * * @param Center|Center[] $center May be an array of center */ public function userCanReachCenter(User $user, $center): bool { if ($center instanceof Traversable) { foreach ($center as $c) { if ($c->userCanReachCenter($user, $c)) { return true; } } return false; } if ($center instanceof Center) { foreach ($user->getGroupCenters() as $groupCenter) { if ($center->getId() === $groupCenter->getCenter()->getId()) { return true; } } return false; } throw new UnexpectedValueException( sprintf( 'The entity given is not an instance of %s, %s given', Center::class, get_class($center) ) ); } /** * Determines if the user has access to the given entity. * * if the entity implements Chill\MainBundle\Entity\HasScopeInterface, * the scope is taken into account. * * @param mixed $entity the entity may also implement HasScopeInterface * @param Role|string $attribute * * @return bool true if the user has access */ public function userHasAccess(User $user, $entity, $attribute) { $centers = $this->centerResolverManager->resolveCenters($entity); foreach ($centers as $c) { if ($this->userHasAccessForCenter($user, $c, $entity, $attribute)) { return true; } } return false; } /** * Test if a parent role may give access to a given child role. * * @param string $childRole The role we want to test if he is reachable * @param string $parentRole The role which should give access to $childRole * * @return bool true if the child role is granted by parent role */ private function isRoleReached(string $childRole, string $parentRole) { return $this->parentRoleHelper->isRoleReached($childRole, $parentRole); } private function userHasAccessForCenter(User $user, Center $center, $entity, $attribute): bool { if (!$this->userCanReachCenter($user, $center)) { $this->logger->debug('user cannot reach center of entity', [ 'center_name' => $center->getName(), 'user' => $user->getUsername(), ]); return false; } foreach ($user->getGroupCenters() as $groupCenter) { //filter on center if ($groupCenter->getCenter() === $center) { $permissionGroup = $groupCenter->getPermissionsGroup(); //iterate on roleScopes foreach ($permissionGroup->getRoleScopes() as $roleScope) { //check that the role allow to reach the required role if ($this->isRoleReached($attribute, $roleScope->getRole())) { //if yes, we have a right on something... // perform check on scope if necessary if ($this->scopeResolverDispatcher->isConcerned($entity)) {// here, we should also check that the role need a scope $scope = $this->scopeResolverDispatcher->resolveScope($entity); if (null === $scope) { return true; } if (is_iterable($scope)) { foreach ($scope as $s) { if ($roleScope->getScope() === $s) { return true; } } } else { if ($roleScope->getScope() === $scope) { return true; } } } else { return true; } } } } } $this->logger->debug('user can reach center entity, but not role', [ 'username' => $user->getUsername(), 'center' => $center->getName(), ]); return false; } }