Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace IMSGlobal\LTI\ToolProvider;
4
 
5
use IMSGlobal\LTI\ToolProvider\DataConnector\DataConnector;
6
use IMSGlobal\LTI\ToolProvider\Service;
7
use IMSGlobal\LTI\HTTPMessage;
8
use IMSGlobal\LTI\OAuth;
9
use stdClass;
10
 
11
/**
12
 * Class to represent a tool consumer
13
 *
14
 * @author  Stephen P Vickers <svickers@imsglobal.org>
15
 * @copyright  IMS Global Learning Consortium Inc
16
 * @date  2016
17
 * @version 3.0.2
18
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
19
 */
20
#[\AllowDynamicProperties]
21
class ToolConsumer
22
{
23
 
24
/**
25
 * Local name of tool consumer.
26
 *
27
 * @var string $name
28
 */
29
    public $name = null;
30
/**
31
 * Shared secret.
32
 *
33
 * @var string $secret
34
 */
35
    public $secret = null;
36
/**
37
 * LTI version (as reported by last tool consumer connection).
38
 *
39
 * @var string $ltiVersion
40
 */
41
    public $ltiVersion = null;
42
/**
43
 * Name of tool consumer (as reported by last tool consumer connection).
44
 *
45
 * @var string $consumerName
46
 */
47
    public $consumerName = null;
48
/**
49
 * Tool consumer version (as reported by last tool consumer connection).
50
 *
51
 * @var string $consumerVersion
52
 */
53
    public $consumerVersion = null;
54
/**
55
 * Tool consumer GUID (as reported by first tool consumer connection).
56
 *
57
 * @var string $consumerGuid
58
 */
59
    public $consumerGuid = null;
60
/**
61
 * Optional CSS path (as reported by last tool consumer connection).
62
 *
63
 * @var string $cssPath
64
 */
65
    public $cssPath = null;
66
/**
67
 * Whether the tool consumer instance is protected by matching the consumer_guid value in incoming requests.
68
 *
69
 * @var boolean $protected
70
 */
71
    public $protected = false;
72
/**
73
 * Whether the tool consumer instance is enabled to accept incoming connection requests.
74
 *
75
 * @var boolean $enabled
76
 */
77
    public $enabled = false;
78
/**
79
 * Date/time from which the the tool consumer instance is enabled to accept incoming connection requests.
80
 *
81
 * @var int $enableFrom
82
 */
83
    public $enableFrom = null;
84
/**
85
 * Date/time until which the tool consumer instance is enabled to accept incoming connection requests.
86
 *
87
 * @var int $enableUntil
88
 */
89
    public $enableUntil = null;
90
/**
91
 * Date of last connection from this tool consumer.
92
 *
93
 * @var int $lastAccess
94
 */
95
    public $lastAccess = null;
96
/**
97
 * Default scope to use when generating an Id value for a user.
98
 *
99
 * @var int $idScope
100
 */
101
    public $idScope = ToolProvider::ID_SCOPE_ID_ONLY;
102
/**
103
 * Default email address (or email domain) to use when no email address is provided for a user.
104
 *
105
 * @var string $defaultEmail
106
 */
107
    public $defaultEmail = '';
108
/**
109
 * Setting values (LTI parameters, custom parameters and local parameters).
110
 *
111
 * @var array $settings
112
 */
113
    public $settings = null;
114
/**
115
 * Date/time when the object was created.
116
 *
117
 * @var int $created
118
 */
119
    public $created = null;
120
/**
121
 * Date/time when the object was last updated.
122
 *
123
 * @var int $updated
124
 */
125
    public $updated = null;
126
/**
127
 * The consumer profile data.
128
 *
129
 * @var stdClass
130
 */
131
    public $profile = null;
132
 
133
/**
134
 * Consumer ID value.
135
 *
136
 * @var int $id
137
 */
138
    private $id = null;
139
/**
140
 * Consumer key value.
141
 *
142
 * @var string $key
143
 */
144
    private $key = null;
145
/**
146
 * Whether the settings value have changed since last saved.
147
 *
148
 * @var boolean $settingsChanged
149
 */
150
    private $settingsChanged = false;
151
/**
152
 * Data connector object or string.
153
 *
154
 * @var mixed $dataConnector
155
 */
156
    private $dataConnector = null;
157
 
158
/**
159
 * Class constructor.
160
 *
161
 * @param string  $key             Consumer key
162
 * @param DataConnector   $dataConnector   A data connector object
163
 * @param boolean $autoEnable      true if the tool consumers is to be enabled automatically (optional, default is false)
164
 */
165
    public function __construct($key = null, $dataConnector = null, $autoEnable = false)
166
    {
167
 
168
        $this->initialize();
169
        if (empty($dataConnector)) {
170
            $dataConnector = DataConnector::getDataConnector();
171
        }
172
        $this->dataConnector = $dataConnector;
173
        if (!empty($key)) {
174
            $this->load($key, $autoEnable);
175
        } else {
176
            $this->secret = DataConnector::getRandomString(32);
177
        }
178
 
179
    }
180
 
181
/**
182
 * Initialise the tool consumer.
183
 */
184
    public function initialize()
185
    {
186
 
187
        $this->id = null;
188
        $this->key = null;
189
        $this->name = null;
190
        $this->secret = null;
191
        $this->ltiVersion = null;
192
        $this->consumerName = null;
193
        $this->consumerVersion = null;
194
        $this->consumerGuid = null;
195
        $this->profile = null;
196
        $this->toolProxy = null;
197
        $this->settings = array();
198
        $this->protected = false;
199
        $this->enabled = false;
200
        $this->enableFrom = null;
201
        $this->enableUntil = null;
202
        $this->lastAccess = null;
203
        $this->idScope = ToolProvider::ID_SCOPE_ID_ONLY;
204
        $this->defaultEmail = '';
205
        $this->created = null;
206
        $this->updated = null;
207
 
208
    }
209
 
210
/**
211
 * Initialise the tool consumer.
212
 *
213
 * Pseudonym for initialize().
214
 */
215
    public function initialise()
216
    {
217
 
218
        $this->initialize();
219
 
220
    }
221
 
222
/**
223
 * Save the tool consumer to the database.
224
 *
225
 * @return boolean True if the object was successfully saved
226
 */
227
    public function save()
228
    {
229
 
230
        $ok = $this->dataConnector->saveToolConsumer($this);
231
        if ($ok) {
232
            $this->settingsChanged = false;
233
        }
234
 
235
        return $ok;
236
 
237
    }
238
 
239
/**
240
 * Delete the tool consumer from the database.
241
 *
242
 * @return boolean True if the object was successfully deleted
243
 */
244
    public function delete()
245
    {
246
 
247
        return $this->dataConnector->deleteToolConsumer($this);
248
 
249
    }
250
 
251
/**
252
 * Get the tool consumer record ID.
253
 *
254
 * @return int Consumer record ID value
255
 */
256
    public function getRecordId()
257
    {
258
 
259
        return $this->id;
260
 
261
    }
262
 
263
/**
264
 * Sets the tool consumer record ID.
265
 *
266
 * @param int $id  Consumer record ID value
267
 */
268
    public function setRecordId($id)
269
    {
270
 
271
        $this->id = $id;
272
 
273
    }
274
 
275
/**
276
 * Get the tool consumer key.
277
 *
278
 * @return string Consumer key value
279
 */
280
    public function getKey()
281
    {
282
 
283
        return $this->key;
284
 
285
    }
286
 
287
/**
288
 * Set the tool consumer key.
289
 *
290
 * @param string $key  Consumer key value
291
 */
292
    public function setKey($key)
293
    {
294
 
295
        $this->key = $key;
296
 
297
    }
298
 
299
/**
300
 * Get the data connector.
301
 *
302
 * @return mixed Data connector object or string
303
 */
304
    public function getDataConnector()
305
    {
306
 
307
        return $this->dataConnector;
308
 
309
    }
310
 
311
/**
312
 * Is the consumer key available to accept launch requests?
313
 *
314
 * @return boolean True if the consumer key is enabled and within any date constraints
315
 */
316
    public function getIsAvailable()
317
    {
318
 
319
        $ok = $this->enabled;
320
 
321
        $now = time();
322
        if ($ok && !is_null($this->enableFrom)) {
323
            $ok = $this->enableFrom <= $now;
324
        }
325
        if ($ok && !is_null($this->enableUntil)) {
326
            $ok = $this->enableUntil > $now;
327
        }
328
 
329
        return $ok;
330
 
331
    }
332
 
333
/**
334
 * Get a setting value.
335
 *
336
 * @param string $name    Name of setting
337
 * @param string $default Value to return if the setting does not exist (optional, default is an empty string)
338
 *
339
 * @return string Setting value
340
 */
341
    public function getSetting($name, $default = '')
342
    {
343
 
344
        if (array_key_exists($name, $this->settings)) {
345
            $value = $this->settings[$name];
346
        } else {
347
            $value = $default;
348
        }
349
 
350
        return $value;
351
 
352
    }
353
 
354
/**
355
 * Set a setting value.
356
 *
357
 * @param string $name  Name of setting
358
 * @param string $value Value to set, use an empty value to delete a setting (optional, default is null)
359
 */
360
    public function setSetting($name, $value = null)
361
    {
362
 
363
        $old_value = $this->getSetting($name);
364
        if ($value !== $old_value) {
365
            if (!empty($value)) {
366
                $this->settings[$name] = $value;
367
            } else {
368
                unset($this->settings[$name]);
369
            }
370
            $this->settingsChanged = true;
371
        }
372
 
373
    }
374
 
375
/**
376
 * Get an array of all setting values.
377
 *
378
 * @return array Associative array of setting values
379
 */
380
    public function getSettings()
381
    {
382
 
383
        return $this->settings;
384
 
385
    }
386
 
387
/**
388
 * Set an array of all setting values.
389
 *
390
 * @param array $settings  Associative array of setting values
391
 */
392
    public function setSettings($settings)
393
    {
394
 
395
        $this->settings = $settings;
396
 
397
    }
398
 
399
/**
400
 * Save setting values.
401
 *
402
 * @return boolean True if the settings were successfully saved
403
 */
404
    public function saveSettings()
405
    {
406
 
407
        if ($this->settingsChanged) {
408
            $ok = $this->save();
409
        } else {
410
            $ok = true;
411
        }
412
 
413
        return $ok;
414
 
415
    }
416
 
417
/**
418
 * Check if the Tool Settings service is supported.
419
 *
420
 * @return boolean True if this tool consumer supports the Tool Settings service
421
 */
422
    public function hasToolSettingsService()
423
    {
424
 
425
        $url = $this->getSetting('custom_system_setting_url');
426
 
427
        return !empty($url);
428
 
429
    }
430
 
431
/**
432
 * Get Tool Settings.
433
 *
434
 * @param boolean  $simple     True if all the simple media type is to be used (optional, default is true)
435
 *
436
 * @return mixed The array of settings if successful, otherwise false
437
 */
438
    public function getToolSettings($simple = true)
439
    {
440
 
441
        $url = $this->getSetting('custom_system_setting_url');
442
        $service = new Service\ToolSettings($this, $url, $simple);
443
        $response = $service->get();
444
 
445
        return $response;
446
 
447
    }
448
 
449
/**
450
 * Perform a Tool Settings service request.
451
 *
452
 * @param array    $settings   An associative array of settings (optional, default is none)
453
 *
454
 * @return boolean True if action was successful, otherwise false
455
 */
456
    public function setToolSettings($settings = array())
457
    {
458
 
459
        $url = $this->getSetting('custom_system_setting_url');
460
        $service = new Service\ToolSettings($this, $url);
461
        $response = $service->set($settings);
462
 
463
        return $response;
464
 
465
    }
466
 
467
/**
468
 * Add the OAuth signature to an LTI message.
469
 *
470
 * @param string  $url         URL for message request
471
 * @param string  $type        LTI message type
472
 * @param string  $version     LTI version
473
 * @param array   $params      Message parameters
474
 *
475
 * @return array Array of signed message parameters
476
 */
477
    public function signParameters($url, $type, $version, $params)
478
    {
479
 
480
        if (!empty($url)) {
481
// Check for query parameters which need to be included in the signature
482
            $queryParams = array();
483
            $queryString = parse_url($url, PHP_URL_QUERY);
484
            if (!is_null($queryString)) {
485
                $queryItems = explode('&', $queryString);
486
                foreach ($queryItems as $item) {
487
                    if (strpos($item, '=') !== false) {
488
                        list($name, $value) = explode('=', $item);
489
                        $queryParams[urldecode($name)] = urldecode($value);
490
                    } else {
491
                        $queryParams[urldecode($item)] = '';
492
                    }
493
                }
494
            }
495
            $params = $params + $queryParams;
496
// Add standard parameters
497
            $params['lti_version'] = $version;
498
            $params['lti_message_type'] = $type;
499
            $params['oauth_callback'] = 'about:blank';
500
// Add OAuth signature
501
            $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1();
502
            $consumer = new OAuth\OAuthConsumer($this->getKey(), $this->secret, null);
503
            $req = OAuth\OAuthRequest::from_consumer_and_token($consumer, null, 'POST', $url, $params);
504
            $req->sign_request($hmacMethod, $consumer, null);
505
            $params = $req->get_parameters();
506
// Remove parameters being passed on the query string
507
            foreach (array_keys($queryParams) as $name) {
508
                unset($params[$name]);
509
            }
510
        }
511
 
512
        return $params;
513
 
514
    }
515
 
516
/**
517
 * Add the OAuth signature to an array of message parameters or to a header string.
518
 *
519
 * @return mixed Array of signed message parameters or header string
520
 */
521
    public static function addSignature($endpoint, $consumerKey, $consumerSecret, $data, $method = 'POST', $type = null)
522
    {
523
 
524
        $params = array();
525
        if (is_array($data)) {
526
            $params = $data;
527
        }
528
// Check for query parameters which need to be included in the signature
529
        $queryParams = array();
530
        $queryString = parse_url($endpoint, PHP_URL_QUERY);
531
        if (!is_null($queryString)) {
532
            $queryItems = explode('&', $queryString);
533
            foreach ($queryItems as $item) {
534
                if (strpos($item, '=') !== false) {
535
                    list($name, $value) = explode('=', $item);
536
                    $queryParams[urldecode($name)] = urldecode($value);
537
                } else {
538
                    $queryParams[urldecode($item)] = '';
539
                }
540
            }
541
            $params = $params + $queryParams;
542
        }
543
 
544
        if (!is_array($data)) {
545
// Calculate body hash
546
            $hash = base64_encode(sha1($data, true));
547
            $params['oauth_body_hash'] = $hash;
548
        }
549
 
550
// Add OAuth signature
551
        $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1();
552
        $oauthConsumer = new OAuth\OAuthConsumer($consumerKey, $consumerSecret, null);
553
        $oauthReq = OAuth\OAuthRequest::from_consumer_and_token($oauthConsumer, null, $method, $endpoint, $params);
554
        $oauthReq->sign_request($hmacMethod, $oauthConsumer, null);
555
        $params = $oauthReq->get_parameters();
556
// Remove parameters being passed on the query string
557
        foreach (array_keys($queryParams) as $name) {
558
            unset($params[$name]);
559
        }
560
 
561
        if (!is_array($data)) {
562
            $header = $oauthReq->to_header();
563
            if (empty($data)) {
564
                if (!empty($type)) {
565
                    $header .= "\nAccept: {$type}";
566
                }
567
            } else if (isset($type)) {
568
                $header .= "\nContent-Type: {$type}";
569
                $header .= "\nContent-Length: " . strlen($data);
570
            }
571
            return $header;
572
        } else {
573
            return $params;
574
        }
575
 
576
    }
577
 
578
/**
579
 * Perform a service request
580
 *
581
 * @param object $service  Service object to be executed
582
 * @param string $method   HTTP action
583
 * @param string $format   Media type
584
 * @param mixed  $data     Array of parameters or body string
585
 *
586
 * @return HTTPMessage HTTP object containing request and response details
587
 */
588
    public function doServiceRequest($service, $method, $format, $data)
589
    {
590
 
591
        $header = ToolConsumer::addSignature($service->endpoint, $this->getKey(), $this->secret, $data, $method, $format);
592
 
593
// Connect to tool consumer
594
        $http = new HTTPMessage($service->endpoint, $method, $data, $header);
595
// Parse JSON response
596
        if ($http->send() && !empty($http->response)) {
597
            $http->responseJson = json_decode($http->response);
598
            $http->ok = !is_null($http->responseJson);
599
        }
600
 
601
        return $http;
602
 
603
    }
604
 
605
/**
606
 * Load the tool consumer from the database by its record ID.
607
 *
608
 * @param string          $id                The consumer key record ID
609
 * @param DataConnector   $dataConnector    Database connection object
610
 *
611
 * @return object ToolConsumer       The tool consumer object
612
 */
613
    public static function fromRecordId($id, $dataConnector)
614
    {
615
 
616
        $toolConsumer = new ToolConsumer(null, $dataConnector);
617
 
618
        $toolConsumer->initialize();
619
        $toolConsumer->setRecordId($id);
620
        if (!$dataConnector->loadToolConsumer($toolConsumer)) {
621
            $toolConsumer->initialize();
622
        }
623
 
624
        return $toolConsumer;
625
 
626
    }
627
 
628
 
629
###
630
###  PRIVATE METHOD
631
###
632
 
633
/**
634
 * Load the tool consumer from the database.
635
 *
636
 * @param string  $key        The consumer key value
637
 * @param boolean $autoEnable True if the consumer should be enabled (optional, default if false)
638
 *
639
 * @return boolean True if the consumer was successfully loaded
640
 */
641
    private function load($key, $autoEnable = false)
642
    {
643
 
644
        $this->key = $key;
645
        $ok = $this->dataConnector->loadToolConsumer($this);
646
        if (!$ok) {
647
            $this->enabled = $autoEnable;
648
        }
649
 
650
        return $ok;
651
 
652
    }
653
 
654
}