The consumer, resource link and user objects will be initialised if the request is valid.
303 {
304
305
306 $doSaveConsumer = false;
307
308 $this->ok = isset(
$_POST[
'lti_message_type']) && array_key_exists(
$_POST[
'lti_message_type'], self::$MESSAGE_TYPES);
309 if (!$this->ok) {
310 $this->reason = 'Invalid or missing lti_message_type parameter.';
311 }
312 if ($this->ok) {
313 $this->ok = isset(
$_POST[
'lti_version']) && in_array(
$_POST[
'lti_version'], self::$LTI_VERSIONS);
314 if (!$this->ok) {
315 $this->reason = 'Invalid or missing lti_version parameter.';
316 }
317 }
318 if ($this->ok) {
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);
321 if (!$this->ok) {
322 $this->reason = 'Missing resource link ID.';
323 }
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;
329 if (!$this->ok) {
330 $this->reason = 'No accept_media_types found.';
331 } else {
332 $this->mediaTypes = $mediaTypes;
333 }
334 } else {
335 $this->ok = false;
336 }
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;
341 if (!$this->ok) {
342 $this->reason = 'Missing or empty accept_presentation_document_targets parameter.';
343 } else {
344 foreach ($documentTargets as $documentTarget) {
346 $documentTarget,
347 array('embed', 'frame', 'iframe', 'window', 'popup', 'overlay', 'none'),
348 'Invalid value in accept_presentation_document_targets parameter: %s.'
349 );
350 if (!$this->ok) {
351 break;
352 }
353 }
354 if ($this->ok) {
355 $this->documentTargets = $documentTargets;
356 }
357 }
358 } else {
359 $this->ok = false;
360 }
361 if ($this->ok) {
362 $this->ok = isset(
$_POST[
'content_item_return_url']) && (strlen(trim(
$_POST[
'content_item_return_url'])) > 0);
363 if (!$this->ok) {
364 $this->reason = 'Missing content_item_return_url parameter.';
365 }
366 }
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.';
374 }
375 }
376 }
377 $now = time();
378
379 $this->logger->debug('Checking consumer key...');
380
381
382 if ($this->ok && (
$_POST[
'lti_message_type'] !=
'ToolProxyRegistrationRequest')) {
383 $this->ok = isset(
$_POST[
'oauth_consumer_key']);
384 if (!$this->ok) {
385 $this->reason = 'Missing consumer key.';
386 }
387 if ($this->ok) {
388
390 $this->ok = !is_null($this->consumer->created);
391 if (!$this->ok) {
392 $this->reason = 'Invalid consumer key.';
393 }
394 }
395 if ($this->ok) {
396 $today = date('Y-m-d', $now);
397 if (is_null($this->consumer->lastAccess)) {
398 $doSaveConsumer = true;
399 } else {
400 $last = date('Y-m-d', $this->consumer->lastAccess);
401 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
402 }
403 $this->consumer->last_access = $now;
404 try {
407 $method = new OAuth\OAuthSignatureMethod_HMAC_SHA1();
408 $server->add_signature_method($method);
409 $request = OAuth\OAuthRequest::from_request();
411 } catch (\Exception $e) {
412 $this->ok = false;
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';
420 }
421 $this->details[] = 'Timestamp: ' . time();
422 $this->details[] = "Signature: {$signature}";
423 $this->details[] = "Base string: {$request->base_string}]";
424 } else {
425 $this->reason = 'OAuth signature check failed - perhaps an incorrect secret or timestamp.';
426 }
427 }
428 }
429 }
430
431 if ($this->ok) {
432 $today = date('Y-m-d', $now);
433 if (is_null($this->consumer->lastAccess)) {
434 $doSaveConsumer = true;
435 } else {
436 $last = date('Y-m-d', $this->consumer->lastAccess);
437 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
438 }
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']);
444 if (!$this->ok) {
445 $this->reason = 'Request is from an invalid tool consumer.';
446 }
447 } else {
448 $this->ok = isset(
$_POST[
'tool_consumer_instance_guid']);
449 if (!$this->ok) {
450 $this->reason = 'A tool consumer GUID must be included in the launch request.';
451 }
452 }
453 }
454 if ($this->ok) {
455 $this->ok = $this->consumer->enabled;
456 if (!$this->ok) {
457 $this->reason = 'Tool consumer has not been enabled by the tool provider.';
458 }
459 }
460 if ($this->ok) {
461 $this->ok = is_null($this->consumer->enableFrom) || ($this->consumer->enableFrom <= $now);
462 if ($this->ok) {
463 $this->ok = is_null($this->consumer->enableUntil) || ($this->consumer->enableUntil > $now);
464 if (!$this->ok) {
465 $this->reason = 'Tool consumer access has expired.';
466 }
467 } else {
468 $this->reason = 'Tool consumer access is not yet available.';
469 }
470 }
471 }
472
473 if ($this->ok) {
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.');
477 }
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.');
480 }
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.');
483 }
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.');
486 }
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.');
489 }
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.'
495 );
496 }
497 }
498 }
499
500 if ($this->ok && (
$_POST[
'lti_message_type'] ===
'ToolProxyRegistrationRequest')) {
501 $this->ok =
$_POST[
'lti_version'] == self::LTI_VERSION2;
502 if (!$this->ok) {
503 $this->reason = 'Invalid lti_version parameter';
504 }
505 if ($this->ok) {
506 $http =
new HTTPMessage(
$_POST[
'tc_profile_url'],
'GET',
null,
'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json');
507 $this->ok =
$http->send();
508 if (!$this->ok) {
509 $this->reason = 'Tool consumer profile not accessible.';
510 } else {
511 $tcProfile = json_decode(
$http->response);
512 $this->ok = !is_null($tcProfile);
513 if (!$this->ok) {
514 $this->reason = 'Invalid JSON in tool consumer profile.';
515 }
516 }
517 }
518
519 if ($this->ok) {
520
522 $this->consumer->profile = $tcProfile;
523 $capabilities = $this->consumer->profile->capability_offered;
524 $missing = array();
525 foreach ($this->resourceHandlers as $resourceHandler) {
526 foreach ($resourceHandler->requiredMessages as
$message) {
527 if (!in_array(
$message->type, $capabilities)) {
529 }
530 }
531 }
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;
536 }
537 }
538 }
539 if (!empty($missing)) {
540 ksort($missing);
541 $this->reason = 'Required capability not offered - \'' . implode('\', \'', array_keys($missing)) . '\'';
542 $this->ok = false;
543 }
544 }
545
546 if ($this->ok) {
547 foreach ($this->requiredServices as $service) {
548 foreach ($service->formats as
$format) {
549 if (!$this->findService(
$format, $service->actions)) {
550 if ($this->ok) {
551 $this->reason = 'Required service(s) not offered - ';
552 $this->ok = false;
553 } else {
554 $this->reason .= ', ';
555 }
556 $this->reason .= "'{$format}' [" . implode(', ', $service->actions) . ']';
557 }
558 }
559 }
560 }
561 if ($this->ok) {
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;
573 }
574 }
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;
582 }
583 }
584 }
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613 $this->logger->debug('Still ok: ' . ($this->ok ? '1' : '0'));
614 if (!$this->ok) {
615 $this->logger->debug('Reason: ' . $this->reason);
616 }
617
618 if ($this->ok) {
619
620
621 if (isset(
$_POST[
'context_id'])) {
622 $this->context = Context::fromConsumer($this->consumer, trim(
$_POST[
'context_id']));
624 if (isset(
$_POST[
'context_title'])) {
626 }
628 $title =
"Course {$this->context->getId()}";
629 }
630 $this->context->title =
$title;
631 }
632
633
634 if (isset(
$_POST[
'resource_link_id'])) {
635 $contentItemId = '';
636 if (isset(
$_POST[
'custom_content_item_id'])) {
637 $contentItemId =
$_POST[
'custom_content_item_id'];
638 }
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());
642 }
644 if (isset(
$_POST[
'resource_link_title'])) {
646 }
648 $title =
"Resource {$this->resourceLink->getId()}";
649 }
650 $this->resourceLink->title =
$title;
651
652 foreach ($this->consumer->getSettings() as
$name => $value) {
653 if (strpos(
$name,
'custom_') === 0) {
654 $this->consumer->setSetting(
$name);
655 $doSaveConsumer = true;
656 }
657 }
658 if (!empty($this->context)) {
659 foreach ($this->context->getSettings() as
$name => $value) {
660 if (strpos(
$name,
'custom_') === 0) {
661 $this->context->setSetting(
$name);
662 }
663 }
664 }
665 foreach ($this->resourceLink->getSettings() as
$name => $value) {
666 if (strpos(
$name,
'custom_') === 0) {
667 $this->resourceLink->setSetting(
$name);
668 }
669 }
670
671 foreach (self::$LTI_CONSUMER_SETTING_NAMES as
$name) {
674 } else {
675 $this->consumer->setSetting(
$name);
676 }
677 }
678 if (!empty($this->context)) {
679 foreach (self::$LTI_CONTEXT_SETTING_NAMES as
$name) {
682 } else {
683 $this->context->setSetting(
$name);
684 }
685 }
686 }
687 foreach (self::$LTI_RESOURCE_LINK_SETTING_NAMES as
$name) {
690 } else {
691 $this->resourceLink->setSetting(
$name);
692 }
693 }
694
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);
699 }
700 }
701 }
702
703
704 $userId = '';
705 if (isset(
$_POST[
'user_id'])) {
706 $userId = trim(
$_POST[
'user_id']);
707 }
708
709 $this->
user = User::fromResourceLink($this->resourceLink, $userId);
710
711
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);
716
717
718 $email = (isset(
$_POST[
'lis_person_contact_email_primary'])) ?
$_POST[
'lis_person_contact_email_primary'] :
'';
719 $this->
user->setEmail(
$email, $this->defaultEmail);
720
721
722 if (isset(
$_POST[
'user_image'])) {
724 }
725
726
727 if (isset(
$_POST[
'roles'])) {
728 $this->
user->roles = self::parseRoles(
$_POST[
'roles']);
729 }
730
731
732 $this->consumer->defaultEmail = $this->defaultEmail;
733 if ($this->consumer->ltiVersion !==
$_POST[
'lti_version']) {
734 $this->consumer->ltiVersion =
$_POST[
'lti_version'];
735 $doSaveConsumer = true;
736 }
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;
741 }
742 }
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']}";
747 }
748
749 if ($this->consumer->consumerVersion !==
$version) {
750 $this->consumer->consumerVersion =
$version;
751 $doSaveConsumer = true;
752 }
753 } elseif (isset(
$_POST[
'ext_lms']) && ($this->consumer->consumerName !==
$_POST[
'ext_lms'])) {
754 $this->consumer->consumerVersion =
$_POST[
'ext_lms'];
755 $doSaveConsumer = true;
756 }
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'];
765 }
766 }
767 }
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;
772 }
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;
780 }
781 }
782
783
784 if ($doSaveConsumer) {
785 $this->consumer->save();
786 }
787 if ($this->ok && isset($this->context)) {
788 $this->context->save();
789 }
790
791
792
793
794 if ($this->ok && isset($this->resourceLink)) {
795
796
797
798
799 $this->resourceLink->save();
800
801
802 if (isset(
$_POST[
'lis_result_sourcedid'])) {
803 if ($this->
user->ltiResultSourcedId !==
$_POST[
'lis_result_sourcedid']) {
804 $this->
user->ltiResultSourcedId =
$_POST[
'lis_result_sourcedid'];
806 }
807 } elseif (!empty($this->
user->ltiResultSourcedId)) {
808 $this->
user->ltiResultSourcedId =
'';
810 }
811 }
812
814 }
foreach($paths as $path) $request
Class to represent an HTTP message.
Class to represent an OAuth Data Store.
if(! $oauthconfig->getBoolean('getUserInfo.enable', FALSE)) $store
catch(Exception $e) $message
foreach($_POST as $key=> $value) $res