ILIAS  release_8 Revision v8.24
System.php
Go to the documentation of this file.
1<?php
2
20
23use ILIAS\LTI\ToolProvider\Http\HTTPMessage;
28
29trait System
30{
36 public bool $ok = true;
37
43 public ?string $secret = null;
44
50 public string $signatureMethod = 'HMAC-SHA1';
51
57 public string $encryptionMethod = '';
58
65
74 public ?string $rsaKey = null;
75
81 public array $requiredScopes = array();
82
88 public ?string $kid = null;
89
95 public ?string $jku = null;
96
102 public ?string $reason = null;
103
109 public array $details = array();
110
116 public bool $debugMode = false;
117
123 public bool $enabled = false;
124
130 public ?int $enableFrom = null;
131
137 public ?int $enableUntil = null;
138
144 public ?int $lastAccess = null;
145
151 public ?int $created = null;
152
158 public ?int $updated = null;
159
165 protected ?ClientInterface $jwt = null;
166
172 protected ?array $rawParameters = null;
173
179 protected ?array $messageParameters = null;
180
186 private ?int $id = null;
187
193 private ?string $key = null;
194
200 private array $settings = []; //changed by UK from $settings = null
201
207 private bool $settingsChanged = false;
208
214 public function getRecordId(): ?int
215 {
216 return $this->id;
217 }
218
223 public function setRecordId(int $id)
224 {
225 $this->id = $id;
226 }
227
233 public function getKey(): ?string
234 {
235 return $this->key;
236 }
237
242 public function setKey(string $key)
243 {
244 $this->key = $key;
245 }
246
253 public function getSetting(string $name, string $default = ''): string
254 {
255 if (array_key_exists($name, $this->settings)) {
256 $value = $this->settings[$name];
257 } else {
258 $value = $default;
259 }
260
261 return $value;
262 }
263
269 public function setSetting(string $name, string $value = null)
270 {
271 $old_value = $this->getSetting($name);
272 if ($value !== $old_value) {
273 if (!empty($value)) {
274 $this->settings[$name] = $value;
275 } else {
276 unset($this->settings[$name]);
277 }
278 $this->settingsChanged = true;
279 }
280 }
281
287 public function getSettings(): array
288 {
289 return $this->settings;
290 }
291
296 public function setSettings(array $settings)
297 {
298 $this->settings = $settings;
299 }
300
306 public function saveSettings(): bool
307 {
308 if ($this->settingsChanged) {
309 $ok = $this->save();
310 } else {
311 $ok = true;
312 }
313
314 return $ok;
315 }
316
322 public function hasJwt(): bool
323 {
324 return !empty($this->jwt) && $this->jwt->hasJwt();
325 }
326
332 public function getJwt(): ClientInterface
333 {
334 return $this->jwt;
335 }
336
342 public function getRawParameters(): array
343 {
344 if (is_null($this->rawParameters)) {
345 $this->rawParameters = LTIOAuth\OAuthUtil::parse_parameters(file_get_contents(LTIOAuth\OAuthRequest::$POST_INPUT));
346// $this->rawParameters = OAuth\OAuthUtil::parse_parameters(file_get_contents(OAuth\OAuthRequest::$POST_INPUT));
347 }
348
350 }
351
357 public function getMessageClaims(bool $fullyQualified = false): array
358 {
359 $messageClaims = null;
360 if (!is_null($this->messageParameters)) {
362 $messageType = '';
363 if (!empty($messageParameters['lti_message_type'])) {
364 if (array_key_exists($messageParameters['lti_message_type'], Util::MESSAGE_TYPE_MAPPING)) {
365 $messageParameters['lti_message_type'] = Util::MESSAGE_TYPE_MAPPING[$messageParameters['lti_message_type']];
366 }
367 $messageType = $messageParameters['lti_message_type'];
368 }
369 if (!empty($messageParameters['accept_media_types'])) {
370 $mediaTypes = array_filter(explode(',', str_replace(' ', '', $messageParameters['accept_media_types'])), 'strlen');
371 $types = array();
372 if (!empty($messageParameters['accept_types'])) {
373 $types = array_filter(explode(',', str_replace(' ', '', $messageParameters['accept_types'])), 'strlen');
374 foreach ($mediaTypes as $mediaType) {
375 if (strpos($mediaType, 'application/vnd.ims.lti.') === 0) {
376 unset($mediaTypes[array_search($mediaType, $mediaTypes)]);
377 }
378 }
379 $messageParameters['accept_media_types'] = implode(',', $mediaTypes);
380 } else {
381 foreach ($mediaTypes as $mediaType) {
382 if ($mediaType === Item::LTI_LINK_MEDIA_TYPE) {
383 unset($mediaTypes[array_search(Item::LTI_LINK_MEDIA_TYPE, $mediaTypes)]);
384 $messageParameters['accept_media_types'] = implode(',', $mediaTypes);
385 $types[] = Item::TYPE_LTI_LINK;
386 } elseif ($mediaType === Item::LTI_ASSIGNMENT_MEDIA_TYPE) {
387 unset($mediaTypes[array_search(Item::LTI_ASSIGNMENT_MEDIA_TYPE, $mediaTypes)]);
388 $messageParameters['accept_media_types'] = implode(',', $mediaTypes);
389 $types[] = Item::TYPE_LTI_ASSIGNMENT;
390 } elseif (substr($mediaType, 0, 6) === 'image/') {
391 $types[] = 'image';
392 $types[] = 'link';
393 $types[] = 'file';
394 } elseif ($mediaType === 'text/html') {
395 $types[] = 'html';
396 $types[] = 'link';
397 $types[] = 'file';
398 } elseif ($mediaType === '*/*') {
399 $types[] = 'html';
400 $types[] = 'image';
401 $types[] = 'file';
402 $types[] = 'link';
403 } else {
404 $types[] = 'file';
405 }
406 }
407 $types = array_unique($types);
408 $messageParameters['accept_types'] = implode(',', $types);
409 }
410 }
411 if (!empty($messageParameters['accept_presentation_document_targets'])) {
412 $documentTargets = array_filter(explode(
413 ',',
414 str_replace(' ', '', $messageParameters['accept_presentation_document_targets'])
415 ), 'strlen');
416 $targets = array();
417 foreach ($documentTargets as $documentTarget) {
418 switch ($documentTarget) {
419 case 'frame':
420 case 'popup':
421 case 'overlay':
422 case 'none':
423 break;
424 default:
425 $targets[] = $documentTarget;
426 break;
427 }
428 }
429 $targets = array_unique($targets);
430 $messageParameters['accept_presentation_document_targets'] = implode(',', $targets);
431 }
432 $messageClaims = array();
433 if (!empty($messageParameters['oauth_consumer_key'])) {
434 $messageClaims['aud'] = array($messageParameters['oauth_consumer_key']);
435 }
436 foreach ($messageParameters as $key => $value) {
437 $ok = true;
438 if (array_key_exists($key, Util::JWT_CLAIM_MAPPING)) {
439 if (array_key_exists("{$key}.{$messageType}", Util::JWT_CLAIM_MAPPING)) {
440 $mapping = Util::JWT_CLAIM_MAPPING["{$key}.{$messageType}"];
441 } else {
442 $mapping = Util::JWT_CLAIM_MAPPING[$key];
443 }
444 if (isset($mapping['isObject']) && $mapping['isObject']) {
445 $value = json_decode($value);
446 } elseif (isset($mapping['isArray']) && $mapping['isArray']) {
447 $value = array_filter(explode(',', str_replace(' ', '', $value)), 'strlen');
448 sort($value);
449 } elseif (isset($mapping['isBoolean']) && $mapping['isBoolean']) {
450 $value = (is_bool($value)) ? $value : $value === 'true';
451 } elseif (isset($mapping['isInteger']) && $mapping['isInteger']) {
452 $value = intval($value);
453 } elseif (is_bool($value)) {
454 $value = ($value) ? 'true' : 'false';
455 } else {
456 $value = strval($value);
457 }
458 $group = '';
459 $claim = Util::JWT_CLAIM_PREFIX;
460 if (!empty($mapping['suffix'])) {
461 $claim .= "-{$mapping['suffix']}";
462 }
463 $claim .= '/claim/';
464 if (is_null($mapping['group'])) {
465 $claim = $mapping['claim'];
466 } elseif (empty($mapping['group'])) {
467 $claim .= $mapping['claim'];
468 } else {
469 $group = $claim . $mapping['group'];
470 $claim = $mapping['claim'];
471 }
472 } elseif (substr($key, 0, 7) === 'custom_') {
473 $group = Util::JWT_CLAIM_PREFIX . '/claim/custom';
474 $claim = substr($key, 7);
475 } elseif (substr($key, 0, 4) === 'ext_') {
476 $group = Util::JWT_CLAIM_PREFIX . '/claim/ext';
477 $claim = substr($key, 4);
478 } elseif (substr($key, 0, 7) === 'lti1p1_') {
479 $group = Util::JWT_CLAIM_PREFIX . '/claim/lti1p1';
480 $claim = substr($key, 7);
481 if (empty($value)) {
482 $value = null;
483 } else {
484 $json = json_decode($value);
485 if (!is_null($json)) {
486 $value = $json;
487 }
488 }
489 } else {
490 $ok = false;
491 }
492 if ($ok) {
493 if ($fullyQualified) {
494 if (empty($group)) {
495 $messageClaims = array_merge($messageClaims, self::fullyQualifyClaim($claim, $value));
496 } else {
497 $messageClaims = array_merge($messageClaims, self::fullyQualifyClaim("{$group}/{$claim}", $value));
498 }
499 } elseif (empty($group)) {
500 $messageClaims[$claim] = $value;
501 } else {
502 $messageClaims[$group][$claim] = $value;
503 }
504 }
505 }
506 if (!empty($messageParameters['unmapped_claims'])) {
507 $claims = json_decode($messageParameters['unmapped_claims']);
508 foreach ($claims as $claim => $value) {
509 if ($fullyQualified) {
510 $messageClaims = array_merge($messageClaims, self::fullyQualifyClaim($claim, $value));
511 } elseif (!is_object($value)) {
512 $messageClaims[$claim] = $value;
513 } elseif (!isset($messageClaims[$claim])) {
514 $messageClaims[$claim] = $value;
515 } else {
516 $objVars = get_object_vars($value);
517 foreach ($objVars as $attrName => $attrValue) {
518 if (is_object($messageClaims[$claim])) {
519 $messageClaims[$claim]->{$attrName} = $attrValue;
520 } else {
521 $messageClaims[$claim][$attrName] = $attrValue;
522 }
523 }
524 }
525 }
526 }
527 }
528
529 return $messageClaims;
530 }
531
538 public static function parseRoles($roles, string $ltiVersion = Util::LTI_VERSION1): array
539 {
540 if (!is_array($roles)) {
541 $roles = array_filter(explode(',', str_replace(' ', '', $roles)), 'strlen');
542 }
543 $parsedRoles = array();
544 foreach ($roles as $role) {
545 $role = trim($role);
546 if (!empty($role)) {
547 if ($ltiVersion === Util::LTI_VERSION1) {
548 if ((substr($role, 0, 4) !== 'urn:') &&
549 (substr($role, 0, 7) !== 'http://') && (substr($role, 0, 8) !== 'https://')) {
550 $role = 'urn:lti:role:ims/lis/' . $role;
551 }
552 } elseif ((substr($role, 0, 7) !== 'http://') && (substr($role, 0, 8) !== 'https://')) {
553 $role = 'http://purl.imsglobal.org/vocab/lis/v2/membership#' . $role;
554 }
555 $parsedRoles[] = $role;
556 }
557 }
558
559 return $parsedRoles;
560 }
561
570 public function signParameters(string $url, string $type, string $version, array $params)
571 {
572 if (!empty($url)) {
573 // Add standard parameters
574 $params['lti_version'] = $version;
575 $params['lti_message_type'] = $type;
576 // Add signature
577 $params = $this->addSignature($url, $params, 'POST', 'application/x-www-form-urlencoded');
578 }
579
580 return $params;
581 }
582
595 public function signMessage(string &$url, string $type, string $version, array $params, string $loginHint = null, string $ltiMessageHint = null)
596 {
597 if (($this instanceof Platform) && ($this->ltiVersion === Util::LTI_VERSION1P3)) {
598 if (!isset($loginHint) || (strlen($loginHint) <= 0)) {
599 if (isset($params['user_id']) && (strlen($params['user_id']) > 0)) {
600 $loginHint = $params['user_id'];
601 } else {
602 $loginHint = 'Anonymous';
603 }
604 }
605 // Add standard parameters
606 $params['lti_version'] = $version;
607 $params['lti_message_type'] = $type;
608 $this->onInitiateLogin($url, $loginHint, $ltiMessageHint, $params);
609
610 $params = array(
611 'iss' => $this->platformId,
612 'target_link_uri' => $url,
613 'login_hint' => $loginHint
614 );
615 if (!is_null($ltiMessageHint)) {
616 $params['lti_message_hint'] = $ltiMessageHint;
617 }
618 if (!empty($this->clientId)) {
619 $params['client_id'] = $this->clientId;
620 }
621 if (!empty($this->deploymentId)) {
622 $params['lti_deployment_id'] = $this->deploymentId;
623 }
624 if (!empty(Tool::$defaultTool)) {
625 $url = Tool::$defaultTool->initiateLoginUrl;
626 }
627 } else {
628 $params = $this->signParameters($url, $type, $version, $params);
629 }
630
631 return $params;
632 }
633
644 public function sendMessage(string $url, string $type, array $messageParams, string $target = '', ?string $userId = null, string $hint = ''): string
645 {
646 $sendParams = $this->signMessage($url, $type, $this->ltiVersion, $messageParams, $userId, $hint);
647 $html = Util::sendForm($url, $sendParams, $target);
648
649 return $html;
650 }
651
660 public function signServiceRequest(string $url, string $method, string $type, $data = null): string
661 {
662 $header = '';
663 if (!empty($url)) {
664 $header = $this->addSignature($url, $data, $method, $type);
665 }
666
667 return $header;
668 }
669
678 public function doServiceRequest(object $service, string $method, string $format, $data): HTTPMessage
679 {
680 $header = $this->addSignature($service->endpoint, $data, $method, $format);
681
682 // Connect to platform
683 $http = new HttpMessage($service->endpoint, $method, $data, $header);
684 // Parse JSON response
685 if ($http->send() && !empty($http->response)) {
686 $http->responseJson = json_decode($http->response);
687 $http->ok = !is_null($http->responseJson);
688 }
689
690 return $http;
691 }
692
698 public function useOAuth1(): bool
699 {
700 return empty($this->signatureMethod) || (substr($this->signatureMethod, 0, 2) !== 'RS');
701 }
702
714 public function addSignature(string $endpoint, $data, string $method = 'POST', ?string $type = null, ?string $nonce = '', ?string $hash = null, ?int $timestamp = null)
715 {
716 if ($this->useOAuth1()) {
717 return $this->addOAuth1Signature($endpoint, $data, $method, $type, $hash, $timestamp);
718 } else {
719 return $this->addJWTSignature($endpoint, $data, $method, $type, $nonce, $timestamp);
720 }
721 }
722
728 public function checkMessage(): bool
729 {
730 $this->ok = $_SERVER['REQUEST_METHOD'] === 'POST';
731 if (!$this->ok) {
732 $this->reason = 'LTI messages must use HTTP POST';
733 } elseif (!empty($this->jwt) && !empty($this->jwt->hasJwt())) {
734 $this->ok = false;
735 if (is_null($this->messageParameters['oauth_consumer_key']) || (strlen($this->messageParameters['oauth_consumer_key']) <= 0)) {
736 $this->reason = 'Missing iss claim';
737 } elseif (empty($this->jwt->getClaim('iat', ''))) {
738 $this->reason = 'Missing iat claim';
739 } elseif (empty($this->jwt->getClaim('exp', ''))) {
740 $this->reason = 'Missing exp claim';
741 } elseif (intval($this->jwt->getClaim('iat')) > intval($this->jwt->getClaim('exp'))) {
742 $this->reason = 'iat claim must not have a value greater than exp claim';
743 } elseif (empty($this->jwt->getClaim('nonce', ''))) {
744 $this->reason = 'Missing nonce claim';
745 } else {
746 $this->ok = true;
747 }
748 }
749 // Set signature method from request
750 if (isset($this->messageParameters['oauth_signature_method'])) {
751 $this->signatureMethod = $this->messageParameters['oauth_signature_method'];
752 if (($this instanceof Tool) && !empty($this->platform)) {
753 $this->platform->signatureMethod = $this->signatureMethod;
754 }
755 }
756 // Check all required launch parameters
757 if ($this->ok) {
758 $this->ok = isset($this->messageParameters['lti_message_type']);
759 if (!$this->ok) {
760 $this->reason = 'Missing lti_message_type parameter.';
761 }
762 }
763 if ($this->ok) {
764 $this->ok = isset($this->messageParameters['lti_version']) && in_array(
765 $this->messageParameters['lti_version'],
767 );
768 if (!$this->ok) {
769 $this->reason = 'Invalid or missing lti_version parameter.';
770 }
771 }
772
773 return $this->ok;
774 }
775
781 public function verifySignature(): bool
782 {
783 $ok = false;
785 $publicKey = ''; //changed
786 if (!empty($key)) {
788 } elseif (($this instanceof Tool) && !empty($this->platform)) {
789 $key = $this->platform->getKey();
790 $secret = $this->platform->secret;
791 } elseif (($this instanceof Platform) && !empty(Tool::$defaultTool)) {
792 $key = Tool::$defaultTool->getKey();
793 $secret = Tool::$defaultTool->secret;
794 }
795 if ($this instanceof Tool) {
796 $platform = $this->platform;
797 $publicKey = $this->platform->rsaKey;
798 $jku = $this->platform->jku;
799 } else {
800 $platform = $this;
801 if (!empty(Tool::$defaultTool)) {
802 $publicKey = Tool::$defaultTool->rsaKey;
804 } else {
805 $publicKey = $this->rsaKey;
807 }
808 }
809
810 if (empty($this->jwt) || empty($this->jwt->hasJwt())) { // OAuth-signed message
811 try {
812 $store = new OAuthDataStore($this);
813// $server = new OAuth\OAuthServer($store);
814 $server = new LTIOAuth\OAuthServer($store);
815 //ToDo OAuthSignatureMethod
816// $method = new OAuth\OAuthSignatureMethod_HMAC_SHA224();
817// $server->add_signature_method($method);
818// $method = new OAuth\OAuthSignatureMethod_HMAC_SHA256();
819// $server->add_signature_method($method);
820// $method = new OAuth\OAuthSignatureMethod_HMAC_SHA384();
821// $server->add_signature_method($method);
822// $method = new OAuth\OAuthSignatureMethod_HMAC_SHA512();
823// $server->add_signature_method($method);
824// $method = new OAuth\OAuthSignatureMethod_HMAC_SHA1();
826 $server->add_signature_method($method);
827// $request = OAuth\OAuthRequest::from_request();
828 $request = LTIOAuth\OAuthRequest::from_request();
829 $server->verify_request($request);
830 $ok = true;
831 } catch (\Exception $e) {
832 if (empty($this->reason)) {
833// $oauthConsumer = new OAuth\OAuthConsumer($key, $secret);
834 $oauthConsumer = new LTIOAuth\OAuthConsumer($key, $secret);
835// $signature = $request->build_signature($method, $oauthConsumer, false);
836 $signature = $request->build_signature($method, $oauthConsumer, null);
837 if ($this->debugMode) {
838 $this->reason = $e->getMessage();
839 }
840 if (empty($this->reason)) {
841 $this->reason = 'OAuth signature check failed - perhaps an incorrect secret or timestamp.';
842 }
843 $this->details[] = "Shared secret: '{$secret}'";
844 $this->details[] = 'Current timestamp: ' . time();
845 $this->details[] = "Expected signature: {$signature}";
846 $this->details[] = "Base string: {$request->base_string}";
847 }
848 }
849 } else { // JWT-signed message
850 $nonce = new PlatformNonce($platform, $this->jwt->getClaim('nonce'));
851
852 $ok = !$nonce->load();
853 if ($ok) {
854 $ok = $nonce->save();
855 }
856 if (!$ok) {
857 $this->reason = 'Invalid nonce.';
858 } elseif (!empty($publicKey) || !empty($jku) || Jwt::$allowJkuHeader) {
859 if (empty($publicKey)) { //added
860 $publicKey = "";
861 }
862 if (empty($jku)) { //added
863 $jku = "";
864 }
865 $ok = $this->jwt->verify($publicKey, $jku);
866 if (!$ok) {
867 $this->reason = 'JWT signature check failed - perhaps an invalid public key or timestamp';
868 }
869 } else {
870 $ok = false;
871 $this->reason = 'Unable to verify JWT signature as neither a public key nor a JSON Web Key URL is specified';
872 }
873 }
874
875 return $ok;
876 }
877
878 ###
879 ### PRIVATE METHODS
880 ###
881
885 private function parseMessage()
886 {
887 if (is_null($this->messageParameters)) {
888 $this->getRawParameters();
889 if (isset($this->rawParameters['id_token']) || isset($this->rawParameters['JWT'])) { // JWT-signed message
890 try {
891 $this->jwt = Jwt::getJwtClient();
892 if (isset($this->rawParameters['id_token'])) {
893 $this->ok = $this->jwt->load($this->rawParameters['id_token'], $this->rsaKey);
894 } else {
895 $this->ok = $this->jwt->load($this->rawParameters['JWT'], $this->rsaKey);
896 }
897 if (!$this->ok) {
898 $this->reason = 'Message does not contain a valid JWT';
899 } else {
900 $this->ok = $this->jwt->hasClaim('iss') && $this->jwt->hasClaim('aud') &&
901 $this->jwt->hasClaim(Util::JWT_CLAIM_PREFIX . '/claim/deployment_id');
902 if ($this->ok) {
903 $iss = $this->jwt->getClaim('iss');
904 $aud = $this->jwt->getClaim('aud');
905 $deploymentId = $this->jwt->getClaim(Util::JWT_CLAIM_PREFIX . '/claim/deployment_id');
906 $this->ok = !empty($iss) && !empty($aud) && !empty($deploymentId);
907 if (!$this->ok) {
908 $this->reason = 'iss, aud and/or deployment_id claim is empty';
909 } elseif (is_array($aud)) {
910 if ($this->jwt->hasClaim('azp')) {
911 $this->ok = !empty($this->jwt->getClaim('azp'));
912 if (!$this->ok) {
913 $this->reason = 'azp claim is empty';
914 } else {
915 $this->ok = in_array($this->jwt->getClaim('azp'), $aud);
916 if ($this->ok) {
917 $aud = $this->jwt->getClaim('azp');
918 } else {
919 $this->reason = 'azp claim value is not included in aud claim';
920 }
921 }
922 } else {
923 $aud = $aud[0];
924 $this->ok = !empty($aud);
925 if (!$this->ok) {
926 $this->reason = 'First element of aud claim is empty';
927 }
928 }
929 } elseif ($this->jwt->hasClaim('azp')) {
930 $this->ok = $this->jwt->getClaim('azp') === $aud;
931 if (!$this->ok) {
932 $this->reason = 'aud claim does not match the azp claim';
933 }
934 }
935 if ($this->ok) {
936 if ($this instanceof Tool) {
937 $this->platform = \ilLTIPlatform::fromPlatformId($iss, $aud, $deploymentId, $this->dataConnector);
938 $this->platform->platformId = $iss;
939 if (isset($this->rawParameters['id_token'])) {
940 $this->ok = !empty($this->rawParameters['state']);
941 if ($this->ok) {
942 $nonce = new PlatformNonce($this->platform, $this->rawParameters['state']);
943 $this->ok = $nonce->load();
944 if (!$this->ok) {
945 $platform = \ilLTIPlatform::fromPlatformId($iss, $aud, null, $this->dataConnector);
946 $nonce = new PlatformNonce($platform, $this->rawParameters['state']);
947 $this->ok = $nonce->load();
948 }
949 if (!$this->ok) {
950 $platform = \ilLTIPlatform::fromPlatformId($iss, null, null, $this->dataConnector);
951 $nonce = new PlatformNonce($platform, $this->rawParameters['state']);
952 $this->ok = $nonce->load();
953 }
954 if ($this->ok) {
955 $this->ok = $nonce->delete();
956 }
957 }
958 }
959 }
960 if ($this->ok) {
961 $this->messageParameters = array();
962 $this->messageParameters['oauth_consumer_key'] = $aud;
963 $this->messageParameters['oauth_signature_method'] = $this->jwt->getHeader('alg');
964 $this->parseClaims();
965 } else {
966 $this->reason = 'state parameter is invalid or missing';
967 }
968 }
969 } else {
970 $this->reason = 'iss, aud and/or deployment_id claim not found';
971 }
972 }
973 } catch (\Exception $e) {
974 $this->ok = false;
975 $this->reason = 'Message does not contain a valid JWT';
976 }
977 } elseif (isset($this->rawParameters['error'])) { // Error with JWT-signed message
978 $this->ok = false;
979 $this->reason = $this->rawParameters['error'];
980 if (!empty($this->rawParameters['error_description'])) {
981 $this->reason .= ": {$this->rawParameters['error_description']}";
982 }
983 } else { // OAuth
984 if (isset($this->rawParameters['oauth_consumer_key']) && ($this instanceof Tool)) {
985 //changed UK temporary
986// $this->platform = Platform::fromConsumerKey($this->rawParameters['oauth_consumer_key'], $this->dataConnector);
987 $this->platform = \ilLTIPlatform::fromConsumerKey($this->rawParameters['oauth_consumer_key'], $this->dataConnector);
988 }
989 $this->messageParameters = $this->rawParameters;
990 }
991 }
992 }
993
997 private function parseClaims()
998 {
999 $payload = Util::cloneObject((object) $this->jwt->getPayload()); //UK: added object
1000 $errors = array();
1001 foreach (Util::JWT_CLAIM_MAPPING as $key => $mapping) {
1002 $claim = Util::JWT_CLAIM_PREFIX;
1003 if (!empty($mapping['suffix'])) {
1004 $claim .= "-{$mapping['suffix']}";
1005 }
1006 $claim .= '/claim/';
1007 if (is_null($mapping['group'])) {
1008 $claim = $mapping['claim'];
1009 } elseif (empty($mapping['group'])) {
1010 $claim .= $mapping['claim'];
1011 } else {
1012 $claim .= $mapping['group'];
1013 }
1014 if ($this->jwt->hasClaim($claim)) {
1015 $value = null;
1016 if (empty($mapping['group'])) {
1017 unset($payload->{$claim});
1018 $value = $this->jwt->getClaim($claim);
1019 } else {
1020 $group = $this->jwt->getClaim($claim);
1021 if (is_array($group) && array_key_exists($mapping['claim'], $group)) {
1022 unset($payload->{$claim}[$mapping['claim']]);
1023 $value = $group[$mapping['claim']];
1024 } elseif (is_object($group) && isset($group->{$mapping['claim']})) {
1025 unset($payload->{$claim}->{$mapping['claim']});
1026 $value = $group->{$mapping['claim']};
1027 }
1028 }
1029 if (!is_null($value)) {
1030 if (isset($mapping['isArray']) && $mapping['isArray']) {
1031 if (!is_array($value)) {
1032 $errors[] = "'{$claim}' claim must be an array";
1033 } else {
1034 $value = implode(',', $value);
1035 }
1036 } elseif (isset($mapping['isObject']) && $mapping['isObject']) {
1037 $value = json_encode($value);
1038 } elseif (isset($mapping['isBoolean']) && $mapping['isBoolean']) {
1039 $value = $value ? 'true' : 'false';
1040 } elseif (isset($mapping['isInteger']) && $mapping['isInteger']) {
1041 $value = strval($value);
1042 }
1043 }
1044 if (!is_null($value) && is_string($value)) {
1045 $this->messageParameters[$key] = $value;
1046 }
1047 }
1048 }
1049 if (!empty($this->messageParameters['lti_message_type']) &&
1050 in_array($this->messageParameters['lti_message_type'], array_values(Util::MESSAGE_TYPE_MAPPING))) {
1051 $this->messageParameters['lti_message_type'] = array_search(
1052 $this->messageParameters['lti_message_type'],
1054 );
1055 }
1056 if (!empty($this->messageParameters['accept_types'])) {
1057 $types = array_filter(explode(',', str_replace(' ', '', $this->messageParameters['accept_types'])), 'strlen');
1058 $mediaTypes = array();
1059 if (!empty($this->messageParameters['accept_media_types'])) {
1060 $mediaTypes = array_filter(
1061 explode(',', str_replace(' ', '', $this->messageParameters['accept_media_types'])),
1062 'strlen'
1063 );
1064 }
1065 if (in_array(Item::TYPE_LTI_LINK, $types)) {
1066 $mediaTypes[] = Item::LTI_LINK_MEDIA_TYPE;
1067 }
1068 if (in_array(Item::TYPE_LTI_ASSIGNMENT, $types)) {
1069 $mediaTypes[] = Item::LTI_ASSIGNMENT_MEDIA_TYPE;
1070 }
1071 if (in_array('html', $types) && !in_array('*/*', $mediaTypes)) {
1072 $mediaTypes[] = 'text/html';
1073 }
1074 if (in_array('image', $types) && !in_array('*/*', $mediaTypes)) {
1075 $mediaTypes[] = 'image/*';
1076 }
1077 $mediaTypes = array_unique($mediaTypes);
1078 $this->messageParameters['accept_media_types'] = implode(',', $mediaTypes);
1079 }
1080 $claim = Util::JWT_CLAIM_PREFIX . '/claim/custom';
1081 if ($this->jwt->hasClaim($claim)) {
1082 unset($payload->{$claim});
1083 $custom = $this->jwt->getClaim($claim);
1084 if (!is_array($custom) && !is_object($custom)) {
1085 $errors[] = "'{$claim}' claim must be an object";
1086 } else {
1087 foreach ($custom as $key => $value) {
1088 $this->messageParameters["custom_{$key}"] = $value;
1089 }
1090 }
1091 }
1092 $claim = Util::JWT_CLAIM_PREFIX . '/claim/ext';
1093 if ($this->jwt->hasClaim($claim)) {
1094 unset($payload->{$claim});
1095 $ext = $this->jwt->getClaim($claim);
1096 if (!is_array($ext) && !is_object($ext)) {
1097 $errors[] = "'{$claim}' claim must be an object";
1098 } else {
1099 foreach ($ext as $key => $value) {
1100 $this->messageParameters["ext_{$key}"] = $value;
1101 }
1102 }
1103 }
1104 $claim = Util::JWT_CLAIM_PREFIX . '/claim/lti1p1';
1105 if ($this->jwt->hasClaim($claim)) {
1106 unset($payload->{$claim});
1107 $lti1p1 = $this->jwt->getClaim($claim);
1108 if (!is_array($lti1p1) && !is_object($lti1p1)) {
1109 $errors[] = "'{$claim}' claim must be an object";
1110 } else {
1111 foreach ($lti1p1 as $key => $value) {
1112 if (is_null($value)) {
1113 $value = '';
1114 } elseif (is_object($value)) {
1115 $value = json_encode($value);
1116 }
1117 $this->messageParameters["lti1p1_{$key}"] = $value;
1118 }
1119 }
1120 }
1121 if (!empty($payload)) {
1122 $objVars = get_object_vars($payload);
1123 foreach ($objVars as $attrName => $attrValue) {
1124 if (empty((array) $attrValue)) {
1125 unset($payload->{$attrName});
1126 }
1127 }
1128 $this->messageParameters['unmapped_claims'] = json_encode($payload);
1129 }
1130 if (!empty($errors)) {
1131 $this->ok = false;
1132 $this->reason = 'Invalid JWT: ' . implode(', ', $errors);
1133 }
1134 }
1135
1141 private function doCallback()
1142 {
1143 if (array_key_exists($this->messageParameters['lti_message_type'], Util::$METHOD_NAMES)) {
1144 $callback = Util::$METHOD_NAMES[$this->messageParameters['lti_message_type']];
1145 } else {
1146 $callback = "on{$this->messageParameters['lti_message_type']}";
1147 }
1148 if (method_exists($this, $callback)) {
1149 $this->$callback();
1150 } elseif ($this->ok) {
1151 $this->ok = false;
1152 $this->reason = "Message type not supported: {$this->messageParameters['lti_message_type']}";
1153 }
1154 }
1155
1166 private function addOAuth1Signature(string $endpoint, $data, string $method, ?string $type, ?string $hash, ?int $timestamp)
1167 {
1168 $params = array();
1169 if (is_array($data)) {
1170 $params = $data;
1171 $params['oauth_callback'] = 'about:blank';
1172 }
1173 // Check for query parameters which need to be included in the signature
1174 $queryString = parse_url($endpoint, PHP_URL_QUERY);
1175// $queryParams = OAuth\OAuthUtil::parse_parameters($queryString);
1176 $queryParams = LTIOAuth\OAuthUtil::parse_parameters($queryString);
1177 $params = array_merge_recursive($queryParams, $params);
1178
1179 if (!is_array($data)) {
1180 if (empty($hash)) { // Calculate body hash
1181 switch ($this->signatureMethod) {
1182 case 'HMAC-SHA224':
1183 $hash = base64_encode(hash('sha224', $data, true));
1184 break;
1185 case 'HMAC-SHA256':
1186 $hash = base64_encode(hash('sha256', $data, true));
1187 break;
1188 case 'HMAC-SHA384':
1189 $hash = base64_encode(hash('sha384', $data, true));
1190 break;
1191 case 'HMAC-SHA512':
1192 $hash = base64_encode(hash('sha512', $data, true));
1193 break;
1194 default:
1195 $hash = base64_encode(sha1($data, true));
1196 break;
1197 }
1198 }
1199 $params['oauth_body_hash'] = $hash;
1200 }
1201 if (!empty($timestamp)) {
1202 $params['oauth_timestamp'] = $timestamp;
1203 }
1204
1205 // Add OAuth signature
1206 switch ($this->signatureMethod) {
1207 //UK: ToDo
1208// case 'HMAC-SHA224':
1209// $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA224();
1210// break;
1211// case 'HMAC-SHA256':
1212// $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA256();
1213// break;
1214// case 'HMAC-SHA384':
1215// $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA384();
1216// break;
1217// case 'HMAC-SHA512':
1218// $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA512();
1219// break;
1220 default:
1221// $hmacMethod = new OAuth\OAuthSignatureMethod_HMAC_SHA1();
1222 $hmacMethod = new LTIOAuth\OAuthSignatureMethod_HMAC_SHA1();
1223 break;
1224 }
1225 $key = $this->key;
1227 if (empty($key)) {
1228 if (($this instanceof Tool) && !empty($this->platform)) {
1229 $key = $this->platform->getKey();
1230 $secret = $this->platform->secret;
1231 } elseif (($this instanceof Platform) && !empty(Tool::$defaultTool)) {
1232 $key = Tool::$defaultTool->getKey();
1233 $secret = Tool::$defaultTool->secret;
1234 }
1235 }
1236// $oauthConsumer = new OAuth\OAuthConsumer($key, $secret, null);
1237 $oauthConsumer = new LTIOAuth\OAuthConsumer($key, $secret, null);
1238// $oauthReq = OAuth\OAuthRequest::from_consumer_and_token($oauthConsumer, null, $method, $endpoint, $params);
1239 $oauthReq = LTIOAuth\OAuthRequest::from_consumer_and_token($oauthConsumer, null, $method, $endpoint, $params);
1240 $oauthReq->sign_request($hmacMethod, $oauthConsumer, null);
1241 if (!is_array($data)) {
1242 $header = $oauthReq->to_header();
1243 if (empty($data)) {
1244 if (!empty($type)) {
1245 $header .= "\nAccept: {$type}";
1246 }
1247 } elseif (isset($type)) {
1248 $header .= "\nContent-Type: {$type}";
1249 $header .= "\nContent-Length: " . strlen($data);
1250 }
1251 return $header;
1252 } else {
1253 // Remove parameters from query string
1254 $params = $oauthReq->get_parameters();
1255 foreach ($queryParams as $key => $value) {
1256 if (!is_array($value)) {
1257 if (!is_array($params[$key])) {
1258 if ($params[$key] === $value) {
1259 unset($params[$key]);
1260 }
1261 } else {
1262 $params[$key] = array_diff($params[$key], array($value));
1263 }
1264 } else {
1265 foreach ($value as $element) {
1266 $params[$key] = array_diff($params[$key], array($value));
1267 }
1268 }
1269 }
1270 // Remove any parameters comprising an empty array of values
1271 foreach ($params as $key => $value) {
1272 if (is_array($value)) {
1273 if (count($value) <= 0) {
1274 unset($params[$key]);
1275 } elseif (count($value) === 1) {
1276 $params[$key] = reset($value);
1277 }
1278 }
1279 }
1280 return $params;
1281 }
1282 }
1283
1294 private function addJWTSignature(string $endpoint, $data, string $method, ?string $type, ?string $nonce, ?int $timestamp)
1295 {
1296 $ok = false;
1297 if (is_array($data)) {
1298 $ok = true;
1299 if (empty($nonce)) {
1300 $nonce = Util::getRandomString(32);
1301 }
1302 $publicKey = null;
1303 if (!array_key_exists('grant_type', $data)) {
1304 $this->messageParameters = $data;
1305 $payload = $this->getMessageClaims();
1307 $kid = $this->kid;
1308 $jku = $this->jku;
1309 if ($this instanceof Platform) {
1310 if (!empty(Tool::$defaultTool)) {
1311 $publicKey = Tool::$defaultTool->rsaKey;
1312 }
1313 $payload['iss'] = $this->platformId;
1314 $payload['aud'] = array($this->clientId);
1315 $payload['azp'] = $this->clientId;
1316 $payload[Util::JWT_CLAIM_PREFIX . '/claim/deployment_id'] = $this->deploymentId;
1317 $payload[Util::JWT_CLAIM_PREFIX . '/claim/target_link_uri'] = $endpoint;
1318 $paramName = 'id_token';
1319 } else {
1320 if (!empty($this->platform)) {
1321 $publicKey = $this->platform->rsaKey;
1322 $payload['iss'] = $this->platform->clientId;
1323 $payload['aud'] = array($this->platform->platformId);
1324 $payload['azp'] = $this->platform->platformId;
1325 $payload[Util::JWT_CLAIM_PREFIX . '/claim/deployment_id'] = $this->platform->deploymentId;
1326 }
1327 $paramName = 'JWT';
1328 }
1329 $payload['nonce'] = $nonce;
1330 } else {
1331 $authorizationId = '';
1332 if ($this instanceof Tool) {
1333 $sub = '';
1334 if (!empty($this->platform)) {
1335 $sub = $this->platform->clientId;
1336 $authorizationId = $this->platform->authorizationServerId;
1337 $publicKey = $this->platform->rsaKey;
1338 }
1340 $kid = $this->kid;
1341 $jku = $this->jku;
1342 } else { // Tool-hosted services not yet defined in LTI
1343 $sub = $this->clientId;
1344 $kid = $this->kid;
1345 $jku = $this->jku;
1347 if (!empty(Tool::$defaultTool)) {
1348 $publicKey = Tool::$defaultTool->rsaKey;
1349 }
1350 }
1351 $payload['iss'] = $sub;
1352 $payload['sub'] = $sub;
1353 if (empty($authorizationId)) {
1354 $authorizationId = $endpoint;
1355 }
1356 $payload['aud'] = array($authorizationId);
1357 $payload['jti'] = $nonce;
1358 $params = $data;
1359 $paramName = 'client_assertion';
1360 }
1361 }
1362 if ($ok) {
1363 if (empty($timestamp)) {
1364 $timestamp = time();
1365 }
1366 $payload['iat'] = $timestamp;
1367 $payload['exp'] = $timestamp + Jwt::$life;
1368 try {
1370 $params[$paramName] = $jwt::sign(
1371 $payload,
1372 $this->signatureMethod,
1374 $kid,
1375 $jku,
1376 $this->encryptionMethod,
1377 $publicKey
1378 );
1379 } catch (\Exception $e) {
1380 $params = array();
1381 }
1382
1383 return $params;
1384 } else {
1385 $header = '';
1386 if ($this instanceof Tool) {
1387 $platform = $this->platform;
1388 } else {
1389 $platform = $this;
1390 }
1391 $accessToken = $platform->getAccessToken();
1392 if (empty($accessToken)) {
1393 $accessToken = new AccessToken($platform);
1394 $platform->setAccessToken($accessToken);
1395 }
1396 if (!$accessToken->hasScope()) { // Check token has not expired
1397 $accessToken->get();
1398 }
1399 if (!empty($accessToken->token)) {
1400 $header = "Authorization: Bearer {$accessToken->token}";
1401 }
1402 if (empty($data) && ($method !== 'DELETE')) {
1403 if (!empty($type)) {
1404 $header .= "\nAccept: {$type}";
1405 }
1406 } elseif (isset($type)) {
1407 $header .= "\nContent-Type: {$type}";
1408 if (!empty($data) && is_string($data)) {
1409 $header .= "\nContent-Length: " . strlen($data);
1410 }
1411 }
1412
1413 return $header;
1414 }
1415 }
1416
1423 private static function fullyQualifyClaim(string $claim, string $value): array
1424 {
1425 $claims = array();
1426 $empty = true;
1427 if (is_object($value)) {
1428 foreach ($value as $c => $v) {
1429 $empty = false;
1430 $claims = array_merge($claims, static::fullyQualifyClaim("{$claim}/{$c}", $v));
1431 }
1432 }
1433 if ($empty) {
1434 $claims[$claim] = $value;
1435 }
1436
1437 return $claims;
1438 }
1439}
$version
Definition: plugin.php:24
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
Class to represent an HTTP message.
Definition: AccessToken.php:33
Class to represent a content-item object.
Definition: Item.php:32
const TYPE_LTI_LINK
Type for LTI link content-item.
Definition: Item.php:41
const TYPE_LTI_ASSIGNMENT
Type for LTI assignment content-item.
Definition: Item.php:46
const LTI_LINK_MEDIA_TYPE
Media type for LTI launch links.
Definition: Item.php:66
const LTI_ASSIGNMENT_MEDIA_TYPE
Media type for LTI assignment links.
Definition: Item.php:71
Class to provide a connection to a persistent store for LTI objects.
Class to represent an HTTP message request.
Definition: Jwt.php:31
static int $life
Life (in seconds) of an issued JWT (default is 1 minute).
Definition: Jwt.php:37
static getJwtClient()
Get the JWT client to use for handling JWTs.
Definition: Jwt.php:85
static bool $allowJkuHeader
Allow use of jku header in JWT.
Definition: Jwt.php:51
Class to represent an OAuth datastore.
Class to represent a platform nonce.
Class to represent a platform.
Definition: Platform.php:36
Class to represent an LTI Tool.
Definition: Tool.php:39
static Tool $defaultTool
Default tool for use with service requests.
Definition: Tool.php:299
const LTI_VERSION1
LTI version 1 for messages.
Definition: Util.php:28
static array $LTI_VERSIONS
Permitted LTI versions for messages.
Definition: Util.php:161
static sendForm(string $url, array $params, string $target='')
Generate a web page containing an auto-submitted form of parameters.
Definition: Util.php:466
const JWT_CLAIM_MAPPING
Mapping for standard message parameters to JWT claim.
Definition: Util.php:58
static array $METHOD_NAMES
List of supported message types and associated class methods.
Definition: Util.php:166
const LTI_VERSION1P3
LTI version 1.3 for messages.
Definition: Util.php:33
static getRandomString(int $length=8)
Generate a random string.
Definition: Util.php:558
static cloneObject(object $obj)
Clone an object and any objects it contains.
Definition: Util.php:590
const MESSAGE_TYPE_MAPPING
Mapping for standard message types.
Definition: Util.php:48
const JWT_CLAIM_PREFIX
Prefix for standard JWT message claims.
Definition: Util.php:43
setSetting(string $a_key, string $a_val)
getSetting(string $a_keyword, ?string $a_default_value=null)
read one value from settingstable
Definition: class.ilias.php:88
static fromConsumerKey(?string $key=null, $dataConnector=null, bool $autoEnable=false)
Load the platform from the database by its consumer key.
static fromPlatformId(string $platformId, string $clientId, string $deploymentId, ilLTIDataConnector $dataConnector=null, bool $autoEnable=false)
Load the platform from the database by its platform, client and deployment IDs.
$c
Definition: cli.php:38
$server
$errors
Definition: imgupload.php:65
Interface to represent an HWT client.
$ltiMessageHint
Definition: ltiauth.php:51
$clientId
Definition: ltiregend.php:27
$privateKey
Definition: ltiregstart.php:68
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:33
$service
Definition: ltiservices.php:43
$claims
Definition: ltitoken.php:71
if(count($parts) !=3) $payload
Definition: ltitoken.php:70
if($format !==null) $name
Definition: metadata.php:247
$format
Definition: metadata.php:235
$store
Definition: metadata.php:107
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: OAuth.php:21
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: AccessToken.php:19
string $encryptionMethod
Algorithm used for encrypting messages.
Definition: System.php:57
array $messageParameters
LTI message parameters.
Definition: System.php:179
parseClaims()
Parse the claims.
Definition: System.php:997
getKey()
Get the consumer key.
Definition: System.php:233
ilLTIDataConnector $dataConnector
Data connector object.
Definition: System.php:64
static parseRoles($roles, string $ltiVersion=Util::LTI_VERSION1)
Get an array of fully qualified user roles.
Definition: System.php:538
checkMessage()
Verify the required properties of an LTI message.
Definition: System.php:728
string $jku
Endpoint for public key.
Definition: System.php:95
getRecordId()
Get the system record ID.
Definition: System.php:214
useOAuth1()
Determine whether this consumer is using the OAuth 1 security model.
Definition: System.php:698
addJWTSignature(string $endpoint, $data, string $method, ?string $type, ?string $nonce, ?int $timestamp)
Add the JWT signature to an array of message parameters or to a header string.
Definition: System.php:1294
string $reason
Error message for last request processed.
Definition: System.php:102
signServiceRequest(string $url, string $method, string $type, $data=null)
Generates the headers for an LTI service request.
Definition: System.php:660
int $enableUntil
Timestamp until which the system instance is enabled to accept connection requests.
Definition: System.php:137
ClientInterface $jwt
JWT object, if any.
Definition: System.php:165
string $kid
Key ID.
Definition: System.php:88
bool $enabled
Whether the system instance is enabled to accept connection requests.
Definition: System.php:123
string $signatureMethod
Method used for signing messages.
Definition: System.php:50
array $requiredScopes
Scopes to request when obtaining an access token.
Definition: System.php:81
doServiceRequest(object $service, string $method, string $format, $data)
Perform a service request.
Definition: System.php:678
signMessage(string &$url, string $type, string $version, array $params, string $loginHint=null, string $ltiMessageHint=null)
Add the signature to an LTI message.
Definition: System.php:595
string $rsaKey
RSA key in PEM or JSON format.
Definition: System.php:74
addOAuth1Signature(string $endpoint, $data, string $method, ?string $type, ?string $hash, ?int $timestamp)
Add the OAuth 1 signature to an array of message parameters or to a header string.
Definition: System.php:1166
parseMessage()
Parse the message.
Definition: System.php:885
signParameters(string $url, string $type, string $version, array $params)
Add the signature to an LTI message.
Definition: System.php:570
string $key
Consumer key/client ID value.
Definition: System.php:193
array $details
Details for error message relating to last request processed.
Definition: System.php:109
int $lastAccess
Timestamp for date of last connection to this system.
Definition: System.php:144
addSignature(string $endpoint, $data, string $method='POST', ?string $type=null, ?string $nonce='', ?string $hash=null, ?int $timestamp=null)
Add the signature to an array of message parameters or to a header string.
Definition: System.php:714
int $enableFrom
Timestamp from which the the system instance is enabled to accept connection requests.
Definition: System.php:130
array $rawParameters
Raw message parameters.
Definition: System.php:172
sendMessage(string $url, string $type, array $messageParams, string $target='', ?string $userId=null, string $hint='')
Generate a web page containing an auto-submitted form of LTI message parameters.
Definition: System.php:644
doCallback()
Call any callback function for the requested action.
Definition: System.php:1141
getRawParameters()
Get the raw POST parameters.
Definition: System.php:342
bool $debugMode
Whether debug level messages are to be reported.
Definition: System.php:116
bool $settingsChanged
Whether the settings value have changed since last saved.
Definition: System.php:207
int $updated
Timestamp for when the object was last updated.
Definition: System.php:158
getJwt()
Get the JWT.
Definition: System.php:332
setKey(string $key)
Set the consumer key.
Definition: System.php:242
getSettings()
Get an array of all setting values.
Definition: System.php:287
int $created
Timestamp for when the object was created.
Definition: System.php:151
int $id
System ID value.
Definition: System.php:186
static fullyQualifyClaim(string $claim, string $value)
Expand a claim into an array of individual fully-qualified claims.
Definition: System.php:1423
setRecordId(int $id)
Sets the system record ID.
Definition: System.php:223
verifySignature()
Verify the signature of a message.
Definition: System.php:781
array $settings
Setting values (LTI parameters, custom parameters and local parameters).
Definition: System.php:200
setSettings(array $settings)
Set an array of all setting values.
Definition: System.php:296
saveSettings()
Save setting values.
Definition: System.php:306
getMessageClaims(bool $fullyQualified=false)
Get the message claims.
Definition: System.php:357
string $secret
Shared secret.
Definition: System.php:43
hasJwt()
Check whether a JWT exists.
Definition: System.php:322
$type
$url
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
$http
Definition: raiseError.php:7