Skip to content

Commit

Permalink
Merge pull request #43 from iconnewmedia-de/lti13
Browse files Browse the repository at this point in the history
adds support for LTI version 1.3
  • Loading branch information
evasys-pm authored Jul 4, 2024
2 parents 6e59f28 + 8e17138 commit adef5b5
Show file tree
Hide file tree
Showing 19 changed files with 2,035 additions and 237 deletions.
2 changes: 1 addition & 1 deletion amd/build/modal-zoom.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion amd/build/spinner.min.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

189 changes: 189 additions & 0 deletions auth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?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/>.

/**
* This file responds to a login authentication request
*
* @package mod_lti
* @copyright 2019 Stephen Vickers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
require_once(__DIR__ . '/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);
$clientid = optional_param('client_id', '', PARAM_TEXT);
$redirecturi = optional_param('redirect_uri', '', PARAM_URL);
$loginhint = optional_param('login_hint', '', PARAM_TEXT);
$ltimessagehintenc = optional_param('lti_message_hint', '', PARAM_TEXT);
$ltimessagehintenc = htmlspecialchars_decode(urldecode($ltimessagehintenc));
$state = optional_param('state', '', PARAM_TEXT);
$responsemode = optional_param('response_mode', '', PARAM_TEXT);
$nonce = optional_param('nonce', '', PARAM_TEXT);
$prompt = optional_param('prompt', '', PARAM_TEXT);
$typeid = block_onlinesurvey_get_lti_typeid();

$ok = !empty($scope) && !empty($responsetype) && !empty($clientid) &&
!empty($redirecturi) && !empty($loginhint) &&
!empty($nonce);

if (!$ok) {
$error = 'invalid_request';
}
$ltimessagehint = json_decode($ltimessagehintenc);
$ok = $ok && isset($ltimessagehint->launchid);
if (!$ok) {
$error = 'invalid_request';
$desc = 'No launch id in LTI hint';
}
if ($ok && ($scope !== 'openid')) {
$ok = false;
$error = 'invalid_scope';
}
if ($ok && ($responsetype !== 'id_token')) {
$ok = false;
$error = 'unsupported_response_type';
}
if ($ok) {
$launchid = $ltimessagehint->launchid;
list($messagetype, $foruserid, $titleb64, $textb64) = explode(',', $SESSION->$launchid, 7);
unset($SESSION->$launchid);
$config = lti_get_type_type_config($typeid);
$ok = ($clientid === $config->lti_clientid);
if (!$ok) {
$error = 'unauthorized_client';
}
}
if ($ok && ($loginhint !== $USER->id)) {
$ok = false;
$error = 'access_denied';
}

// If we're unable to load up config; we cannot trust the redirect uri for POSTing to.
if (empty($config)) {
throw new moodle_exception('invalidrequest', 'error');
} else {
$uris = array_map("trim", explode("\n", $config->lti_redirectionuris));
if (!in_array($redirecturi, $uris)) {
throw new moodle_exception('invalidrequest', 'error');
}
}
if ($ok) {
if (isset($responsemode)) {
$ok = ($responsemode === 'form_post');
if (!$ok) {
$error = 'invalid_request';
$desc = 'Invalid response_mode';
}
} else {
$ok = false;
$error = 'invalid_request';
$desc = 'Missing response_mode';
}
}
if ($ok && !empty($prompt) && ($prompt !== 'none')) {
$ok = false;
$error = 'invalid_request';
$desc = 'Invalid prompt';
}
if (isset($state)) {
$SESSION->lti_state = $state;
} else {
$state = $SESSION->lti_state;
}
if ($ok) {
$config = get_config('block_onlinesurvey');
require_login();
$context = context_system::instance();
$lti = get_config('block_onlinesurvey');
list($endpoint, $params) = block_onlinesurvey_lti_get_launch_data($lti, $nonce, $messagetype, $foruserid);
$params['state'] = $state;
setcookie('state', $state, ['samesite' => 'None']);
setcookie('lti1p3_' . $state, $state, ['samesite' => 'None', 'path' => '/']);
} else {
$params['error'] = $error;
if (!empty($desc)) {
$params['error_description'] = $desc;
}
}

$params['lti1p3_' . $SESSION->lti_state] = $SESSION->lti_state;
if (isset($SESSION->lti_state)) {
setcookie('lti1p3_' . $SESSION->lti_state, $SESSION->lti_state);
block_onlinesurvey_remove_outdated_cookies($SESSION->lti_state);
}
unset($SESSION->lti_message_hint);
$config = block_onlinesurvey_get_launch_config();
$return = block_onlinesurvey_lti_post_launch_html_curl($params, $redirecturi, $config);
if ($config->presentation == BLOCK_ONLINESURVEY_PRESENTATION_BRIEF) {
if (isset($SESSION->modalzoom)) {
$modalzoom = $SESSION->modalzoom;
unset($SESSION->modalzoom);
} else {
$modalzoom = optional_param('modalZoom', 0, PARAM_INT);
}
if (!$modalzoom) {
$return = block_onlinesurvey_get_summary($return, $config, $modalzoom, $foruserid);
$return .= '<link rel="stylesheet" href="' . $CFG->wwwroot . '/blocks/onlinesurvey/style/block_onlinesurvey_iframe_compact.css">';
$return .= '<link rel="stylesheet" href="' . $CFG->wwwroot . '/blocks/onlinesurvey/lib/fonts/font-awesome-4.7.0/css/font-awesome.min.css">';
}
}
if ($modalzoom || $config->presentation != BLOCK_ONLINESURVEY_PRESENTATION_BRIEF) {
$pathinfo = pathinfo($config->lti_url);
$base = $pathinfo['dirname'];
if (strpos($return, '<head>') !== false) {
$return = str_replace('<head>', '<head><base href="' . $base . '/" />', $return);
} else {
$return = str_replace('<html>', '<html><head><base href="' . $base . '/" /></head>', $return);
}
$return .= '<script>
// make iframe height match its content
var block_onlinesurvey_iframe_height = document.documentElement.offsetHeight + 40;
window.parent.parent.document.getElementById(\'block_onlinesurvey_contentframe\').style.height = block_onlinesurvey_iframe_height + \'px\';
</script>';
}
echo $return;
//$r = '<form action="' . $redirecturi . "\" name=\"ltiAuthForm\" id=\"ltiAuthForm\" " .
// "method=\"post\" enctype=\"application/x-www-form-urlencoded\">\n";
//if (!empty($params)) {
// foreach ($params as $key => $value) {
// $key = htmlspecialchars($key, ENT_COMPAT);
// $value = htmlspecialchars($value, ENT_COMPAT);
// $r .= " <input type=\"hidden\" name=\"{$key}\" value=\"{$value}\"/>\n";
// }
//}
//$r .= "</form>\n";
//$r .= "<script type=\"text/javascript\">\n" .
// "//<![CDATA[\n" .
// "document.ltiAuthForm.submit();\n" .
// "//]]>\n" .
// "</script>\n";
//echo $r;
64 changes: 44 additions & 20 deletions block_onlinesurvey.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
*/

defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot . '/mod/lti/locallib.php');
require_once(__DIR__ . '/locallib.php');
/**
* Onlinesurvey block.
*
Expand Down Expand Up @@ -120,32 +121,31 @@ public function init() {
$this->isconfigured = false;
$this->error = "WSDL namespace parse error";
}
} else if ($this->connectiontype == 'LTI') {
} else if ($this->connectiontype == 'LTI' || $this->connectiontype == LTI_VERSION_1P3) {
// Quick check of some LTI settings.
if (empty($config->lti_url) || empty($config->lti_password) || empty($config->lti_learnermapping)) {
$this->isconfigured = true;

$errorinfo = '';
if (empty($config->lti_url)) {
$errorinfo .= get_string('error_lti_url_missing', 'block_onlinesurvey').'<br>';
}
if (empty($config->lti_password) && $this->connectiontype == 'LTI') {
$errorinfo .= get_string('error_lti_password_missing', 'block_onlinesurvey').'<br>';
}
if (empty($config->lti_learnermapping)) {
$errorinfo .= get_string('error_lti_learnermapping_missing', 'block_onlinesurvey').'<br>';
}

if (!empty($errorinfo)) {
$this->isconfigured = false;
$this->error = get_string('error_lti_settings_error', 'block_onlinesurvey');

$errorinfo = '';
if (empty($config->lti_url)) {
$errorinfo .= get_string('error_lti_url_missing', 'block_onlinesurvey').'<br>';
}
if (empty($config->lti_password)) {
$errorinfo .= get_string('error_lti_password_missing', 'block_onlinesurvey').'<br>';
}
if (empty($config->lti_learnermapping)) {
$errorinfo .= get_string('error_lti_learnermapping_missing', 'block_onlinesurvey').'<br>';
}

$context = context_system::instance();
if (has_capability('block/onlinesurvey:view_debugdetails', $context)) {
if (!empty($errorinfo)) {
$this->error .= "<br>".$errorinfo;
$this->error .= "<br>" . $errorinfo;
}
}

} else {
$this->isconfigured = true;
}
}
} else {
Expand All @@ -164,8 +164,10 @@ public function init() {
* @return void
*/
public function get_content() {
global $CFG, $USER;

global $CFG, $USER, $PAGE, $SESSION;
if (isset($SESSION->lti_state)) {
block_onlinesurvey_remove_outdated_cookies($SESSION->lti_state);
}
// Block settings.
$config = get_config("block_onlinesurvey");

Expand Down Expand Up @@ -277,6 +279,10 @@ public function has_config() {
return true;
}

function instance_allow_config() {
return true;
}

/**
* Returns false which means that only one instance is allowed.
*
Expand Down Expand Up @@ -314,4 +320,22 @@ public function applicable_formats() {
public function get_title() {
return $this->title;
}


/**
* Return the plugin config settings for external functions.
*
* @return stdClass the configs for both the block instance and plugin
* @since Moodle 3.8
*/
public function get_config_for_external() {
// Return all settings for all users since it is safe (no private keys, etc..).
$instanceconfigs = !empty($this->config) ? $this->config : new stdClass();
$pluginconfigs = get_config('block_onlinesurvey');

return (object) [
'instance' => $instanceconfigs,
'plugin' => $pluginconfigs,
];
}
}
39 changes: 39 additions & 0 deletions certs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?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/>.

/**
* This file returns an array of available public keys
*
* @package mod_lti
* @copyright 2019 Stephen Vickers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use block_onlinesurvey\local\ltiopenid\jwks_helper;

define('NO_DEBUG_DISPLAY', true);
define('NO_MOODLE_COOKIES', true);

require_once(__DIR__ . '/../../config.php');
require_once(__DIR__ . '/classes/local/ltiopenid/jwks_helper.php');

@header('Content-Type: application/json; charset=utf-8');
try {
$jwks = jwks_helper::get_jwks();
$json = json_encode($jwks, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
echo $json;
} catch(Exception $e) {
// nothing here yet
}
Loading

0 comments on commit adef5b5

Please sign in to comment.