Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 * Get the path for service requests. 341 * 342 * @return string 343 */ 344 public static function get_service_path() { 345 346 $url = new \moodle_url('/mod/lti/services.php'); 347 348 return $url->out(false); 349 350 } 351 352 /** 353 * Parse a string for custom substitution parameter variables supported by this service's resources. 354 * 355 * @param string $value Value to be parsed 356 * 357 * @return string 358 */ 359 public function parse_value($value) { 360 361 if (empty($this->resources)) { 362 $this->resources = $this->get_resources(); 363 } 364 if (!empty($this->resources)) { 365 foreach ($this->resources as $resource) { 366 $value = $resource->parse_value($value); 367 } 368 } 369 370 return $value; 371 372 } 373 374 /** 375 * Check that the request has been properly signed and is permitted. 376 * 377 * @param string $typeid LTI type ID 378 * @param string $body Request body (null if none) 379 * @param string[] $scopes Array of required scope(s) for incoming request 380 * 381 * @return boolean 382 */ 383 public function check_tool($typeid, $body = null, $scopes = null) { 384 385 $ok = true; 386 $toolproxy = null; 387 $consumerkey = lti\get_oauth_key_from_headers($typeid, $scopes); 388 if ($consumerkey === false) { 389 $ok = $this->is_unsigned(); 390 } else { 391 if (empty($typeid) && is_int($consumerkey)) { 392 $typeid = $consumerkey; 393 } 394 if (!empty($typeid)) { 395 $this->type = lti_get_type($typeid); 396 $this->typeconfig = lti_get_type_config($typeid); 397 $ok = !empty($this->type->id); 398 if ($ok && !empty($this->type->toolproxyid)) { 399 $this->toolproxy = lti_get_tool_proxy($this->type->toolproxyid); 400 } 401 } else { 402 $toolproxy = lti_get_tool_proxy_from_guid($consumerkey); 403 if ($toolproxy !== false) { 404 $this->toolproxy = $toolproxy; 405 } 406 } 407 } 408 if ($ok && is_string($consumerkey)) { 409 if (!empty($this->toolproxy)) { 410 $key = $this->toolproxy->guid; 411 $secret = $this->toolproxy->secret; 412 } else { 413 $key = $this->typeconfig['resourcekey']; 414 $secret = $this->typeconfig['password']; 415 } 416 if (!$this->is_unsigned() && ($key == $consumerkey)) { 417 $ok = $this->check_signature($key, $secret, $body); 418 } else { 419 $ok = $this->is_unsigned(); 420 } 421 } 422 423 return $ok; 424 425 } 426 427 /** 428 * Check that the request has been properly signed. 429 * 430 * @param string $toolproxyguid Tool Proxy GUID 431 * @param string $body Request body (null if none) 432 * 433 * @return boolean 434 * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more. 435 * @see service_base::check_tool() 436 */ 437 public function check_tool_proxy($toolproxyguid, $body = null) { 438 439 debugging('check_tool_proxy() is deprecated to allow LTI 1 connections to support services. ' . 440 'Please use service_base::check_tool() instead.', DEBUG_DEVELOPER); 441 $ok = false; 442 $toolproxy = null; 443 $consumerkey = lti\get_oauth_key_from_headers(); 444 if (empty($toolproxyguid)) { 445 $toolproxyguid = $consumerkey; 446 } 447 448 if (!empty($toolproxyguid)) { 449 $toolproxy = lti_get_tool_proxy_from_guid($toolproxyguid); 450 if ($toolproxy !== false) { 451 if (!$this->is_unsigned() && ($toolproxy->guid == $consumerkey)) { 452 $ok = $this->check_signature($toolproxy->guid, $toolproxy->secret, $body); 453 } else { 454 $ok = $this->is_unsigned(); 455 } 456 } 457 } 458 if ($ok) { 459 $this->toolproxy = $toolproxy; 460 } 461 462 return $ok; 463 464 } 465 466 /** 467 * Check that the request has been properly signed. 468 * 469 * @param int $typeid The tool id 470 * @param int $courseid The course we are at 471 * @param string $body Request body (null if none) 472 * 473 * @return bool 474 * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more. 475 * @see service_base::check_tool() 476 */ 477 public function check_type($typeid, $courseid, $body = null) { 478 debugging('check_type() is deprecated to allow LTI 1 connections to support services. ' . 479 'Please use service_base::check_tool() instead.', DEBUG_DEVELOPER); 480 $ok = false; 481 $tool = null; 482 $consumerkey = lti\get_oauth_key_from_headers(); 483 if (empty($typeid)) { 484 return $ok; 485 } else if ($this->is_allowed_in_context($typeid, $courseid)) { 486 $tool = lti_get_type_type_config($typeid); 487 if ($tool !== false) { 488 if (!$this->is_unsigned() && ($tool->lti_resourcekey == $consumerkey)) { 489 $ok = $this->check_signature($tool->lti_resourcekey, $tool->lti_password, $body); 490 } else { 491 $ok = $this->is_unsigned(); 492 } 493 } 494 } 495 return $ok; 496 } 497 498 /** 499 * Check the request signature. 500 * 501 * @param string $consumerkey Consumer key 502 * @param string $secret Shared secret 503 * @param string $body Request body 504 * 505 * @return boolean 506 */ 507 private function check_signature($consumerkey, $secret, $body) { 508 509 $ok = true; 510 try { 511 // TODO: Switch to core oauthlib once implemented - MDL-30149. 512 lti\handle_oauth_body_post($consumerkey, $secret, $body); 513 } catch (\Exception $e) { 514 debugging($e->getMessage() . "\n"); 515 $ok = false; 516 } 517 518 return $ok; 519 520 } 521 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body