From 5c3fc99dd3347580843e45a47e980457a26e4389 Mon Sep 17 00:00:00 2001 From: Michael Kotlyar Date: Mon, 18 Nov 2024 12:11:08 +0000 Subject: [PATCH] MDL-80948: Launch to SEB continues session. --- .../seb/classes/continue_session.php | 81 +++++++++++++++++++ .../accessrule/seb/lang/en/quizaccess_seb.php | 2 + mod/quiz/accessrule/seb/redirect.php | 41 ++++++++++ mod/quiz/accessrule/seb/rule.php | 13 ++- mod/quiz/accessrule/seb/settings.php | 6 ++ mod/quiz/accessrule/seb/version.php | 2 +- 6 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 mod/quiz/accessrule/seb/classes/continue_session.php create mode 100644 mod/quiz/accessrule/seb/redirect.php diff --git a/mod/quiz/accessrule/seb/classes/continue_session.php b/mod/quiz/accessrule/seb/classes/continue_session.php new file mode 100644 index 0000000000000..9fbbbb583db34 --- /dev/null +++ b/mod/quiz/accessrule/seb/classes/continue_session.php @@ -0,0 +1,81 @@ +. + +namespace quizaccess_seb; + +/** + * Class continue_session + * + * @package quizaccess_seb + * @copyright 2024 Michael Kotlyar + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class continue_session { + + const SCRIPT = 'seb'; + + public static function create_sessionkey($userid) { + global $CFG; + + // Security checks. + require_login(); + + // Generate URL. + $user = get_complete_user_data('id', $userid, $CFG->mnet_localhost_id, true); + + $userid = $user->id; + $iprestriction = $user->lastip ?: getremoteaddr(); + $validuntil = time() + 60; + + return create_user_key(self::SCRIPT, $userid, $userid, $iprestriction, $validuntil); + } + + + /** + * Logs a user in using userkey and redirects after. + * + * @throws \moodle_exception If something went wrong. + */ + public static function handle_sessionkey($key, $userid) { + global $CFG; + + // Validate key. + try { + $key = validate_user_key($key, self::SCRIPT, $userid); + } catch (\moodle_exception $exception) { + // If user is logged in and key is not valid, we'd like to logout a user. + if (isloggedin()) { + require_logout(); + } + throw $exception; + } + + // Validate and login user. + if (isloggedin()) { + global $USER; + if ($USER->id != $key->userid) { + // Logout the current user if it's different to one that associated to the valid key. + require_logout(); + } + } else { + $user = get_complete_user_data('id', $key->userid, $CFG->mnet_localhost_id, true); + complete_user_login($user); + } + + // Delete keys. + delete_user_key(self::SCRIPT, $userid); + } +} diff --git a/mod/quiz/accessrule/seb/lang/en/quizaccess_seb.php b/mod/quiz/accessrule/seb/lang/en/quizaccess_seb.php index c6e307f3da033..4d37d6b40b3a7 100644 --- a/mod/quiz/accessrule/seb/lang/en/quizaccess_seb.php +++ b/mod/quiz/accessrule/seb/lang/en/quizaccess_seb.php @@ -187,6 +187,8 @@ $string['sebrequired'] = "This quiz has been configured so that students may only attempt it using the Safe Exam Browser."; $string['setting:autoreconfigureseb'] = 'Auto-configure SEB'; $string['setting:autoreconfigureseb_desc'] = 'If enabled, users who navigate to the quiz using the Safe Exam Browser will be automatically forced to reconfigure their Safe Exam Browser.'; +$string['setting:continuesessionwhenlaunchseb'] = 'Continue session when launching Safe Exam Browser'; +$string['setting:continuesessionwhenlaunchseb_desc'] = 'If enabled, users will not have to re-login when launching the quiz in their Safe Exam Browser'; $string['setting:displayblocksbeforestart'] = 'Display blocks before starting quiz'; $string['setting:displayblocksbeforestart_desc'] = 'If enabled, blocks will be displayed before a user attempts the quiz.'; $string['setting:displayblockswhenfinished'] = 'Display blocks after finishing quiz'; diff --git a/mod/quiz/accessrule/seb/redirect.php b/mod/quiz/accessrule/seb/redirect.php new file mode 100644 index 0000000000000..724bf2e07396c --- /dev/null +++ b/mod/quiz/accessrule/seb/redirect.php @@ -0,0 +1,41 @@ +. + +/** + * TODO describe file redirect + * + * @package quizaccess_seb + * @copyright 2024 Michael Kotlyar + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require('../../../../config.php'); + +use \quizaccess_seb\continue_session; + +$key = required_param('key', PARAM_TEXT); +$userid = required_param('userid', PARAM_INT); +$cmid = required_param('cmid', PARAM_INT); + +// Verify and login. +try { + continue_session::handle_sessionkey($key, $userid); +} catch (exception $e) { + header("Location: {$CFG->wwwroot}"); + exit; +} + +redirect(new \moodle_url('/mod/quiz/accessrule/seb/config.php', ['cmid' => $cmid])); diff --git a/mod/quiz/accessrule/seb/rule.php b/mod/quiz/accessrule/seb/rule.php index b419f703b23b6..d6ec94c96c721 100644 --- a/mod/quiz/accessrule/seb/rule.php +++ b/mod/quiz/accessrule/seb/rule.php @@ -547,7 +547,18 @@ private function get_download_seb_button(): string { */ private function get_launch_seb_button(): string { // Rendering as a href and not as button in a form to circumvent browser warnings for sending to URL with unknown protocol. - $seblink = \quizaccess_seb\link_generator::get_link($this->quiz->cmid, true, is_https()); + $continuesession = get_config('quizaccess_seb', 'continuesessionwhenlaunchseb'); + if ($continuesession) { + global $USER; + $key = \quizaccess_seb\continue_session::create_sessionkey($USER->id, $this->quiz->cmid); + $seblink = new moodle_url( + '/mod/quiz/accessrule/seb/redirect.php', + ['key' => $key, 'userid' => $USER->id, 'cmid' => $this->quiz->cmid], + ); + $seblink->set_scheme('sebs'); + } else { + $seblink = \quizaccess_seb\link_generator::get_link($this->quiz->cmid, false, is_https()); + } $buttonlink = html_writer::start_tag('div', ['class' => 'singlebutton']); $buttonlink .= html_writer::link($seblink, get_string('seblinkbutton', 'quizaccess_seb'), diff --git a/mod/quiz/accessrule/seb/settings.php b/mod/quiz/accessrule/seb/settings.php index 7e38f62739fb7..9d7059ed3d93f 100644 --- a/mod/quiz/accessrule/seb/settings.php +++ b/mod/quiz/accessrule/seb/settings.php @@ -69,6 +69,12 @@ get_string('setting:displayblockswhenfinished', 'quizaccess_seb'), get_string('setting:displayblockswhenfinished_desc', 'quizaccess_seb'), '1')); + + $settings->add(new admin_setting_configcheckbox('quizaccess_seb/continuesessionwhenlaunchseb', + get_string('setting:continuesessionwhenlaunchseb', 'quizaccess_seb'), + get_string('setting:continuesessionwhenlaunchseb_desc', 'quizaccess_seb'), + '1')); + } if (has_capability('quizaccess/seb:managetemplates', context_system::instance())) { diff --git a/mod/quiz/accessrule/seb/version.php b/mod/quiz/accessrule/seb/version.php index 4fb5bcbd8d917..2db3c4a6ddccb 100644 --- a/mod/quiz/accessrule/seb/version.php +++ b/mod/quiz/accessrule/seb/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024100700; +$plugin->version = 2024110700; $plugin->requires = 2024100100; $plugin->component = 'quizaccess_seb'; $plugin->maturity = MATURITY_STABLE;