Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 402] [Versions 310 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 resource
  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  
  34  
  35  /**
  36   * The mod_lti\local\ltiservice\resource_base class.
  37   *
  38   * @package    mod_lti
  39   * @since      Moodle 2.8
  40   * @copyright  2014 Vital Source Technologies http://vitalsource.com
  41   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  42   */
  43  abstract class resource_base {
  44  
  45      /**  HTTP Post method */
  46      const HTTP_POST = 'POST';
  47      /**  HTTP Get method */
  48      const HTTP_GET = 'GET';
  49      /**  HTTP Put method */
  50      const HTTP_PUT = 'PUT';
  51      /**  HTTP Delete method */
  52      const HTTP_DELETE = 'DELETE';
  53  
  54      /** @var service_base Service associated with this resource. */
  55      private $service;
  56      /** @var string Type for this resource. */
  57      protected $type;
  58      /** @var string ID for this resource. */
  59      protected $id;
  60      /** @var string Template for this resource. */
  61      protected $template;
  62      /** @var array Custom parameter substitution variables associated with this resource. */
  63      protected $variables;
  64      /** @var array Media types supported by this resource. */
  65      protected $formats;
  66      /** @var array HTTP actions supported by this resource. */
  67      protected $methods;
  68      /** @var array Template variables parsed from the resource template. */
  69      protected $params;
  70  
  71  
  72      /**
  73       * Class constructor.
  74       *
  75       * @param service_base $service Service instance
  76       */
  77      public function __construct($service) {
  78  
  79          $this->service = $service;
  80          $this->type = 'RestService';
  81          $this->id = null;
  82          $this->template = null;
  83          $this->methods = array();
  84          $this->variables = array();
  85          $this->formats = array();
  86          $this->methods = array();
  87          $this->params = null;
  88  
  89      }
  90  
  91      /**
  92       * Get the resource ID.
  93       *
  94       * @return string
  95       */
  96      public function get_id() {
  97  
  98          return $this->id;
  99  
 100      }
 101  
 102      /**
 103       * Get the resource template.
 104       *
 105       * @return string
 106       */
 107      public function get_template() {
 108  
 109          return $this->template;
 110  
 111      }
 112  
 113      /**
 114       * Get the resource path.
 115       *
 116       * @return string
 117       */
 118      public function get_path() {
 119  
 120          return $this->get_template();
 121  
 122      }
 123  
 124      /**
 125       * Get the resource type.
 126       *
 127       * @return string
 128       */
 129      public function get_type() {
 130  
 131          return $this->type;
 132  
 133      }
 134  
 135      /**
 136       * Get the resource's service.
 137       *
 138       * @return mixed
 139       */
 140      public function get_service() {
 141  
 142          return $this->service;
 143  
 144      }
 145  
 146      /**
 147       * Get the resource methods.
 148       *
 149       * @return array
 150       */
 151      public function get_methods() {
 152  
 153          return $this->methods;
 154  
 155      }
 156  
 157      /**
 158       * Get the resource media types.
 159       *
 160       * @return array
 161       */
 162      public function get_formats() {
 163  
 164          return $this->formats;
 165  
 166      }
 167  
 168      /**
 169       * Get the resource template variables.
 170       *
 171       * @return array
 172       */
 173      public function get_variables() {
 174  
 175          return $this->variables;
 176  
 177      }
 178  
 179      /**
 180       * Get the resource fully qualified endpoint.
 181       *
 182       * @return string
 183       */
 184      public function get_endpoint() {
 185  
 186          $this->parse_template();
 187          $template = preg_replace('/[\(\)]/', '', $this->get_template());
 188          $url = $this->get_service()->get_service_path() . $template;
 189          foreach ($this->params as $key => $value) {
 190              $url = str_replace('{' . $key . '}', $value, $url);
 191          }
 192          $toolproxy = $this->get_service()->get_tool_proxy();
 193          if (!empty($toolproxy)) {
 194              $url = str_replace('{config_type}', 'toolproxy', $url);
 195              $url = str_replace('{tool_proxy_id}', $toolproxy->guid, $url);
 196          } else {
 197              $url = str_replace('{config_type}', 'tool', $url);
 198              $url = str_replace('{tool_proxy_id}', $this->get_service()->get_type()->id, $url);
 199          }
 200  
 201          return $url;
 202  
 203      }
 204  
 205      /**
 206       * Execute the request for this resource.
 207       *
 208       * @param response $response  Response object for this request.
 209       */
 210      public abstract function execute($response);
 211  
 212      /**
 213       * Check to make sure the request is valid.
 214       *
 215       * @param int $typeid                   The typeid we want to use
 216       * @param string $body                  Body of HTTP request message
 217       * @param string[] $scopes              Array of scope(s) required for incoming request
 218       *
 219       * @return boolean
 220       */
 221      public function check_tool($typeid, $body = null, $scopes = null) {
 222  
 223          $ok = $this->get_service()->check_tool($typeid, $body, $scopes);
 224          if ($ok) {
 225              if ($this->get_service()->get_tool_proxy()) {
 226                  $toolproxyjson = $this->get_service()->get_tool_proxy()->toolproxy;
 227              }
 228              if (!empty($toolproxyjson)) {
 229                  // Check tool proxy to ensure service being requested is included.
 230                  $toolproxy = json_decode($toolproxyjson);
 231                  if (!empty($toolproxy) && isset($toolproxy->security_contract->tool_service)) {
 232                      $contexts = lti_get_contexts($toolproxy);
 233                      $tpservices = $toolproxy->security_contract->tool_service;
 234                      foreach ($tpservices as $service) {
 235                          $fqid = lti_get_fqid($contexts, $service->service);
 236                          $id = explode('#', $fqid, 2);
 237                          if ($this->get_id() === $id[1]) {
 238                              $ok = true;
 239                              break;
 240                          }
 241                      }
 242                  }
 243                  if (!$ok) {
 244                      debugging('Requested service not permitted: ' . $this->get_id(), DEBUG_DEVELOPER);
 245                  }
 246              } else {
 247                  // Check that the scope required for the service request is included in those granted for the
 248                  // access token being used.
 249                  $permittedscopes = $this->get_service()->get_permitted_scopes();
 250                  $ok = is_null($permittedscopes) || empty($scopes) || !empty(array_intersect($permittedscopes, $scopes));
 251              }
 252          }
 253  
 254          return $ok;
 255  
 256      }
 257  
 258      /**
 259       * Check to make sure the request is valid.
 260       *
 261       * @param string $toolproxyguid Consumer key
 262       * @param string $body          Body of HTTP request message
 263       *
 264       * @return boolean
 265       * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more.
 266       * @see resource_base::check_tool()
 267       */
 268      public function check_tool_proxy($toolproxyguid, $body = null) {
 269  
 270          debugging('check_tool_proxy() is deprecated to allow LTI 1 connections to support services. ' .
 271                    'Please use resource_base::check_tool() instead.', DEBUG_DEVELOPER);
 272          $ok = false;
 273          if ($this->get_service()->check_tool_proxy($toolproxyguid, $body)) {
 274              $toolproxyjson = $this->get_service()->get_tool_proxy()->toolproxy;
 275              if (empty($toolproxyjson)) {
 276                  $ok = true;
 277              } else {
 278                  $toolproxy = json_decode($toolproxyjson);
 279                  if (!empty($toolproxy) && isset($toolproxy->security_contract->tool_service)) {
 280                      $contexts = lti_get_contexts($toolproxy);
 281                      $tpservices = $toolproxy->security_contract->tool_service;
 282                      foreach ($tpservices as $service) {
 283                          $fqid = lti_get_fqid($contexts, $service->service);
 284                          $id = explode('#', $fqid, 2);
 285                          if ($this->get_id() === $id[1]) {
 286                              $ok = true;
 287                              break;
 288                          }
 289                      }
 290                  }
 291                  if (!$ok) {
 292                      debugging('Requested service not included in tool proxy: ' . $this->get_id());
 293                  }
 294              }
 295          }
 296  
 297          return $ok;
 298  
 299      }
 300  
 301      /**
 302       * Check to make sure the request is valid.
 303       *
 304       * @param int $typeid                   The typeid we want to use
 305       * @param int $contextid                The course we are at
 306       * @param string $permissionrequested   The permission to be checked
 307       * @param string $body                  Body of HTTP request message
 308       *
 309       * @return boolean
 310       * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more.
 311       * @see resource_base::check_tool()
 312       */
 313      public function check_type($typeid, $contextid, $permissionrequested, $body = null) {
 314          debugging('check_type() is deprecated to allow LTI 1 connections to support services. ' .
 315                    'Please use resource_base::check_tool() instead.', DEBUG_DEVELOPER);
 316          $ok = false;
 317          if ($this->get_service()->check_type($typeid, $contextid, $body)) {
 318              $neededpermissions = $this->get_permissions($typeid);
 319              foreach ($neededpermissions as $permission) {
 320                  if ($permission == $permissionrequested) {
 321                      $ok = true;
 322                      break;
 323                  }
 324              }
 325              if (!$ok) {
 326                  debugging('Requested service ' . $permissionrequested . ' not included in tool type: ' . $typeid,
 327                      DEBUG_DEVELOPER);
 328              }
 329          }
 330          return $ok;
 331      }
 332  
 333      /**
 334       * get permissions from the config of the tool for that resource
 335       *
 336       * @param int $ltitype Type of LTI
 337       * @return array with the permissions related to this resource by the $ltitype or empty if none.
 338       * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more.
 339       * @see resource_base::check_tool()
 340       */
 341      public function get_permissions($ltitype) {
 342          debugging('get_permissions() is deprecated to allow LTI 1 connections to support services. ' .
 343                    'Please use resource_base::check_tool() instead.', DEBUG_DEVELOPER);
 344          return array();
 345      }
 346  
 347      /**
 348       * Parse a value for custom parameter substitution variables.
 349       *
 350       * @param string $value String to be parsed
 351       *
 352       * @return string
 353       */
 354      public function parse_value($value) {
 355  
 356          return $value;
 357  
 358      }
 359  
 360      /**
 361       * Parse the template for variables.
 362       *
 363       * @return array
 364       */
 365      protected function parse_template() {
 366  
 367          if (empty($this->params)) {
 368              $this->params = array();
 369              if (!empty($_SERVER['PATH_INFO'])) {
 370                  $path = explode('/', $_SERVER['PATH_INFO']);
 371                  $template = preg_replace('/\([0-9a-zA-Z_\-,\/]+\)/', '', $this->get_template());
 372                  $parts = explode('/', $template);
 373                  for ($i = 0; $i < count($parts); $i++) {
 374                      if ((substr($parts[$i], 0, 1) == '{') && (substr($parts[$i], -1) == '}')) {
 375                          $value = '';
 376                          if ($i < count($path)) {
 377                              $value = $path[$i];
 378                          }
 379                          $this->params[substr($parts[$i], 1, -1)] = $value;
 380                      }
 381                  }
 382              }
 383          }
 384  
 385          return $this->params;
 386  
 387      }
 388  
 389  }