mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 04:22:07 +02:00
MDL-71887 mod_lti: repost when no cookie due to crosssite request
This commit is contained in:
parent
3610f1ee3b
commit
c8c81a1357
@ -24,6 +24,19 @@
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
global $_POST, $_SERVER;
|
||||
|
||||
if (!isloggedin() && empty($_POST['repost'])) {
|
||||
header_remove("Set-Cookie");
|
||||
$PAGE->set_pagelayout('popup');
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$output = $PAGE->get_renderer('mod_lti');
|
||||
$page = new \mod_lti\output\repost_crosssite_page($_SERVER['REQUEST_URI'], $_POST);
|
||||
echo $output->header();
|
||||
echo $output->render($page);
|
||||
echo $output->footer();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope = optional_param('scope', '', PARAM_TEXT);
|
||||
$responsetype = optional_param('response_type', '', PARAM_TEXT);
|
||||
|
@ -71,4 +71,17 @@ class renderer extends plugin_renderer_base {
|
||||
$data = $page->export_for_template($this);
|
||||
return parent::render_from_template('mod_lti/registration_upgrade_choice_page', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the reposting of the cross site request.
|
||||
*
|
||||
* @param repost_crosssite_page $page the page renderable.
|
||||
*
|
||||
* @return string rendered html for the page.
|
||||
*/
|
||||
public function render_repost_crosssite_page(repost_crosssite_page $page): string {
|
||||
$data = $page->export_for_template($this);
|
||||
return parent::render_from_template('mod_lti/repost_crosssite', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
76
mod/lti/classes/output/repost_crosssite_page.php
Normal file
76
mod/lti/classes/output/repost_crosssite_page.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Render a page containing a simple form which reposts to self via JS.
|
||||
*
|
||||
* The purpose of this form is to resend a cross-site request to self, which allows the browsers to include the Moodle
|
||||
* session cookie alongside the original POST data, allowing LTI flows to function despite browsers blocking
|
||||
* cross-site cookies.
|
||||
*
|
||||
* @copyright 2021 Cengage
|
||||
* @package mod_lti
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_lti\output;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->dirroot.'/mod/lti/locallib.php');
|
||||
|
||||
use renderable;
|
||||
use templatable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Render a page containing a simple form which reposts to self via JS.
|
||||
*
|
||||
* The purpose of this form is to resend a cross-site request to self, which allows the browsers to include the Moodle
|
||||
* session cookie alongside the original POST data, allowing LTI flows to function despite browsers blocking
|
||||
* cross-site cookies.
|
||||
*
|
||||
* @copyright 2021 Cengage
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class repost_crosssite_page implements renderable, templatable {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $url moodle URL to repost to
|
||||
* @param array $post the POST params to be re-posted
|
||||
*/
|
||||
public function __construct(string $url, array $post) {
|
||||
$this->params = array_map(function($k) use ($post) {
|
||||
return ["key" => $k, "value" => str_replace("\"", """, $post[$k])];
|
||||
}, array_keys($post));
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output The renderer
|
||||
* @return stdClass Data to be used by the template
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
$renderdata = new stdClass();
|
||||
$renderdata->url = $this->url;
|
||||
$renderdata->params = $this->params;
|
||||
return $renderdata;
|
||||
}
|
||||
}
|
@ -31,6 +31,28 @@ $courseid = required_param('course', PARAM_INT);
|
||||
|
||||
$jwt = optional_param('JWT', '', PARAM_RAW);
|
||||
|
||||
$context = context_course::instance($courseid);
|
||||
|
||||
$pageurl = new moodle_url('/mod/lti/contentitem_return.php');
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_pagelayout('popup');
|
||||
$PAGE->set_context($context);
|
||||
|
||||
// Cross-Site causes the cookie to be lost if not POSTed from same site.
|
||||
global $_POST;
|
||||
if (!empty($_POST["repost"])) {
|
||||
// Unset the param so that LTI 1.1 signature validation passes.
|
||||
unset($_POST["repost"]);
|
||||
} else if (!isloggedin()) {
|
||||
header_remove("Set-Cookie");
|
||||
$output = $PAGE->get_renderer('mod_lti');
|
||||
$page = new \mod_lti\output\repost_crosssite_page($_SERVER['REQUEST_URI'], $_POST);
|
||||
echo $output->header();
|
||||
echo $output->render($page);
|
||||
echo $output->footer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($jwt)) {
|
||||
$params = lti_convert_from_jwt($id, $jwt);
|
||||
$consumerkey = $params['oauth_consumer_key'] ?? '';
|
||||
@ -52,7 +74,6 @@ if (!empty($jwt)) {
|
||||
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
|
||||
require_login($course);
|
||||
require_sesskey();
|
||||
$context = context_course::instance($courseid);
|
||||
require_capability('moodle/course:manageactivities', $context);
|
||||
require_capability('mod/lti:addcoursetool', $context);
|
||||
|
||||
@ -66,9 +87,6 @@ if (empty($errormsg) && !empty($items)) {
|
||||
}
|
||||
}
|
||||
|
||||
$pageurl = new moodle_url('/mod/lti/contentitem_return.php');
|
||||
$PAGE->set_url($pageurl);
|
||||
$PAGE->set_pagelayout('popup');
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Call JS module to redirect the user to the course page or close the dialogue on error/cancel.
|
||||
|
49
mod/lti/templates/repost_crosssite.mustache
Normal file
49
mod/lti/templates/repost_crosssite.mustache
Normal file
@ -0,0 +1,49 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_lti/repost_crosssite
|
||||
|
||||
This template re-executes a cross site request but from the site domain, avoiding the cross site issue.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Context variables required for this template:
|
||||
*
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"url":"https://some.tool.example/mod/lti/auth.php",
|
||||
"params": {
|
||||
"response_type": "id_token"
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
<form action="{{{url}}}" method="POST" id="autopostme">
|
||||
{{#params}}
|
||||
<input type="hidden" name="{{{key}}}" value="{{{value}}}">
|
||||
{{/params}}
|
||||
<input type="hidden" name="repost" value="true">
|
||||
</form>
|
||||
|
||||
{{#js}}
|
||||
document.getElementById("autopostme").submit();
|
||||
{{/js}}
|
Loading…
x
Reference in New Issue
Block a user