Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * This file contains an abstract definition of an LTI service 19 * 20 * @package mod_lti 21 * @copyright 2014 Vital Source Technologies http://vitalsource.com 22 * @author Stephen Vickers 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 27 namespace mod_lti\local\ltiservice; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 global $CFG; 32 require_once($CFG->dirroot . '/mod/lti/locallib.php'); 33 require_once($CFG->dirroot . '/mod/lti/OAuthBody.php'); 34 35 // TODO: Switch to core oauthlib once implemented - MDL-30149. 36 use moodle\mod\lti as lti; 37 use stdClass; 38 39 40 /** 41 * The mod_lti\local\ltiservice\service_base class. 42 * 43 * @package mod_lti 44 * @since Moodle 2.8 45 * @copyright 2014 Vital Source Technologies http://vitalsource.com 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 47 */ 48 abstract class service_base { 49 50 /** Label representing an LTI 2 message type */ 51 const LTI_VERSION2P0 = 'LTI-2p0'; 52 /** Service enabled */ 53 const SERVICE_ENABLED = 1; 54 55 /** @var string ID for the service. */ 56 protected $id; 57 /** @var string Human readable name for the service. */ 58 protected $name; 59 /** @var boolean <code>true</code> if requests for this service do not need to be signed. */ 60 protected $unsigned; 61 /** @var stdClass Tool proxy object for the current service request. */ 62 private $toolproxy; 63 /** @var stdClass LTI type object for the current service request. */ 64 private $type; 65 /** @var array LTI type config array for the current service request. */ 66 private $typeconfig; 67 /** @var array Instances of the resources associated with this service. */ 68 protected $resources; 69 70 71 /** 72 * Class constructor. 73 */ 74 public function __construct() { 75 76 $this->id = null; 77 $this->name = null; 78 $this->unsigned = false; 79 $this->toolproxy = null; 80 $this->type = null; 81 $this->typeconfig = null; 82 $this->resources = null; 83 84 } 85 86 /** 87 * Get the service ID. 88 * 89 * @return string 90 */ 91 public function get_id() { 92 93 return $this->id; 94 95 } 96 97 /** 98 * Get the service compoent ID. 99 * 100 * @return string 101 */ 102 public function get_component_id() { 103 104 return 'ltiservice_' . $this->id; 105 106 } 107 108 /** 109 * Get the service name. 110 * 111 * @return string 112 */ 113 public function get_name() { 114 115 return $this->name; 116 117 } 118 119 /** 120 * Get whether the service requests need to be signed. 121 * 122 * @return boolean 123 */ 124 public function is_unsigned() { 125 126 return $this->unsigned; 127 128 } 129 130 /** 131 * Get the tool proxy object. 132 * 133 * @return stdClass 134 */ 135 public function get_tool_proxy() { 136 137 return $this->toolproxy; 138 139 } 140 141 /** 142 * Set the tool proxy object. 143 * 144 * @param object $toolproxy The tool proxy for this service request 145 * 146 * @var stdClass 147 */ 148 public function set_tool_proxy($toolproxy) { 149 150 $this->toolproxy = $toolproxy; 151 152 } 153 154 /** 155 * Get the type object. 156 * 157 * @return stdClass 158 */ 159 public function get_type() { 160 161 return $this->type; 162 163 } 164 165 /** 166 * Set the LTI type object. 167 * 168 * @param object $type The LTI type for this service request 169 * 170 * @var stdClass 171 */ 172 public function set_type($type) { 173 174 $this->type = $type; 175 176 } 177 178 /** 179 * Get the type config array. 180 * 181 * @return array|null 182 */ 183 public function get_typeconfig() { 184 185 return $this->typeconfig; 186 187 } 188 189 /** 190 * Set the LTI type config object. 191 * 192 * @param array $typeconfig The LTI type config for this service request 193 * 194 * @var array 195 */ 196 public function set_typeconfig($typeconfig) { 197 198 $this->typeconfig = $typeconfig; 199 200 } 201 202 /** 203 * Get the resources for this service. 204 * 205 * @return resource_base[] 206 */ 207 abstract public function get_resources(); 208 209 /** 210 * Get the scope(s) permitted for this service in the context of a particular tool type. 211 * 212 * A null value indicates that no scopes are required to access the service. 213 * 214 * @return array|null 215 */ 216 public function get_permitted_scopes() { 217 return null; 218 } 219 220 /** 221 * Get the scope(s) permitted for this service. 222 * 223 * A null value indicates that no scopes are required to access the service. 224 * 225 * @return array|null 226 */ 227 public function get_scopes() { 228 return null; 229 } 230 231 /** 232 * Returns the configuration options for this service. 233 * 234 * @param \MoodleQuickForm $mform Moodle quickform object definition 235 */ 236 public function get_configuration_options(&$mform) { 237 238 } 239 240 /** 241 * Called when a new LTI Instance is added. 242 * 243 * @param object $lti LTI Instance. 244 */ 245 public function instance_added(object $lti): void { 246 247 } 248 249 /** 250 * Called when a new LTI Instance is updated. 251 * 252 * @param object $lti LTI Instance. 253 */ 254 public function instance_updated(object $lti): void { 255 256 } 257 258 /** 259 * Called when a new LTI Instance is deleted. 260 * 261 * @param int $id LTI Instance. 262 */ 263 public function instance_deleted(int $id): void { 264 265 } 266 267 /** 268 * Set the form data when displaying the LTI Instance form. 269 * 270 * @param object $defaultvalues Default form values. 271 */ 272 public function set_instance_form_values(object $defaultvalues): void { 273 274 } 275 276 /** 277 * Return an array with the names of the parameters that the service will be saving in the configuration 278 * 279 * @return array Names list of the parameters that the service will be saving in the configuration 280 * @deprecated since Moodle 3.7 - please do not use this function any more. 281 */ 282 public function get_configuration_parameter_names() { 283 debugging('get_configuration_parameter_names() has been deprecated.', DEBUG_DEVELOPER); 284 return array(); 285 } 286 287 /** 288 * Default implementation will check for the existence of at least one mod_lti entry for that tool and context. 289 * 290 * It may be overridden if other inferences can be done. 291 * 292 * Ideally a Site Tool should be explicitly engaged with a course, the check on the presence of a link is a proxy 293 * to infer a Site Tool engagement until an explicit Site Tool - Course relationship exists. 294 * 295 * @param int $typeid The tool lti type id. 296 * @param int $courseid The course id. 297 * @return bool returns True if tool is used in context, false otherwise. 298 */ 299 public function is_used_in_context($typeid, $courseid) { 300 global $DB; 301 302 $ok = $DB->record_exists('lti', array('course' => $courseid, 'typeid' => $typeid)); 303 return $ok || $DB->record_exists('lti_types', array('course' => $courseid, 'id' => $typeid)); 304 } 305 306 /** 307 * Checks if there is a site tool or a course tool for this site. 308 * 309 * @param int $typeid The tool lti type id. 310 * @param int $courseid The course id. 311 * @return bool returns True if tool is allowed in context, false otherwise. 312 */ 313 public function is_allowed_in_context($typeid, $courseid) { 314 global $DB; 315 316 // Check if it is a Course tool for this course or a Site tool. 317 $type = $DB->get_record('lti_types', array('id' => $typeid)); 318 319 return $type && ($type->course == $courseid || $type->course == SITEID); 320 } 321 322 /** 323 * Return an array of key/values to add to the launch parameters. 324 * 325 * @param string $messagetype 'basic-lti-launch-request' or 'ContentItemSelectionRequest'. 326 * @param string $courseid The course id. 327 * @param string $userid The user id. 328 * @param string $typeid The tool lti type id. 329 * @param string $modlti The id of the lti activity. 330 * 331 * The type is passed to check the configuration and not return parameters for services not used. 332 * 333 * @return array Key/value pairs to add as launch parameters. 334 */ 335 public function get_launch_parameters($messagetype, $courseid, $userid, $typeid, $modlti = null) { 336 return array(); 337 } 338 339 /** 340 * Return an array of key/claim mapping allowing LTI 1.1 custom parameters 341 * to be transformed to LTI 1.3 claims. 342 * 343 * @return array Key/value pairs of params to claim mapping. 344 */ 345 public function get_jwt_claim_mappings(): array { 346 return []; 347 } 348 349 /** 350 * Get the path for service requests. 351 * 352 * @return string 353 */ 354 public static function get_service_path() { 355 356 $url = new \moodle_url('/mod/lti/services.php'); 357 358 return $url->out(false); 359 360 } 361 362 /** 363 * Parse a string for custom substitution parameter variables supported by this service's resources. 364 * 365 * @param string $value Value to be parsed 366 * 367 * @return string 368 */ 369 public function parse_value($value) { 370 371 if (empty($this->resources)) { 372 $this->resources = $this->get_resources(); 373 } 374 if (!empty($this->resources)) { 375 foreach ($this->resources as $resource) { 376 $value = $resource->parse_value($value); 377 } 378 } 379 380 return $value; 381 382 } 383 384 /** 385 * Check that the request has been properly signed and is permitted. 386 * 387 * @param string $typeid LTI type ID 388 * @param string $body Request body (null if none) 389 * @param string[] $scopes Array of required scope(s) for incoming request 390 * 391 * @return boolean 392 */ 393 public function check_tool($typeid, $body = null, $scopes = null) { 394 395 $ok = true; 396 $toolproxy = null; 397 $consumerkey = lti\get_oauth_key_from_headers($typeid, $scopes); 398 if ($consumerkey === false) { 399 $ok = $this->is_unsigned(); 400 } else { 401 if (empty($typeid) && is_int($consumerkey)) { 402 $typeid = $consumerkey; 403 } 404 if (!empty($typeid)) { 405 $this->type = lti_get_type($typeid); 406 $this->typeconfig = lti_get_type_config($typeid); 407 $ok = !empty($this->type->id); 408 if ($ok && !empty($this->type->toolproxyid)) { 409 $this->toolproxy = lti_get_tool_proxy($this->type->toolproxyid); 410 } 411 } else { 412 $toolproxy = lti_get_tool_proxy_from_guid($consumerkey); 413 if ($toolproxy !== false) { 414 $this->toolproxy = $toolproxy; 415 } 416 } 417 } 418 if ($ok && is_string($consumerkey)) { 419 if (!empty($this->toolproxy)) { 420 $key = $this->toolproxy->guid; 421 $secret = $this->toolproxy->secret; 422 } else { 423 $key = $this->typeconfig['resourcekey']; 424 $secret = $this->typeconfig['password']; 425 } 426 if (!$this->is_unsigned() && ($key == $consumerkey)) { 427 $ok = $this->check_signature($key, $secret, $body); 428 } else { 429 $ok = $this->is_unsigned(); 430 } 431 } 432 433 return $ok; 434 435 } 436 437 /** 438 * Check that the request has been properly signed. 439 * 440 * @param string $toolproxyguid Tool Proxy GUID 441 * @param string $body Request body (null if none) 442 * 443 * @return boolean 444 * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more. 445 * @see service_base::check_tool() 446 */ 447 public function check_tool_proxy($toolproxyguid, $body = null) { 448 449 debugging('check_tool_proxy() is deprecated to allow LTI 1 connections to support services. ' . 450 'Please use service_base::check_tool() instead.', DEBUG_DEVELOPER); 451 $ok = false; 452 $toolproxy = null; 453 $consumerkey = lti\get_oauth_key_from_headers(); 454 if (empty($toolproxyguid)) { 455 $toolproxyguid = $consumerkey; 456 } 457 458 if (!empty($toolproxyguid)) { 459 $toolproxy = lti_get_tool_proxy_from_guid($toolproxyguid); 460 if ($toolproxy !== false) { 461 if (!$this->is_unsigned() && ($toolproxy->guid == $consumerkey)) { 462 $ok = $this->check_signature($toolproxy->guid, $toolproxy->secret, $body); 463 } else { 464 $ok = $this->is_unsigned(); 465 } 466 } 467 } 468 if ($ok) { 469 $this->toolproxy = $toolproxy; 470 } 471 472 return $ok; 473 474 } 475 476 /** 477 * Check that the request has been properly signed. 478 * 479 * @param int $typeid The tool id 480 * @param int $courseid The course we are at 481 * @param string $body Request body (null if none) 482 * 483 * @return bool 484 * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more. 485 * @see service_base::check_tool() 486 */ 487 public function check_type($typeid, $courseid, $body = null) { 488 debugging('check_type() is deprecated to allow LTI 1 connections to support services. ' . 489 'Please use service_base::check_tool() instead.', DEBUG_DEVELOPER); 490 $ok = false; 491 $tool = null; 492 $consumerkey = lti\get_oauth_key_from_headers(); 493 if (empty($typeid)) { 494 return $ok; 495 } else if ($this->is_allowed_in_context($typeid, $courseid)) { 496 $tool = lti_get_type_type_config($typeid); 497 if ($tool !== false) { 498 if (!$this->is_unsigned() && ($tool->lti_resourcekey == $consumerkey)) { 499 $ok = $this->check_signature($tool->lti_resourcekey, $tool->lti_password, $body); 500 } else { 501 $ok = $this->is_unsigned(); 502 } 503 } 504 } 505 return $ok; 506 } 507 508 /** 509 * Check the request signature. 510 * 511 * @param string $consumerkey Consumer key 512 * @param string $secret Shared secret 513 * @param string $body Request body 514 * 515 * @return boolean 516 */ 517 private function check_signature($consumerkey, $secret, $body) { 518 519 $ok = true; 520 try { 521 // TODO: Switch to core oauthlib once implemented - MDL-30149. 522 lti\handle_oauth_body_post($consumerkey, $secret, $body); 523 } catch (\Exception $e) { 524 debugging($e->getMessage() . "\n"); 525 $ok = false; 526 } 527 528 return $ok; 529 530 } 531 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body