MDL-62599 mod_lti: correct deprecations in service_base
[moodle.git] / mod / lti / classes / local / ltiservice / service_base.php
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/>.
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  */
27 namespace mod_lti\local\ltiservice;
29 defined('MOODLE_INTERNAL') || die();
31 global $CFG;
32 require_once($CFG->dirroot . '/mod/lti/locallib.php');
33 require_once($CFG->dirroot . '/mod/lti/OAuthBody.php');
35 // TODO: Switch to core oauthlib once implemented - MDL-30149.
36 use moodle\mod\lti as lti;
37 use stdClass;
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 {
50     /** Label representing an LTI 2 message type */
51     const LTI_VERSION2P0 = 'LTI-2p0';
52     /** Service enabled */
53     const SERVICE_ENABLED = 1;
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;
71     /**
72      * Class constructor.
73      */
74     public function __construct() {
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;
84     }
86     /**
87      * Get the service ID.
88      *
89      * @return string
90      */
91     public function get_id() {
93         return $this->id;
95     }
97     /**
98      * Get the service compoent ID.
99      *
100      * @return string
101      */
102     public function get_component_id() {
104         return 'ltiservice_' . $this->id;
106     }
108     /**
109      * Get the service name.
110      *
111      * @return string
112      */
113     public function get_name() {
115         return $this->name;
117     }
119     /**
120      * Get whether the service requests need to be signed.
121      *
122      * @return boolean
123      */
124     public function is_unsigned() {
126         return $this->unsigned;
128     }
130     /**
131      * Get the tool proxy object.
132      *
133      * @return stdClass
134      */
135     public function get_tool_proxy() {
137         return $this->toolproxy;
139     }
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) {
150         $this->toolproxy = $toolproxy;
152     }
154     /**
155      * Get the type object.
156      *
157      * @return stdClass
158      */
159     public function get_type() {
161         return $this->type;
163     }
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) {
174         $this->type = $type;
176     }
178     /**
179      * Get the type config array.
180      *
181      * @return array|null
182      */
183     public function get_typeconfig() {
185         return $this->typeconfig;
187     }
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) {
198         $this->typeconfig = $typeconfig;
200     }
202     /**
203      * Get the resources for this service.
204      *
205      * @return resource_base[]
206      */
207     abstract public function get_resources();
209     /**
210      * Get the scope(s) permitted for this service.
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     }
220     /**
221      * Returns the configuration options for this service.
222      *
223      * @param \MoodleQuickForm $mform Moodle quickform object definition
224      */
225     public function get_configuration_options(&$mform) {
227     }
229     /**
230      * Return an array with the names of the parameters that the service will be saving in the configuration
231      *
232      * @return array  Names list of the parameters that the service will be saving in the configuration
233      * @deprecated since Moodle 3.7 - please do not use this function any more.
234      */
235     public function get_configuration_parameter_names() {
236         debugging('get_configuration_parameter_names() has been deprecated.', DEBUG_DEVELOPER);
237         return array();
238     }
240     /**
241      * Default implementation will check for the existence of at least one mod_lti entry for that tool and context.
242      *
243      * It may be overridden if other inferences can be done.
244      *
245      * Ideally a Site Tool should be explicitly engaged with a course, the check on the presence of a link is a proxy
246      * to infer a Site Tool engagement until an explicit Site Tool - Course relationship exists.
247      *
248      * @param int $typeid The tool lti type id.
249      * @param int $courseid The course id.
250      * @return bool returns True if tool is used in context, false otherwise.
251      */
252     public function is_used_in_context($typeid, $courseid) {
253         global $DB;
255         $ok = $DB->record_exists('lti', array('course' => $courseid, 'typeid' => $typeid));
256         return $ok || $DB->record_exists('lti_types', array('course' => $courseid, 'id' => $typeid));
257     }
259     /**
260      * Checks if there is a site tool or a course tool for this site.
261      *
262      * @param int $typeid The tool lti type id.
263      * @param int $courseid The course id.
264      * @return bool returns True if tool is allowed in context, false otherwise.
265      */
266     public function is_allowed_in_context($typeid, $courseid) {
267         global $DB;
269         // Check if it is a Course tool for this course or a Site tool.
270         $type = $DB->get_record('lti_types', array('id' => $typeid));
272         return $type && ($type->course == $courseid || $type->course == SITEID);
273     }
275     /**
276      * Return an array of key/values to add to the launch parameters.
277      *
278      * @param string $messagetype  'basic-lti-launch-request' or 'ContentItemSelectionRequest'.
279      * @param string $courseid     The course id.
280      * @param string $userid       The user id.
281      * @param string $typeid       The tool lti type id.
282      * @param string $modlti       The id of the lti activity.
283      *
284      * The type is passed to check the configuration and not return parameters for services not used.
285      *
286      * @return array Key/value pairs to add as launch parameters.
287      */
288     public function get_launch_parameters($messagetype, $courseid, $userid, $typeid, $modlti = null) {
289         return array();
290     }
292     /**
293      * Get the path for service requests.
294      *
295      * @return string
296      */
297     public static function get_service_path() {
299         $url = new \moodle_url('/mod/lti/services.php');
301         return $url->out(false);
303     }
305     /**
306      * Parse a string for custom substitution parameter variables supported by this service's resources.
307      *
308      * @param string $value  Value to be parsed
309      *
310      * @return string
311      */
312     public function parse_value($value) {
314         if (empty($this->resources)) {
315             $this->resources = $this->get_resources();
316         }
317         if (!empty($this->resources)) {
318             foreach ($this->resources as $resource) {
319                 $value = $resource->parse_value($value);
320             }
321         }
323         return $value;
325     }
327     /**
328      * Check that the request has been properly signed and is permitted.
329      *
330      * @param string $typeid    LTI type ID
331      * @param string $body      Request body (null if none)
332      * @param string[] $scopes  Array of required scope(s) for incoming request
333      *
334      * @return boolean
335      */
336     public function check_tool($typeid, $body = null, $scopes = null) {
338         $ok = true;
339         $toolproxy = null;
340         $consumerkey = lti\get_oauth_key_from_headers($typeid, $scopes);
341         if ($consumerkey === false) {
342             $ok = $this->is_unsigned();
343         } else {
344             if (empty($typeid) && is_int($consumerkey)) {
345                 $typeid = $consumerkey;
346             }
347             if (!empty($typeid)) {
348                 $this->type = lti_get_type($typeid);
349                 $this->typeconfig = lti_get_type_config($typeid);
350                 $ok = !empty($this->type->id);
351                 if ($ok && !empty($this->type->toolproxyid)) {
352                     $this->toolproxy = lti_get_tool_proxy($this->type->toolproxyid);
353                 }
354             } else {
355                 $toolproxy = lti_get_tool_proxy_from_guid($consumerkey);
356                 if ($toolproxy !== false) {
357                     $this->toolproxy = $toolproxy;
358                 }
359             }
360         }
361         if ($ok && is_string($consumerkey)) {
362             if (!empty($this->toolproxy)) {
363                 $key = $this->toolproxy->guid;
364                 $secret = $this->toolproxy->secret;
365             } else {
366                 $key = $this->typeconfig['resourcekey'];
367                 $secret = $this->typeconfig['password'];
368             }
369             if (!$this->is_unsigned() && ($key == $consumerkey)) {
370                 $ok = $this->check_signature($key, $secret, $body);
371             } else {
372                 $ok = $this->is_unsigned();
373             }
374         }
376         return $ok;
378     }
380     /**
381      * Check that the request has been properly signed.
382      *
383      * @param string $toolproxyguid  Tool Proxy GUID
384      * @param string $body           Request body (null if none)
385      *
386      * @return boolean
387      * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more.
388      * @see service_base::check_tool()
389      */
390     public function check_tool_proxy($toolproxyguid, $body = null) {
392         debugging('check_tool_proxy() is deprecated to allow LTI 1 connections to support services. ' .
393                   'Please use service_base::check_tool() instead.', DEBUG_DEVELOPER);
394         $ok = false;
395         $toolproxy = null;
396         $consumerkey = lti\get_oauth_key_from_headers();
397         if (empty($toolproxyguid)) {
398             $toolproxyguid = $consumerkey;
399         }
401         if (!empty($toolproxyguid)) {
402             $toolproxy = lti_get_tool_proxy_from_guid($toolproxyguid);
403             if ($toolproxy !== false) {
404                 if (!$this->is_unsigned() && ($toolproxy->guid == $consumerkey)) {
405                     $ok = $this->check_signature($toolproxy->guid, $toolproxy->secret, $body);
406                 } else {
407                     $ok = $this->is_unsigned();
408                 }
409             }
410         }
411         if ($ok) {
412             $this->toolproxy = $toolproxy;
413         }
415         return $ok;
417     }
419     /**
420      * Check that the request has been properly signed.
421      *
422      * @param int $typeid The tool id
423      * @param int $courseid The course we are at
424      * @param string $body Request body (null if none)
425      *
426      * @return bool
427      * @deprecated since Moodle 3.7 MDL-62599 - please do not use this function any more.
428      * @see service_base::check_tool()
429      */
430     public function check_type($typeid, $courseid, $body = null) {
431         debugging('check_type() is deprecated to allow LTI 1 connections to support services. ' .
432                   'Please use service_base::check_tool() instead.', DEBUG_DEVELOPER);
433         $ok = false;
434         $tool = null;
435         $consumerkey = lti\get_oauth_key_from_headers();
436         if (empty($typeid)) {
437             return $ok;
438         } else if ($this->is_allowed_in_context($typeid, $courseid)) {
439             $tool = lti_get_type_type_config($typeid);
440             if ($tool !== false) {
441                 if (!$this->is_unsigned() && ($tool->lti_resourcekey == $consumerkey)) {
442                     $ok = $this->check_signature($tool->lti_resourcekey, $tool->lti_password, $body);
443                 } else {
444                     $ok = $this->is_unsigned();
445                 }
446             }
447         }
448         return $ok;
449     }
451     /**
452      * Check the request signature.
453      *
454      * @param string $consumerkey    Consumer key
455      * @param string $secret         Shared secret
456      * @param string $body           Request body
457      *
458      * @return boolean
459      */
460     private function check_signature($consumerkey, $secret, $body) {
462         $ok = true;
463         try {
464             // TODO: Switch to core oauthlib once implemented - MDL-30149.
465             lti\handle_oauth_body_post($consumerkey, $secret, $body);
466         } catch (\Exception $e) {
467             debugging($e->getMessage() . "\n");
468             $ok = false;
469         }
471         return $ok;
473     }