SessionConfiguration.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. namespace Drupal\Core\Session;
  3. use Symfony\Component\HttpFoundation\Request;
  4. /**
  5. * Defines the default session configuration generator.
  6. */
  7. class SessionConfiguration implements SessionConfigurationInterface {
  8. /**
  9. * An associative array of session ini settings.
  10. */
  11. protected $options;
  12. /**
  13. * Constructs a new session configuration instance.
  14. *
  15. * @param array $options
  16. * An associative array of session ini settings.
  17. *
  18. * @see \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage::__construct()
  19. * @see http://php.net/manual/session.configuration.php
  20. */
  21. public function __construct($options = []) {
  22. $this->options = $options;
  23. }
  24. /**
  25. * {@inheritdoc}
  26. */
  27. public function hasSession(Request $request) {
  28. return $request->cookies->has($this->getName($request));
  29. }
  30. /**
  31. * {@inheritdoc}
  32. */
  33. public function getOptions(Request $request) {
  34. $options = $this->options;
  35. // Generate / validate the cookie domain.
  36. $options['cookie_domain'] = $this->getCookieDomain($request) ?: '';
  37. // If the site is accessed via SSL, ensure that the session cookie is
  38. // issued with the secure flag.
  39. $options['cookie_secure'] = $request->isSecure();
  40. // Set the session cookie name.
  41. $options['name'] = $this->getName($request);
  42. return $options;
  43. }
  44. /**
  45. * Returns the session cookie name.
  46. *
  47. * @param \Symfony\Component\HttpFoundation\Request $request
  48. * The request.
  49. *
  50. * @return string
  51. * The name of the session cookie.
  52. */
  53. protected function getName(Request $request) {
  54. // To prevent session cookies from being hijacked, a user can configure the
  55. // SSL version of their website to only transfer session cookies via SSL by
  56. // using PHP's session.cookie_secure setting. The browser will then use two
  57. // separate session cookies for the HTTPS and HTTP versions of the site. So
  58. // we must use different session identifiers for HTTPS and HTTP to prevent a
  59. // cookie collision.
  60. $prefix = $request->isSecure() ? 'SSESS' : 'SESS';
  61. return $prefix . $this->getUnprefixedName($request);
  62. }
  63. /**
  64. * Returns the session cookie name without the secure/insecure prefix.
  65. *
  66. * @param \Symfony\Component\HttpFoundation\Request $request
  67. * The request.
  68. *
  69. * @returns string
  70. * The session name without the prefix (SESS/SSESS).
  71. */
  72. protected function getUnprefixedName(Request $request) {
  73. if ($test_prefix = $this->drupalValidTestUa()) {
  74. $session_name = $test_prefix;
  75. }
  76. elseif (isset($this->options['cookie_domain'])) {
  77. // If the user specifies the cookie domain, also use it for session name.
  78. $session_name = $this->options['cookie_domain'];
  79. }
  80. else {
  81. // Otherwise use $base_url as session name, without the protocol
  82. // to use the same session identifiers across HTTP and HTTPS.
  83. $session_name = $request->getHost() . $request->getBasePath();
  84. // Replace "core" out of session_name so core scripts redirect properly,
  85. // specifically install.php.
  86. $session_name = preg_replace('#/core$#', '', $session_name);
  87. }
  88. return substr(hash('sha256', $session_name), 0, 32);
  89. }
  90. /**
  91. * Return the session cookie domain.
  92. *
  93. * The Set-Cookie response header and its domain attribute are defined in RFC
  94. * 2109, RFC 2965 and RFC 6265 each one superseding the previous version.
  95. *
  96. * @see http://tools.ietf.org/html/rfc2109
  97. * @see http://tools.ietf.org/html/rfc2965
  98. * @see http://tools.ietf.org/html/rfc6265
  99. *
  100. * @param \Symfony\Component\HttpFoundation\Request $request
  101. * The request.
  102. *
  103. * @returns string
  104. * The session cookie domain.
  105. */
  106. protected function getCookieDomain(Request $request) {
  107. if (isset($this->options['cookie_domain'])) {
  108. $cookie_domain = $this->options['cookie_domain'];
  109. }
  110. else {
  111. $host = $request->getHost();
  112. // To maximize compatibility and normalize the behavior across user
  113. // agents, the cookie domain should start with a dot.
  114. $cookie_domain = '.' . $host;
  115. }
  116. // Cookies for domains without an embedded dot will be rejected by user
  117. // agents in order to defeat malicious websites attempting to set cookies
  118. // for top-level domains. Also IP addresses may not be used in the domain
  119. // attribute of a Set-Cookie header.
  120. if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
  121. return $cookie_domain;
  122. }
  123. }
  124. /**
  125. * Wraps drupal_valid_test_ua().
  126. *
  127. * @return string|false
  128. * Either the simpletest prefix (the string "simpletest" followed by any
  129. * number of digits) or FALSE if the user agent does not contain a valid
  130. * HMAC and timestamp.
  131. */
  132. protected function drupalValidTestUa() {
  133. return drupal_valid_test_ua();
  134. }
  135. }