public function addSessionScripts() { $response = $this->pageStack->getPageResponse(); $session = array(); $session['userId'] = null; $session['lang'] = 'en'; if ($this->pageStack->getSession() && $this->pageStack->getSession()->has('admin_language')) { $session['lang'] = $this->pageStack->getSession()->get('admin_language'); } $session['access'] = $this->acl->check(ACLRequest::create('jarves/entryPoint', ['path' => '/admin'])); if ($this->pageStack->isLoggedIn()) { $user = $this->pageStack->getUser(); $session['userId'] = $user->getId(); $session['username'] = $user->getUsername(); $session['lastLogin'] = $user->getLastLogin(); $session['firstName'] = $user->getFirstName(); $session['lastName'] = $user->getLastName(); // $email = $user->getEmail(); // $session['emailMd5'] = $email ? md5(strtolower(trim($email))) : null; $session['imagePath'] = $user->getImagePath(); } $session['token'] = get_class($this->pageStack->getToken()); $css = 'window._session = ' . json_encode($session) . ';'; $response->addJs($css); }
public function onKernelRequest(GetResponseEvent $event) { /** @var PageStack $pageStack */ $pageStack = $this->container->get('jarves.page_stack'); /** @var ACL $acl */ $acl = $this->container->get('jarves.acl'); $editorNodeId = $pageStack->getRequest()->get('_jarves_editor_node'); $editorDomainId = $pageStack->getRequest()->get('_jarves_editor_domain'); if (null !== $editorNodeId || null !== $editorDomainId) { $pk = $editorNodeId ? ['id' => $editorNodeId] : null; if (!$acl->isUpdatable('jarves/node', $pk)) { throw new AccessDeniedException('Access denied'); } } if ($pageStack->isAdmin()) { $whiteList = ['', '/admin/backend/css', '/admin/backend/script', '/admin/ui/languages', '/admin/ui/language', '/admin/ui/language-plural', '/admin/login', '/admin/logged-in']; $adminPrefix = $pageStack->getAdminPrefix(); $url = substr($event->getRequest()->getPathInfo(), strlen($adminPrefix)); if (in_array($url, $whiteList)) { return; } $hasUser = (bool) $pageStack->getUser(); $aclPath = '/jarves' . $url; //acl rules start always with /jarves $hasAccess = $acl->check(ACLRequest::create('jarves/entryPoint', ['path' => $aclPath])); if (!$hasUser || !$hasAccess) { $response = new Response(json_encode(['status' => 403, 'error' => 'AccessDeniedException', 'message' => 'Access denied.' . (!$pageStack->getUser() ? ' Not logged in.' : '')], JSON_PRETTY_PRINT), 403); $response->headers->set('Content-Type', 'application/json'); $event->setResponse($response); } } }
/** * @param ACLRequest $aclRequest * * @return bool */ public function check(ACLRequest $aclRequest) { $objectKey = Objects::normalizeObjectKey($aclRequest->getObjectKey()); $targetType = $aclRequest->getTargetType(); $targetId = $aclRequest->getTargetId(); $pk = $aclRequest->getPrimaryKey(); $field = $aclRequest->getField(); $pk = $this->objects->normalizePkString($objectKey, $pk); if (ACL::TARGET_TYPE_USER === $targetType && null === $targetId) { //0 means guest $targetId = $this->pageStack->getUser() ? $this->pageStack->getUser()->getId() : 0; } $user = $this->pageStack->getUser(); if ($user) { $groupIds = $user->getGroupIds(); if (false !== strpos(',' . $groupIds . ',', ',1,')) { //user is in the admin group, so he has always access. return true; } } if (ACL::TARGET_TYPE_USER === $targetType && 1 === $targetId) { //user admin has always access return true; } if (ACL::TARGET_TYPE_GROUP === $targetType && 1 === $targetId) { //group admin has always access return true; } if (0 === $targetId) { //guests do always have no access return false; } if (ACL::TARGET_TYPE_GROUP === $targetType && !$targetId) { throw new \InvalidArgumentException('For type TARGET_TYPE_GROUP a targetId is required.'); } $cacheKey = null; if ($pk && $this->getCaching()) { $pkString = $this->objects->getObjectUrlId($objectKey, $pk); $cacheKey = md5($targetType . '.' . $targetId . '.' . $objectKey . '/' . $pkString . '/' . json_encode($field)); $cached = $this->cacher->getDistributedCache('core/acl/' . $cacheKey); if (null !== $cached) { return $cached; } } $rules = self::getRules($objectKey, $aclRequest->getMode(), $targetType, $targetId); if (count($rules) === 0) { //no rules found, so we have no access return false; } $access = null; $currentObjectPk = $pk; $definition = $this->objects->getDefinition($objectKey); $not_found = true; //starts directly as if we were in the parent checking. $parent_acl = $aclRequest->isAsParent(); $fCount = null; $fKey = null; $fValue = null; $fIsArray = is_array($field); if ($fIsArray) { $fCount = count($field); $fKey = key($field); $fValue = current($field); if (is_int($fKey)) { $fKey = $fValue; $fValue = null; } } $depth = 0; $match = false; $originObjectItemPk = $currentObjectPk; while ($not_found) { $currentObjectPkString = null; if ($currentObjectPk) { $currentObjectPkString = $this->objects->getObjectUrlId($objectKey, $currentObjectPk); } $depth++; if ($depth > 50) { $not_found = false; break; } foreach ($rules as $aclRule) { if ($parent_acl && !$aclRule['sub']) { //as soon we enter the parent_acl mode we only take acl rules into consideration //that are also valid for children (sub=true) continue; } $match = false; /* * CUSTOM CONSTRAINT */ if ($aclRule['constraint_type'] === ACL::CONSTRAINT_CONDITION) { $objectItem = null; if ($originObjectItemPk === $currentObjectPk && null !== $aclRequest->getPrimaryObjectItem()) { $objectItem = $aclRequest->getPrimaryObjectItem(); } else { if ($originObjectItemPk) { $objectItem = $this->objects->get($objectKey, $currentObjectPk); } } if ($objectItem && $this->conditionOperator->satisfy($aclRule['constraint_code'], $objectItem, $objectKey)) { $match = true; } /* * EXACT */ } else { if ($aclRule['constraint_type'] === ACL::CONSTRAINT_EXACT) { if ($currentObjectPk && $aclRule['constraint_code'] === $currentObjectPkString) { $match = true; } /** * ALL */ } else { $match = true; } } if (!$match && $aclRule['sub'] && $currentObjectPk) { // we need to check if a parent matches this $acl as we have sub=true $parentItem = $this->objects->normalizePkString($objectKey, $currentObjectPk); $parentCondition = Condition::create($aclRule['constraint_code']); $parentOptions['fields'] = $this->conditionOperator->extractFields($parentCondition); while ($parentItem = $this->objects->getParent($objectKey, $this->objects->getObjectPk($objectKey, $parentItem), $parentOptions)) { if ($aclRule['constraint_type'] === ACL::CONSTRAINT_CONDITION && $this->conditionOperator->satisfy($parentCondition, $parentItem)) { $match = true; break; } else { if ($aclRule['constraint_type'] === ACL::CONSTRAINT_EXACT && $aclRule['constraint_code'] === $this->objects->getObjectUrlId($objectKey, $parentItem)) { $match = true; break; } } } } if ($match) { //match, check all $field $field2Key = $field; if ($field) { if ($fIsArray && $fCount === 1) { if (is_string($fKey) && is_array($aclRule['fields'][$fKey])) { //this field has limits if (($field2Acl = $aclRule['fields'][$fKey]) !== null) { if (is_array($field2Acl[0])) { //complex field rule, $field2Acl = ([{access: no, condition: [['id', '>', 2], ..]}, {}, ..]) foreach ($field2Acl as $fRule) { $satisfy = false; if (($f = $definition->getField($fKey)) && $f->getType() === 'object') { $uri = $f->getObject() . '/' . $fValue; $uriObject = $this->objects->getFromUrl($uri); $satisfy = $this->conditionOperator->satisfy($fRule['condition'], $uriObject); } else { if (null !== $fValue) { $satisfy = $this->conditionOperator->satisfy($fRule['condition'], $field); } } if ($satisfy) { return $fRule['access'] === 1 ? true : false; } } //if no field rules fits, we consider the whole rule if ($aclRule['access'] !== 2) { return $aclRule['access'] === 1 ? true : false; } } else { //simple field rule $field2Acl = ({"value1": yes, "value2": no} if ($field2Acl[$fKey] !== null) { return $field2Acl[$fKey] === 1 ? true : false; } else { //current($field) is not exactly defined in $field2Acl, so we set $access to $acl['access'] // //if access = 2 then wo do not know it, cause 2 means 'inherited', so maybe //a other rule has more detailed rule if ($aclRule['access'] !== 2) { $access = $aclRule['access'] === 1 ? true : false; break; } } } } } else { //this field has only true or false $field2Key = $fKey; } } if (!is_array($field2Key)) { if ($aclRule['fields'] && ($field2Acl = $aclRule['fields'][$field2Key]) !== null && !is_array($aclRule['fields'][$field2Key])) { $access = $field2Acl === 1 ? true : false; break; } else { //$field is not exactly defined, so we set $access to $acl['access'] //and maybe a rule with the same code has the field defined // if access = 2 then this rule is only for exactly define fields if ($aclRule['access'] !== 2) { $access = $aclRule['access'] === 1 ? true : false; break; } } } } else { $access = $aclRule['access'] === 1 ? true : false; break; } } } //foreach if (null === $access && $definition->isNested() && $pk) { //$access has not defined yet (no rule matched yet). Check if nested and $pk is given //load its root and check again if (null === ($currentObjectPk = $this->objects->getParentPk($objectKey, $currentObjectPk))) { $access = $aclRequest->isRootHasAccess() ? true : $access; break; } $parent_acl = true; } else { break; } } $access = (bool) $access; if ($pk && $this->getCaching()) { $this->cacher->setDistributedCache('core/acl/' . $cacheKey, $access); } return $access; }
/** * @ApiDoc( * section="Backend", * description="Returns all available menu/entryPoint items for the main navigation bar in the administration" * ) * * @Rest\View() * @Rest\Get("/admin/backend/menus") * * @return array */ public function getMenusAction() { $entryPoints = array(); foreach ($this->jarves->getConfigs() as $bundleName => $bundleConfig) { foreach ($bundleConfig->getAllEntryPoints() as $subEntryPoint) { $path = $subEntryPoint->getFullPath(); if (substr_count($path, '/') <= 3) { if ($subEntryPoint->isLink()) { if ($this->acl->check(ACLRequest::create('jarves/entryPoint', ['path' => '/' . $path]))) { $entryPoints[$path] = array('label' => $subEntryPoint->getLabel(), 'icon' => $subEntryPoint->getIcon(), 'fullPath' => $path, 'path' => $subEntryPoint->getPath(), 'type' => $subEntryPoint->getType(), 'system' => $subEntryPoint->getSystem(), 'templateUrl' => $subEntryPoint->getTemplateUrl(), 'level' => substr_count($path, '/')); } } } } } return $entryPoints; }
public function testObjectGeneral() { ItemQuery::create()->deleteAll(); TestQuery::create()->deleteAll(); $this->getACL()->removeObjectRules('test/item'); $this->getACL()->setCaching(false); $user = new User(); $user->setUsername('TestUser'); $user->save(); $group = new Group(); $group->setName('ACL Test group'); $group->addUser($user); $group->save(); $item1 = new Item(); $item1->setTitle('Item 1'); $item1->save(); $item2 = new Item(); $item2->setTitle('Item 2'); $item2->save(); $test1 = new Test(); $test1->setName('Test 1'); $test1->save(); $aclRequestItem1OnlyListing = ACLRequest::create('test/item', $item1->getId())->onlyListingMode(); $this->assertFalse($this->getACL()->check($aclRequestItem1OnlyListing->targetGroup($group->getId())), 'we have no rules, so everyone except admin user and admin group has no access.'); $this->assertTrue($this->getACL()->check($aclRequestItem1OnlyListing->targetGroup(1)), 'we have no rules, so only group admin has access.'); $this->assertTrue($this->getACL()->check($aclRequestItem1OnlyListing->targetUser(1)), 'we have no rules, so only user admin has access.'); $this->getACL()->removeObjectRules('test/item'); $this->getACL()->setObjectList('test/item', \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), true); $this->assertTrue($this->getACL()->check($aclRequestItem1OnlyListing->targetGroup($group->getId())), 'testGroup got list access to all test/item objects.'); $this->getACL()->setObjectListExact('test/item', $item1->getId(), \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), false); $this->assertFalse($this->getACL()->check($aclRequestItem1OnlyListing->targetGroup($group->getId())), 'testGroup got list access-denied to item 1.'); $aclRequestItem2OnlyListing = ACLRequest::create('test/item', $item2->getId())->onlyListingMode(); $this->assertTrue($this->getACL()->check($aclRequestItem2OnlyListing->targetGroup($group->getId())), 'testGroup still have access to item2.'); $this->getACL()->setObjectListExact('test/item', $item2->getId(), \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), false); $this->assertFalse($this->getACL()->check($aclRequestItem2OnlyListing->targetGroup($group->getId())), 'testGroup does not have access to item2 anymore.'); $acl = $this->getACL()->setObjectListExact('test/item', $item2->getId(), \Jarves\ACL::TARGET_TYPE_USER, $user->getId(), true); $this->assertTrue($this->getACL()->check($aclRequestItem2OnlyListing->targetUser($user->getId())), 'testUser got access through a rule for only him.'); $acl->setAccess(false); $acl->save(); $this->assertFalse($this->getACL()->check($aclRequestItem2OnlyListing->targetUser($user->getId())), 'testUser got no-access through a rule for only him.'); //access to every item $acl = $this->getACL()->setObjectList('test/item', \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), true); $this->assertTrue($this->getACL()->check($aclRequestItem2OnlyListing->targetUser($user->getId())), 'testUser has now access to all items through his group.'); $this->assertTrue($this->getACL()->check($aclRequestItem1OnlyListing->targetGroup($group->getId())), 'testGroup has now access to all items.'); $this->assertTrue($this->getACL()->check($aclRequestItem2OnlyListing->targetGroup($group->getId())), 'testGroup has now access to all items.'); //remove the acl item that gives access to anything. $acl->delete(); $this->assertFalse($this->getACL()->check($aclRequestItem2OnlyListing->targetUser($user->getId())), 'testUser has no access anymore, since we deleted the access-for-all rule.'); $this->assertFalse($this->getACL()->check($aclRequestItem1OnlyListing->targetGroup($group->getId())), 'testGroup has no access anymore to all items (item1).'); $this->assertFalse($this->getACL()->check($aclRequestItem2OnlyListing->targetGroup($group->getId())), 'testGroup has no access anymore to all items (item2).'); //check checkListCondition $this->getACL()->setObjectListCondition('test/item', array(array('id', '>', $item1->getId())), \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), true); $this->assertTrue($this->getACL()->check($aclRequestItem2OnlyListing->targetGroup($group->getId())), 'testGroup has access to all items after item1'); $this->assertFalse($this->getACL()->check($aclRequestItem1OnlyListing->targetGroup($group->getId())), 'testGroup has access to all items after item1, but only > , so not item1 itself.'); //revoke anything to object 'test\item' $this->getACL()->setObjectList('test/item', \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), false); $this->assertFalse($this->getACL()->check($aclRequestItem2OnlyListing->targetGroup($group->getId())), 'testGroup has no access to all items after item1'); //check against object test $aclRequestTest1OnlyListing = ACLRequest::create('test/test', $test1->getId())->onlyListingMode(); $this->getACL()->setObjectListExact('test/test', $test1->getId(), \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), true); $this->assertTrue($this->getACL()->check($aclRequestTest1OnlyListing->targetGroup($group->getId())), 'testGroup has access test1.'); $this->getACL()->setObjectList('test/test', \Jarves\ACL::TARGET_TYPE_GROUP, $group->getId(), false); $this->assertFalse($this->getACL()->check($aclRequestTest1OnlyListing->targetGroup($group->getId())), 'testGroup has no access test1.'); $this->getACL()->setCaching(true); $this->getACL()->removeObjectRules('test/item'); }
/** * @ApiDoc( * section="Administration", * description="Logs in a user to the current session" * ) * * Result on success: * { * token: "c7405b2be7da96b0db784f2dc8b2b974", * userId: 1, * username: "******", * access: true, #administration access * firstName: "Admini", * lastName: "strator", * emailMd5: <emailAsMd5>, //for gravatar * imagePath: "/path/to/image.jpg" *} * * @Rest\RequestParam(name="username", requirements=".+", strict=true) * @Rest\RequestParam(name="password", requirements=".+", strict=true) * * @Rest\Post("/admin/login") * * @param ParamFetcher $paramFetcher * * @return array|bool Returns false on failure or a array if successful. */ public function loginUserAction(ParamFetcher $paramFetcher, Request $request) { $username = $paramFetcher->get('username'); $password = $paramFetcher->get('password'); $user = $this->userProvider->loadUserByUsername($username); if (!$user) { $this->logger->warning(sprintf('Login failed for "%s". User not found', $username)); sleep(1); return false; } $encoder = $this->encoderFactory->getEncoder($user); if (!$encoder->isPasswordValid($user->getPassword(), $password, null)) { $this->logger->warning(sprintf('Login failed for "%s". Password missmatch ', $username)); sleep(1); return false; } $token = new UsernamePasswordToken($user, null, "main", $user->getGroupRoles()); $this->tokenStorage->setToken($token); //now dispatch the login event $event = new InteractiveLoginEvent($request, $token); $this->get("event_dispatcher")->dispatch("security.interactive_login", $event); return array('userId' => $user->getId(), 'username' => $user->getUsername(), 'lastLogin' => $user->getLastLogin(), 'access' => $this->acl->check(ACLRequest::create('jarves/entryPoint', ['path' => '/admin'])), 'firstName' => $user->getFirstName(), 'lastName' => $user->getLastName(), 'imagePath' => $user->getImagePath()); }
/** * Returns file information as array. * * @param string|integer $path * @return array|null */ protected function getFile($path) { $file = $this->webFilesystem->getFile($path); $file = $file->toArray(); $aclRequest = ACLRequest::create('jarves/file', $file)->onlyListingMode(); if (!$file || !$this->acl->check($aclRequest)) { return null; } $file['writeAccess'] = $this->acl->check($aclRequest->onlyUpdateMode()); $this->appendImageInformation($file); return $file; }
/** * Patches a object entry. This means, only defined fields will be saved. Fields which are not defined will * not be overwritten. * * @param array $pk * * @param Request|array $requestOrData * @return bool * * @throws AccessDeniedException * @throws ObjectNotFoundException * @throws \Exception */ public function patch($pk, $requestOrData) { $storageController = $this->objects->getStorageController($this->getObject()); $pk = $storageController->normalizePrimaryKey($pk); $this->primaryKey = $pk; $values = $this->collectData($requestOrData); $args = ['pk' => $pk, 'values' => &$values, 'controller' => $this, 'mode' => 'update']; $eventPre = new GenericEvent($this->getObject(), $args); $this->eventDispatcher->dispatch('core/object/modify-pre', $eventPre); $this->eventDispatcher->dispatch('core/object/patch-pre', $eventPre); $item = $this->getItem($pk); if ($this->getPermissionCheck()) { if (!$item) { return null; } if (!$this->acl->check(ACLRequest::create($this->getObject(), $pk)->onlyUpdateMode())) { return null; } foreach ($values as $fieldName => $value) { $aclRequest = ACLRequest::create($this->getObject(), $pk)->setField([$fieldName => $value])->onlyUpdateMode(); if (!$this->acl->check($aclRequest)) { throw new AccessDeniedException(sprintf('Not allowed to change `%s`', $fieldName)); } } } if (($condition = $this->getCondition()) && $condition->hasRules()) { if (!$this->conditionOperator->satisfy($condition, $item, $this->getObject())) { return null; } } $incomingFields = $requestOrData instanceof Request ? array_keys($requestOrData->request->all()) : array_keys($requestOrData); if (!$incomingFields) { return false; } $changedData = $this->mapData($values, $incomingFields, $item); if ($this->getWithNewsFeed()) { $this->utils->newNewsFeed($this->objects, $this->getObject(), array_merge($values, $pk), 'updated'); } $result = $storageController->patch($pk, $changedData); $args['result'] = $result; $event = new GenericEvent($this->getObject(), $args); $this->eventDispatcher->dispatch('core/object/modify', $event); $this->eventDispatcher->dispatch('core/object/patch', $event); return $result; }