The consumer, resource link and user objects will be initialised if the request is valid.
306 $doSaveConsumer =
false;
308 $this->ok = isset(
$_POST[
'lti_message_type']) && array_key_exists(
$_POST[
'lti_message_type'], self::$MESSAGE_TYPES);
310 $this->reason =
'Invalid or missing lti_message_type parameter.';
313 $this->ok = isset(
$_POST[
'lti_version']) && in_array(
$_POST[
'lti_version'], self::$LTI_VERSIONS);
315 $this->reason =
'Invalid or missing lti_version parameter.';
319 if (
$_POST[
'lti_message_type'] ===
'basic-lti-launch-request') {
320 $this->ok = isset(
$_POST[
'resource_link_id']) && (strlen(trim(
$_POST[
'resource_link_id'])) > 0);
322 $this->reason =
'Missing resource link ID.';
324 } elseif (
$_POST[
'lti_message_type'] ===
'ContentItemSelectionRequest') {
325 if (isset(
$_POST[
'accept_media_types']) && (strlen(trim(
$_POST[
'accept_media_types'])) > 0)) {
326 $mediaTypes = array_filter(explode(
',', str_replace(
' ',
'',
$_POST[
'accept_media_types'])),
'strlen');
327 $mediaTypes = array_unique($mediaTypes);
328 $this->ok = count($mediaTypes) > 0;
330 $this->reason =
'No accept_media_types found.';
332 $this->mediaTypes = $mediaTypes;
337 if ($this->ok && isset(
$_POST[
'accept_presentation_document_targets']) && (strlen(trim(
$_POST[
'accept_presentation_document_targets'])) > 0)) {
338 $documentTargets = array_filter(explode(
',', str_replace(
' ',
'',
$_POST[
'accept_presentation_document_targets'])),
'strlen');
339 $documentTargets = array_unique($documentTargets);
340 $this->ok = count($documentTargets) > 0;
342 $this->reason =
'Missing or empty accept_presentation_document_targets parameter.';
344 foreach ($documentTargets as $documentTarget) {
347 array(
'embed',
'frame',
'iframe',
'window',
'popup',
'overlay',
'none'),
348 'Invalid value in accept_presentation_document_targets parameter: %s.' 355 $this->documentTargets = $documentTargets;
362 $this->ok = isset(
$_POST[
'content_item_return_url']) && (strlen(trim(
$_POST[
'content_item_return_url'])) > 0);
364 $this->reason =
'Missing content_item_return_url parameter.';
367 } elseif (
$_POST[
'lti_message_type'] ==
'ToolProxyRegistrationRequest') {
368 $this->ok = ((isset(
$_POST[
'reg_key']) && (strlen(trim(
$_POST[
'reg_key'])) > 0)) &&
369 (isset(
$_POST[
'reg_password']) && (strlen(trim(
$_POST[
'reg_password'])) > 0)) &&
370 (isset(
$_POST[
'tc_profile_url']) && (strlen(trim(
$_POST[
'tc_profile_url'])) > 0)) &&
371 (isset(
$_POST[
'launch_presentation_return_url']) && (strlen(trim(
$_POST[
'launch_presentation_return_url'])) > 0)));
372 if ($this->debugMode && !$this->ok) {
373 $this->reason =
'Missing message parameters.';
379 $this->logger->debug(
'Checking consumer key...');
382 if ($this->ok && (
$_POST[
'lti_message_type'] !=
'ToolProxyRegistrationRequest')) {
383 $this->ok = isset(
$_POST[
'oauth_consumer_key']);
385 $this->reason =
'Missing consumer key.';
390 $this->ok = !is_null($this->consumer->created);
392 $this->reason =
'Invalid consumer key.';
396 $today = date(
'Y-m-d', $now);
397 if (is_null($this->consumer->lastAccess)) {
398 $doSaveConsumer =
true;
400 $last = date(
'Y-m-d', $this->consumer->lastAccess);
401 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
403 $this->consumer->last_access = $now;
407 $method =
new OAuth\OAuthSignatureMethod_HMAC_SHA1();
408 $server->add_signature_method($method);
409 $request = OAuth\OAuthRequest::from_request();
413 if (empty($this->reason)) {
414 if ($this->debugMode) {
415 $consumer =
new OAuth\OAuthConsumer($this->consumer->getKey(), $this->consumer->secret);
416 $signature =
$request->build_signature($method, $consumer,
false);
417 $this->reason = $e->getMessage();
418 if (empty($this->reason)) {
419 $this->reason =
'OAuth exception';
421 $this->details[] =
'Timestamp: ' . time();
422 $this->details[] =
"Signature: {$signature}";
423 $this->details[] =
"Base string: {$request->base_string}]";
425 $this->reason =
'OAuth signature check failed - perhaps an incorrect secret or timestamp.';
432 $today = date(
'Y-m-d', $now);
433 if (is_null($this->consumer->lastAccess)) {
434 $doSaveConsumer =
true;
436 $last = date(
'Y-m-d', $this->consumer->lastAccess);
437 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
439 $this->consumer->last_access = $now;
440 if ($this->consumer->protected) {
441 if (!is_null($this->consumer->consumerGuid)) {
442 $this->ok = empty(
$_POST[
'tool_consumer_instance_guid']) ||
443 ($this->consumer->consumerGuid ===
$_POST[
'tool_consumer_instance_guid']);
445 $this->reason =
'Request is from an invalid tool consumer.';
448 $this->ok = isset(
$_POST[
'tool_consumer_instance_guid']);
450 $this->reason =
'A tool consumer GUID must be included in the launch request.';
455 $this->ok = $this->consumer->enabled;
457 $this->reason =
'Tool consumer has not been enabled by the tool provider.';
461 $this->ok = is_null($this->consumer->enableFrom) || ($this->consumer->enableFrom <= $now);
463 $this->ok = is_null($this->consumer->enableUntil) || ($this->consumer->enableUntil > $now);
465 $this->reason =
'Tool consumer access has expired.';
468 $this->reason =
'Tool consumer access is not yet available.';
474 if (
$_POST[
'lti_message_type'] ===
'ContentItemSelectionRequest') {
475 if (isset(
$_POST[
'accept_unsigned'])) {
476 $this->ok = $this->
checkValue(
$_POST[
'accept_unsigned'], array(
'true',
'false'),
'Invalid value for accept_unsigned parameter: %s.');
478 if ($this->ok && isset(
$_POST[
'accept_multiple'])) {
479 $this->ok = $this->
checkValue(
$_POST[
'accept_multiple'], array(
'true',
'false'),
'Invalid value for accept_multiple parameter: %s.');
481 if ($this->ok && isset(
$_POST[
'accept_copy_advice'])) {
482 $this->ok = $this->
checkValue(
$_POST[
'accept_copy_advice'], array(
'true',
'false'),
'Invalid value for accept_copy_advice parameter: %s.');
484 if ($this->ok && isset(
$_POST[
'auto_create'])) {
485 $this->ok = $this->
checkValue(
$_POST[
'auto_create'], array(
'true',
'false'),
'Invalid value for auto_create parameter: %s.');
487 if ($this->ok && isset(
$_POST[
'can_confirm'])) {
488 $this->ok = $this->
checkValue(
$_POST[
'can_confirm'], array(
'true',
'false'),
'Invalid value for can_confirm parameter: %s.');
490 } elseif (isset(
$_POST[
'launch_presentation_document_target'])) {
492 $_POST[
'launch_presentation_document_target'],
493 array(
'embed',
'frame',
'iframe',
'window',
'popup',
'overlay'),
494 'Invalid value for launch_presentation_document_target parameter: %s.' 500 if ($this->ok && (
$_POST[
'lti_message_type'] ===
'ToolProxyRegistrationRequest')) {
501 $this->ok =
$_POST[
'lti_version'] == self::LTI_VERSION2;
503 $this->reason =
'Invalid lti_version parameter';
506 $http =
new HTTPMessage(
$_POST[
'tc_profile_url'],
'GET', null,
'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json');
507 $this->ok =
$http->send();
509 $this->reason =
'Tool consumer profile not accessible.';
511 $tcProfile = json_decode(
$http->response);
512 $this->ok = !is_null($tcProfile);
514 $this->reason =
'Invalid JSON in tool consumer profile.';
522 $this->consumer->profile = $tcProfile;
523 $capabilities = $this->consumer->profile->capability_offered;
525 foreach ($this->resourceHandlers as $resourceHandler) {
526 foreach ($resourceHandler->requiredMessages as
$message) {
527 if (!in_array($message->type, $capabilities)) {
528 $missing[$message->type] =
true;
532 foreach ($this->constraints as
$name => $constraint) {
533 if ($constraint[
'required']) {
534 if (!in_array(
$name, $capabilities) && !in_array(
$name, array_flip($capabilities))) {
535 $missing[
$name] =
true;
539 if (!empty($missing)) {
541 $this->reason =
'Required capability not offered - \'' . implode(
'\', \
'', array_keys($missing)) .
'\'';
547 foreach ($this->requiredServices as $service) {
548 foreach ($service->formats as
$format) {
549 if (!$this->findService($format, $service->actions)) {
551 $this->reason =
'Required service(s) not offered - ';
554 $this->reason .=
', ';
556 $this->reason .=
"'{$format}' [" . implode(
', ', $service->actions) .
']';
562 if (
$_POST[
'lti_message_type'] ===
'ToolProxyRegistrationRequest') {
563 $this->consumer->profile = $tcProfile;
564 $this->consumer->secret =
$_POST[
'reg_password'];
565 $this->consumer->ltiVersion =
$_POST[
'lti_version'];
566 $this->consumer->name = $tcProfile->product_instance->service_owner->service_owner_name->default_value;
567 $this->consumer->consumerName = $this->consumer->name;
568 $this->consumer->consumerVersion =
"{$tcProfile->product_instance->product_info->product_family->code}-{$tcProfile->product_instance->product_info->product_version}";
569 $this->consumer->consumerGuid = $tcProfile->product_instance->guid;
570 $this->consumer->enabled =
true;
571 $this->consumer->protected =
true;
572 $doSaveConsumer =
true;
575 } elseif ($this->ok && !empty(
$_POST[
'custom_tc_profile_url']) && empty($this->consumer->profile)) {
576 $http =
new HTTPMessage(
$_POST[
'custom_tc_profile_url'],
'GET', null,
'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json');
578 $tcProfile = json_decode(
$http->response);
579 if (!is_null($tcProfile)) {
580 $this->consumer->profile = $tcProfile;
581 $doSaveConsumer =
true;
613 $this->logger->debug(
'Still ok: ' . ($this->ok ?
'1' :
'0'));
615 $this->logger->debug(
'Reason: ' . $this->reason);
621 if (isset(
$_POST[
'context_id'])) {
622 $this->context = Context::fromConsumer($this->consumer, trim(
$_POST[
'context_id']));
624 if (isset(
$_POST[
'context_title'])) {
628 $title =
"Course {$this->context->getId()}";
630 $this->context->title =
$title;
634 if (isset(
$_POST[
'resource_link_id'])) {
636 if (isset(
$_POST[
'custom_content_item_id'])) {
637 $contentItemId =
$_POST[
'custom_content_item_id'];
639 $this->resourceLink = ResourceLink::fromConsumer($this->consumer, trim(
$_POST[
'resource_link_id']), $contentItemId);
640 if (!empty($this->context)) {
641 $this->resourceLink->setContextId($this->context->getRecordId());
644 if (isset(
$_POST[
'resource_link_title'])) {
648 $title =
"Resource {$this->resourceLink->getId()}";
650 $this->resourceLink->title =
$title;
652 foreach ($this->consumer->getSettings() as
$name => $value) {
653 if (strpos($name,
'custom_') === 0) {
654 $this->consumer->setSetting($name);
655 $doSaveConsumer =
true;
658 if (!empty($this->context)) {
659 foreach ($this->context->getSettings() as $name => $value) {
660 if (strpos($name,
'custom_') === 0) {
661 $this->context->setSetting($name);
665 foreach ($this->resourceLink->getSettings() as $name => $value) {
666 if (strpos($name,
'custom_') === 0) {
667 $this->resourceLink->setSetting($name);
671 foreach (self::$LTI_CONSUMER_SETTING_NAMES as $name) {
672 if (isset(
$_POST[$name])) {
673 $this->consumer->setSetting($name,
$_POST[$name]);
675 $this->consumer->setSetting($name);
678 if (!empty($this->context)) {
679 foreach (self::$LTI_CONTEXT_SETTING_NAMES as $name) {
680 if (isset(
$_POST[$name])) {
681 $this->context->setSetting($name,
$_POST[$name]);
683 $this->context->setSetting($name);
687 foreach (self::$LTI_RESOURCE_LINK_SETTING_NAMES as $name) {
688 if (isset(
$_POST[$name])) {
689 $this->resourceLink->setSetting($name,
$_POST[$name]);
691 $this->resourceLink->setSetting($name);
695 foreach (
$_POST as $name => $value) {
696 if ((strpos($name,
'custom_') === 0) &&
697 !in_array($name, array_merge(self::$LTI_CONSUMER_SETTING_NAMES, self::$LTI_CONTEXT_SETTING_NAMES, self::$LTI_RESOURCE_LINK_SETTING_NAMES))) {
698 $this->resourceLink->setSetting($name, $value);
705 if (isset(
$_POST[
'user_id'])) {
706 $userId = trim(
$_POST[
'user_id']);
709 $this->
user = User::fromResourceLink($this->resourceLink, $userId);
712 $firstname = (isset(
$_POST[
'lis_person_name_given'])) ?
$_POST[
'lis_person_name_given'] :
'';
713 $lastname = (isset(
$_POST[
'lis_person_name_family'])) ?
$_POST[
'lis_person_name_family'] :
'';
714 $fullname = (isset(
$_POST[
'lis_person_name_full'])) ?
$_POST[
'lis_person_name_full'] :
'';
715 $this->
user->setNames($firstname, $lastname, $fullname);
718 $email = (isset(
$_POST[
'lis_person_contact_email_primary'])) ?
$_POST[
'lis_person_contact_email_primary'] :
'';
719 $this->
user->setEmail(
$email, $this->defaultEmail);
722 if (isset(
$_POST[
'user_image'])) {
727 if (isset(
$_POST[
'roles'])) {
728 $this->
user->roles = self::parseRoles(
$_POST[
'roles']);
732 $this->consumer->defaultEmail = $this->defaultEmail;
733 if ($this->consumer->ltiVersion !==
$_POST[
'lti_version']) {
734 $this->consumer->ltiVersion =
$_POST[
'lti_version'];
735 $doSaveConsumer =
true;
737 if (isset(
$_POST[
'tool_consumer_instance_name'])) {
738 if ($this->consumer->consumerName !==
$_POST[
'tool_consumer_instance_name']) {
739 $this->consumer->consumerName =
$_POST[
'tool_consumer_instance_name'];
740 $doSaveConsumer =
true;
743 if (isset(
$_POST[
'tool_consumer_info_product_family_code'])) {
745 if (isset(
$_POST[
'tool_consumer_info_version'])) {
746 $version .=
"-{$_POST['tool_consumer_info_version']}";
749 if ($this->consumer->consumerVersion !==
$version) {
750 $this->consumer->consumerVersion =
$version;
751 $doSaveConsumer =
true;
753 } elseif (isset(
$_POST[
'ext_lms']) && ($this->consumer->consumerName !==
$_POST[
'ext_lms'])) {
754 $this->consumer->consumerVersion =
$_POST[
'ext_lms'];
755 $doSaveConsumer =
true;
757 if (isset(
$_POST[
'tool_consumer_instance_guid'])) {
758 if (is_null($this->consumer->consumerGuid)) {
759 $this->consumer->consumerGuid =
$_POST[
'tool_consumer_instance_guid'];
760 $doSaveConsumer =
true;
761 } elseif (!$this->consumer->protected) {
762 $doSaveConsumer = ($this->consumer->consumerGuid !==
$_POST[
'tool_consumer_instance_guid']);
763 if ($doSaveConsumer) {
764 $this->consumer->consumerGuid =
$_POST[
'tool_consumer_instance_guid'];
768 if (isset(
$_POST[
'launch_presentation_css_url'])) {
769 if ($this->consumer->cssPath !==
$_POST[
'launch_presentation_css_url']) {
770 $this->consumer->cssPath =
$_POST[
'launch_presentation_css_url'];
771 $doSaveConsumer =
true;
773 } elseif (isset(
$_POST[
'ext_launch_presentation_css_url']) &&
774 ($this->consumer->cssPath !==
$_POST[
'ext_launch_presentation_css_url'])) {
775 $this->consumer->cssPath =
$_POST[
'ext_launch_presentation_css_url'];
776 $doSaveConsumer =
true;
777 } elseif (!empty($this->consumer->cssPath)) {
778 $this->consumer->cssPath = null;
779 $doSaveConsumer =
true;
784 if ($doSaveConsumer) {
785 $this->consumer->save();
787 if ($this->ok && isset($this->context)) {
788 $this->context->save();
794 if ($this->ok && isset($this->resourceLink)) {
799 $this->resourceLink->save();
802 if (isset(
$_POST[
'lis_result_sourcedid'])) {
803 if ($this->
user->ltiResultSourcedId !==
$_POST[
'lis_result_sourcedid']) {
804 $this->
user->ltiResultSourcedId =
$_POST[
'lis_result_sourcedid'];
807 } elseif (!empty($this->
user->ltiResultSourcedId)) {
808 $this->
user->ltiResultSourcedId =
'';
Class to represent an OAuth Data Store.
foreach($paths as $path) $request
if(! $oauthconfig->getBoolean('getUserInfo.enable', FALSE)) $store
catch(Exception $e) $message
foreach($_POST as $key=> $value) $res
Class to represent an HTTP message.