centerResolverDispatcher = $centerResolverDispatcher; $this->logger = $logger; $this->scopeResolverDispatcher = $scopeResolverDispatcher; $this->userACLAwareRepository = $userACLAwareRepository; $this->parentRoleHelper = $parentRoleHelper; } /** * 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 User $user * @param mixed $entity the entity may also implement HasScopeInterface * @param string|Role $attribute * @return boolean true if the user has access */ public function userHasAccess(User $user, $entity, $attribute) { $center = $this->centerResolverDispatcher->resolveCenter($entity); if (is_iterable($center)) { foreach ($center as $c) { if ($this->userHasAccessForCenter($user, $c, $entity, $attribute)) { return true; } } return false; } elseif ($center instanceof Center) { return $this->userHasAccessForCenter($user, $center, $entity, $attribute); } elseif (NULL === $center) { return false; } else { throw new \UnexpectedValueException("could not resolver a center"); } } 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)) { $scope = $this->scopeResolverDispatcher->resolveScope($entity); if (NULL === $scope) { return true; } if (is_iterable($scope)) { foreach ($scope as $s) { if ($s === $roleScope->getScope()) { return true; } } } else { if ($scope === $roleScope->getScope()) { return true; } } } else { return true; } } } } } $this->logger->debug("user can reach center entity, but not role", [ 'username' => $user->getUsername(), 'center' => $center->getName() ]); return false; } /** * Get reachable Centers for the given user, role, * and optionally Scope * * @return Center[]|array */ public function getReachableCenters(UserInterface $user, string $role, ?Scope $scope = null): array { if ($role instanceof Role) { $role = $role->getRole(); } $centers = array(); 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 ($scope === null) { $centers[] = $groupCenter->getCenter(); break 1; } if ($scope->getId() == $roleScope->getScope()->getId()){ $centers[] = $groupCenter->getCenter(); break 1; } } } } return $centers; } /** * 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|Center $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; } /** * Return all reachable scope for a given user, center and role * * @deprecated Use getReachableCircles * * @param Center|Center[] $center * @return Scope[]|array */ public function getReachableScopes(UserInterface $user, string $role, $center): array { if ($role instanceof Role) { $role = $role->getRole(); } return $this->getReachableCircles($user, $role, $center); } /** * Return all reachable circle for a given user, center and role * * @param string|Role $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; } /** * * @deprecated use UserACLAwareRepositoryInterface::findUsersByReachedACL instead * @param Center|Center[]|array $center * @param Scope|Scope[]|array|null $scope * @param bool $onlyActive true if get only active users * @return User[] */ public function findUsersReaching(string $role, $center, $scope = null, bool $onlyEnabled = true): array { return $this->userACLAwareRepository ->findUsersByReachedACL($role, $center, $scope, $onlyEnabled); } /** * 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 boolean true if the child role is granted by parent role */ private function isRoleReached(string $childRole, string $parentRole) { return $this->parentRoleHelper->isRoleReached($childRole, $parentRole); } /** * Return all the role which give access to the given role. Only the role * which are registered into Chill are taken into account. * * @param string $role * @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); } }