From: skodak Date: Sun, 18 Jan 2009 18:00:44 +0000 (+0000) Subject: MDL-17942 more session refactoring X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=e8656befac1ad4719024a1d760f4706b49f8172b;p=moodle.git MDL-17942 more session refactoring --- diff --git a/admin/auth.php b/admin/auth.php index caed90baeb..7115ff04cf 100644 --- a/admin/auth.php +++ b/admin/auth.php @@ -52,7 +52,7 @@ switch ($action) { if ($auth == $CFG->registerauth) { set_config('registerauth', ''); } - session_get_instance()->gc(); // remove stale sessions + session_gc(); // remove stale sessions break; case 'enable': @@ -62,7 +62,7 @@ switch ($action) { $authsenabled = array_unique($authsenabled); set_config('auth', implode(',', $authsenabled)); } - session_get_instance()->gc(); // remove stale sessions + session_gc(); // remove stale sessions break; case 'down': diff --git a/admin/cron.php b/admin/cron.php index 661cccf9ec..fa15f56b21 100644 --- a/admin/cron.php +++ b/admin/cron.php @@ -87,7 +87,7 @@ /// Session gc mtrace("Cleaning up stale sessions"); - session_get_instance()->gc(); + session_gc(); /// Run all cron jobs for each module diff --git a/admin/user.php b/admin/user.php index 0ef6cf246f..1ff160de21 100644 --- a/admin/user.php +++ b/admin/user.php @@ -80,7 +80,7 @@ } else { notify(get_string('deletednot', '', fullname($user, true))); } - session_get_instance()->gc(); // remove stale sessions + session_gc(); // remove stale sessions } } else if ($acl and confirm_sesskey()) { if (!has_capability('moodle/user:delete', $sitecontext)) { diff --git a/admin/user/user_bulk_delete.php b/admin/user/user_bulk_delete.php index 5df513572c..8278f8307e 100755 --- a/admin/user/user_bulk_delete.php +++ b/admin/user/user_bulk_delete.php @@ -35,7 +35,7 @@ if ($confirm and confirm_sesskey()) { } $rs->close; } - session_get_instance()->gc(); // remove stale sessions + session_gc(); // remove stale sessions redirect($return, get_string('changessaved')); } else { diff --git a/lib/authlib.php b/lib/authlib.php index 164dc3b468..1e143884d9 100644 --- a/lib/authlib.php +++ b/lib/authlib.php @@ -343,7 +343,16 @@ class auth_plugin_base { //override if needed } - function ignore_timeout_hook($userid, $userauth, $sid, $timecreated, $timemodified) { + /** + * Hook called before timing out of database session. + * This is usueful for SSO and MNET. + * @param object $user + * @param string $sid session id + * @param int $timecreated start of session + * @param int $timemodified user last seen + * @return bool true means do not timeout session yet + */ + function ignore_timeout_hook($user, $sid, $timecreated, $timemodified) { return false; } diff --git a/lib/sessionlib.php b/lib/sessionlib.php index 71d2dcf33a..fad7cab382 100644 --- a/lib/sessionlib.php +++ b/lib/sessionlib.php @@ -10,8 +10,12 @@ function session_get_instance() { static $session = null; if (is_null($session)) { + if (empty($CFG->sessiontimeout)) { + $CFG->sessiontimeout = 7200; + } + if (defined('SESSION_CUSTOM')) { - // this is a hook for custom session handling, webservices, etc. + // this is a hook for webservices, key based login, etc. if (defined('SESSION_CUSTOM_FILE')) { require_once($CFG->dirroot.SESSION_CUSTOM_FILE); } @@ -38,26 +42,12 @@ interface moodle_session { */ public function terminate_current(); - /** - * Terminates all sessions, auth hooks are not executed. - * Useful in ugrade scripts. - */ - public function terminate_all(); - /** * No more changes in session expected. * Unblocks the sesions, other scripts may start executing in parallel. * @return void */ public function write_close(); - - /** - * Session garbage collection - * - verify timeout for all users - * - kill sessions of all deleted users - * - kill sessions of users with disabled plugins or 'nologin' plugin - */ - public function gc(); } /** @@ -304,9 +294,6 @@ class legacy_file_session extends session_stub { ini_set('session.gc_probability', 1); } - if (empty($CFG->sessiontimeout)) { - $CFG->sessiontimeout = 7200; - } ini_set('session.gc_maxlifetime', $CFG->sessiontimeout); if (!file_exists($CFG->dataroot .'/sessions')) { @@ -317,25 +304,6 @@ class legacy_file_session extends session_stub { } ini_set('session.save_path', $CFG->dataroot .'/sessions'); } - - /** - * Terminates all sessions, auth hooks are not executed. - * Useful in ugrade scripts. - */ - public function terminate_all() { - // TODO - } - - /** - * Session garbage collection - * - verify timeout for all users - * - kill sessions of all deleted users - * - kill sessions of users with disabled plugins or 'nologin' plugin - */ - public function gc() { - // difficult/slow - } - } /** @@ -357,9 +325,6 @@ class database_session extends session_stub { // gc only from CRON - individual user timeouts now checked during each access ini_set('session.gc_probability', 0); - if (empty($CFG->sessiontimeout)) { - $CFG->sessiontimeout = 7200; - } ini_set('session.gc_maxlifetime', $CFG->sessiontimeout); $result = session_set_save_handler(array($this, 'handler_open'), @@ -373,72 +338,6 @@ class database_session extends session_stub { } } - /** - * Terminates all sessions, auth hooks are not executed. - * Useful in ugrade scripts. - */ - public function terminate_all() { - try { - // do not show any warnings - might be during upgrade/installation - $this->database->delete_records('sessions'); - } catch (dml_exception $ignored) { - } - } - - /** - * Session garbage collection - * - verify timeout for all users - * - kill sessions of all deleted users - * - kill sessions of users with disabled plugins or 'nologin' plugin - */ - public function gc() { - global $CFG; - $maxlifetime = $CFG->sessiontimeout; - - if (empty($CFG->rolesactive)) { - return; - } - - try { - /// kill all sessions of deleted users - $this->database->delete_records_select('sessions', "userid IN (SELECT id FROM {user} WHERE deleted <> 0)"); - - /// kill sessions of users with disabled plugins - $auth_sequence = get_enabled_auth_plugins(true); - $auth_sequence = array_flip($auth_sequence); - unset($auth_sequence['nologin']); // no login allowed - $auth_sequence = array_flip($auth_sequence); - $notplugins = null; - list($notplugins, $params) = $this->database->get_in_or_equal($auth_sequence, SQL_PARAMS_QM, '', false); - $this->database->delete_records_select('sessions', "userid IN (SELECT id FROM {user} WHERE auth $notplugins)", $params); - - /// now get a list of time-out candidates - $sql = "SELECT s.*, u.auth, u.username - FROM {sessions} s - JOIN {user} u ON u.id = s.userid - WHERE s.timemodified + ? < ?"; - $params = array($maxlifetime, time()); - - $authplugins = array(); - foreach($auth_sequence as $authname) { - $authplugins[$authname] = get_auth_plugin($authname); - } - $records = $this->database->get_records_sql($sql, $params); - foreach ($records as $record) { - if (!empty($record->userid) and $record->username !== 'guest') { // skips not logged in and guests - foreach ($authplugins as $authplugin) { - if ($authplugin->ignore_timeout_hook($record->userid, $records->auth, $record->sid, $record->timecreated, $record->timemodified)) { - continue; - } - } - } - $this->database->delete_records('sessions', array('id'=>$record->id)); - } - } catch (dml_exception $ex) { - error_log('Error gc-ing sessions'); - } - } - public function handler_open($save_path, $session_name) { return true; } @@ -489,7 +388,7 @@ class database_session extends session_stub { $authsequence = get_enabled_auth_plugins(); // auths, in sequence foreach($authsequence as $authname) { $authplugin = get_auth_plugin($authname); - if ($authplugin->ignore_timeout_hook($user->id, $user->auth, $record->sid, $record->timecreated, $record->timemodified)) { + if ($authplugin->ignore_timeout_hook($user, $record->sid, $record->timecreated, $record->timemodified)) { $ignoretimeout = true; break; } @@ -593,7 +492,117 @@ class database_session extends session_stub { $this->gc(); return true; } +} + +/** + * Terminates all sessions, auth hooks are not executed. + * Useful in ugrade scripts. + */ +function session_kill_all() { + global $CFG, $DB; + + try { + // do not show any warnings - might be during upgrade/installation + $DB->delete_records('sessions'); + } catch (dml_exception $ignored) { + } + $sessiondir = "$CFG->dataroot/sessions/"; + if (is_dir($sessiondir)) { + // TODO: delete all files, watch out some might be locked + } +} + +/** + * Terminates one sessions, auth hooks are not executed. + * + * @param string $sid session id + */ +function session_kill($sid) { + global $CFG, $DB; + + try { + // do not show any warnings - might be during upgrade/installation + $$DB->delete_records('sessions', array('sid'=>$sid)); + } catch (dml_exception $ignored) { + } + + $sessionfile = clean_param("$CFG->dataroot/sessions/$sid", PARAM_FILE); + if (file_exists($sessionfile)) { + // TODO: delete file, watch out might be locked + } +} + +/** + * Terminates all sessions of one user, auth hooks are not executed. + * NOTE: This can not work for file based sessions! + * + * @param int $userid user id + */ +function session_kill_user($userid) { + global $CFG, $DB; + + try { + // do not show any warnings - might be during upgrade/installation + $$DB->delete_records('sessions', array('userid'=>$userid)); + } catch (dml_exception $ignored) { + } +} + +/** + * Session garbage collection + * - verify timeout for all users + * - kill sessions of all deleted users + * - kill sessions of users with disabled plugins or 'nologin' plugin + * + * NOTE: this can not work when legacy file sessions used! + */ +function session_gc() { + global $CFG, $DB; + + $maxlifetime = $CFG->sessiontimeout; + + if (empty($CFG->rolesactive)) { + return; + } + + try { + /// kill all sessions of deleted users + $DB->delete_records_select('sessions', "userid IN (SELECT id FROM {user} WHERE deleted <> 0)"); + + /// kill sessions of users with disabled plugins + $auth_sequence = get_enabled_auth_plugins(true); + $auth_sequence = array_flip($auth_sequence); + unset($auth_sequence['nologin']); // no login allowed + $auth_sequence = array_flip($auth_sequence); + $notplugins = null; + list($notplugins, $params) = $DB->get_in_or_equal($auth_sequence, SQL_PARAMS_QM, '', false); + $DB->delete_records_select('sessions', "userid IN (SELECT id FROM {user} WHERE auth $notplugins)", $params); + + /// now get a list of time-out candidates + $sql = "SELECT u.*, s.sid, s.timecreated AS s_timecreated, s.timemodified AS s_timemodified + FROM {user} u + JOIN {sessions} s ON s.userid = u.id + WHERE s.timemodified + ? < ? AND u.username <> 'guest'"; + $params = array($maxlifetime, time()); + + $authplugins = array(); + foreach($auth_sequence as $authname) { + $authplugins[$authname] = get_auth_plugin($authname); + } + $rs = $DB->get_recordset_sql($sql, $params); + foreach ($rs as $user) { + foreach ($authplugins as $authplugin) { + if ($authplugin->ignore_timeout_hook($user, $user->sid, $user->s_timecreated, $user->s_timemodified)) { + continue; + } + } + $DB->delete_records('sessions', array('sid'=>$user->sid)); + } + $rs->close(); + } catch (dml_exception $ex) { + error_log('Error gc-ing sessions'); + } } /** @@ -689,6 +698,7 @@ function get_moodle_cookie() { } } + /** * Setup $USER object - called during login, loginas, etc. * Preloads capabilities and checks enrolment plugins diff --git a/user/editadvanced.php b/user/editadvanced.php index 81c45ffce2..f765a65d7e 100644 --- a/user/editadvanced.php +++ b/user/editadvanced.php @@ -177,7 +177,7 @@ redirect("$CFG->wwwroot/user/view.php?id=$USER->id&course=$course->id"); } } else { - session_get_instance()->gc(); // remove stale sessions + session_gc(); // remove stale sessions redirect("$CFG->wwwroot/$CFG->admin/user.php"); } //never reached