Mercurial > hg > isophonics-drupal-site
diff core/lib/Drupal/Core/Access/CsrfRequestHeaderAccessCheck.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 129ea1e6d783 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/lib/Drupal/Core/Access/CsrfRequestHeaderAccessCheck.php Wed Nov 29 16:09:58 2017 +0000 @@ -0,0 +1,115 @@ +<?php + +namespace Drupal\Core\Access; + +use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Session\SessionConfigurationInterface; +use Symfony\Component\Routing\Route; +use Symfony\Component\HttpFoundation\Request; + +/** + * Access protection against CSRF attacks. + */ +class CsrfRequestHeaderAccessCheck implements AccessCheckInterface { + + /** + * A string key that will used to designate the token used by this class. + */ + const TOKEN_KEY = 'X-CSRF-Token request header'; + + /** + * The session configuration. + * + * @var \Drupal\Core\Session\SessionConfigurationInterface + */ + protected $sessionConfiguration; + + /** + * The token generator. + * + * @var \Drupal\Core\Access\CsrfTokenGenerator + */ + protected $csrfToken; + + /** + * Constructs a new rest CSRF access check. + * + * @param \Drupal\Core\Session\SessionConfigurationInterface $session_configuration + * The session configuration. + * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token + * The token generator. + */ + public function __construct(SessionConfigurationInterface $session_configuration, CsrfTokenGenerator $csrf_token) { + $this->sessionConfiguration = $session_configuration; + $this->csrfToken = $csrf_token; + } + + /** + * {@inheritdoc} + */ + public function applies(Route $route) { + $requirements = $route->getRequirements(); + // Check for current requirement _csrf_request_header_token and deprecated + // REST requirement. + $applicable_requirements = [ + '_csrf_request_header_token', + // @todo Remove _access_rest_csrf in Drupal 9.0.0. + '_access_rest_csrf', + ]; + $requirement_keys = array_keys($requirements); + + if (array_intersect($applicable_requirements, $requirement_keys)) { + if (isset($requirements['_method'])) { + // There could be more than one method requirement separated with '|'. + $methods = explode('|', $requirements['_method']); + // CSRF protection only applies to write operations, so we can filter + // out any routes that require reading methods only. + $write_methods = array_diff($methods, ['GET', 'HEAD', 'OPTIONS', 'TRACE']); + if (empty($write_methods)) { + return FALSE; + } + } + // No method requirement given, so we run this access check to be on the + // safe side. + return TRUE; + } + } + + /** + * Checks access. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * @param \Drupal\Core\Session\AccountInterface $account + * The currently logged in account. + * + * @return \Drupal\Core\Access\AccessResultInterface + * The access result. + */ + public function access(Request $request, AccountInterface $account) { + $method = $request->getMethod(); + + // This check only applies if + // 1. this is a write operation + // 2. the user was successfully authenticated and + // 3. the request comes with a session cookie. + if (!in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE']) + && $account->isAuthenticated() + && $this->sessionConfiguration->hasSession($request) + ) { + if (!$request->headers->has('X-CSRF-Token')) { + return AccessResult::forbidden()->setReason('X-CSRF-Token request header is missing')->setCacheMaxAge(0); + } + $csrf_token = $request->headers->get('X-CSRF-Token'); + // @todo Remove validate call using 'rest' in 8.3. + // Kept here for sessions active during update. + if (!$this->csrfToken->validate($csrf_token, self::TOKEN_KEY) + && !$this->csrfToken->validate($csrf_token, 'rest')) { + return AccessResult::forbidden()->setReason('X-CSRF-Token request header is invalid')->setCacheMaxAge(0); + } + } + // Let other access checkers decide if the request is legit. + return AccessResult::allowed()->setCacheMaxAge(0); + } + +}