Chris@0: sessionConfiguration = $session_configuration; Chris@0: $this->csrfToken = $csrf_token; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function applies(Route $route) { Chris@0: $requirements = $route->getRequirements(); Chris@0: // Check for current requirement _csrf_request_header_token and deprecated Chris@0: // REST requirement. Chris@0: $applicable_requirements = [ Chris@0: '_csrf_request_header_token', Chris@0: // @todo Remove _access_rest_csrf in Drupal 9.0.0. Chris@0: '_access_rest_csrf', Chris@0: ]; Chris@0: $requirement_keys = array_keys($requirements); Chris@0: Chris@0: if (array_intersect($applicable_requirements, $requirement_keys)) { Chris@0: if (isset($requirements['_method'])) { Chris@0: // There could be more than one method requirement separated with '|'. Chris@0: $methods = explode('|', $requirements['_method']); Chris@0: // CSRF protection only applies to write operations, so we can filter Chris@0: // out any routes that require reading methods only. Chris@0: $write_methods = array_diff($methods, ['GET', 'HEAD', 'OPTIONS', 'TRACE']); Chris@0: if (empty($write_methods)) { Chris@0: return FALSE; Chris@0: } Chris@0: } Chris@0: // No method requirement given, so we run this access check to be on the Chris@0: // safe side. Chris@0: return TRUE; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Checks access. Chris@0: * Chris@0: * @param \Symfony\Component\HttpFoundation\Request $request Chris@0: * The request object. Chris@0: * @param \Drupal\Core\Session\AccountInterface $account Chris@0: * The currently logged in account. Chris@0: * Chris@0: * @return \Drupal\Core\Access\AccessResultInterface Chris@0: * The access result. Chris@0: */ Chris@0: public function access(Request $request, AccountInterface $account) { Chris@0: $method = $request->getMethod(); Chris@0: Chris@17: // Read-only operations are always allowed. Chris@17: if (in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE'], TRUE)) { Chris@17: return AccessResult::allowed(); Chris@17: } Chris@17: Chris@0: // This check only applies if Chris@17: // 1. the user was successfully authenticated and Chris@17: // 2. the request comes with a session cookie. Chris@17: if ($account->isAuthenticated() Chris@0: && $this->sessionConfiguration->hasSession($request) Chris@0: ) { Chris@0: if (!$request->headers->has('X-CSRF-Token')) { Chris@0: return AccessResult::forbidden()->setReason('X-CSRF-Token request header is missing')->setCacheMaxAge(0); Chris@0: } Chris@0: $csrf_token = $request->headers->get('X-CSRF-Token'); Chris@0: // @todo Remove validate call using 'rest' in 8.3. Chris@0: // Kept here for sessions active during update. Chris@0: if (!$this->csrfToken->validate($csrf_token, self::TOKEN_KEY) Chris@0: && !$this->csrfToken->validate($csrf_token, 'rest')) { Chris@0: return AccessResult::forbidden()->setReason('X-CSRF-Token request header is invalid')->setCacheMaxAge(0); Chris@0: } Chris@0: } Chris@0: // Let other access checkers decide if the request is legit. Chris@0: return AccessResult::allowed()->setCacheMaxAge(0); Chris@0: } Chris@0: Chris@0: }