From 139b1efb291c0ae9263091125e9f32512be999f1 Mon Sep 17 00:00:00 2001
From: Peter Philipp <peter.philipp@cando-image.com>
Date: Fri, 11 Nov 2011 08:48:11 +0100
Subject: [PATCH] Issue #1131986 by das-peter, Damien Tournoud, pisco, akaoni:
 Session handling fails on multiple switches between http /
 https

---
 core/includes/session.inc |   27 +++++++++++++++++++++------
 1 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/core/includes/session.inc b/core/includes/session.inc
index df70f0e..ef8a0e5 100644
--- a/core/includes/session.inc
+++ b/core/includes/session.inc
@@ -100,7 +100,14 @@ function _drupal_session_read($sid) {
   }
   else {
     $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid", array(':sid' => $sid))->fetchObject();
+
+    // If the user once was stepped up to https don't allow a stepdown
+    if (!empty($user->ssid)) {
+      require_once DRUPAL_ROOT . '/core/includes/common.inc';
+      drupal_goto($_GET['q'], array('https' => TRUE, 'alias' => TRUE));
+    }
   }
+  $ssid = (!empty($user->ssid) ? $user->ssid : NULL);
 
   // We found the client's session record and they are an authenticated,
   // active user.
@@ -131,6 +138,7 @@ function _drupal_session_read($sid) {
   $last_read = &drupal_static('drupal_session_last_read');
   $last_read = array(
     'sid' => $sid,
+    'ssid' => $ssid,
     'value' => $user->session,
   );
 
@@ -168,7 +176,7 @@ function _drupal_session_write($sid, $value) {
 
     // Check whether $_SESSION has been changed in this request.
     $last_read = &drupal_static('drupal_session_last_read');
-    $is_changed = !isset($last_read) || $last_read['sid'] != $sid || $last_read['value'] !== $value;
+    $is_changed = !isset($last_read) || $last_read['sid'] != $sid || (empty($last_read['ssid']) && $is_https) || $last_read['value'] !== $value;
 
     // For performance reasons, do not update the sessions table, unless
     // $_SESSION has changed or more than 180 has passed since the last update.
@@ -182,10 +190,9 @@ function _drupal_session_write($sid, $value) {
         'timestamp' => REQUEST_TIME,
       );
 
-      // Use the session ID as 'sid' and an empty string as 'ssid' by default.
-      // _drupal_session_read() does not allow empty strings so that's a safe
-      // default.
-      $key = array('sid' => $sid, 'ssid' => '');
+      // Use the session ID as 'sid' without setting a 'ssid' by default to
+      // prevent a duplication when stepping down from https to http.
+      $key = array('sid' => $sid);
       // On HTTPS connections, use the session ID as both 'sid' and 'ssid'.
       if ($is_https) {
         $key['ssid'] = $sid;
@@ -196,6 +203,14 @@ function _drupal_session_write($sid, $value) {
           $insecure_session_name = substr(session_name(), 1);
           if (isset($_COOKIE[$insecure_session_name])) {
             $key['sid'] = $_COOKIE[$insecure_session_name];
+            // If this is the initial setup of the secure session, don't use the
+            // 'ssid' as key since it doesn't exist yet. But make sure it's set.
+            if (!isset($_COOKIE[session_name()])) {
+              // Save the secure session id.
+              $fields['ssid'] = $sid;
+              // Don't use 'ssid' as key.
+              $key['ssid'] = '';
+            }
           }
         }
       }
@@ -490,4 +505,4 @@ function drupal_save_session($status = NULL) {
     $save_session = $status;
   }
   return $save_session;
-}
+}
\ No newline at end of file
-- 
1.7.7.msysgit.1

