thomascube
2007-03-27 aad6e2a9c4857715c8bd56693d21b87dd0c16263
New session authentication, should fix bugs #1483951 and #1484299; testing required

6 files modified
109 ■■■■ changed files
CHANGELOG 6 ●●●●● patch | view | raw | blame | history
UPGRADING 1 ●●●● patch | view | raw | blame | history
config/main.inc.php.dist 6 ●●●● patch | view | raw | blame | history
index.php 16 ●●●●● patch | view | raw | blame | history
program/include/main.inc 43 ●●●●● patch | view | raw | blame | history
program/include/session.inc 37 ●●●●● patch | view | raw | blame | history
CHANGELOG
@@ -1,6 +1,12 @@
CHANGELOG RoundCube Webmail
---------------------------
2007/03/27 (thomasb)
----------
- New session authentication: Change sessid cookie when login, authentication with sessauth cookie is now configurable.
  Should close bugs #1483951 and #1484299
2007/03/23 (thomasb)
----------
- Correctly translate mailbox names (closes #1484276)
UPGRADING
@@ -16,6 +16,7 @@
  $rcmail_config['htmleditor'] = TRUE;
  $rcmail_config['preview_pane'] = TRUE;
  $rcmail_config['date_today'] = 'H:i';
  $rcmail_config['double_auth'] = TRUE;
form version 0.1-beta
config/main.inc.php.dist
@@ -97,7 +97,11 @@
$rcmail_config['session_lifetime'] = 10;
// check client IP in session athorization
$rcmail_config['ip_check'] = TRUE;
$rcmail_config['ip_check'] = false;
// Use an additional frequently changing cookie to athenticate user sessions.
// There have been problems reported with this feature.
$rcmail_config['double_auth'] = false;
// this key is used to encrypt the users imap password which is stored
// in the session record (and the client cookie if remember password is enabled).
index.php
@@ -2,7 +2,7 @@
/*
 +-----------------------------------------------------------------------+
 | RoundCube Webmail IMAP Client                                         |
 | Version 0.1-20070301                                                  |
 | Version 0.1-20070327                                                  |
 |                                                                       |
 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
 | Licensed under the GNU GPL                                            |
@@ -40,7 +40,7 @@
*/
define('RCMAIL_VERSION', '0.1-20070301');
define('RCMAIL_VERSION', '0.1-20070327');
// define global vars
$CHARSET = 'UTF-8';
@@ -172,10 +172,17 @@
    {
    show_message("cookiesdisabled", 'warning');
    }
  else if (isset($_POST['_user']) && isset($_POST['_pass']) &&
  else if ($_SESSION['temp'] && isset($_POST['_user']) && isset($_POST['_pass']) &&
           rcmail_login(get_input_value('_user', RCUBE_INPUT_POST),
              get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host))
    {
    // create new session ID
    unset($_SESSION['temp']);
    sess_regenerate_id();
    // send auth cookie if necessary
    rcmail_authenticate_session();
    // send redirect
    header("Location: $COMM_PATH");
    exit;
@@ -197,8 +204,7 @@
// check session and auth cookie
else if ($_action != 'login' && $_SESSION['user_id'] && $_action != 'send')
  {
  if (!rcmail_authenticate_session() ||
      (!empty($CONFIG['session_lifetime']) && isset($SESS_CHANGED) && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < mktime()))
  if (!rcmail_authenticate_session())
    {
    $message = show_message('sessionerror', 'error');
    rcmail_kill_session();
program/include/main.inc
@@ -33,7 +33,7 @@
// register session and connect to server
function rcmail_startup($task='mail')
  {
  global $sess_id, $sess_auth, $sess_user_lang;
  global $sess_id, $sess_user_lang;
  global $CONFIG, $INSTALL_PATH, $BROWSER, $OUTPUT, $_SESSION, $IMAP, $DB, $JS_OBJECT_NAME;
  // check client
@@ -53,9 +53,8 @@
  $DB->sqlite_initials = $INSTALL_PATH.'SQL/sqlite.initial.sql';
  $DB->db_connect('w');
  // we can use the database for storing session data
  if (!$DB->is_error())
    include_once('include/session.inc');
  // use database for storing session data
  include_once('include/session.inc');
  // init session
  session_start();
@@ -65,8 +64,8 @@
  if (!isset($_SESSION['auth_time']))
    {
    $_SESSION['user_lang'] = rcube_language_prop($CONFIG['locale_string']);
    $_SESSION['auth_time'] = mktime();
    setcookie('sessauth', rcmail_auth_hash($sess_id, $_SESSION['auth_time']));
    $_SESSION['auth_time'] = time();
    $_SESSION['temp'] = true;
    }
  // set session vars global
@@ -178,17 +177,29 @@
// compare the auth hash sent by the client with the local session credentials
function rcmail_authenticate_session()
  {
  $now = mktime();
  $valid = ($_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['auth_time']) ||
                        $_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['last_auth']));
  global $CONFIG, $SESS_CLIENT_IP, $SESS_CHANGED;
  // advanced session authentication
  if ($CONFIG['double_auth'])
  {
    $now = time();
    $valid = ($_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['auth_time']) ||
              $_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['last_auth']));
  // renew auth cookie every 5 minutes (only for GET requests)
  if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now-$_SESSION['auth_time'] > 300))
    // renew auth cookie every 5 minutes (only for GET requests)
    if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now-$_SESSION['auth_time'] > 300))
    {
    $_SESSION['last_auth'] = $_SESSION['auth_time'];
    $_SESSION['auth_time'] = $now;
    setcookie('sessauth', rcmail_auth_hash(session_id(), $now));
      $_SESSION['last_auth'] = $_SESSION['auth_time'];
      $_SESSION['auth_time'] = $now;
      setcookie('sessauth', rcmail_auth_hash(session_id(), $now));
    }
  }
  else
    $valid = $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] == $SESS_CLIENT_IP : true;
  // check session filetime
  if (!empty($CONFIG['session_lifetime']) && isset($SESS_CHANGED) && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < time())
    $valid = false;
  return $valid;
  }
@@ -275,8 +286,8 @@
    rcmail_save_user_prefs($a_user_prefs);
    }
  $_SESSION = array();
  session_destroy();
  $_SESSION = array('user_lang' => $GLOBALS['sess_user_lang'], 'auth_time' => time(), 'temp' => true);
  setcookie('sessauth', '-del-', time()-60);
  }
program/include/session.inc
@@ -36,7 +36,10 @@
// read session data
function sess_read($key)
  {
  global $DB, $SESS_CHANGED;
  global $DB, $SESS_CHANGED, $SESS_CLIENT_IP;
  if ($DB->is_error())
    return FALSE;
  
  $sql_result = $DB->query("SELECT vars, ip, ".$DB->unixtimestamp('changed')." AS changed
                            FROM ".get_table_name('session')."
@@ -46,6 +49,7 @@
  if ($sql_arr = $DB->fetch_assoc($sql_result))
    {
    $SESS_CHANGED = $sql_arr['changed'];
    $SESS_CLIENT_IP = $sql_arr['ip'];
    if (strlen($sql_arr['vars']))
      return $sql_arr['vars'];
@@ -59,6 +63,9 @@
function sess_write($key, $vars)
  {
  global $DB;
  if ($DB->is_error())
    return FALSE;
  $sql_result = $DB->query("SELECT 1
                            FROM ".get_table_name('session')."
@@ -96,6 +103,9 @@
  {
  global $DB;
  
  if ($DB->is_error())
    return FALSE;
  // delete session entries in cache table
  $DB->query("DELETE FROM ".get_table_name('cache')."
              WHERE  session_id=?",
@@ -113,6 +123,9 @@
function sess_gc($maxlifetime)
  {
  global $DB;
  if ($DB->is_error())
    return FALSE;
  // get all expired sessions  
  $sql_result = $DB->query("SELECT sess_id
@@ -144,6 +157,28 @@
  }
function sess_regenerate_id()
  {
  $randlen = 32;
  $randval = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  $random = "";
  for ($i=1; $i <= $randlen; $i++)
    $random .= substr($randval, rand(0,(strlen($randval) - 1)), 1);
  // use md5 value for id or remove capitals from string $randval
  $random = md5($random);
  // delete old session record
  sess_destroy(session_id());
  session_id($random);
  $cookie = session_get_cookie_params();
  setcookie(session_name(), $random, $cookie['lifetime'], $cookie['path']);
  return true;
  }
// set custom functions for PHP session management
session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');