diff --git a/auth/shibboleth/classes/helper.php b/auth/shibboleth/classes/helper.php new file mode 100644 index 00000000000..c1d57057509 --- /dev/null +++ b/auth/shibboleth/classes/helper.php @@ -0,0 +1,123 @@ +. + +/** + * Contains a helper class for the Shibboleth authentication plugin. + * + * @package auth_shibboleth + * @copyright 2018 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace auth_shibboleth; + +defined('MOODLE_INTERNAL') || die(); + +/** + * The helper class for the Shibboleth authentication plugin. + * + * @package auth_shibboleth + * @copyright 2018 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class helper { + + /** + * Delete session of user using file sessions. + * + * @param string $spsessionid SP-provided Shibboleth Session ID + * @return \SoapFault or void if everything was fine + */ + public static function logout_file_session($spsessionid) { + global $CFG; + + if (!empty($CFG->session_file_save_path)) { + $dir = $CFG->session_file_save_path; + } else { + $dir = $CFG->dataroot . '/sessions'; + } + + if (is_dir($dir)) { + if ($dh = opendir($dir)) { + // Read all session files. + while (($file = readdir($dh)) !== false) { + // Check if it is a file. + if (is_file($dir.'/'.$file)) { + // Read session file data. + $data = file($dir.'/'.$file); + if (isset($data[0])) { + $usersession = self::unserializesession($data[0]); + // Check if we have found session that shall be deleted. + if (isset($usersession['SESSION']) && isset($usersession['SESSION']->shibboleth_session_id)) { + // If there is a match, delete file. + if ($usersession['SESSION']->shibboleth_session_id == $spsessionid) { + // Delete session file. + if (!unlink($dir.'/'.$file)) { + return new SoapFault('LogoutError', 'Could not delete Moodle session file.'); + } + } + } + } + } + } + closedir($dh); + } + } + } + + /** + * Delete session of user using DB sessions. + * + * @param string $spsessionid SP-provided Shibboleth Session ID + */ + public static function logout_db_session($spsessionid) { + global $CFG, $DB; + + $sessions = $DB->get_records_sql( + 'SELECT userid, sessdata FROM {sessions} WHERE timemodified > ?', + array(time() - $CFG->sessiontimeout) + ); + + foreach ($sessions as $session) { + // Get user session from DB. + if (session_decode(base64_decode($session->sessdata))) { + if (isset($_SESSION['SESSION']) && isset($_SESSION['SESSION']->shibboleth_session_id)) { + // If there is a match, kill the session. + if ($_SESSION['SESSION']->shibboleth_session_id == trim($spsessionid)) { + // Delete this user's sessions. + \core\session\manager::kill_user_sessions($session->userid); + } + } + } + } + } + + /** + * Unserialize a session string. + * + * @param string $serializedstring + * @return array + */ + private static function unserializesession($serializedstring) { + $variables = array(); + $a = preg_split("/(\w+)\|/", $serializedstring, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + $counta = count($a); + for ($i = 0; $i < $counta; $i = $i + 2) { + $variables[$a[$i]] = unserialize($a[$i + 1]); + } + return $variables; + } +} diff --git a/auth/shibboleth/logout.php b/auth/shibboleth/logout.php index ae57977e587..c9fa33d72ec 100644 --- a/auth/shibboleth/logout.php +++ b/auth/shibboleth/logout.php @@ -135,94 +135,19 @@ function LogoutNotification($spsessionid) { if (!empty($CFG->session_handler_class)) { $sessionclass = $CFG->session_handler_class; if (preg_match('/database/i', $sessionclass) === 1) { - return logoutdbsession($spsessionid); + return \auth_shibboleth\helper::logout_db_session($spsessionid); } else if (preg_match('/file/i', $sessionclass) === 1) { - return logoutfilesession($spsessionid); + return \auth_shibboleth\helper::logout_file_session($spsessionid); } else { throw new moodle_exception("Shibboleth logout not implemented for '$sessionclass'"); } } else { // Session handler class is not specified, check dbsessions instead. if (!empty($CFG->dbsessions)) { - return logoutdbsession($spsessionid); + return \auth_shibboleth\helper::logout_db_session($spsessionid); } // Assume file sessions if dbsessions isn't used. - return logoutfilesession($spsessionid); + return \auth_shibboleth\helper::logout_file_session($spsessionid); } // If no SoapFault was thrown, the function will return OK as the SP assumes. } - -// Delete session of user using $spsessionid. -function logoutfilesession($spsessionid) { - global $CFG; - - if (!empty($CFG->session_file_save_path)) { - $dir = $CFG->session_file_save_path; - } else { - $dir = $CFG->dataroot . '/sessions'; - } - - if (is_dir($dir)) { - if ($dh = opendir($dir)) { - // Read all session files. - while (($file = readdir($dh)) !== false) { - // Check if it is a file. - if (is_file($dir.'/'.$file)) { - - // Read session file data. - $data = file($dir.'/'.$file); - if (isset($data[0])) { - $usersession = unserializesession($data[0]); - - // Check if we have found session that shall be deleted. - if (isset($usersession['SESSION']) && isset($usersession['SESSION']->shibboleth_session_id)) { - - // If there is a match, delete file. - if ($usersession['SESSION']->shibboleth_session_id == $spsessionid) { - // Delete session file. - if (!unlink($dir.'/'.$file)) { - return new SoapFault('LogoutError', 'Could not delete Moodle session file.'); - } - } - } - } - } - } - closedir($dh); - } - } -} - -function logoutdbsession($spsessionid) { - global $CFG, $DB; - $sessions = $DB->get_records_sql( - 'SELECT userid, sessdata FROM {sessions} WHERE timemodified > ?', - array(time() - $CFG->sessiontimeout) - ); - foreach ($sessions as $session) { - // Get user session from DB. - if (session_decode(base64_decode($session->sessdata))) { - if (isset($_SESSION['SESSION']) && isset($_SESSION['SESSION']->shibboleth_session_id)) { - // If there is a match, kill the session. - if ($_SESSION['SESSION']->shibboleth_session_id == trim($spsessionid)) { - // Delete this user's sessions. - \core\session\manager::kill_user_sessions($session->userid); - } - } - } - } -} - -/*****************************************************************************/ - -// Same function as in adodb, but cannot be used for file session for some reason... -function unserializesession($serialized_string) { - $variables = array(); - $a = preg_split("/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); - $counta = count($a); - for ($i = 0; $i < $counta; $i = $i+2) { - $variables[$a[$i]] = unserialize($a[$i+1]); - } - return $variables; -} - diff --git a/auth/shibboleth/upgrade.txt b/auth/shibboleth/upgrade.txt index dbd7b4b03ed..9083025cd42 100644 --- a/auth/shibboleth/upgrade.txt +++ b/auth/shibboleth/upgrade.txt @@ -1,6 +1,11 @@ This files describes API changes in /auth/shibboleth/*, information provided here is intended especially for developers. +=== 3.5.2 === + +* Moved the public function unserializesession in auth/shibboleth/logout.php to auth/shibboleth/classes/helper.php and + made it private. This function should not have been used outside of this file. + === 3.3 === * The config.html file was migrated to use the admin settings API.