mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-67301 mod_lti: dynamic registration
This commit is contained in:
parent
5ecd01fb19
commit
84e90d5db4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
define ("mod_lti/tool_configure_controller",["jquery","core/ajax","core/notification","core/templates","mod_lti/events","mod_lti/keys","mod_lti/tool_type","mod_lti/tool_proxy","core/str"],function(a,b,c,d,e,f,g,h,i){var j={EXTERNAL_REGISTRATION_CONTAINER:"#external-registration-container",EXTERNAL_REGISTRATION_PAGE_CONTAINER:"#external-registration-page-container",CARTRIDGE_REGISTRATION_CONTAINER:"#cartridge-registration-container",CARTRIDGE_REGISTRATION_FORM:"#cartridge-registration-form",ADD_TOOL_FORM:"#add-tool-form",TOOL_LIST_CONTAINER:"#tool-list-container",TOOL_CREATE_BUTTON:"#tool-create-button",REGISTRATION_CHOICE_CONTAINER:"#registration-choice-container",TOOL_URL:"#tool-url"},k=function(){return a(j.TOOL_CREATE_BUTTON)},l=function(){return a(j.TOOL_LIST_CONTAINER)},m=function(){return a(j.EXTERNAL_REGISTRATION_CONTAINER)},n=function(){return a(j.CARTRIDGE_REGISTRATION_CONTAINER)},o=function(){return a(j.REGISTRATION_CHOICE_CONTAINER)},p=function(){return a(j.TOOL_URL).val()},q=function(){m().addClass("hidden")},r=function(){n().addClass("hidden")},s=function(){o().addClass("hidden")},t=function(){r();s();m().removeClass("hidden");w(m())},u=function(a){q();s();var b=n();b.find("input").val("");b.removeClass("hidden");b.find(j.CARTRIDGE_REGISTRATION_FORM).attr("data-cartridge-url",a);w(b)},v=function(){q();r();o().removeClass("hidden");w(o())},w=function(a){var b=a.children().detach();b.appendTo(a)},x=function(){l().addClass("hidden")},y=function(){l().removeClass("hidden")},z=function(a){var b=a.error?"error":"success";c.addNotification({message:a.message,type:b})},A=function(a){a.addClass("loading")},B=function(a){a.removeClass("loading")},C=function(){var b=a.Deferred(),e=l();A(e);a.when(g.query(),h.query({orphanedonly:!0})).done(function(a,c){d.render("mod_lti/tool_list",{tools:a,proxies:c}).done(function(a,c){e.empty();e.append(a);d.runTemplateJS(c);b.resolve()}).fail(b.reject)}).fail(b.reject);b.fail(c.exception).always(function(){B(e)})},D=function(){var b=a.trim(p());if(""===b){return a.Deferred().resolve()}var d=k();A(d);var f=g.isCartridge(b);f.always(function(){B(d)});f.done(function(c){if(c.iscartridge){a(j.TOOL_URL).val("");a(document).trigger(e.START_CARTRIDGE_REGISTRATION,b)}else{a(document).trigger(e.START_EXTERNAL_REGISTRATION,{url:b})}});f.fail(function(){i.get_string("errorbadurl","mod_lti").done(function(b){a(document).trigger(e.REGISTRATION_FEEDBACK,{message:b,error:!0})}).fail(c.exception)});return f},E=function(){a(document).on(e.NEW_TOOL_TYPE,function(){C()});a(document).on(e.START_EXTERNAL_REGISTRATION,function(){t();a(j.TOOL_URL).val("");x()});a(document).on(e.STOP_EXTERNAL_REGISTRATION,function(){y();v()});a(document).on(e.START_CARTRIDGE_REGISTRATION,function(a,b){u(b)});a(document).on(e.STOP_CARTRIDGE_REGISTRATION,function(){n().find(j.CARTRIDGE_REGISTRATION_FORM).removeAttr("data-cartridge-url");v()});a(document).on(e.REGISTRATION_FEEDBACK,function(a,b){z(b)});var b=a(j.ADD_TOOL_FORM);b.submit(function(a){a.preventDefault();D()})};return{init:function init(){E();C()}}});
|
||||
define ("mod_lti/tool_configure_controller",["jquery","core/ajax","core/notification","core/templates","mod_lti/events","mod_lti/keys","mod_lti/tool_type","mod_lti/tool_proxy","core/str"],function(a,b,c,d,e,f,g,h,i){var j={EXTERNAL_REGISTRATION_CONTAINER:"#external-registration-container",EXTERNAL_REGISTRATION_PAGE_CONTAINER:"#external-registration-page-container",EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER:"#external-registration-template-container",CARTRIDGE_REGISTRATION_CONTAINER:"#cartridge-registration-container",CARTRIDGE_REGISTRATION_FORM:"#cartridge-registration-form",ADD_TOOL_FORM:"#add-tool-form",TOOL_LIST_CONTAINER:"#tool-list-container",TOOL_CREATE_BUTTON:"#tool-create-button",TOOL_CREATE_LTILEGACY_BUTTON:"#tool-createltilegacy-button",REGISTRATION_CHOICE_CONTAINER:"#registration-choice-container",TOOL_URL:"#tool-url"},k=function(){return a(j.TOOL_LIST_CONTAINER)},l=function(){return a(j.EXTERNAL_REGISTRATION_CONTAINER)},m=function(){return a(j.CARTRIDGE_REGISTRATION_CONTAINER)},n=function(){return a(j.REGISTRATION_CHOICE_CONTAINER)},o=function(b){if(b.data&&"org.imsglobal.lti.close"===b.data.subject){a(j.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER).empty();r();w();z();w();D()}},p=function(b){a(j.EXTERNAL_REGISTRATION_PAGE_CONTAINER).removeClass("hidden");var c=a(j.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER);c.append(a("<iframe src='startltiadvregistration.php?url="+encodeURIComponent(b)+"'></iframe>"));u();window.addEventListener("message",o,!1)},q=function(){return a(j.TOOL_URL).val()},r=function(){l().addClass("hidden")},s=function(){m().addClass("hidden")},t=function(){n().addClass("hidden")},u=function(){s();t();l().removeClass("hidden");x(l())},v=function(a){r();t();var b=m();b.find("input").val("");b.removeClass("hidden");b.find(j.CARTRIDGE_REGISTRATION_FORM).attr("data-cartridge-url",a);x(b)},w=function(){r();s();n().removeClass("hidden");x(n())},x=function(a){var b=a.children().detach();b.appendTo(a)},y=function(){k().addClass("hidden")},z=function(){k().removeClass("hidden")},A=function(a){var b=a.error?"error":"success";c.addNotification({message:a.message,type:b})},B=function(a){a.addClass("loading")},C=function(a){a.removeClass("loading")},D=function(){var b=a.Deferred(),e=k();B(e);a.when(g.query(),h.query({orphanedonly:!0})).done(function(a,c){d.render("mod_lti/tool_list",{tools:a,proxies:c}).done(function(a,c){e.empty();e.append(a);d.runTemplateJS(c);b.resolve()}).fail(b.reject)}).fail(b.reject);b.fail(c.exception).always(function(){C(e)})},E=function(){var b=a.trim(q());if(b){a(j.TOOL_URL).val("");y();p(b)}},F=function(){var b=a.trim(q());if(""===b){return a.Deferred().resolve()}var d=a(j.TOOL_CREATE_LTILEGACY_BUTTON);B(d);var f=g.isCartridge(b);f.always(function(){C(d)});f.done(function(c){if(c.iscartridge){a(j.TOOL_URL).val("");a(document).trigger(e.START_CARTRIDGE_REGISTRATION,b)}else{a(document).trigger(e.START_EXTERNAL_REGISTRATION,{url:b})}});f.fail(function(){i.get_string("errorbadurl","mod_lti").done(function(b){a(document).trigger(e.REGISTRATION_FEEDBACK,{message:b,error:!0})}).fail(c.exception)});return f},G=function(){a(document).on(e.NEW_TOOL_TYPE,function(){D()});a(document).on(e.START_EXTERNAL_REGISTRATION,function(){u();a(j.TOOL_URL).val("");y()});a(document).on(e.STOP_EXTERNAL_REGISTRATION,function(){z();w()});a(document).on(e.START_CARTRIDGE_REGISTRATION,function(a,b){v(b)});a(document).on(e.STOP_CARTRIDGE_REGISTRATION,function(){m().find(j.CARTRIDGE_REGISTRATION_FORM).removeAttr("data-cartridge-url");w()});a(document).on(e.REGISTRATION_FEEDBACK,function(a,b){A(b)});var b=a(j.TOOL_CREATE_LTILEGACY_BUTTON);b.click(function(a){a.preventDefault();F()});var c=a(j.TOOL_CREATE_BUTTON);c.click(function(a){a.preventDefault();E()})};return{init:function init(){G();D()}}});
|
||||
//# sourceMappingURL=tool_configure_controller.min.js.map
|
||||
|
File diff suppressed because one or more lines are too long
@ -484,10 +484,7 @@
|
||||
return toolTypeData;
|
||||
}).then(function(toolTypeData) {
|
||||
return templates.render('mod_lti/tool_card', toolTypeData);
|
||||
}).then(function(renderResult) {
|
||||
var html = renderResult[0];
|
||||
var js = renderResult[1];
|
||||
|
||||
}).then(function(html, js) {
|
||||
templates.replaceNode(element, html, js);
|
||||
return;
|
||||
}).catch(function() {
|
||||
|
@ -32,26 +32,17 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/e
|
||||
var SELECTORS = {
|
||||
EXTERNAL_REGISTRATION_CONTAINER: '#external-registration-container',
|
||||
EXTERNAL_REGISTRATION_PAGE_CONTAINER: '#external-registration-page-container',
|
||||
EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER: '#external-registration-template-container',
|
||||
CARTRIDGE_REGISTRATION_CONTAINER: '#cartridge-registration-container',
|
||||
CARTRIDGE_REGISTRATION_FORM: '#cartridge-registration-form',
|
||||
ADD_TOOL_FORM: '#add-tool-form',
|
||||
TOOL_LIST_CONTAINER: '#tool-list-container',
|
||||
TOOL_CREATE_BUTTON: '#tool-create-button',
|
||||
TOOL_CREATE_LTILEGACY_BUTTON: '#tool-createltilegacy-button',
|
||||
REGISTRATION_CHOICE_CONTAINER: '#registration-choice-container',
|
||||
TOOL_URL: '#tool-url'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the tool create button element.
|
||||
*
|
||||
* @method getToolCreateButton
|
||||
* @private
|
||||
* @return {Object} jQuery object
|
||||
*/
|
||||
var getToolCreateButton = function() {
|
||||
return $(SELECTORS.TOOL_CREATE_BUTTON);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the tool list container element.
|
||||
*
|
||||
@ -96,6 +87,40 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/e
|
||||
return $(SELECTORS.REGISTRATION_CHOICE_CONTAINER);
|
||||
};
|
||||
|
||||
/**
|
||||
* Close the LTI Advantage Registration IFrame.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} e post message event sent from the registration frame.
|
||||
*/
|
||||
var closeLTIAdvRegistration = function(e) {
|
||||
if (e.data && 'org.imsglobal.lti.close' === e.data.subject) {
|
||||
$(SELECTORS.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER).empty();
|
||||
hideExternalRegistration();
|
||||
showRegistrationChoices();
|
||||
showToolList();
|
||||
showRegistrationChoices();
|
||||
reloadToolList();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the external registration template and render it in the DOM and display it.
|
||||
*
|
||||
* @method initiateRegistration
|
||||
* @private
|
||||
* @param {String} url where to send the registration request
|
||||
*/
|
||||
var initiateRegistration = function(url) {
|
||||
// Show the external registration page in an iframe.
|
||||
$(SELECTORS.EXTERNAL_REGISTRATION_PAGE_CONTAINER).removeClass('hidden');
|
||||
var container = $(SELECTORS.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER);
|
||||
container.append($("<iframe src='startltiadvregistration.php?url="
|
||||
+ encodeURIComponent(url) + "'></iframe>"));
|
||||
showExternalRegistration();
|
||||
window.addEventListener("message", closeLTIAdvRegistration, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the tool type URL.
|
||||
*
|
||||
@ -287,22 +312,38 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/e
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start the LTI Advantage registration.
|
||||
*
|
||||
* @method addLTIAdvTool
|
||||
* @private
|
||||
*/
|
||||
var addLTIAdvTool = function() {
|
||||
var url = $.trim(getToolURL());
|
||||
|
||||
if (url) {
|
||||
$(SELECTORS.TOOL_URL).val('');
|
||||
hideToolList();
|
||||
initiateRegistration(url);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger appropriate registration process process for the user input
|
||||
* URL. It can either be a cartridge or a registration url.
|
||||
*
|
||||
* @method addTool
|
||||
* @method addLTILegacyTool
|
||||
* @private
|
||||
* @return {Promise} jQuery Deferred object
|
||||
*/
|
||||
var addTool = function() {
|
||||
var addLTILegacyTool = function() {
|
||||
var url = $.trim(getToolURL());
|
||||
|
||||
if (url === "") {
|
||||
return $.Deferred().resolve();
|
||||
}
|
||||
|
||||
var toolButton = getToolCreateButton();
|
||||
var toolButton = $(SELECTORS.TOOL_CREATE_LTILEGACY_BUTTON);
|
||||
startLoading(toolButton);
|
||||
|
||||
var promise = toolType.isCartridge(url);
|
||||
@ -372,10 +413,16 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/e
|
||||
showRegistrationFeedback(data);
|
||||
});
|
||||
|
||||
var form = $(SELECTORS.ADD_TOOL_FORM);
|
||||
form.submit(function(e) {
|
||||
var addLegacyButton = $(SELECTORS.TOOL_CREATE_LTILEGACY_BUTTON);
|
||||
addLegacyButton.click(function(e) {
|
||||
e.preventDefault();
|
||||
addTool();
|
||||
addLTILegacyTool();
|
||||
});
|
||||
|
||||
var addLTIButton = $(SELECTORS.TOOL_CREATE_BUTTON);
|
||||
addLTIButton.click(function(e) {
|
||||
e.preventDefault();
|
||||
addLTIAdvTool();
|
||||
});
|
||||
|
||||
};
|
||||
|
@ -21,28 +21,13 @@
|
||||
* @copyright 2019 Stephen Vickers
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
use mod_lti\local\ltiopenid\jwks_helper;
|
||||
|
||||
define('NO_DEBUG_DISPLAY', true);
|
||||
define('NO_MOODLE_COOKIES', true);
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
|
||||
$jwks = array('keys' => array());
|
||||
|
||||
$privatekey = get_config('mod_lti', 'privatekey');
|
||||
$res = openssl_pkey_get_private($privatekey);
|
||||
$details = openssl_pkey_get_details($res);
|
||||
|
||||
$jwk = array();
|
||||
$jwk['kty'] = 'RSA';
|
||||
$jwk['alg'] = 'RS256';
|
||||
$jwk['kid'] = get_config('mod_lti', 'kid');
|
||||
$jwk['e'] = rtrim(strtr(base64_encode($details['rsa']['e']), '+/', '-_'), '=');
|
||||
$jwk['n'] = rtrim(strtr(base64_encode($details['rsa']['n']), '+/', '-_'), '=');
|
||||
$jwk['use'] = 'sig';
|
||||
|
||||
$jwks['keys'][] = $jwk;
|
||||
|
||||
@header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
echo json_encode($jwks, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||||
echo json_encode(jwks_helper::get_jwks(), JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||||
|
72
mod/lti/classes/local/ltiopenid/jwks_helper.php
Normal file
72
mod/lti/classes/local/ltiopenid/jwks_helper.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?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 files exposes functions for LTI 1.3 Key Management.
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Claude Vervoort (Cengage)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_lti\local\ltiopenid;
|
||||
|
||||
/**
|
||||
* This class exposes functions for LTI 1.3 Key Management.
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Claude Vervoort (Cengage)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class jwks_helper {
|
||||
|
||||
/**
|
||||
* Returns the private key to use to sign outgoing JWT.
|
||||
*
|
||||
* @return array keys are kid and key in PEM format.
|
||||
*/
|
||||
public static function get_private_key() {
|
||||
$privatekey = get_config('mod_lti', 'privatekey');
|
||||
$kid = get_config('mod_lti', 'kid');
|
||||
return [
|
||||
"key" => $privatekey,
|
||||
"kid" => $kid
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWK Key Set for this site.
|
||||
* @return array keyset exposting the site public key.
|
||||
*/
|
||||
public static function get_jwks() {
|
||||
$jwks = array('keys' => array());
|
||||
|
||||
$privatekey = self::get_private_key();
|
||||
$res = openssl_pkey_get_private($privatekey['key']);
|
||||
$details = openssl_pkey_get_details($res);
|
||||
|
||||
$jwk = array();
|
||||
$jwk['kty'] = 'RSA';
|
||||
$jwk['alg'] = 'RS256';
|
||||
$jwk['kid'] = $privatekey['kid'];
|
||||
$jwk['e'] = rtrim(strtr(base64_encode($details['rsa']['e']), '+/', '-_'), '=');
|
||||
$jwk['n'] = rtrim(strtr(base64_encode($details['rsa']['n']), '+/', '-_'), '=');
|
||||
$jwk['use'] = 'sig';
|
||||
|
||||
$jwks['keys'][] = $jwk;
|
||||
return $jwks;
|
||||
}
|
||||
|
||||
}
|
32
mod/lti/classes/local/ltiopenid/registration_exception.php
Normal file
32
mod/lti/classes/local/ltiopenid/registration_exception.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?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 library exposes functions for LTI Dynamic Registration.
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Claude Vervoort (Cengage), Carlos Costa, Adrian Hutchinson (Macgraw Hill)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_lti\local\ltiopenid;
|
||||
|
||||
/**
|
||||
* Exception when transforming the registration to LTI config.
|
||||
*
|
||||
* Code is the HTTP Error code.
|
||||
*/
|
||||
class registration_exception extends \Exception {
|
||||
}
|
345
mod/lti/classes/local/ltiopenid/registration_helper.php
Normal file
345
mod/lti/classes/local/ltiopenid/registration_helper.php
Normal file
@ -0,0 +1,345 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* A Helper for LTI Dynamic Registration.
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Claude Vervoort (Cengage), Carlos Costa, Adrian Hutchinson (Macgraw Hill)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_lti\local\ltiopenid;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
use Firebase\JWT\JWK;
|
||||
use Firebase\JWT\JWT;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* This class exposes functions for LTI Dynamic Registration.
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Claude Vervoort (Cengage), Carlos Costa, Adrian Hutchinson (Macgraw Hill)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class registration_helper {
|
||||
/** score scope */
|
||||
const SCOPE_SCORE = 'https://purl.imsglobal.org/spec/lti-ags/scope/score';
|
||||
/** result scope */
|
||||
const SCOPE_RESULT = 'https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly';
|
||||
/** lineitem read-only scope */
|
||||
const SCOPE_LINEITEM_RO = 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly';
|
||||
/** lineitem full access scope */
|
||||
const SCOPE_LINEITEM = 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem';
|
||||
/** Names and Roles (membership) scope */
|
||||
const SCOPE_NRPS = 'https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly';
|
||||
/** Tool Settings scope */
|
||||
const SCOPE_TOOL_SETTING = 'https://purl.imsglobal.org/spec/lti-ts/scope/toolsetting';
|
||||
|
||||
|
||||
/**
|
||||
* Function used to validate parameters.
|
||||
*
|
||||
* This function is needed because the payload contains nested
|
||||
* objects, and optional_param() does not support arrays of arrays.
|
||||
*
|
||||
* @param array $payload that may contain the parameter key
|
||||
* @param string $key the key of the value to be looked for in the payload
|
||||
* @param bool $required if required, not finding a value will raise a registration_exception
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function get_parameter(array $payload, string $key, bool $required) {
|
||||
if (!isset($payload[$key]) || empty($payload[$key])) {
|
||||
if ($required) {
|
||||
throw new registration_exception('missing required attribute '.$key, 400);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
$parameter = $payload[$key];
|
||||
// Cleans parameters to avoid XSS and other issues.
|
||||
if (is_array($parameter)) {
|
||||
return clean_param_array($parameter, PARAM_TEXT, true);
|
||||
}
|
||||
return clean_param($parameter, PARAM_TEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an LTI 1.3 Registration to a Moodle LTI Config.
|
||||
*
|
||||
* @param array $registrationpayload the registration data received from the tool.
|
||||
* @param string $clientid the clientid to be issued for that tool.
|
||||
*
|
||||
* @return object the Moodle LTI config.
|
||||
*/
|
||||
public static function registration_to_config(array $registrationpayload, string $clientid): object {
|
||||
$responsetypes = self::get_parameter($registrationpayload, 'response_types', true);
|
||||
$initiateloginuri = self::get_parameter($registrationpayload, 'initiate_login_uri', true);
|
||||
$redirecturis = self::get_parameter($registrationpayload, 'redirect_uris', true);
|
||||
$clientname = self::get_parameter($registrationpayload, 'client_name', true);
|
||||
$jwksuri = self::get_parameter($registrationpayload, 'jwks_uri', true);
|
||||
$tokenendpointauthmethod = self::get_parameter($registrationpayload, 'token_endpoint_auth_method', true);
|
||||
|
||||
$applicationtype = self::get_parameter($registrationpayload, 'application_type', false);
|
||||
$logouri = self::get_parameter($registrationpayload, 'logo_uri', false);
|
||||
|
||||
$ltitoolconfiguration = self::get_parameter($registrationpayload,
|
||||
'https://purl.imsglobal.org/spec/lti-tool-configuration', true);
|
||||
|
||||
$domain = self::get_parameter($ltitoolconfiguration, 'domain', true);
|
||||
$targetlinkuri = self::get_parameter($ltitoolconfiguration, 'target_link_uri', true);
|
||||
$customparameters = self::get_parameter($ltitoolconfiguration, 'custom_parameters', false);
|
||||
$scopes = explode(" ", self::get_parameter($registrationpayload, 'scope', false) ?? '');
|
||||
$claims = self::get_parameter($ltitoolconfiguration, 'claims', false);
|
||||
$messages = $ltitoolconfiguration['messages'] ?? [];
|
||||
$description = self::get_parameter($ltitoolconfiguration, 'description', false);
|
||||
|
||||
// Validate response type.
|
||||
// According to specification, for this scenario, id_token must be explicitly set.
|
||||
if (!in_array('id_token', $responsetypes)) {
|
||||
throw new registration_exception('invalid_response_types', 400);
|
||||
}
|
||||
|
||||
// According to specification, this parameter needs to be an array.
|
||||
if (!is_array($redirecturis)) {
|
||||
throw new registration_exception('invalid_redirect_uris', 400);
|
||||
}
|
||||
|
||||
// According to specification, for this scenario private_key_jwt must be explicitly set.
|
||||
if ($tokenendpointauthmethod !== 'private_key_jwt') {
|
||||
throw new registration_exception('invalid_token_endpoint_auth_method', 400);
|
||||
}
|
||||
|
||||
if (!empty($applicationtype) && $applicationtype !== 'web') {
|
||||
throw new registration_exception('invalid_application_type', 400);
|
||||
}
|
||||
|
||||
$config = new stdClass();
|
||||
$config->lti_clientid = $clientid;
|
||||
$config->lti_toolurl = $targetlinkuri;
|
||||
$config->lti_tooldomain = $domain;
|
||||
$config->lti_typename = $clientname;
|
||||
$config->lti_description = $description;
|
||||
$config->lti_ltiversion = LTI_VERSION_1P3;
|
||||
$config->lti_organizationid_default = LTI_DEFAULT_ORGID_SITEID;
|
||||
$config->lti_icon = $logouri;
|
||||
$config->lti_coursevisible = LTI_COURSEVISIBLE_PRECONFIGURED;
|
||||
$config->lti_contentitem = 0;
|
||||
// Sets Content Item.
|
||||
if (!empty($messages)) {
|
||||
$messagesresponse = [];
|
||||
foreach ($messages as $value) {
|
||||
if ($value['type'] === 'LtiDeepLinkingRequest') {
|
||||
$config->lti_contentitem = 1;
|
||||
$config->lti_toolurl_ContentItemSelectionRequest = $value['target_link_uri'] ?? '';
|
||||
array_push($messagesresponse, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config->lti_keytype = 'JWK_KEYSET';
|
||||
$config->lti_publickeyset = $jwksuri;
|
||||
$config->lti_initiatelogin = $initiateloginuri;
|
||||
$config->lti_redirectionuris = implode(PHP_EOL, $redirecturis);
|
||||
$config->lti_customparameters = '';
|
||||
// Sets custom parameters.
|
||||
if (isset($customparameters)) {
|
||||
$paramssarray = [];
|
||||
foreach ($customparameters as $key => $value) {
|
||||
array_push($paramssarray, $key . '=' . $value);
|
||||
}
|
||||
$config->lti_customparameters = implode(PHP_EOL, $paramssarray);
|
||||
}
|
||||
// Sets launch container.
|
||||
$config->lti_launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
|
||||
|
||||
// Sets Service info based on scopes.
|
||||
$config->lti_acceptgrades = LTI_SETTING_NEVER;
|
||||
$config->ltiservice_gradesynchronization = 0;
|
||||
$config->ltiservice_memberships = 0;
|
||||
$config->ltiservice_toolsettings = 0;
|
||||
if (isset($scopes)) {
|
||||
// Sets Assignment and Grade Services info.
|
||||
|
||||
if (in_array(self::SCOPE_SCORE, $scopes)) {
|
||||
$config->lti_acceptgrades = LTI_SETTING_DELEGATE;
|
||||
$config->ltiservice_gradesynchronization = 1;
|
||||
}
|
||||
if (in_array(self::SCOPE_RESULT, $scopes)) {
|
||||
$config->lti_acceptgrades = LTI_SETTING_DELEGATE;
|
||||
$config->ltiservice_gradesynchronization = 1;
|
||||
}
|
||||
if (in_array(self::SCOPE_LINEITEM_RO, $scopes)) {
|
||||
$config->lti_acceptgrades = LTI_SETTING_DELEGATE;
|
||||
$config->ltiservice_gradesynchronization = 1;
|
||||
}
|
||||
if (in_array(self::SCOPE_LINEITEM, $scopes)) {
|
||||
$config->lti_acceptgrades = LTI_SETTING_DELEGATE;
|
||||
$config->ltiservice_gradesynchronization = 2;
|
||||
}
|
||||
|
||||
// Sets Names and Role Provisioning info.
|
||||
if (in_array(self::SCOPE_NRPS, $scopes)) {
|
||||
$config->ltiservice_memberships = 1;
|
||||
}
|
||||
|
||||
// Sets Tool Settings info.
|
||||
if (in_array(self::SCOPE_TOOL_SETTING, $scopes)) {
|
||||
$config->ltiservice_toolsettings = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Sets privacy settings.
|
||||
$config->lti_sendname = LTI_SETTING_NEVER;
|
||||
$config->lti_sendemailaddr = LTI_SETTING_NEVER;
|
||||
if (isset($claims)) {
|
||||
// Sets name privacy settings.
|
||||
|
||||
if (in_array('name', $claims)) {
|
||||
$config->lti_sendname = LTI_SETTING_ALWAYS;
|
||||
}
|
||||
if (in_array('given_name', $claims)) {
|
||||
$config->lti_sendname = LTI_SETTING_ALWAYS;
|
||||
}
|
||||
if (in_array('family_name', $claims)) {
|
||||
$config->lti_sendname = LTI_SETTING_ALWAYS;
|
||||
}
|
||||
|
||||
// Sets email privacy settings.
|
||||
if (in_array('email', $claims)) {
|
||||
$config->lti_sendemailaddr = LTI_SETTING_ALWAYS;
|
||||
}
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a moodle LTI 1.3 Config to an OAuth/LTI Client Registration.
|
||||
*
|
||||
* @param object $config Moodle LTI Config.
|
||||
* @param int $typeid which is the LTI deployment id.
|
||||
*
|
||||
* @return array the Client Registration as an associative array.
|
||||
*/
|
||||
public static function config_to_registration(object $config, int $typeid): array {
|
||||
$registrationresponse = [];
|
||||
$registrationresponse['client_id'] = $config->lti_clientid;
|
||||
$registrationresponse['token_endpoint_auth_method'] = ['private_key_jwt'];
|
||||
$registrationresponse['response_types'] = ['id_token'];
|
||||
$registrationresponse['jwks_uri'] = $config->lti_publickeyset;
|
||||
$registrationresponse['initiate_login_uri'] = $config->lti_initiatelogin;
|
||||
$registrationresponse['grant_types'] = ['client_credentials', 'implicit'];
|
||||
$registrationresponse['redirect_uris'] = explode(PHP_EOL, $config->lti_redirectionuris);
|
||||
$registrationresponse['application_type'] = ['web'];
|
||||
$registrationresponse['token_endpoint_auth_method'] = 'private_key_jwt';
|
||||
$registrationresponse['client_name'] = $config->lti_typename;
|
||||
$registrationresponse['logo_uri'] = $config->lti_icon ?? '';
|
||||
$lticonfigurationresponse = [];
|
||||
$lticonfigurationresponse['deployment_id'] = strval($typeid);
|
||||
$lticonfigurationresponse['target_link_uri'] = $config->lti_toolurl;
|
||||
$lticonfigurationresponse['domain'] = $config->lti_tooldomain ?? '';
|
||||
$lticonfigurationresponse['description'] = $config->lti_description ?? '';
|
||||
if ($config->lti_contentitem == 1) {
|
||||
$contentitemmessage = [];
|
||||
$contentitemmessage['type'] = 'LtiDeepLinkingRequest';
|
||||
if (isset($config->lti_toolurl_ContentItemSelectionRequest)) {
|
||||
$contentitemmessage['target_link_uri'] = $config->lti_toolurl_ContentItemSelectionRequest;
|
||||
}
|
||||
$lticonfigurationresponse['messages'] = [$contentitemmessage];
|
||||
}
|
||||
if (isset($config->lti_customparameters) && !empty($config->lti_customparameters)) {
|
||||
$params = [];
|
||||
foreach (explode(PHP_EOL, $config->lti_customparameters) as $param) {
|
||||
$split = explode('=', $param);
|
||||
$params[$split[0]] = $split[1];
|
||||
}
|
||||
$lticonfigurationresponse['custom_parameters'] = $params;
|
||||
}
|
||||
$scopesresponse = [];
|
||||
if ($config->ltiservice_gradesynchronization > 0) {
|
||||
$scopesresponse[] = self::SCOPE_SCORE;
|
||||
$scopesresponse[] = self::SCOPE_RESULT;
|
||||
$scopesresponse[] = self::SCOPE_LINEITEM_RO;
|
||||
}
|
||||
if ($config->ltiservice_gradesynchronization == 2) {
|
||||
$scopesresponse[] = self::SCOPE_LINEITEM;
|
||||
}
|
||||
if ($config->ltiservice_memberships == 1) {
|
||||
$scopesresponse[] = self::SCOPE_NRPS;
|
||||
}
|
||||
if ($config->ltiservice_toolsettings == 1) {
|
||||
$scopesresponse[] = self::SCOPE_TOOL_SETTING;
|
||||
}
|
||||
$registrationresponse['scope'] = implode(' ', $scopesresponse);
|
||||
|
||||
$claimsresponse = ['sub', 'iss'];
|
||||
if ($config->lti_sendname = LTI_SETTING_ALWAYS) {
|
||||
$claimsresponse[] = 'name';
|
||||
$claimsresponse[] = 'family_name';
|
||||
$claimsresponse[] = 'middle_name';
|
||||
}
|
||||
if ($config->lti_sendemailaddr = LTI_SETTING_ALWAYS) {
|
||||
$claimsresponse[] = 'email';
|
||||
}
|
||||
$lticonfigurationresponse['claims'] = $claimsresponse;
|
||||
$registrationresponse['https://purl.imsglobal.org/spec/lti-tool-configuration'] = $lticonfigurationresponse;
|
||||
return $registrationresponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the registration token is properly signed and not used yet.
|
||||
* Return the client id to use for this registration.
|
||||
*
|
||||
* @param string $registrationtokenjwt registration token
|
||||
*
|
||||
* @return string client id for the registration
|
||||
*/
|
||||
public static function validate_registration_token(string $registrationtokenjwt): string {
|
||||
global $DB;
|
||||
$keys = JWK::parseKeySet(jwks_helper::get_jwks());
|
||||
$registrationtoken = JWT::decode($registrationtokenjwt, $keys, ['RS256']);
|
||||
|
||||
// Get clientid from registrationtoken.
|
||||
$clientid = $registrationtoken->sub;
|
||||
|
||||
// Checks if clientid is already registered.
|
||||
if (!empty($DB->get_record('lti_types', array('clientid' => $clientid)))) {
|
||||
throw new registration_exception("token_already_used", 401);
|
||||
}
|
||||
return $clientid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an array with the scopes for services supported by the LTI module
|
||||
*
|
||||
* @return array List of scopes
|
||||
*/
|
||||
public static function lti_get_service_scopes() {
|
||||
|
||||
$services = lti_get_services();
|
||||
$scopes = array();
|
||||
foreach ($services as $service) {
|
||||
$servicescopes = $service->get_scopes();
|
||||
if (!empty($servicescopes)) {
|
||||
$scopes = array_merge($scopes, $servicescopes);
|
||||
}
|
||||
}
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
}
|
@ -207,7 +207,7 @@ abstract class service_base {
|
||||
abstract public function get_resources();
|
||||
|
||||
/**
|
||||
* Get the scope(s) permitted for this service.
|
||||
* Get the scope(s) permitted for this service in the context of a particular tool type.
|
||||
*
|
||||
* A null value indicates that no scopes are required to access the service.
|
||||
*
|
||||
@ -217,6 +217,17 @@ abstract class service_base {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scope(s) permitted for this service.
|
||||
*
|
||||
* A null value indicates that no scopes are required to access the service.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_scopes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration options for this service.
|
||||
*
|
||||
|
@ -66,6 +66,8 @@ $string['activate'] = 'Activate';
|
||||
$string['activatetoadddescription'] = 'You will need to activate this tool before you can add a description.';
|
||||
$string['active'] = 'Active';
|
||||
$string['activity'] = 'Activity';
|
||||
$string['add_ltiadv'] = 'Add LTI Advantage';
|
||||
$string['add_ltilegacy'] = 'Add Legacy LTI';
|
||||
$string['addnewapp'] = 'Enable external application';
|
||||
$string['addserver'] = 'Add new trusted server';
|
||||
$string['addtype'] = 'Add preconfigured tool';
|
||||
|
@ -54,6 +54,7 @@ defined('MOODLE_INTERNAL') || die;
|
||||
use moodle\mod\lti as lti;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\JWK;
|
||||
use mod_lti\local\ltiopenid\jwks_helper;
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot.'/mod/lti/OAuth.php');
|
||||
@ -2720,7 +2721,11 @@ function lti_get_type_type_config($id) {
|
||||
function lti_prepare_type_for_save($type, $config) {
|
||||
if (isset($config->lti_toolurl)) {
|
||||
$type->baseurl = $config->lti_toolurl;
|
||||
$type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);
|
||||
if (isset($config->lti_tooldomain)) {
|
||||
$type->tooldomain = $config->lti_tooldomain;
|
||||
} else {
|
||||
$type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);
|
||||
}
|
||||
}
|
||||
if (isset($config->lti_description)) {
|
||||
$type->description = $config->lti_description;
|
||||
@ -3273,9 +3278,8 @@ function lti_sign_jwt($parms, $endpoint, $oauthconsumerkey, $typeid = 0, $nonce
|
||||
}
|
||||
}
|
||||
|
||||
$privatekey = get_config('mod_lti', 'privatekey');
|
||||
$kid = get_config('mod_lti', 'kid');
|
||||
$jwt = JWT::encode($payload, $privatekey, 'RS256', $kid);
|
||||
$privatekey = jwks_helper::get_private_key();
|
||||
$jwt = JWT::encode($payload, $privatekey['key'], 'RS256', $privatekey['kid']);
|
||||
|
||||
$newparms = array();
|
||||
$newparms['id_token'] = $jwt;
|
||||
@ -3820,6 +3824,7 @@ function lti_get_service_by_resource_id($services, $resourceid) {
|
||||
|
||||
/**
|
||||
* Initializes an array with the scopes for services supported by the LTI module
|
||||
* and authorized for this particular tool instance.
|
||||
*
|
||||
* @param object $type LTI tool type
|
||||
* @param array $typeconfig LTI tool type configuration
|
||||
@ -3840,7 +3845,6 @@ function lti_get_permitted_service_scopes($type, $typeconfig) {
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4455,3 +4459,4 @@ function lti_new_access_token($typeid, $scopes) {
|
||||
return $newtoken;
|
||||
|
||||
}
|
||||
|
||||
|
61
mod/lti/openid-configuration.php
Normal file
61
mod/lti/openid-configuration.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?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 the OpenId/LTI Configuration for this site.
|
||||
*
|
||||
* It is part of the LTI Tool Dynamic Registration, and used by
|
||||
* tools to get the site configuration and registration end-point.
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Claude Vervoort (Cengage), Carlos Costa, Adrian Hutchinson (Macgraw Hill)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_lti\local\ltiopenid\registration_helper;
|
||||
|
||||
define('NO_DEBUG_DISPLAY', true);
|
||||
define('NO_MOODLE_COOKIES', true);
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
require_once($CFG->libdir.'/weblib.php');
|
||||
|
||||
$scopes = registration_helper::lti_get_service_scopes();
|
||||
$scopes[] = 'openid';
|
||||
$conf = [
|
||||
'issuer' => $CFG->wwwroot,
|
||||
'token_endpoint' => (new moodle_url('/mod/lti/token.php'))->out(false),
|
||||
'token_endpoint_auth_methods_supported' => ['private_key_jwt'],
|
||||
'token_endpoint_auth_signing_alg_values_supported' => ['RS256'],
|
||||
'jwks_uri' => (new moodle_url('/mod/lti/certs.php'))->out(false),
|
||||
'registration_endpoint' => (new moodle_url('/mod/lti/openid-registration.php'))->out(false),
|
||||
'scopes_supported' => $scopes,
|
||||
'response_types_supported' => ['id_token'],
|
||||
'subject_types_supported' => ['public', 'pairwise'],
|
||||
'id_token_signing_alg_values_supported' => ['RS256'],
|
||||
'claims_supported' => ['sub', 'iss', 'name', 'given_name', 'family_name', 'email'],
|
||||
'https://purl.imsglobal.org/spec/lti-platform-configuration ' => [
|
||||
'product_family_code' => 'moodle',
|
||||
'version' => $CFG->release,
|
||||
'messages_supported' => ['LtiResourceLink', 'LtiDeepLinkingRequest'],
|
||||
'placements' => ['AddContentMenu'],
|
||||
'variables' => array_keys(lti_get_capabilities())
|
||||
]
|
||||
];
|
||||
|
||||
@header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
echo json_encode($conf, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
62
mod/lti/openid-registration.php
Normal file
62
mod/lti/openid-registration.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?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 receives a registration request along with the registration token and returns a client_id.
|
||||
*
|
||||
* @copyright 2020 Claude Vervoort (Cengage), Carlos Costa, Adrian Hutchinson (Macgraw Hill)
|
||||
* @package mod_lti
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define('NO_DEBUG_DISPLAY', true);
|
||||
define('NO_MOODLE_COOKIES', true);
|
||||
|
||||
use mod_lti\local\ltiopenid\registration_helper;
|
||||
use mod_lti\local\ltiopenid\registration_exception;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/lti/locallib.php');
|
||||
|
||||
$code = 200;
|
||||
$message = '';
|
||||
// Retrieve registration token from Bearer Authorization header.
|
||||
$authheader = moodle\mod\lti\OAuthUtil::get_headers() ['Authorization'] ?? '';
|
||||
if (!($authheader && substr($authheader, 0, 7) == 'Bearer ')) {
|
||||
$message = 'missing_registration_token';
|
||||
$code = 401;
|
||||
} else {
|
||||
$registrationpayload = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
// Registers tool.
|
||||
$type = new stdClass();
|
||||
$type->state = LTI_TOOL_STATE_PENDING;
|
||||
try {
|
||||
$clientid = registration_helper::validate_registration_token(trim(substr($authheader, 7)));
|
||||
$config = registration_helper::registration_to_config($registrationpayload, $clientid);
|
||||
$typeid = lti_add_type($type, clone $config);
|
||||
$message = json_encode(registration_helper::config_to_registration($config, $typeid));
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
} catch (registration_exception $e) {
|
||||
$code = $e->getCode();
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
}
|
||||
$response = new \mod_lti\local\ltiservice\response();
|
||||
// Set code.
|
||||
$response->set_code($code);
|
||||
// Set body.
|
||||
$response->set_body($message);
|
||||
$response->send();
|
@ -81,4 +81,13 @@ class basicoutcomes extends \mod_lti\local\ltiservice\service_base {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scope(s) permitted for the tool relevant to this service.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_scopes() {
|
||||
return [self::SCOPE_BASIC_OUTCOMES];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -112,6 +112,16 @@ class gradebookservices extends service_base {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scopes defined by this service.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_scopes() {
|
||||
return [self::SCOPE_GRADEBOOKSERVICES_LINEITEM_READ, self::SCOPE_GRADEBOOKSERVICES_RESULT_READ,
|
||||
self::SCOPE_GRADEBOOKSERVICES_SCORE, self::SCOPE_GRADEBOOKSERVICES_LINEITEM];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds form elements for gradebook sync add/edit page.
|
||||
*
|
||||
|
@ -102,6 +102,15 @@ class memberships extends \mod_lti\local\ltiservice\service_base {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scope(s) defined by this service.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_scopes() {
|
||||
return [self::SCOPE_MEMBERSHIPS_READ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON for members.
|
||||
*
|
||||
|
@ -88,6 +88,15 @@ class toolsettings extends \mod_lti\local\ltiservice\service_base {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scope(s) defined this service.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_scopes() {
|
||||
return [self::SCOPE_TOOL_SETTINGS];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distinct settings from each level by removing any duplicates from higher levels.
|
||||
*
|
||||
|
51
mod/lti/startltiadvregistration.php
Normal file
51
mod/lti/startltiadvregistration.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Redirect the user to registration with token and openid config url as query params.
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Cengage
|
||||
* @author Claude Vervoort
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
|
||||
use mod_lti\local\ltiopenid\jwks_helper;
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir.'/weblib.php');
|
||||
|
||||
require_login();
|
||||
$context = context_system::instance();
|
||||
require_capability('moodle/site:config', $context);
|
||||
|
||||
$starturl = required_param('url', PARAM_URL);
|
||||
$now = time();
|
||||
$token = [
|
||||
"sub" => random_string(15),
|
||||
"scope" => "reg",
|
||||
"iat" => $now,
|
||||
"exp" => $now + HOURSECS
|
||||
];
|
||||
$privatekey = jwks_helper::get_private_key();
|
||||
$regtoken = JWT::encode($token, $privatekey['key'], 'RS256', $privatekey['kid']);
|
||||
$confurl = new moodle_url('/mod/lti/openid-configuration.php');
|
||||
$url = new moodle_url($starturl);
|
||||
$url->param('openid_configuration', $confurl->out(false));
|
||||
$url->param('registration_token', $regtoken);
|
||||
header("Location: ".$url->out(false));
|
@ -75,15 +75,15 @@
|
||||
<div class="controls">
|
||||
<button id="cartridge-registration-submit" type="submit" class="btn btn-success">
|
||||
<span class="btn-text">{{#str}} savechanges {{/str}}</span>
|
||||
<div class="btn-loader">
|
||||
<span class="btn-loader">
|
||||
{{> mod_lti/loader }}
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
<button id="cartridge-registration-cancel" type="button" class="btn">
|
||||
<span class="btn-text">{{#str}} cancel {{/str}}</span>
|
||||
<div class="btn-loader">
|
||||
<span class="btn-loader">
|
||||
{{> mod_lti/loader }}
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,13 +29,17 @@
|
||||
Context variables required for this template:
|
||||
*
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
|
||||
}}
|
||||
<div id="external-registration-page-container">
|
||||
<button id="cancel-external-registration" class="btn btn-danger">
|
||||
<span class="btn-text">{{#str}} cancel {{/str}}</span>
|
||||
<div class="btn-loader">
|
||||
<span class="btn-loader">
|
||||
{{> mod_lti/loader }}
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
<div id="external-registration-template-container"></div>
|
||||
</div>
|
||||
|
@ -34,6 +34,6 @@
|
||||
}
|
||||
|
||||
}}
|
||||
<div class="loader">
|
||||
<span class="loader">
|
||||
{{#pix}} i/loading, core, {{#str}} loadinghelp, moodle {{/str}} {{/pix}}
|
||||
</div>
|
||||
</span>
|
||||
|
@ -29,6 +29,13 @@
|
||||
Context variables required for this template:
|
||||
*
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"configuremanualurl":"https://some.tool.example/mod/lti/typessettings.php?sesskey=OKl37bHflL&returnto=toolconfigure",
|
||||
"managetoolsurl":"https://some.tool.example/admin/settings.php?section=modsettinglti",
|
||||
"managetoolproxiesurl":"https://some.tool.example/mod/lti/toolproxies.php"
|
||||
}
|
||||
|
||||
}}
|
||||
<h2>{{#str}} manage_external_tools, mod_lti {{/str}}</h2>
|
||||
<div id="main-content-container">
|
||||
@ -46,10 +53,16 @@
|
||||
placeholder="{{#str}} toolurlplaceholder, mod_lti {{/str}}"
|
||||
required>
|
||||
<button id="tool-create-button" type="submit" class="btn btn-success">
|
||||
<span class="btn-text">{{#str}} add {{/str}}</span>
|
||||
<div class="btn-loader">
|
||||
<span class="btn-text">{{#str}} add_ltiadv, mod_lti {{/str}}</span>
|
||||
<span class="btn-loader">
|
||||
{{> mod_lti/loader }}
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
<button id="tool-createltilegacy-button" type="button" class="btn btn-warning">
|
||||
<span class="btn-text">{{#str}} add_ltilegacy, mod_lti {{/str}}</span>
|
||||
<span class="btn-loader">
|
||||
{{> mod_lti/loader }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -22,7 +22,7 @@ Feature: Configure tool types
|
||||
@javascript
|
||||
Scenario: Add a tool type from a cartridge URL
|
||||
When I set the field "url" to local url "/mod/lti/tests/fixtures/ims_cartridge_basic_lti_link.xml"
|
||||
And I press "Add"
|
||||
And I press "Add Legacy LTI"
|
||||
Then I should see "Enter your consumer key and shared secret"
|
||||
And I press "Save changes"
|
||||
And I should see "Example tool"
|
||||
@ -30,7 +30,7 @@ Feature: Configure tool types
|
||||
@javascript
|
||||
Scenario: Try to add a non-existant cartridge
|
||||
When I set the field "url" to local url "/mod/lti/tests/fixtures/nonexistant.xml"
|
||||
And I press "Add"
|
||||
And I press "Add Legacy LTI"
|
||||
Then I should see "Enter your consumer key and shared secret"
|
||||
And I press "Save changes"
|
||||
And I should see "Failed to create new tool. Please check the URL and try again."
|
||||
@ -38,6 +38,6 @@ Feature: Configure tool types
|
||||
@javascript
|
||||
Scenario: Attempt to add a tool type from a configuration URL, then cancel
|
||||
When I set the field "url" to local url "/mod/lti/tests/fixtures/tool_provider.php"
|
||||
And I press "Add"
|
||||
And I press "Add Legacy LTI"
|
||||
Then I should see "Cancel"
|
||||
And I press "cancel-external-registration"
|
||||
|
269
mod/lti/tests/openidregistration_test.php
Normal file
269
mod/lti/tests/openidregistration_test.php
Normal file
@ -0,0 +1,269 @@
|
||||
<?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 is part of BasicLTI4Moodle
|
||||
//
|
||||
// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
|
||||
// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
|
||||
// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
|
||||
// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
|
||||
// are already supporting or going to support BasicLTI. This project Implements the consumer
|
||||
// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
|
||||
// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
|
||||
// at the GESSI research group at UPC.
|
||||
// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
|
||||
// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
|
||||
// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
|
||||
//
|
||||
// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
|
||||
// of the Universitat Politecnica de Catalunya http://www.upc.edu
|
||||
// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu.
|
||||
|
||||
/**
|
||||
* This file contains unit tests for lti/openidregistrationlib.php
|
||||
*
|
||||
* @package mod_lti
|
||||
* @copyright 2020 Claude Vervoort, Cengage
|
||||
* @author Claude Vervoort
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_lti\local\ltiopenid\registration_exception;
|
||||
use mod_lti\local\ltiopenid\registration_helper;
|
||||
|
||||
/**
|
||||
* OpenId LTI Registration library tests
|
||||
*/
|
||||
class mod_lti_openidregistrationlib_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* @var string A has-it-all client registration.
|
||||
*/
|
||||
private $registrationfulljson = <<<EOD
|
||||
{
|
||||
"application_type": "web",
|
||||
"response_types": ["id_token"],
|
||||
"grant_types": ["implict", "client_credentials"],
|
||||
"initiate_login_uri": "https://client.example.org/lti/init",
|
||||
"redirect_uris":
|
||||
["https://client.example.org/callback",
|
||||
"https://client.example.org/callback2"],
|
||||
"client_name": "Virtual Garden",
|
||||
"client_name#ja": "バーチャルガーデン",
|
||||
"jwks_uri": "https://client.example.org/.well-known/jwks.json",
|
||||
"logo_uri": "https://client.example.org/logo.png",
|
||||
"policy_uri": "https://client.example.org/privacy",
|
||||
"policy_uri#ja": "https://client.example.org/privacy?lang=ja",
|
||||
"tos_uri": "https://client.example.org/tos",
|
||||
"tos_uri#ja": "https://client.example.org/tos?lang=ja",
|
||||
"token_endpoint_auth_method": "private_key_jwt",
|
||||
"contacts": ["ve7jtb@example.org", "mary@example.org"],
|
||||
"scope": "https://purl.imsglobal.org/spec/lti-ags/scope/score https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
|
||||
"https://purl.imsglobal.org/spec/lti-tool-configuration": {
|
||||
"domain": "client.example.org",
|
||||
"description": "Learn Botany by tending to your little (virtual) garden.",
|
||||
"description#ja": "小さな(仮想)庭に行くことで植物学を学びましょう。",
|
||||
"target_link_uri": "https://client.example.org/lti",
|
||||
"custom_parameters": {
|
||||
"context_history": "\$Context.id.history"
|
||||
},
|
||||
"claims": ["iss", "sub", "name", "given_name", "family_name", "email"],
|
||||
"messages": [
|
||||
{
|
||||
"type": "LtiDeepLinkingRequest",
|
||||
"target_link_uri": "https://client.example.org/lti/dl",
|
||||
"label": "Add a virtual garden",
|
||||
"label#ja": "バーチャルガーデンを追加する"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
EOD;
|
||||
|
||||
/**
|
||||
* @var string A minimalist client registration.
|
||||
*/
|
||||
private $registrationminimaljson = <<<EOD
|
||||
{
|
||||
"application_type": "web",
|
||||
"response_types": ["id_token"],
|
||||
"grant_types": ["implict", "client_credentials"],
|
||||
"initiate_login_uri": "https://client.example.org/lti/init",
|
||||
"redirect_uris":
|
||||
["https://client.example.org/callback"],
|
||||
"client_name": "Virtual Garden",
|
||||
"jwks_uri": "https://client.example.org/.well-known/jwks.json",
|
||||
"token_endpoint_auth_method": "private_key_jwt",
|
||||
"https://purl.imsglobal.org/spec/lti-tool-configuration": {
|
||||
"domain": "client.example.org",
|
||||
"target_link_uri": "https://client.example.org/lti"
|
||||
}
|
||||
}
|
||||
EOD;
|
||||
|
||||
/**
|
||||
* @var string A minimalist with deep linking client registration.
|
||||
*/
|
||||
private $registrationminimaldljson = <<<EOD
|
||||
{
|
||||
"application_type": "web",
|
||||
"response_types": ["id_token"],
|
||||
"grant_types": ["implict", "client_credentials"],
|
||||
"initiate_login_uri": "https://client.example.org/lti/init",
|
||||
"redirect_uris":
|
||||
["https://client.example.org/callback"],
|
||||
"client_name": "Virtual Garden",
|
||||
"jwks_uri": "https://client.example.org/.well-known/jwks.json",
|
||||
"token_endpoint_auth_method": "private_key_jwt",
|
||||
"https://purl.imsglobal.org/spec/lti-tool-configuration": {
|
||||
"domain": "client.example.org",
|
||||
"target_link_uri": "https://client.example.org/lti",
|
||||
"messages": [
|
||||
{
|
||||
"type": "LtiDeepLinkingRequest"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
EOD;
|
||||
|
||||
/**
|
||||
* Test the mapping from Registration JSON to LTI Config for a has-it-all tool registration.
|
||||
*/
|
||||
public function test_to_config_full() {
|
||||
$registration = json_decode($this->registrationfulljson, true);
|
||||
$registration['scope'] .= ' https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly';
|
||||
$config = registration_helper::registration_to_config($registration, 'TheClientId');
|
||||
$this->assertEquals('JWK_KEYSET', $config->lti_keytype);
|
||||
$this->assertEquals(LTI_VERSION_1P3, $config->lti_ltiversion);
|
||||
$this->assertEquals('TheClientId', $config->lti_clientid);
|
||||
$this->assertEquals('Virtual Garden', $config->lti_typename);
|
||||
$this->assertEquals('Learn Botany by tending to your little (virtual) garden.', $config->lti_description);
|
||||
$this->assertEquals('https://client.example.org/lti/init', $config->lti_initiatelogin);
|
||||
$this->assertEquals(implode(PHP_EOL, ["https://client.example.org/callback",
|
||||
"https://client.example.org/callback2"]), $config->lti_redirectionuris);
|
||||
$this->assertEquals("context_history=\$Context.id.history", $config->lti_customparameters);
|
||||
$this->assertEquals("https://client.example.org/.well-known/jwks.json", $config->lti_publickeyset);
|
||||
$this->assertEquals("https://client.example.org/logo.png", $config->lti_icon);
|
||||
$this->assertEquals(2, $config->ltiservice_gradesynchronization);
|
||||
$this->assertEquals(LTI_SETTING_DELEGATE, $config->lti_acceptgrades);
|
||||
$this->assertEquals(1, $config->ltiservice_memberships);
|
||||
$this->assertEquals(0, $config->ltiservice_toolsettings);
|
||||
$this->assertEquals(LTI_SETTING_ALWAYS, $config->lti_sendname);
|
||||
$this->assertEquals(LTI_SETTING_ALWAYS, $config->lti_sendemailaddr);
|
||||
$this->assertEquals(1, $config->lti_contentitem);
|
||||
$this->assertEquals('https://client.example.org/lti/dl', $config->lti_toolurl_ContentItemSelectionRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the mapping from Registration JSON to LTI Config for a minimal tool registration.
|
||||
*/
|
||||
public function test_to_config_minimal() {
|
||||
$registration = json_decode($this->registrationminimaljson, true);
|
||||
$config = registration_helper::registration_to_config($registration, 'TheClientId');
|
||||
$this->assertEquals('JWK_KEYSET', $config->lti_keytype);
|
||||
$this->assertEquals(LTI_VERSION_1P3, $config->lti_ltiversion);
|
||||
$this->assertEquals('TheClientId', $config->lti_clientid);
|
||||
$this->assertEquals('Virtual Garden', $config->lti_typename);
|
||||
$this->assertEmpty($config->lti_description);
|
||||
$this->assertEquals('https://client.example.org/lti/init', $config->lti_initiatelogin);
|
||||
$this->assertEquals('https://client.example.org/callback', $config->lti_redirectionuris);
|
||||
$this->assertEmpty($config->lti_customparameters);
|
||||
$this->assertEquals("https://client.example.org/.well-known/jwks.json", $config->lti_publickeyset);
|
||||
$this->assertEmpty($config->lti_icon);
|
||||
$this->assertEquals(0, $config->ltiservice_gradesynchronization);
|
||||
$this->assertEquals(LTI_SETTING_NEVER, $config->lti_acceptgrades);
|
||||
$this->assertEquals(0, $config->ltiservice_memberships);
|
||||
$this->assertEquals(LTI_SETTING_NEVER, $config->lti_sendname);
|
||||
$this->assertEquals(LTI_SETTING_NEVER, $config->lti_sendemailaddr);
|
||||
$this->assertEquals(0, $config->lti_contentitem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the mapping from Registration JSON to LTI Config for a minimal tool with
|
||||
* deep linking support registration.
|
||||
*/
|
||||
public function test_to_config_minimal_with_deeplinking() {
|
||||
$registration = json_decode($this->registrationminimaldljson, true);
|
||||
$config = registration_helper::registration_to_config($registration, 'TheClientId');
|
||||
$this->assertEquals(1, $config->lti_contentitem);
|
||||
$this->assertEmpty($config->lti_toolurl_ContentItemSelectionRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation Test: initiation login.
|
||||
*/
|
||||
public function test_validation_initlogin() {
|
||||
$registration = json_decode($this->registrationfulljson, true);
|
||||
$this->expectException(registration_exception::class);
|
||||
$this->expectExceptionCode(400);
|
||||
unset($registration['initiate_login_uri']);
|
||||
registration_helper::registration_to_config($registration, 'TheClientId');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation Test: redirect uris.
|
||||
*/
|
||||
public function test_validation_redirecturis() {
|
||||
$registration = json_decode($this->registrationfulljson, true);
|
||||
$this->expectException(registration_exception::class);
|
||||
$this->expectExceptionCode(400);
|
||||
unset($registration['redirect_uris']);
|
||||
registration_helper::registration_to_config($registration, 'TheClientId');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation Test: jwks uri empty.
|
||||
*/
|
||||
public function test_validation_jwks() {
|
||||
$registration = json_decode($this->registrationfulljson, true);
|
||||
$this->expectException(registration_exception::class);
|
||||
$this->expectExceptionCode(400);
|
||||
$registration['jwks_uri'] = '';
|
||||
registration_helper::registration_to_config($registration, 'TheClientId');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the transformation from lti config to OpenId LTI Client Registration response.
|
||||
*/
|
||||
public function test_config_to_registration() {
|
||||
$orig = json_decode($this->registrationfulljson, true);
|
||||
$orig['scope'] .= ' https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly';
|
||||
$reg = registration_helper::config_to_registration(registration_helper::registration_to_config($orig, 'clid'), 12);
|
||||
$this->assertEquals('clid', $reg['client_id']);
|
||||
$this->assertEquals($orig['response_types'], $reg['response_types']);
|
||||
$this->assertEquals($orig['initiate_login_uri'], $reg['initiate_login_uri']);
|
||||
$this->assertEquals($orig['redirect_uris'], $reg['redirect_uris']);
|
||||
$this->assertEquals($orig['jwks_uri'], $reg['jwks_uri']);
|
||||
$this->assertEquals($orig['logo_uri'], $reg['logo_uri']);
|
||||
$this->assertEquals('https://purl.imsglobal.org/spec/lti-ags/scope/score '.
|
||||
'https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly '.
|
||||
'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly '.
|
||||
'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem '.
|
||||
'https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly', $reg['scope']);
|
||||
$ltiorig = $orig['https://purl.imsglobal.org/spec/lti-tool-configuration'];
|
||||
$lti = $reg['https://purl.imsglobal.org/spec/lti-tool-configuration'];
|
||||
$this->assertEquals("12", $lti['deployment_id']);
|
||||
$this->assertEquals($ltiorig['target_link_uri'], $lti['target_link_uri']);
|
||||
$this->assertEquals($ltiorig['domain'], $lti['domain']);
|
||||
$this->assertEquals($ltiorig['custom_parameters'], $lti['custom_parameters']);
|
||||
$this->assertEquals($ltiorig['description'], $lti['description']);
|
||||
$dlmsgorig = $ltiorig['messages'][0];
|
||||
$dlmsg = $lti['messages'][0];
|
||||
$this->assertEquals($dlmsgorig['type'], $dlmsg['type']);
|
||||
$this->assertEquals($dlmsgorig['target_link_uri'], $dlmsg['target_link_uri']);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user