/** * @param integer $step * @return void * @Flow\SkipCsrfProtection */ public function indexAction($step = 0) { $this->currentStepIndex = $step; $this->checkRequestedStepIndex(); $currentStep = $this->instantiateCurrentStep(); $controller = $this; $callback = function (\Neos\Form\Core\Model\FinisherContext $finisherContext) use($controller, $currentStep) { $controller->postProcessStep($finisherContext->getFormValues(), $currentStep); }; $formDefinition = $currentStep->getFormDefinition($callback); if ($this->currentStepIndex > 0) { $formDefinition->setRenderingOption('previousStepUri', $this->uriBuilder->uriFor('index', ['step' => $this->currentStepIndex - 1])); } if ($currentStep->isOptional()) { $formDefinition->setRenderingOption('nextStepUri', $this->uriBuilder->uriFor('index', ['step' => $this->currentStepIndex + 1])); } $totalAmountOfSteps = count($this->settings['steps']); if ($this->currentStepIndex === $totalAmountOfSteps - 1) { $formDefinition->setRenderingOption('finalStep', true); $this->authenticationManager->logout(); } $response = new \Neos\Flow\Http\Response($this->response); $form = $formDefinition->bind($this->request, $response); try { $renderedForm = $form->render(); } catch (\Neos\Setup\Exception $exception) { $this->addFlashMessage($exception->getMessage(), 'Exception while executing setup step', \Neos\Error\Messages\Message::SEVERITY_ERROR); $this->redirect('index', null, null, ['step' => $this->currentStepIndex]); } $this->view->assignMultiple(['form' => $renderedForm, 'totalAmountOfSteps' => $totalAmountOfSteps, 'currentStepNumber' => $this->currentStepIndex + 1]); }
/** * Sets up this test case */ public function setUp() { $this->securityContext = $this->getAccessibleMock(Context::class, ['separateActiveAndInactiveTokens']); $this->mockAuthenticationManager = $this->createMock(AuthenticationManagerInterface::class); $this->mockAuthenticationManager->expects($this->any())->method('getTokens')->will($this->returnValue([])); $this->securityContext->injectAuthenticationManager($this->mockAuthenticationManager); $this->mockActionRequest = $this->getMockBuilder(ActionRequest::class)->disableOriginalConstructor()->getMock(); $this->securityContext->setRequest($this->mockActionRequest); }
/** * Matches a \Neos\Flow\Mvc\RequestInterface against the configured CSRF pattern rules and * searches for invalid csrf tokens. If this returns TRUE, the request is invalid! * * @param RequestInterface $request The request that should be matched * @return boolean TRUE if the pattern matched, FALSE otherwise * @throws AuthenticationRequiredException */ public function matchRequest(RequestInterface $request) { if (!$request instanceof ActionRequest || $request->getHttpRequest()->isMethodSafe()) { $this->systemLogger->log('CSRF: No token required, safe request', LOG_DEBUG); return false; } if ($this->authenticationManager->isAuthenticated() === false) { $this->systemLogger->log('CSRF: No token required, not authenticated', LOG_DEBUG); return false; } if ($this->securityContext->areAuthorizationChecksDisabled() === true) { $this->systemLogger->log('CSRF: No token required, authorization checks are disabled', LOG_DEBUG); return false; } $controllerClassName = $this->objectManager->getClassNameByObjectName($request->getControllerObjectName()); $actionMethodName = $request->getControllerActionName() . 'Action'; if (!$this->hasPolicyEntryForMethod($controllerClassName, $actionMethodName)) { $this->systemLogger->log(sprintf('CSRF: No token required, method %s::%s() is not restricted by a policy.', $controllerClassName, $actionMethodName), LOG_DEBUG); return false; } if ($this->reflectionService->isMethodTaggedWith($controllerClassName, $actionMethodName, 'skipcsrfprotection')) { $this->systemLogger->log(sprintf('CSRF: No token required, method %s::%s() is tagged with a "skipcsrfprotection" annotation', $controllerClassName, $actionMethodName), LOG_DEBUG); return false; } $httpRequest = $request->getHttpRequest(); if ($httpRequest->hasHeader('X-Flow-Csrftoken')) { $csrfToken = $httpRequest->getHeader('X-Flow-Csrftoken'); } else { $internalArguments = $request->getMainRequest()->getInternalArguments(); $csrfToken = isset($internalArguments['__csrfToken']) ? $internalArguments['__csrfToken'] : null; } if (empty($csrfToken)) { $this->systemLogger->log(sprintf('CSRF: token was empty but a valid token is required for %s::%s()', $controllerClassName, $actionMethodName), LOG_DEBUG); return true; } if (!$this->securityContext->hasCsrfProtectionTokens()) { throw new AuthenticationRequiredException(sprintf('CSRF: No CSRF tokens in security context, possible session timeout. A valid token is required for %s::%s()', $controllerClassName, $actionMethodName), 1317309673); } if ($this->securityContext->isCsrfProtectionTokenValid($csrfToken) === false) { $this->systemLogger->log(sprintf('CSRF: token was invalid but a valid token is required for %s::%s()', $controllerClassName, $actionMethodName), LOG_DEBUG); return true; } $this->systemLogger->log(sprintf('CSRF: Successfully verified token for %s::%s()', $controllerClassName, $actionMethodName), LOG_DEBUG); return false; }
/** * @test */ public function csrfTokenFieldIsRenderedForUnsafeRequests() { /** @var FormViewHelper|\PHPUnit_Framework_MockObject_MockObject $viewHelper */ $viewHelper = $this->getAccessibleMock(\Neos\FluidAdaptor\ViewHelpers\FormViewHelper::class, null, array(), '', false); $this->injectDependenciesIntoViewHelper($viewHelper); $this->securityContext->expects($this->any())->method('isInitialized')->will($this->returnValue(true)); $this->mockAuthenticationManager->expects($this->any())->method('isAuthenticated')->will($this->returnValue(true)); $this->securityContext->expects($this->atLeastOnce())->method('getCsrfProtectionToken')->will($this->returnValue('CSRFTOKEN')); $this->assertEquals('<input type="hidden" name="__csrfToken" value="CSRFTOKEN" />' . chr(10), $viewHelper->_call('renderCsrfTokenField')); }
/** * Prepares the environment for and conducts an account authentication * * @param \Neos\Flow\Security\Account $account * @return void * @api */ protected function authenticateAccount(\Neos\Flow\Security\Account $account) { $this->testingProvider->setAuthenticationStatus(\Neos\Flow\Security\Authentication\TokenInterface::AUTHENTICATION_SUCCESSFUL); $this->testingProvider->setAccount($account); $this->securityContext->clearContext(); $requestHandler = self::$bootstrap->getActiveRequestHandler(); $actionRequest = $this->route($requestHandler->getHttpRequest()); $this->securityContext->setRequest($actionRequest); $this->authenticationManager->authenticate(); }
/** * Render the a hidden field with a CSRF token * * @return string the CSRF token field */ protected function renderCsrfTokenField() { if (strtolower($this->arguments['method']) === 'get') { return ''; } if (!$this->securityContext->isInitialized() || !$this->authenticationManager->isAuthenticated()) { return ''; } $csrfToken = $this->securityContext->getCsrfProtectionToken(); return '<input type="hidden" name="__csrfToken" value="' . htmlspecialchars($csrfToken) . '" />' . chr(10); }
/** * Invokes the security interception * * @return boolean TRUE if the security checks was passed * @throws AccessDeniedException * @throws AuthenticationRequiredException if an entity could not be found (assuming it is bound to the current session), causing a redirect to the authentication entrypoint * @throws NoTokensAuthenticatedException if no tokens could be found and the accessDecisionManager denied access to the privilege target, causing a redirect to the authentication entrypoint */ public function invoke() { $reason = ''; $privilegeSubject = new MethodPrivilegeSubject($this->joinPoint); try { $this->authenticationManager->authenticate(); } catch (EntityNotFoundException $exception) { throw new AuthenticationRequiredException('Could not authenticate. Looks like a broken session.', 1358971444, $exception); } catch (NoTokensAuthenticatedException $noTokensAuthenticatedException) { // We still need to check if the privilege is available to "Neos.Flow:Everybody". if ($this->privilegeManager->isGranted(MethodPrivilegeInterface::class, $privilegeSubject, $reason) === false) { throw new NoTokensAuthenticatedException($noTokensAuthenticatedException->getMessage() . chr(10) . $reason, $noTokensAuthenticatedException->getCode()); } } if ($this->privilegeManager->isGranted(MethodPrivilegeInterface::class, $privilegeSubject, $reason) === false) { throw new AccessDeniedException($this->renderDecisionReasonMessage($reason), 1222268609); } }
/** * Invokes the the authentication, if needed. * * @return boolean TRUE if the security checks was passed */ public function invoke() { $this->authenticationManager->authenticate(); }
/** * Logs all active tokens out. Override this, if you want to * have some custom action here. You can always call the parent * method to do the actual logout. * * @return void */ public function logoutAction() { $this->authenticationManager->logout(); }
/** * Logout all active authentication tokens. * * @return void */ public function logoutAction() { $this->authenticationManager->logout(); $this->addFlashMessage('Successfully logged out.', 'Logged out'); $this->redirect('login'); }
/** * Returns TRUE, if at least one of the currently authenticated accounts holds * a role with the given identifier, also recursively. * * @param string $roleIdentifier The string representation of the role to search for * @return boolean TRUE, if a role with the given string representation was found */ public function hasRole($roleIdentifier) { if ($roleIdentifier === 'Neos.Flow:Everybody') { return true; } if ($roleIdentifier === 'Neos.Flow:Anonymous') { return !$this->authenticationManager->isAuthenticated(); } if ($roleIdentifier === 'Neos.Flow:AuthenticatedUser') { return $this->authenticationManager->isAuthenticated(); } $roles = $this->getRoles(); return isset($roles[$roleIdentifier]); }
/** * Sets a new password for the given user * * This method will iterate over all accounts owned by the given user and, if the account uses a UsernamePasswordToken, * sets a new password accordingly. * * @param User $user The user to set the password for * @param string $password A new password * @return void * @api */ public function setUserPassword(User $user, $password) { $tokens = $this->authenticationManager->getTokens(); $indexedTokens = array(); foreach ($tokens as $token) { /** @var TokenInterface $token */ $indexedTokens[$token->getAuthenticationProviderName()] = $token; } foreach ($user->getAccounts() as $account) { /** @var Account $account */ $authenticationProviderName = $account->getAuthenticationProviderName(); if (isset($indexedTokens[$authenticationProviderName]) && $indexedTokens[$authenticationProviderName] instanceof UsernamePassword) { $account->setCredentialsSource($this->hashService->hashPassword($password)); $this->accountRepository->update($account); } } }