Commit 304d50a7 authored by alexpott's avatar alexpott

Issue #2330279 by znerol: Fixed When operating in mixed mode SSL: data from...

Issue #2330279 by znerol: Fixed When operating in mixed mode SSL: data from anonymous non-HTTP session is still available after login.
parent a782ad53
...@@ -40,6 +40,13 @@ class SessionHandler extends AbstractProxy implements \SessionHandlerInterface { ...@@ -40,6 +40,13 @@ class SessionHandler extends AbstractProxy implements \SessionHandlerInterface {
*/ */
protected $connection; protected $connection;
/**
* An associative array of obsolete sessions with session id as key, and db-key as value.
*
* @var array
*/
protected $obsoleteSessionIds = array();
/** /**
* Constructs a new SessionHandler instance. * Constructs a new SessionHandler instance.
* *
...@@ -94,9 +101,12 @@ public function read($sid) { ...@@ -94,9 +101,12 @@ public function read($sid) {
// Fallback and try to load the anonymous non-HTTPS session. Use the // Fallback and try to load the anonymous non-HTTPS session. Use the
// non-HTTPS session id as the key. // non-HTTPS session id as the key.
if ($cookies->has($insecure_session_name)) { if ($cookies->has($insecure_session_name)) {
$values = $this->connection->query("SELECT u.*, s.* FROM {users_field_data} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE u.default_langcode = 1 AND s.sid = :sid AND s.uid = 0", array( $insecure_session_id = $cookies->get($insecure_session_name);
':sid' => Crypt::hashBase64($cookies->get($insecure_session_name)), $args = array(':sid' => Crypt::hashBase64($insecure_session_id));
))->fetchAssoc(); $values = $this->connection->query("SELECT u.*, s.* FROM {users_field_data} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE u.default_langcode = 1 AND s.sid = :sid AND s.uid = 0", $args)->fetchAssoc();
if ($values) {
$this->sessionSetObsolete($insecure_session_id);
}
} }
} }
} }
...@@ -181,6 +191,9 @@ public function write($sid, $value) { ...@@ -181,6 +191,9 @@ public function write($sid, $value) {
->fields($fields) ->fields($fields)
->execute(); ->execute();
// Remove obsolete sessions.
$this->cleanupObsoleteSessions();
// Likewise, do not update access time more than once per 180 seconds. // Likewise, do not update access time more than once per 180 seconds.
if ($user->isAuthenticated() && REQUEST_TIME - $user->getLastAccessedTime() > Settings::get('session_write_interval', 180)) { if ($user->isAuthenticated() && REQUEST_TIME - $user->getLastAccessedTime() > Settings::get('session_write_interval', 180)) {
/** @var \Drupal\user\UserStorageInterface $storage */ /** @var \Drupal\user\UserStorageInterface $storage */
...@@ -237,6 +250,10 @@ public function destroy($sid) { ...@@ -237,6 +250,10 @@ public function destroy($sid) {
elseif ($this->sessionManager->isMixedMode()) { elseif ($this->sessionManager->isMixedMode()) {
$this->deleteCookie('S' . $this->getName(), TRUE); $this->deleteCookie('S' . $this->getName(), TRUE);
} }
// Remove obsolete sessions.
$this->cleanupObsoleteSessions();
return TRUE; return TRUE;
} }
...@@ -275,4 +292,22 @@ protected function deleteCookie($name, $secure = NULL) { ...@@ -275,4 +292,22 @@ protected function deleteCookie($name, $secure = NULL) {
} }
} }
/**
* Mark a session for garbage collection upon session save.
*/
protected function sessionSetObsolete($sid, $https = FALSE) {
$this->obsoleteSessionIds[$sid] = $https ? 'ssid' : 'sid';
}
/**
* Remove sessions marked for garbage collection.
*/
protected function cleanupObsoleteSessions() {
foreach ($this->obsoleteSessionIds as $sid => $key) {
$this->connection->delete('sessions')
->condition($key, Crypt::hashBase64($sid))
->execute();
}
}
} }
...@@ -241,9 +241,6 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) { ...@@ -241,9 +241,6 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) {
if ($is_https && $this->isMixedMode()) { if ($is_https && $this->isMixedMode()) {
$insecure_session_name = $this->getInsecureName(); $insecure_session_name = $this->getInsecureName();
if ($this->isStarted() && $cookies->has($insecure_session_name)) {
$old_insecure_session_id = $cookies->get($insecure_session_name);
}
$params = session_get_cookie_params(); $params = session_get_cookie_params();
$session_id = Crypt::randomBytesBase64(); $session_id = Crypt::randomBytesBase64();
// If a session cookie lifetime is set, the session will expire // If a session cookie lifetime is set, the session will expire
...@@ -279,16 +276,8 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) { ...@@ -279,16 +276,8 @@ public function regenerate($destroy = FALSE, $lifetime = NULL) {
->condition($is_https ? 'ssid' : 'sid', Crypt::hashBase64($old_session_id)) ->condition($is_https ? 'ssid' : 'sid', Crypt::hashBase64($old_session_id))
->execute(); ->execute();
} }
elseif (isset($old_insecure_session_id)) {
// If logging in to the secure site, and there was no active session on if (!$this->isStarted()) {
// the secure site but a session was active on the insecure site, update
// the insecure session with the new session identifiers.
$this->connection->update('sessions')
->fields(array('sid' => Crypt::hashBase64($session_id), 'ssid' => Crypt::hashBase64($this->getId())))
->condition('sid', Crypt::hashBase64($old_insecure_session_id))
->execute();
}
else {
// Start the session when it doesn't exist yet. // Start the session when it doesn't exist yet.
// Preserve the logged in user, as it will be reset to anonymous // Preserve the logged in user, as it will be reset to anonymous
// by \Drupal\Core\Session\SessionHandler::read(). // by \Drupal\Core\Session\SessionHandler::read().
......
...@@ -200,7 +200,7 @@ protected function testMixedModeSslSession() { ...@@ -200,7 +200,7 @@ protected function testMixedModeSslSession() {
// Test that session data saved before login is not available using the // Test that session data saved before login is not available using the
// pre-login anonymous cookie. // pre-login anonymous cookie.
$this->cookies = array(); $this->cookies = array();
$this->drupalGet('session-test/get', array('Cookie: ' . $anonymous_cookie)); $this->drupalGet('session-test/get', array(), array('Cookie: ' . $anonymous_cookie));
$this->assertNoText($session_data, 'Initial anonymous session is inactive after login.'); $this->assertNoText($session_data, 'Initial anonymous session is inactive after login.');
// Clear browser cookie jar. // Clear browser cookie jar.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment