diff --git a/core/core.services.yml b/core/core.services.yml index 7fa6be4..0ad8be5 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -721,7 +721,7 @@ services: arguments: ['@authentication', '@request'] session_manager: class: Drupal\Core\Session\SessionManager - arguments: ['@request_stack', '@database', '@session_manager.metadata_bag'] + arguments: ['@request_stack', '@database', '@session_manager.metadata_bag', '@settings'] tags: - { name: persist } session_manager.metadata_bag: diff --git a/core/lib/Drupal/Core/Session/SessionHandler.php b/core/lib/Drupal/Core/Session/SessionHandler.php index 873df04..71e7302 100644 --- a/core/lib/Drupal/Core/Session/SessionHandler.php +++ b/core/lib/Drupal/Core/Session/SessionHandler.php @@ -71,7 +71,7 @@ public function read($sid) { // Handle the case of first time visitors and clients that don't store // cookies (eg. web crawlers). - $insecure_session_name = substr($this->getName(), 1); + $insecure_session_name = $this->sessionManager->getInsecureName(); $cookies = $this->requestStack->getCurrentRequest()->cookies; if (!$cookies->has($this->getName()) && !$cookies->has($insecure_session_name)) { $user = new UserSession(); @@ -166,14 +166,14 @@ public function write($sid, $value) { // secure and insecure session cookies. If enabled and both cookies // are presented then use both keys. The session ID from the cookie is // hashed before being stored in the database as a security measure. - if (Settings::get('mixed_mode_sessions', FALSE)) { - $insecure_session_name = substr($this->getName(), 1); + if ($this->sessionManager->isMixedMode()) { + $insecure_session_name = $this->sessionManager->getInsecureName(); if ($cookies->has($insecure_session_name)) { $key['sid'] = Crypt::hashBase64($cookies->get($insecure_session_name)); } } } - elseif (Settings::get('mixed_mode_sessions', FALSE)) { + elseif ($this->sessionManager->isMixedMode()) { unset($key['ssid']); } $this->connection->merge('sessions') @@ -235,9 +235,9 @@ public function destroy($sid) { // Unset the session cookies. $this->deleteCookie($this->getName()); if ($is_https) { - $this->deleteCookie(substr($this->getName(), 1), FALSE); + $this->deleteCookie($this->sessionManager->getInsecureName(), FALSE); } - elseif (Settings::get('mixed_mode_sessions', FALSE)) { + elseif ($this->sessionManager->isMixedMode()) { $this->deleteCookie('S' . $this->getName(), TRUE); } return TRUE; diff --git a/core/lib/Drupal/Core/Session/SessionManager.php b/core/lib/Drupal/Core/Session/SessionManager.php index 75174f7..f0e25b1 100644 --- a/core/lib/Drupal/Core/Session/SessionManager.php +++ b/core/lib/Drupal/Core/Session/SessionManager.php @@ -23,6 +23,13 @@ class SessionManager extends NativeSessionStorage implements SessionManagerInterface { /** + * Whether or not the session manager is operating in mixed mode SSL. + * + * @var bool + */ + protected $mixedMode; + + /** * The request stack. * * @var \Symfony\Component\HttpFoundation\RequestStack @@ -70,13 +77,17 @@ class SessionManager extends NativeSessionStorage implements SessionManagerInter * The database connection. * @param \Symfony\Component\HttpFoundation\Session\Storage\MetadataBag $metadata_bag * The session metadata bag. + * @param \Drupal\Component\Utility\Settings $settings + * The settings instance. */ - public function __construct(RequestStack $request_stack, Connection $connection, SymfonyMetadataBag $metadata_bag) { + public function __construct(RequestStack $request_stack, Connection $connection, SymfonyMetadataBag $metadata_bag, Settings $settings) { parent::__construct(); $this->requestStack = $request_stack; $this->connection = $connection; $this->setMetadataBag($metadata_bag); + $this->setMixedMode($settings->get('mixed_mode_sessions', FALSE)); + // @todo: When not using the Symfony Session object, the list of bags in the // NativeSessionStorage will remain uninitialized. This will lead to errors // in NativeSessionHandler::loadSession. Remove this as soon as we are using @@ -99,7 +110,8 @@ public function initialize() { $is_https = $this->requestStack->getCurrentRequest()->isSecure(); $cookies = $this->requestStack->getCurrentRequest()->cookies; - if (($cookies->has($this->getName()) && ($session_name = $cookies->get($this->getName()))) || ($is_https && Settings::get('mixed_mode_sessions', FALSE) && ($cookies->has(substr($this->getName(), 1))) && ($session_name = $cookies->get(substr($this->getName(), 1))))) { + $insecure_session_name = $this->getInsecureName(); + if (($cookies->has($this->getName()) && ($session_name = $cookies->get($this->getName()))) || ($is_https && $this->isMixedMode() && ($cookies->has($insecure_session_name) && ($session_name = $cookies->get($insecure_session_name))))) { // If a session cookie exists, initialize the session. Otherwise the // session is only started on demand in save(), making // anonymous users not use a session cookie unless something is stored in @@ -117,8 +129,7 @@ public function initialize() { $this->lazySession = TRUE; $user = new AnonymousUserSession(); $this->setId(Crypt::randomBytesBase64()); - if ($is_https && Settings::get('mixed_mode_sessions', FALSE)) { - $insecure_session_name = substr($this->getName(), 1); + if ($is_https && $this->isMixedMode()) { $session_id = Crypt::randomBytesBase64(); $cookies->set($insecure_session_name, $session_id); } @@ -170,8 +181,8 @@ public function save() { // started. if (!$this->isStarted()) { $this->start(); - if ($this->requestStack->getCurrentRequest()->isSecure() && Settings::get('mixed_mode_sessions', FALSE)) { - $insecure_session_name = substr($this->getName(), 1); + if ($this->requestStack->getCurrentRequest()->isSecure() && $this->isMixedMode()) { + $insecure_session_name = $this->getInsecureName(); $params = session_get_cookie_params(); $expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0; $cookie_params = $this->requestStack->getCurrentRequest()->cookies; @@ -203,15 +214,15 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) { // We do not support the optional $destroy and $lifetime parameters as long // as #2238561 remains open. - if ($destroy || isset($options)) { + if ($destroy || isset($lifetime)) { throw new \InvalidArgumentException('The optional parameters $destroy and $lifetime of SessionManager::regenerate() are not supported currently'); } $is_https = $this->requestStack->getCurrentRequest()->isSecure(); $cookies = $this->requestStack->getCurrentRequest()->cookies; - if ($is_https && Settings::get('mixed_mode_sessions', FALSE)) { - $insecure_session_name = substr($this->getName(), 1); + if ($is_https && $this->isMixedMode()) { + $insecure_session_name = $this->getInsecureName(); if (!isset($this->lazySession) && $cookies->has($insecure_session_name)) { $old_insecure_session_id = $cookies->get($insecure_session_name); } @@ -239,7 +250,7 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) { $fields['ssid'] = Crypt::hashBase64($this->getId()); // If the "secure pages" setting is enabled, use the newly-created // insecure session identifier as the regenerated sid. - if (Settings::get('mixed_mode_sessions', FALSE)) { + if ($this->isMixedMode()) { $fields['sid'] = Crypt::hashBase64($session_id); } } @@ -305,6 +316,27 @@ public function enable() { } /** + * {@inheritdoc} + */ + public function isMixedMode() { + return $this->mixedMode; + } + + /** + * {@inheritdoc} + */ + public function setMixedMode($mixed_mode) { + $this->mixedMode = (bool) $mixed_mode; + } + + /** + * {@inheritdoc} + */ + public function getInsecureName() { + return substr($this->getName(), 1); + } + + /** * Returns whether the current PHP process runs on CLI. * * Command line clients do not support cookies nor sessions. diff --git a/core/lib/Drupal/Core/Session/SessionManagerInterface.php b/core/lib/Drupal/Core/Session/SessionManagerInterface.php index 82e1952..0d06b05 100644 --- a/core/lib/Drupal/Core/Session/SessionManagerInterface.php +++ b/core/lib/Drupal/Core/Session/SessionManagerInterface.php @@ -57,4 +57,24 @@ public function disable(); */ public function enable(); + /** + * Return whether mixed mode SSL sessions are enabled in the session manager. + * + * @return bool + * Value of the mixed mode SSL sessions flag. + */ + public function isMixedMode(); + + /** + * Whether or not to enable mixed mode SSL sessions in the session manager. + * + * @param bool $mixed_mode + * New value for the mixed mode SSL sessions flag. + */ + public function setMixedMode($mixed_mode); + + /** + * The name of the insecure session when operating in mixed mode SSL. + */ + public function getInsecureName(); }