Upgraded drupal core with security updates
[yaffs-website] / web / core / lib / Drupal / Core / Access / CsrfRequestHeaderAccessCheck.php
1 <?php
2
3 namespace Drupal\Core\Access;
4
5 use Drupal\Core\Session\AccountInterface;
6 use Drupal\Core\Session\SessionConfigurationInterface;
7 use Symfony\Component\Routing\Route;
8 use Symfony\Component\HttpFoundation\Request;
9
10 /**
11  * Access protection against CSRF attacks.
12  */
13 class CsrfRequestHeaderAccessCheck implements AccessCheckInterface {
14
15   /**
16    * A string key that will used to designate the token used by this class.
17    */
18   const TOKEN_KEY = 'X-CSRF-Token request header';
19
20   /**
21    * The session configuration.
22    *
23    * @var \Drupal\Core\Session\SessionConfigurationInterface
24    */
25   protected $sessionConfiguration;
26
27   /**
28    * The token generator.
29    *
30    * @var \Drupal\Core\Access\CsrfTokenGenerator
31    */
32   protected $csrfToken;
33
34   /**
35    * Constructs a new rest CSRF access check.
36    *
37    * @param \Drupal\Core\Session\SessionConfigurationInterface $session_configuration
38    *   The session configuration.
39    * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
40    *   The token generator.
41    */
42   public function __construct(SessionConfigurationInterface $session_configuration, CsrfTokenGenerator $csrf_token) {
43     $this->sessionConfiguration = $session_configuration;
44     $this->csrfToken = $csrf_token;
45   }
46
47   /**
48    * {@inheritdoc}
49    */
50   public function applies(Route $route) {
51     $requirements = $route->getRequirements();
52     // Check for current requirement _csrf_request_header_token and deprecated
53     // REST requirement.
54     $applicable_requirements = [
55       '_csrf_request_header_token',
56       // @todo Remove _access_rest_csrf in Drupal 9.0.0.
57       '_access_rest_csrf',
58     ];
59     $requirement_keys = array_keys($requirements);
60
61     if (array_intersect($applicable_requirements, $requirement_keys)) {
62       if (isset($requirements['_method'])) {
63         // There could be more than one method requirement separated with '|'.
64         $methods = explode('|', $requirements['_method']);
65         // CSRF protection only applies to write operations, so we can filter
66         // out any routes that require reading methods only.
67         $write_methods = array_diff($methods, ['GET', 'HEAD', 'OPTIONS', 'TRACE']);
68         if (empty($write_methods)) {
69           return FALSE;
70         }
71       }
72       // No method requirement given, so we run this access check to be on the
73       // safe side.
74       return TRUE;
75     }
76   }
77
78   /**
79    * Checks access.
80    *
81    * @param \Symfony\Component\HttpFoundation\Request $request
82    *   The request object.
83    * @param \Drupal\Core\Session\AccountInterface $account
84    *   The currently logged in account.
85    *
86    * @return \Drupal\Core\Access\AccessResultInterface
87    *   The access result.
88    */
89   public function access(Request $request, AccountInterface $account) {
90     $method = $request->getMethod();
91
92     // This check only applies if
93     // 1. this is a write operation
94     // 2. the user was successfully authenticated and
95     // 3. the request comes with a session cookie.
96     if (!in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE'])
97       && $account->isAuthenticated()
98       && $this->sessionConfiguration->hasSession($request)
99     ) {
100       if (!$request->headers->has('X-CSRF-Token')) {
101         return AccessResult::forbidden()->setReason('X-CSRF-Token request header is missing')->setCacheMaxAge(0);
102       }
103       $csrf_token = $request->headers->get('X-CSRF-Token');
104       // @todo Remove validate call using 'rest' in 8.3.
105       //   Kept here for sessions active during update.
106       if (!$this->csrfToken->validate($csrf_token, self::TOKEN_KEY)
107         && !$this->csrfToken->validate($csrf_token, 'rest')) {
108         return AccessResult::forbidden()->setReason('X-CSRF-Token request header is invalid')->setCacheMaxAge(0);
109       }
110     }
111     // Let other access checkers decide if the request is legit.
112     return AccessResult::allowed()->setCacheMaxAge(0);
113   }
114
115 }