/** * TODO: Document this Method! ( assignVariables ) */ public function preToolbarRendering() { $account = $this->context->getAccount(); $votes = array(); $privilege = array('PRIVILEGE_ABSTAIN', 'PRIVILEGE_GRANT', 'PRIVILEGE_DENY'); $roleVotes = \Debug\Toolbar\Service\DataStorage::get('Security:RoleVotes'); if (is_array($roleVotes)) { foreach ($roleVotes as $key => $value) { $vote = array('role' => (string) $value['role']); $vote['privilege'] = ''; if (is_array($value['privileges'])) { foreach ($value['privileges'] as $k => $p) { $vote['privilege'] = $privilege[$p]; } } $votes[$value['role'] . ':' . $vote['privilege']] = $vote; } } else { $roles = $this->context->getRoles(); foreach ($roles as $key => $value) { $vote = array('role' => (string) $value); $votes[] = $vote; } } \Debug\Toolbar\Service\Collector::getModule('Security')->getToolbar()->addIcon('user')->addText(is_object($account) ? $account->getAccountIdentifier() : 'Guest')->getPopup()->addPartial('Security', array('roles' => $this->context->getRoles(), 'account' => $this->context->getaccount(), 'votes' => $votes))->getPanel()->addPartial('Security', array('roles' => $this->context->getRoles(), 'account' => $this->context->getaccount(), 'votes' => $votes)); }
/** * Gets the SQL query part to add to a query. * * @param ClassMetaData $targetEntity Metadata object for the target entity to be filtered * @param string $targetTableAlias The target table alias used in the current query * @return string The constraint SQL if there is available, empty string otherwise */ public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias) { $this->initializeDependencies(); /* * TODO: Instead of checking for class account we could introduce some interface for white listing entities from entity security checks * Problem with checking the Account is, that this filter calls getRoles() on the security context while accounts are not * yet fully initialized. By this we get a half built account object that will end up in access denied exception, * as it has no roles (and other properties) set */ if ($this->securityContext->areAuthorizationChecksDisabled() || $targetEntity->getName() === \TYPO3\Flow\Security\Account::class) { return ''; } if (!$this->securityContext->isInitialized()) { if (!$this->securityContext->canBeInitialized()) { return ''; } $this->securityContext->initialize(); } // This is needed to include the current context of roles into query cache identifier $this->setParameter('__contextHash', $this->securityContext->getContextHash(), 'string'); $sqlConstraints = array(); $grantedConstraints = array(); $deniedConstraints = array(); foreach ($this->securityContext->getRoles() as $role) { $entityPrivileges = $role->getPrivilegesByType(\TYPO3\Flow\Security\Authorization\Privilege\Entity\EntityPrivilegeInterface::class); /** @var EntityPrivilegeInterface $privilege */ foreach ($entityPrivileges as $privilege) { if (!$privilege->matchesEntityType($targetEntity->getName())) { continue; } $sqlConstraint = $privilege->getSqlConstraint($targetEntity, $targetTableAlias); if ($sqlConstraint === null) { continue; } $sqlConstraints[] = ' NOT (' . $sqlConstraint . ')'; if ($privilege->isGranted()) { $grantedConstraints[] = ' NOT (' . $sqlConstraint . ')'; } elseif ($privilege->isDenied()) { $deniedConstraints[] = ' NOT (' . $sqlConstraint . ')'; } } } $grantedConstraints = array_diff($grantedConstraints, $deniedConstraints); $effectiveConstraints = array_diff($sqlConstraints, $grantedConstraints); if (count($effectiveConstraints) > 0) { return ' (' . implode(') AND (', $effectiveConstraints) . ') '; } return ''; }
/** * Checks, if the current policy allows the retrieval of the object fetched by getObjectDataByIdentifier() * * @Flow\Around("within(TYPO3\Flow\Persistence\PersistenceManagerInterface) && method(.*->getObjectByIdentifier()) && setting(TYPO3.Flow.security.enable)") * @param \TYPO3\Flow\Aop\JoinPointInterface $joinPoint The current joinpoint * @return array The object data of the original object, or NULL if access is not permitted */ public function checkAccessAfterFetchingAnObjectByIdentifier(JoinPointInterface $joinPoint) { $result = $joinPoint->getAdviceChain()->proceed($joinPoint); if ($this->securityContext->areAuthorizationChecksDisabled() === TRUE || $this->policyService->hasPolicyEntriesForEntities() === FALSE) { return $result; } if ($this->securityContext->isInitialized() === FALSE) { if ($this->securityContext->canBeInitialized() === TRUE) { $this->securityContext->initialize(); } else { return $result; } } $authenticatedRoles = $this->securityContext->getRoles(); $entityType = $this->reflectionService->getClassNameByObject($result); if ($this->policyService->hasPolicyEntryForEntityType($entityType, $authenticatedRoles)) { if ($this->policyService->isGeneralAccessForEntityTypeGranted($entityType, $authenticatedRoles) === FALSE) { return NULL; } $policyConstraintsDefinition = $this->policyService->getResourcesConstraintsForEntityTypeAndRoles($entityType, $authenticatedRoles); if ($this->checkConstraintDefinitionsOnResultObject($policyConstraintsDefinition, $result) === FALSE) { return NULL; } } return $result; }
/** * This is the default Policy voter, it votes for the access privilege for the given resource * * @param \TYPO3\Flow\Security\Context $securityContext The current security context * @param string $resource The resource to vote for * @return integer One of: VOTE_GRANT, VOTE_ABSTAIN, VOTE_DENY */ public function voteForResource(\TYPO3\Flow\Security\Context $securityContext, $resource) { $accessGrants = 0; $accessDenies = 0; foreach ($securityContext->getRoles() as $role) { try { $privilege = $this->policyService->getPrivilegeForResource($role, $resource); } catch (\TYPO3\Flow\Security\Exception\NoEntryInPolicyException $e) { return self::VOTE_ABSTAIN; } if ($privilege === NULL) { continue; } if ($privilege === \TYPO3\Flow\Security\Policy\PolicyService::PRIVILEGE_GRANT) { $accessGrants++; } elseif ($privilege === \TYPO3\Flow\Security\Policy\PolicyService::PRIVILEGE_DENY) { $accessDenies++; } } if ($accessDenies > 0) { return self::VOTE_DENY; } if ($accessGrants > 0) { return self::VOTE_GRANT; } return self::VOTE_ABSTAIN; }
/** * Returns a string message, giving insights what happened during privilege evaluation. * * @param string $privilegeReasonMessage * @return string */ protected function renderDecisionReasonMessage($privilegeReasonMessage) { if (count($this->securityContext->getRoles()) === 0) { $rolesMessage = 'No authenticated roles'; } else { $rolesMessage = 'Authenticated roles: ' . implode(', ', array_keys($this->securityContext->getRoles())); } return sprintf('Access denied for method' . chr(10) . 'Method: %s::%s()' . chr(10) . chr(10) . '%s' . chr(10) . chr(10) . '%s', $this->joinPoint->getClassName(), $this->joinPoint->getMethodName(), $privilegeReasonMessage, $rolesMessage); }
/** * @return array */ public function getAccountRoleIdentifiers() { $roleIdentifiers = []; foreach ($this->securityContext->getRoles() as $role) { /** @var Role $role */ $roleIdentifiers[] = $role->getIdentifier(); } return $roleIdentifiers; }
/** * Check if an administrator is logged in and deny access if someone else is trying to access */ public function checkAdministratorAndDenyIfNeeded() { // check if the user has access to this project if (!array_key_exists('GIB.GradingTool:Administrator', $this->securityContext->getRoles())) { // add a flash message $message = new \TYPO3\Flow\Error\Message('Access denied.', \TYPO3\Flow\Error\Message::SEVERITY_ERROR); $this->flashMessageContainer->addMessage($message); $this->redirect('index', 'Standard'); } }
/** * Allow access to content if it is my content or when i have the allowed role * * @param string $contentUserIdentifier * @param array $allowedRoles * @param array $disallowedRoles * @return string */ public function render($contentUserIdentifier, $allowedRoles = [], $disallowedRoles = []) { try { $profile = $this->profileService->getCurrentPartyProfile(); } catch (\Exception $exception) { return; } $myRoles = $this->securityContext->getRoles(); $accessBasedOnRole = FALSE; foreach (array_unique($allowedRoles) as $role) { if (in_array($role, $myRoles)) { $accessBasedOnRole = TRUE; } } foreach (array_unique($disallowedRoles) as $role) { if (in_array($role, $myRoles)) { $accessBasedOnRole = FALSE; } } if ($profile->getIdentifier() === $contentUserIdentifier || $accessBasedOnRole === TRUE) { return $this->renderThenChild(); } return $this->renderElseChild(); }
/** * Returns the publish path and filename to be used to publish the specified persistent resource * * @Flow\Around("method(TYPO3\Flow\Resource\Publishing\FileSystemPublishingTarget->buildPersistentResourcePublishPathAndFilename()) && setting(TYPO3.Flow.security.enable)") * @param \TYPO3\Flow\Aop\JoinPointInterface $joinPoint The current join point * @return mixed Result of the target method */ public function rewritePersistentResourcePublishPathAndFilenameForPrivateResources(\TYPO3\Flow\Aop\JoinPointInterface $joinPoint) { $resource = $joinPoint->getMethodArgument('resource'); /** @var $configuration \TYPO3\Flow\Security\Authorization\Resource\SecurityPublishingConfiguration */ $configuration = $resource->getPublishingConfiguration(); $returnFilename = $joinPoint->getMethodArgument('returnFilename'); if ($configuration === NULL || $configuration instanceof \TYPO3\Flow\Security\Authorization\Resource\SecurityPublishingConfiguration === FALSE) { return $joinPoint->getAdviceChain()->proceed($joinPoint); } $publishingPath = FALSE; $allowedRoles = $configuration->getAllowedRoles(); if (count(array_intersect($allowedRoles, $this->securityContext->getRoles())) > 0) { $publishingPath = \TYPO3\Flow\Utility\Files::concatenatePaths(array($joinPoint->getProxy()->getResourcesPublishingPath(), 'Persistent/', $this->session->getID())) . '/'; $filename = $resource->getResourcePointer()->getHash() . '.' . $resource->getFileExtension(); \TYPO3\Flow\Utility\Files::createDirectoryRecursively($publishingPath); $this->accessRestrictionPublisher->publishAccessRestrictionsForPath($publishingPath); if ($this->settings['resource']['publishing']['fileSystem']['mirrorMode'] === 'link') { foreach ($allowedRoles as $role) { $roleDirectory = \TYPO3\Flow\Utility\Files::concatenatePaths(array($this->environment->getPathToTemporaryDirectory(), 'PrivateResourcePublishing/', $role)); \TYPO3\Flow\Utility\Files::createDirectoryRecursively($roleDirectory); if (file_exists($publishingPath . $role)) { if (\TYPO3\Flow\Utility\Files::is_link(\TYPO3\Flow\Utility\Files::concatenatePaths(array($publishingPath, $role))) && realpath(\TYPO3\Flow\Utility\Files::concatenatePaths(array($publishingPath, $role))) === $roleDirectory) { continue; } unlink($publishingPath . $role); symlink($roleDirectory, \TYPO3\Flow\Utility\Files::concatenatePaths(array($publishingPath, $role))); } else { symlink($roleDirectory, \TYPO3\Flow\Utility\Files::concatenatePaths(array($publishingPath, $role))); } } $publishingPath = \TYPO3\Flow\Utility\Files::concatenatePaths(array($publishingPath, $allowedRoles[0])) . '/'; } if ($returnFilename === TRUE) { $publishingPath = \TYPO3\Flow\Utility\Files::concatenatePaths(array($publishingPath, $filename)); } } return $publishingPath; }
/** * @param NodeInterface $node * @return string[] Array of granted node property names */ public function getDeniedNodePropertiesForEditing(NodeInterface $node) { $privilegeSubject = new PropertyAwareNodePrivilegeSubject($node); $deniedNodePropertyNames = array(); $grantedNodePropertyNames = array(); $abstainedNodePropertyNames = array(); foreach ($this->securityContext->getRoles() as $role) { /** @var EditNodePropertyPrivilege $editNodePropertyPrivilege */ foreach ($role->getPrivilegesByType(EditNodePropertyPrivilege::class) as $editNodePropertyPrivilege) { if (!$editNodePropertyPrivilege->matchesSubject($privilegeSubject)) { continue; } if ($editNodePropertyPrivilege->isGranted()) { $grantedNodePropertyNames = array_merge($grantedNodePropertyNames, $editNodePropertyPrivilege->getNodePropertyNames()); } elseif ($editNodePropertyPrivilege->isDenied()) { $deniedNodePropertyNames = array_merge($deniedNodePropertyNames, $editNodePropertyPrivilege->getNodePropertyNames()); } else { $abstainedNodePropertyNames = array_merge($abstainedNodePropertyNames, $editNodePropertyPrivilege->getNodePropertyNames()); } } } $implicitlyDeniedNodePropertyNames = array_diff($abstainedNodePropertyNames, $grantedNodePropertyNames); return array_merge($implicitlyDeniedNodePropertyNames, $deniedNodePropertyNames); }
/** * Returns TRUE if access is granted on the given privilege target in the current security context * * @param string $privilegeTargetIdentifier The identifier of the privilege target to decide on * @param array $privilegeParameters Optional array of privilege parameters (simple key => value array) * @return boolean TRUE if access is granted, FALSE otherwise */ public function isPrivilegeTargetGranted($privilegeTargetIdentifier, array $privilegeParameters = array()) { return $this->isPrivilegeTargetGrantedForRoles($this->securityContext->getRoles(), $privilegeTargetIdentifier, $privilegeParameters); }
/** * @param \Exception $exception * @return void */ public function logException(\Exception $exception) { if (!isset($this->settings['host']) || strlen($this->settings['host']) === 0) { return; } $statusCode = NULL; if ($exception instanceof FlowException) { $statusCode = $exception->getStatusCode(); } // skip exceptions with status codes matching "skipStatusCodes" setting if (isset($this->settings['skipStatusCodes']) && in_array($statusCode, $this->settings['skipStatusCodes'])) { return; } $host = $this->settings['host']; $port = isset($this->settings['port']) ? $this->settings['port'] : UdpTransport::DEFAULT_PORT; // set chunk size option to wan (default) or lan if (isset($this->settings['chunksize']) && strtolower($this->settings['chunksize']) === 'lan') { $chunkSize = UdpTransport::CHUNK_SIZE_LAN; } else { $chunkSize = UdpTransport::CHUNK_SIZE_WAN; } // setup connection to graylog server $transport = new UdpTransport($host, $port, $chunkSize); $publisher = new Publisher(); $publisher->addTransport($transport); // set logLevel depending on http status code $logLevel = 4; // warning if ($statusCode === 500) { $logLevel = 3; // error } // build message context $messageContext = array('full_message' => $exception->getTraceAsString(), 'reference_code' => $exception instanceof FlowException ? $exception->getReferenceCode() : NULL, 'response_status' => $statusCode, 'short_message' => sprintf('%d %s', $statusCode, Response::getStatusMessageByCode($statusCode)), 'code' => $exception->getCode(), 'file' => $exception->getFile(), 'line' => $exception->getLine()); if ($this->securityContext !== NULL && $this->securityContext->isInitialized()) { $account = $this->securityContext->getAccount(); if ($account !== NULL) { $messageContext['authenticated_account'] = $account->getAccountIdentifier() . ' (' . $this->persistenceManager->getIdentifierByObject($account) . ')'; $messageContext['authenticated_roles'] = implode(', ', array_keys($this->securityContext->getRoles())); if ($this->objectManager->isRegistered(PartyService::class)) { /** @var PartyService $partyService */ $partyService = $this->objectManager->get(PartyService::class); $person = $partyService->getAssignedPartyOfAccount($account); if ($person instanceof Person) { $messageContext['authenticated_person'] = (string) $person->getName() . ' (' . $this->persistenceManager->getIdentifierByObject($person) . ')'; } } } } // prepare request details if (Bootstrap::$staticObjectManager instanceof ObjectManagerInterface) { $bootstrap = Bootstrap::$staticObjectManager->get('TYPO3\\Flow\\Core\\Bootstrap'); /* @var Bootstrap $bootstrap */ $requestHandler = $bootstrap->getActiveRequestHandler(); if ($requestHandler instanceof HttpRequestHandlerInterface) { $request = $requestHandler->getHttpRequest(); $requestData = array('request_domain' => $request->getHeader('Host'), 'request_remote_addr' => $request->getClientIpAddress(), 'request_path' => $request->getRelativePath(), 'request_uri' => $request->getUri()->getPath(), 'request_user_agent' => $request->getHeader('User-Agent'), 'request_method' => $request->getMethod(), 'request_port' => $request->getPort()); $messageContext = array_merge($messageContext, $requestData); } } // send message to graylog server $logger = new Logger($publisher); $logger->log($logLevel, $exception->getMessage(), $messageContext); }