/** * {@inheritdoc} */ public function search($query, $page, $perPage, $searchById = false) { list($search, $entityClass, $permission, $entityId, $excludeCurrentUser) = explode(';', $query); $entityClass = str_replace('_', '\\', $entityClass); if ($entityId) { $object = $this->em->getRepository($entityClass)->find((int) $entityId); } else { $object = 'entity:' . $entityClass; } $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $isGranted = $this->getSecurityContext()->isGranted($permission, $object); if ($isGranted) { $results = []; if ($searchById) { $results[] = $this->em->getRepository('OroUserBundle:User')->find((int) $query); } else { $user = $this->getSecurityContext()->getToken()->getUser(); $organization = $this->getSecurityContext()->getToken()->getOrganizationContext(); $queryBuilder = $this->getSearchQueryBuilder($search); if ((bool) $excludeCurrentUser) { $this->excludeUser($queryBuilder, $user); } $this->addAcl($queryBuilder, $observer->getAccessLevel(), $user, $organization); $results = $queryBuilder->getQuery()->getResult(); } $resultsData = []; foreach ($results as $user) { $resultsData[] = $this->convertItem($user); } } else { $resultsData = []; } return ['results' => $resultsData, 'more' => false]; }
/** * @param BuildBefore $event */ public function onBuildBefore(BuildBefore $event) { $config = $event->getConfig(); $object = 'entity:Oro\\Bundle\\OrganizationBundle\\Entity\\BusinessUnit'; $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $this->getSecurityContext()->isGranted('VIEW', $object); $user = $this->getSecurityContext()->getToken()->getUser(); $organization = $this->getSecurityContext()->getToken()->getOrganizationContext(); $accessLevel = $observer->getAccessLevel(); $where = $config->offsetGetByPath('[source][query][where][and]', []); if ($accessLevel == AccessLevel::GLOBAL_LEVEL) { $leftJoins = $config->offsetGetByPath('[source][query][join][inner]', []); $leftJoins[] = ['join' => 'u.organization', 'alias' => 'org']; $config->offsetSetByPath('[source][query][join][inner]', $leftJoins); $where = array_merge($where, ['org.id in (' . $organization->getId() . ')']); } elseif ($accessLevel !== AccessLevel::SYSTEM_LEVEL) { $resultBuIds = []; if ($accessLevel == AccessLevel::LOCAL_LEVEL) { $resultBuIds = $this->treeProvider->getTree()->getUserBusinessUnitIds($user->getId(), $organization->getId()); } elseif ($accessLevel == AccessLevel::DEEP_LEVEL) { $resultBuIds = $this->treeProvider->getTree()->getUserSubordinateBusinessUnitIds($user->getId(), $organization->getId()); } if (count($resultBuIds)) { $where = array_merge($where, ['u.id in (' . implode(', ', $resultBuIds) . ')']); } else { // There are no records to show, make query to return empty result $where = array_merge($where, ['1 = 0']); } } if (count($where)) { $config->offsetSetByPath('[source][query][where][and]', $where); } }
/** * Get data for query acl access level check * Return null if entity has full access, empty array if user does't have access to the entity * and array with entity field and field values witch user have access. * * @param $entityClassName * @param $permissions * @return null|array */ public function getAclConditionData($entityClassName, $permissions = 'VIEW') { if ($this->aclVoter === null || !$this->getUserId() || !$this->entityMetadataProvider->isProtectedEntity($entityClassName)) { return []; } $condition = null; $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $isGranted = $this->getSecurityContext()->isGranted($permissions, 'entity:' . $entityClassName); if ($isGranted) { $condition = $this->buildConstraintIfAccessIsGranted($entityClassName, $observer->getAccessLevel(), $this->metadataProvider->getMetadata($entityClassName)); } return $condition; }
/** * Check is granting user to object in given permission * * @param string $permission * @param object|string $object */ protected function checkIsGranted($permission, $object) { $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $this->isAssignGranted = $this->securityFacade->isGranted($permission, $object); $this->accessLevel = $observer->getAccessLevel(); }
/** * Get ACL sql conditions and join statements to check shared records * * @param string $entityName * @param string $entityAlias * @param mixed $permissions * * @return array */ public function getAclShareData($entityName, $entityAlias, $permissions = BasicPermissionMap::PERMISSION_VIEW) { if ($permissions !== BasicPermissionMap::PERMISSION_VIEW) { return null; } $aclClass = $this->getObjectManager()->getRepository('OroSecurityBundle:AclClass')->findOneBy(['classType' => $entityName]); if (!$aclClass) { return null; } $shareConfig = null; if ($this->configProvider->hasConfig($entityName)) { $shareConfig = $this->configProvider->getConfig($entityName)->get('share_scopes'); } if (!$shareConfig) { return null; } $aclSIds = $this->getSecurityIdentityIds((array) $shareConfig); if (empty($aclSIds)) { return null; } $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $isGranted = $this->getSecurityContext()->isGranted($permissions, 'entity:' . $entityName); if (!$isGranted || !in_array($observer->getAccessLevel(), $this->shareAccessLevels)) { return null; } $shareCondition = ['existsSubselect' => ['select' => 1, 'from' => ['schemaName' => self::ACL_ENTRIES_SCHEMA_NAME, 'alias' => self::ACL_ENTRIES_ALIAS], 'where' => $this->getShareSubselectWhereConditions($entityAlias, $aclSIds, $aclClass)], 'not' => false]; //Add query components for OutputSqlWalker $queryComponents[self::ACL_ENTRIES_ALIAS] = ['metadata' => $this->getObjectManager()->getClassMetadata(self::ACL_ENTRIES_SCHEMA_NAME), 'parent' => null, 'relation' => null, 'map' => null, 'nestingLevel' => null, 'token' => null]; return [$shareCondition, $queryComponents]; }
/** * @param BuildBefore $event */ public function onBuildBefore(BuildBefore $event) { $config = $event->getConfig(); $parameters = $event->getDatagrid()->getParameters(); $permission = $parameters->get('permission'); $entityClass = str_replace('_', '\\', $parameters->get('entity')); $entityId = $parameters->get('entity_id'); if ($entityId) { $object = $this->em->getRepository($entityClass)->find((int) $entityId); } else { $object = 'entity:' . $entityClass; } $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $this->getSecurityContext()->isGranted($permission, $object); $user = $this->getSecurityContext()->getToken()->getUser(); $organization = $this->getSecurityContext()->getToken()->getOrganizationContext(); $accessLevel = $observer->getAccessLevel(); $where = $config->offsetGetByPath('[source][query][where][and]', []); /** todo: refactor this check usages */ if ($accessLevel == AccessLevel::BASIC_LEVEL) { $where = array_merge($where, ['u.id = ' . $user->getId()]); } elseif ($accessLevel == AccessLevel::GLOBAL_LEVEL) { $leftJoins = $config->offsetGetByPath('[source][query][join][inner]', []); $leftJoins[] = ['join' => 'u.organizations', 'alias' => 'org']; $config->offsetSetByPath('[source][query][join][inner]', $leftJoins); $where = array_merge($where, ['org.id in (' . $organization->getId() . ')']); } elseif ($accessLevel !== AccessLevel::SYSTEM_LEVEL) { $resultBuIds = []; if ($accessLevel == AccessLevel::LOCAL_LEVEL) { $resultBuIds = $this->treeProvider->getTree()->getUserBusinessUnitIds($user->getId(), $organization->getId()); } elseif ($accessLevel == AccessLevel::DEEP_LEVEL) { $resultBuIds = $this->treeProvider->getTree()->getUserSubordinateBusinessUnitIds($user->getId(), $organization->getId()); } $leftJoins = $config->offsetGetByPath('[source][query][join][inner]', []); $leftJoins[] = ['join' => 'u.businessUnits', 'alias' => 'bu']; $config->offsetSetByPath('[source][query][join][inner]', $leftJoins); $where = array_merge($where, ['bu.id in (' . implode(', ', $resultBuIds) . ')']); } if (count($where)) { $config->offsetSetByPath('[source][query][where][and]', $where); } }
/** * {@inheritdoc} * * @SuppressWarnings(PHPMD.NPathComplexity) */ public function search($query, $page, $perPage, $searchById = false) { list($search, $entityClass, $permission, $entityId, $excludeCurrentUser) = explode(';', $query); $entityClass = $this->decodeClassName($entityClass); $hasMore = false; $object = $entityId ? $this->em->getRepository($entityClass)->find((int) $entityId) : 'entity:' . $entityClass; $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); if ($this->getSecurityContext()->isGranted($permission, $object)) { $results = []; if ($searchById) { $results = $this->searchById($search); } else { $page = (int) $page > 0 ? (int) $page : 1; $perPage = (int) $perPage > 0 ? (int) $perPage : 10; $firstResult = ($page - 1) * $perPage; $perPage += 1; $user = $this->getSecurityContext()->getToken()->getUser(); $organization = $this->getSecurityContext()->getToken()->getOrganizationContext(); $queryBuilder = $this->createQueryBuilder(); $this->addSearchCriteria($queryBuilder, $search); if ((bool) $excludeCurrentUser) { $this->excludeUser($queryBuilder, $user); } $this->addAdditionalFilterCriteria($queryBuilder); $queryBuilder->setFirstResult($firstResult)->setMaxResults($perPage); $query = $this->applyAcl($queryBuilder, $observer->getAccessLevel(), $user, $organization); $results = $query->getResult(); $hasMore = count($results) == $perPage; } $resultsData = []; foreach ($results as $user) { $resultsData[] = $this->convertItem($user); } } else { $resultsData = []; } return ['results' => $resultsData, 'more' => $hasMore]; }
/** * Get data for query acl access level check * Return empty array if entity has full access, null if user does't have access to the entity * and array with entity field and field values which user have access. * * @param $entityClassName * @param $permissions * * @return null|array */ public function getAclConditionData($entityClassName, $permissions = 'VIEW') { if ($this->aclVoter === null || !$this->getUserId() || !$this->entityMetadataProvider->isProtectedEntity($entityClassName)) { // return full access to the entity return []; } $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $groupedEntityClassName = $entityClassName; if ($this->aclGroupProvider) { $group = $this->aclGroupProvider->getGroup(); if ($group) { $groupedEntityClassName = sprintf('%s@%s', $this->aclGroupProvider->getGroup(), $entityClassName); } } $isGranted = $this->getSecurityContext()->isGranted($permissions, new ObjectIdentity('entity', $groupedEntityClassName)); if ($isGranted) { $condition = $this->buildConstraintIfAccessIsGranted($entityClassName, $observer->getAccessLevel(), $this->metadataProvider->getMetadata($entityClassName)); } else { $condition = $this->getAccessDeniedCondition(); } return $condition; }
/** * @param BuildBefore $event */ public function onBuildBefore(BuildBefore $event) { $parameters = $event->getDatagrid()->getParameters(); $permission = $parameters->get('permission'); if ($parameters->get('entity')) { $entityClass = str_replace('_', '\\', $parameters->get('entity')); } else { $entityClass = 'Oro\\Bundle\\UserBundle\\Entity\\User'; } $entityId = $parameters->get('entity_id'); if ($entityId) { $object = $this->em->getRepository($entityClass)->find((int) $entityId); } else { $object = 'entity:' . $entityClass; } $observer = new OneShotIsGrantedObserver(); $this->aclVoter->addOneShotIsGrantedObserver($observer); $this->getSecurityContext()->isGranted($permission, $object); $accessLevel = $observer->getAccessLevel(); $config = $event->getConfig(); $user = $this->getSecurityContext()->getToken()->getUser(); $organization = $this->getSecurityContext()->getToken()->getOrganizationContext(); $this->applyACL($config, $accessLevel, $user, $organization); }
public function testVote() { $configProvider = $this->getMockBuilder('Oro\\Bundle\\EntityConfigBundle\\Provider\\ConfigProvider')->disableOriginalConstructor()->getMock(); $selector = $this->getMockBuilder('Oro\\Bundle\\SecurityBundle\\Acl\\Extension\\AclExtensionSelector')->disableOriginalConstructor()->getMock(); $permissionMap = $this->getMock('Symfony\\Component\\Security\\Acl\\Permission\\PermissionMapInterface'); $voter = new AclVoter($this->getMock('Symfony\\Component\\Security\\Acl\\Model\\AclProviderInterface'), $this->getMock('Symfony\\Component\\Security\\Acl\\Model\\ObjectIdentityRetrievalStrategyInterface'), $this->getMock('Symfony\\Component\\Security\\Acl\\Model\\SecurityIdentityRetrievalStrategyInterface'), $permissionMap); $voter->setAclExtensionSelector($selector); $voter->setConfigProvider($configProvider); $token = $this->getMock('Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface'); $object = new \stdClass(); $extension = $this->getMock('Oro\\Bundle\\SecurityBundle\\Acl\\Extension\\AclExtensionInterface'); $extension->expects($this->once())->method('getAccessLevel')->with($this->equalTo(1))->will($this->returnValue(AccessLevel::LOCAL_LEVEL)); $isGrantedObserver = $this->getMockBuilder('Oro\\Bundle\\SecurityBundle\\Acl\\Domain\\OneShotIsGrantedObserver')->disableOriginalConstructor()->getMock(); $voter->addOneShotIsGrantedObserver($isGrantedObserver); $isGrantedObserver->expects($this->once())->method('setAccessLevel')->with($this->equalTo(AccessLevel::LOCAL_LEVEL)); $selector->expects($this->exactly(2))->method('select')->with($this->identicalTo($object))->will($this->returnValue($extension)); $inVoteToken = null; $inVoteObject = null; $inVoteExtension = null; $permissionMap->expects($this->exactly(2))->method('contains')->with('test')->will($this->returnValue(true)); $permissionMap->expects($this->exactly(2))->method('getMasks')->will($this->returnCallback(function () use(&$voter, &$inVoteToken, &$inVoteObject, &$inVoteExtension) { $inVoteToken = $voter->getSecurityToken(); $inVoteObject = $voter->getObject(); $inVoteExtension = $voter->getAclExtension(); $voter->setTriggeredMask(1); return null; })); $this->assertNull($voter->getSecurityToken()); $this->assertNull($voter->getObject()); $this->assertNull($voter->getAclExtension()); $voter->vote($token, $object, array('test')); $this->assertNull($voter->getSecurityToken()); $this->assertNull($voter->getObject()); $this->assertNull($voter->getAclExtension()); $this->assertSame($token, $inVoteToken); $this->assertSame($object, $inVoteObject); $this->assertSame($extension, $inVoteExtension); // call the vote method one more time to ensure that OneShotIsGrantedObserver was removed from the voter $voter->vote($token, $object, array('test')); }