mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
Merge branch 'MDL-78258-master' of https://github.com/snake/moodle
This commit is contained in:
commit
f32f669f53
@ -4,7 +4,7 @@ A library used for building IMS-certified LTI 1.3 tool providers in PHP.
|
||||
|
||||
This library is a fork of the [packbackbooks/lti-1-3-php-library](https://github.com/packbackbooks/lti-1-3-php-library), patched specifically for use in [Moodle](https://github.com/moodle/moodle).
|
||||
|
||||
It is currently based on version [5.2.6 of the packbackbooks/lti-1-3-php-library](https://github.com/packbackbooks/lti-1-3-php-library/releases/tag/v5.2.6) library.
|
||||
It is currently based on version [5.4.1 of the packbackbooks/lti-1-3-php-library](https://github.com/packbackbooks/lti-1-3-php-library/releases/tag/v5.4.1) library.
|
||||
|
||||
The following changes are included so that the library may be used with Moodle:
|
||||
|
||||
|
@ -36,6 +36,13 @@ abstract class LtiAbstractService
|
||||
|
||||
abstract public function getScope(): array;
|
||||
|
||||
protected function validateScopes(array $scopes): void
|
||||
{
|
||||
if (empty(array_intersect($scopes, $this->getScope()))) {
|
||||
throw new LtiException('Missing required scope', 1);
|
||||
}
|
||||
}
|
||||
|
||||
protected function makeServiceRequest(IServiceRequest $request): array
|
||||
{
|
||||
return $this->serviceConnector->makeServiceRequest(
|
||||
|
@ -30,9 +30,7 @@ class LtiAssignmentsGradesService extends LtiAbstractService
|
||||
|
||||
public function putGrade(LtiGrade $grade, LtiLineitem $lineitem = null)
|
||||
{
|
||||
if (!in_array(LtiConstants::AGS_SCOPE_SCORE, $this->getScope())) {
|
||||
throw new LtiException('Missing required scope', 1);
|
||||
}
|
||||
$this->validateScopes([LtiConstants::AGS_SCOPE_SCORE]);
|
||||
|
||||
$lineitem = $this->ensureLineItemExists($lineitem);
|
||||
|
||||
@ -70,7 +68,7 @@ class LtiAssignmentsGradesService extends LtiAbstractService
|
||||
{
|
||||
$request = new ServiceRequest(
|
||||
ServiceRequest::METHOD_PUT,
|
||||
$this->getServiceData()['lineitems'],
|
||||
$this->getServiceData()['lineitem'],
|
||||
ServiceRequest::TYPE_UPDATE_LINEITEM
|
||||
);
|
||||
|
||||
@ -98,6 +96,17 @@ class LtiAssignmentsGradesService extends LtiAbstractService
|
||||
return new LtiLineitem($createdLineItem['body']);
|
||||
}
|
||||
|
||||
public function deleteLineitem(): array
|
||||
{
|
||||
$request = new ServiceRequest(
|
||||
ServiceRequest::METHOD_DELETE,
|
||||
$this->getServiceData()['lineitem'],
|
||||
ServiceRequest::TYPE_DELETE_LINEITEM
|
||||
);
|
||||
|
||||
return $this->makeServiceRequest($request);
|
||||
}
|
||||
|
||||
public function findOrCreateLineitem(LtiLineitem $newLineItem): LtiLineitem
|
||||
{
|
||||
return $this->findLineItem($newLineItem) ?? $this->createLineitem($newLineItem);
|
||||
@ -118,16 +127,13 @@ class LtiAssignmentsGradesService extends LtiAbstractService
|
||||
ServiceRequest::TYPE_GET_GRADES
|
||||
);
|
||||
$request->setAccept(static::CONTENTTYPE_RESULTCONTAINER);
|
||||
$scores = $this->makeServiceRequest($request);
|
||||
|
||||
return $scores['body'];
|
||||
return $this->getAll($request);
|
||||
}
|
||||
|
||||
public function getLineItems(): array
|
||||
{
|
||||
if (!in_array(LtiConstants::AGS_SCOPE_LINEITEM, $this->getScope())) {
|
||||
throw new LtiException('Missing required scope', 1);
|
||||
}
|
||||
$this->validateScopes([LtiConstants::AGS_SCOPE_LINEITEM, LtiConstants::AGS_SCOPE_LINEITEM_READONLY]);
|
||||
|
||||
$request = new ServiceRequest(
|
||||
ServiceRequest::METHOD_GET,
|
||||
@ -148,9 +154,7 @@ class LtiAssignmentsGradesService extends LtiAbstractService
|
||||
|
||||
public function getLineItem(string $url): LtiLineitem
|
||||
{
|
||||
if (!in_array(LtiConstants::AGS_SCOPE_LINEITEM, $this->getScope())) {
|
||||
throw new LtiException('Missing required scope', 1);
|
||||
}
|
||||
$this->validateScopes([LtiConstants::AGS_SCOPE_LINEITEM, LtiConstants::AGS_SCOPE_LINEITEM_READONLY]);
|
||||
|
||||
$request = new ServiceRequest(
|
||||
ServiceRequest::METHOD_GET,
|
||||
|
@ -27,6 +27,7 @@ class LtiConstants
|
||||
public const DL_CONTENT_ITEMS = 'https://purl.imsglobal.org/spec/lti-dl/claim/content_items';
|
||||
public const DL_DATA = 'https://purl.imsglobal.org/spec/lti-dl/claim/data';
|
||||
public const DL_DEEP_LINK_SETTINGS = 'https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings';
|
||||
public const DL_RESOURCE_LINK_TYPE = 'ltiResourceLink';
|
||||
|
||||
// LTI NRPS
|
||||
public const NRPS_CLAIM_SERVICE = 'https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice';
|
||||
@ -72,6 +73,7 @@ class LtiConstants
|
||||
public const MEMBERSHIP_MANAGER = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Manager';
|
||||
public const MEMBERSHIP_MEMBER = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Member';
|
||||
public const MEMBERSHIP_OFFICER = 'http://purl.imsglobal.org/vocab/lis/v2/membership#Officer';
|
||||
|
||||
// Context sub-roles
|
||||
public const MEMBERSHIP_EXTERNALINSTRUCTOR = 'http://purl.imsglobal.org/vocab/lis/v2/membership/Instructor#ExternalInstructor';
|
||||
public const MEMBERSHIP_GRADER = 'http://purl.imsglobal.org/vocab/lis/v2/membership/Instructor#Grader';
|
||||
@ -94,6 +96,7 @@ class LtiConstants
|
||||
|
||||
// Message Types
|
||||
public const MESSAGE_TYPE_DEEPLINK = 'LtiDeepLinkingRequest';
|
||||
public const MESSAGE_TYPE_DEEPLINK_RESPONSE = 'LtiDeepLinkingResponse';
|
||||
public const MESSAGE_TYPE_RESOURCE = 'LtiResourceLinkRequest';
|
||||
public const MESSAGE_TYPE_SUBMISSIONREVIEW = 'LtiSubmissionReviewRequest';
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class LtiDeepLink
|
||||
'iat' => time(),
|
||||
'nonce' => LtiOidcLogin::secureRandomString('nonce-'),
|
||||
LtiConstants::DEPLOYMENT_ID => $this->deployment_id,
|
||||
LtiConstants::MESSAGE_TYPE => 'LtiDeepLinkingResponse',
|
||||
LtiConstants::MESSAGE_TYPE => LtiConstants::MESSAGE_TYPE_DEEPLINK_RESPONSE,
|
||||
LtiConstants::VERSION => LtiConstants::V1_3,
|
||||
LtiConstants::DL_CONTENT_ITEMS => array_map(function ($resource) {
|
||||
return $resource->toArray();
|
||||
@ -43,19 +43,27 @@ class LtiDeepLink
|
||||
return JWT::encode($message_jwt, $this->registration->getToolPrivateKey(), 'RS256', $this->registration->getKid());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds an auto-submitting HTML form to post the deep linking response message
|
||||
* back to platform, as per LTI-DL 2.0 specification. The resulting HTML is then written to standard output,
|
||||
* so calling this method will automatically send an HTTP response to conclude the content selection flow.
|
||||
*
|
||||
* @param LtiDeepLinkResource[] $resources The list of selected resources to be sent to the platform
|
||||
*
|
||||
* @todo Consider wrapping the content inside a well-formed HTML document,
|
||||
* and returning it instead of directly writing to standard output
|
||||
*/
|
||||
public function outputResponseForm($resources)
|
||||
{
|
||||
$jwt = $this->getResponseJwt($resources);
|
||||
/*
|
||||
* @todo Fix this
|
||||
*/ ?>
|
||||
<form id="auto_submit" action="<?php echo $this->deep_link_settings['deep_link_return_url']; ?>" method="POST">
|
||||
<input type="hidden" name="JWT" value="<?php echo $jwt; ?>" />
|
||||
<input type="submit" name="Go" />
|
||||
</form>
|
||||
<script>
|
||||
document.getElementById('auto_submit').submit();
|
||||
</script>
|
||||
<?php
|
||||
$formActionUrl = $this->deep_link_settings['deep_link_return_url'];
|
||||
|
||||
echo <<<HTML
|
||||
<form id="auto_submit" action="{$formActionUrl}" method="POST">
|
||||
<input type="hidden" name="JWT" value="{$jwt}" />
|
||||
<input type="submit" name="Go" />
|
||||
</form>
|
||||
<script>document.getElementById('auto_submit').submit();</script>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
72
lib/lti1p3/src/LtiDeepLinkDateTimeInterval.php
Normal file
72
lib/lti1p3/src/LtiDeepLinkDateTimeInterval.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Packback\Lti1p3;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class LtiDeepLinkDateTimeInterval
|
||||
{
|
||||
private ?DateTime $start;
|
||||
private ?DateTime $end;
|
||||
|
||||
public function __construct(DateTime $start = null, DateTime $end = null)
|
||||
{
|
||||
if ($start !== null && $end !== null && $end < $start) {
|
||||
throw new LtiException('Interval start time cannot be greater than end time');
|
||||
}
|
||||
|
||||
$this->start = $start ?? null;
|
||||
$this->end = $end ?? null;
|
||||
}
|
||||
|
||||
public static function new(): LtiDeepLinkDateTimeInterval
|
||||
{
|
||||
return new LtiDeepLinkDateTimeInterval();
|
||||
}
|
||||
|
||||
public function setStart(?DateTime $start): LtiDeepLinkDateTimeInterval
|
||||
{
|
||||
$this->start = $start;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStart(): ?DateTime
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
public function setEnd(?DateTime $end): LtiDeepLinkDateTimeInterval
|
||||
{
|
||||
$this->end = $end;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEnd(): ?DateTime
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
if (!isset($this->start) && !isset($this->end)) {
|
||||
throw new LtiException('At least one of the interval bounds must be specified on the object instance');
|
||||
}
|
||||
|
||||
if ($this->start !== null && $this->end !== null && $this->end < $this->start) {
|
||||
throw new LtiException('Interval start time cannot be greater than end time');
|
||||
}
|
||||
|
||||
$dateTimeInterval = [];
|
||||
|
||||
if (isset($this->start)) {
|
||||
$dateTimeInterval['startDateTime'] = $this->start->format(DateTime::ATOM);
|
||||
}
|
||||
if (isset($this->end)) {
|
||||
$dateTimeInterval['endDateTime'] = $this->end->format(DateTime::ATOM);
|
||||
}
|
||||
|
||||
return $dateTimeInterval;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ namespace Packback\Lti1p3;
|
||||
|
||||
class LtiDeepLinkResource
|
||||
{
|
||||
private $type = 'ltiResourceLink';
|
||||
private $type = LtiConstants::DL_RESOURCE_LINK_TYPE;
|
||||
private $title;
|
||||
private $text;
|
||||
private $url;
|
||||
@ -13,6 +13,10 @@ class LtiDeepLinkResource
|
||||
private $thumbnail;
|
||||
private $custom_params = [];
|
||||
private $target = 'iframe';
|
||||
private $iframe;
|
||||
private $window;
|
||||
private $availability_interval;
|
||||
private $submission_interval;
|
||||
|
||||
public static function new(): LtiDeepLinkResource
|
||||
{
|
||||
@ -115,11 +119,19 @@ class LtiDeepLinkResource
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This field maps the "presentation" resource property, which is non-standard.
|
||||
* Consider using "iframe" and/or "window" instead.
|
||||
*/
|
||||
public function getTarget(): string
|
||||
{
|
||||
return $this->target;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This field maps the "presentation" resource property, which is non-standard.
|
||||
* Consider using "iframe" and/or "window" instead.
|
||||
*/
|
||||
public function setTarget(string $value): LtiDeepLinkResource
|
||||
{
|
||||
$this->target = $value;
|
||||
@ -127,17 +139,69 @@ class LtiDeepLinkResource
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIframe(): ?LtiDeepLinkResourceIframe
|
||||
{
|
||||
return $this->iframe;
|
||||
}
|
||||
|
||||
public function setIframe(?LtiDeepLinkResourceIframe $iframe): LtiDeepLinkResource
|
||||
{
|
||||
$this->iframe = $iframe;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWindow(): ?LtiDeepLinkResourceWindow
|
||||
{
|
||||
return $this->window;
|
||||
}
|
||||
|
||||
public function setWindow(?LtiDeepLinkResourceWindow $window): LtiDeepLinkResource
|
||||
{
|
||||
$this->window = $window;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAvailabilityInterval(): ?LtiDeepLinkDateTimeInterval
|
||||
{
|
||||
return $this->availability_interval;
|
||||
}
|
||||
|
||||
public function setAvailabilityInterval(?LtiDeepLinkDateTimeInterval $availabilityInterval): LtiDeepLinkResource
|
||||
{
|
||||
$this->availability_interval = $availabilityInterval;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubmissionInterval(): ?LtiDeepLinkDateTimeInterval
|
||||
{
|
||||
return $this->submission_interval;
|
||||
}
|
||||
|
||||
public function setSubmissionInterval(?LtiDeepLinkDateTimeInterval $submissionInterval): LtiDeepLinkResource
|
||||
{
|
||||
$this->submission_interval = $submissionInterval;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$resource = [
|
||||
'type' => $this->type,
|
||||
'title' => $this->title,
|
||||
'text' => $this->text,
|
||||
'url' => $this->url,
|
||||
'presentation' => [
|
||||
'documentTarget' => $this->target,
|
||||
],
|
||||
];
|
||||
|
||||
if (isset($this->title)) {
|
||||
$resource['title'] = $this->title;
|
||||
}
|
||||
if (isset($this->text)) {
|
||||
$resource['text'] = $this->text;
|
||||
}
|
||||
if (isset($this->url)) {
|
||||
$resource['url'] = $this->url;
|
||||
}
|
||||
if (!empty($this->custom_params)) {
|
||||
$resource['custom'] = $this->custom_params;
|
||||
}
|
||||
@ -154,6 +218,26 @@ class LtiDeepLinkResource
|
||||
];
|
||||
}
|
||||
|
||||
// Kept for backwards compatibility
|
||||
if (!isset($this->iframe) && !isset($this->window)) {
|
||||
$resource['presentation'] = [
|
||||
'documentTarget' => $this->target,
|
||||
];
|
||||
}
|
||||
|
||||
if (isset($this->iframe)) {
|
||||
$resource['iframe'] = $this->iframe->toArray();
|
||||
}
|
||||
if (isset($this->window)) {
|
||||
$resource['window'] = $this->window->toArray();
|
||||
}
|
||||
if (isset($this->availability_interval)) {
|
||||
$resource['available'] = $this->availability_interval->toArray();
|
||||
}
|
||||
if (isset($this->submission_interval)) {
|
||||
$resource['submission'] = $this->submission_interval->toArray();
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
}
|
||||
|
58
lib/lti1p3/src/LtiDeepLinkResourceIframe.php
Normal file
58
lib/lti1p3/src/LtiDeepLinkResourceIframe.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Packback\Lti1p3;
|
||||
|
||||
class LtiDeepLinkResourceIframe
|
||||
{
|
||||
private ?int $width;
|
||||
private ?int $height;
|
||||
|
||||
public function __construct(int $width = null, int $height = null)
|
||||
{
|
||||
$this->width = $width ?? null;
|
||||
$this->height = $height ?? null;
|
||||
}
|
||||
|
||||
public static function new(): LtiDeepLinkResourceIframe
|
||||
{
|
||||
return new LtiDeepLinkResourceIframe();
|
||||
}
|
||||
|
||||
public function setWidth(?int $width): LtiDeepLinkResourceIframe
|
||||
{
|
||||
$this->width = $width;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWidth(): ?int
|
||||
{
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
public function setHeight(?int $height): LtiDeepLinkResourceIframe
|
||||
{
|
||||
$this->height = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHeight(): ?int
|
||||
{
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$iframe = [];
|
||||
|
||||
if (isset($this->width)) {
|
||||
$iframe['width'] = $this->width;
|
||||
}
|
||||
if (isset($this->height)) {
|
||||
$iframe['height'] = $this->height;
|
||||
}
|
||||
|
||||
return $iframe;
|
||||
}
|
||||
}
|
92
lib/lti1p3/src/LtiDeepLinkResourceWindow.php
Normal file
92
lib/lti1p3/src/LtiDeepLinkResourceWindow.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Packback\Lti1p3;
|
||||
|
||||
class LtiDeepLinkResourceWindow
|
||||
{
|
||||
private ?string $target_name;
|
||||
private ?int $width;
|
||||
private ?int $height;
|
||||
private ?string $window_features;
|
||||
|
||||
public function __construct(string $targetName = null, int $width = null, int $height = null, string $windowFeatures = null)
|
||||
{
|
||||
$this->target_name = $targetName ?? null;
|
||||
$this->width = $width ?? null;
|
||||
$this->height = $height ?? null;
|
||||
$this->window_features = $windowFeatures ?? null;
|
||||
}
|
||||
|
||||
public static function new(): LtiDeepLinkResourceWindow
|
||||
{
|
||||
return new LtiDeepLinkResourceWindow();
|
||||
}
|
||||
|
||||
public function setTargetName(?string $targetName): LtiDeepLinkResourceWindow
|
||||
{
|
||||
$this->target_name = $targetName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTargetName(): ?string
|
||||
{
|
||||
return $this->target_name;
|
||||
}
|
||||
|
||||
public function setWidth(?int $width): LtiDeepLinkResourceWindow
|
||||
{
|
||||
$this->width = $width;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWidth(): ?int
|
||||
{
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
public function setHeight(?int $height): LtiDeepLinkResourceWindow
|
||||
{
|
||||
$this->height = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHeight(): ?int
|
||||
{
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
public function setWindowFeatures(?string $windowFeatures): LtiDeepLinkResourceWindow
|
||||
{
|
||||
$this->window_features = $windowFeatures;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWindowFeatures(): ?string
|
||||
{
|
||||
return $this->window_features;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$window = [];
|
||||
|
||||
if (isset($this->target_name)) {
|
||||
$window['targetName'] = $this->target_name;
|
||||
}
|
||||
if (isset($this->width)) {
|
||||
$window['width'] = $this->width;
|
||||
}
|
||||
if (isset($this->height)) {
|
||||
$window['height'] = $this->height;
|
||||
}
|
||||
if (isset($this->window_features)) {
|
||||
$window['windowFeatures'] = $this->window_features;
|
||||
}
|
||||
|
||||
return $window;
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ use Exception;
|
||||
use Firebase\JWT\ExpiredException;
|
||||
use Firebase\JWT\JWK;
|
||||
use Firebase\JWT\JWT;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\TransferException;
|
||||
use Packback\Lti1p3\Interfaces\ICache;
|
||||
use Packback\Lti1p3\Interfaces\ICookie;
|
||||
@ -21,9 +20,9 @@ class LtiMessageLaunch
|
||||
public const TYPE_DEEPLINK = 'LtiDeepLinkingRequest';
|
||||
public const TYPE_SUBMISSIONREVIEW = 'LtiSubmissionReviewRequest';
|
||||
public const TYPE_RESOURCELINK = 'LtiResourceLinkRequest';
|
||||
|
||||
public const ERR_FETCH_PUBLIC_KEY = 'Failed to fetch public key.';
|
||||
public const ERR_NO_PUBLIC_KEY = 'Unable to find public key.';
|
||||
public const ERR_NO_MATCHING_PUBLIC_KEY = 'Unable to find a public key which matches your JWT.';
|
||||
public const ERR_STATE_NOT_FOUND = 'Please make sure you have cookies enabled in this browser and that you are not in private or incognito mode';
|
||||
public const ERR_MISSING_ID_TOKEN = 'Missing id_token.';
|
||||
public const ERR_INVALID_ID_TOKEN = 'Invalid id_token, JWT must contain 3 parts';
|
||||
@ -36,7 +35,6 @@ class LtiMessageLaunch
|
||||
* error message is built.
|
||||
*/
|
||||
public const ERR_MISSING_REGISTRATION = 'LTI 1.3 Registration not found for Issuer :issuerUrl and Client ID :clientId. Please make sure the LMS has provided the right information, and that the LMS has been registered correctly in the tool.';
|
||||
|
||||
public const ERR_CLIENT_NOT_REGISTERED = 'Client id not registered for this issuer.';
|
||||
public const ERR_NO_KID = 'No KID specified in the JWT Header.';
|
||||
public const ERR_INVALID_SIGNATURE = 'Invalid signature on id_token';
|
||||
@ -47,7 +45,6 @@ class LtiMessageLaunch
|
||||
public const ERR_INVALID_MESSAGE = 'Message validation failed.';
|
||||
public const ERR_INVALID_ALG = 'Invalid alg was specified in the JWT header.';
|
||||
public const ERR_MISMATCHED_ALG_KEY = 'The alg specified in the JWT header is incompatible with the JWK key type.';
|
||||
|
||||
private $db;
|
||||
private $cache;
|
||||
private $cookie;
|
||||
@ -70,10 +67,10 @@ class LtiMessageLaunch
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param IDatabase $database Instance of the database interface used for looking up registrations and deployments
|
||||
* @param ICache $cache Instance of the Cache interface used to loading and storing launches
|
||||
* @param ICookie $cookie Instance of the Cookie interface used to set and read cookies
|
||||
* @param ILtiServiceConnector $serviceConnector Instance of the LtiServiceConnector used to by LTI services to make API requests
|
||||
* @param IDatabase $database Instance of the database interface used for looking up registrations and deployments
|
||||
* @param ICache $cache Instance of the Cache interface used to loading and storing launches
|
||||
* @param ICookie $cookie Instance of the Cookie interface used to set and read cookies
|
||||
* @param ILtiServiceConnector $serviceConnector Instance of the LtiServiceConnector used to by LTI services to make API requests
|
||||
*/
|
||||
public function __construct(
|
||||
IDatabase $database,
|
||||
@ -105,13 +102,12 @@ class LtiMessageLaunch
|
||||
/**
|
||||
* Load an LtiMessageLaunch from a Cache using a launch id.
|
||||
*
|
||||
* @param string $launch_id The launch id of the LtiMessageLaunch object that is being pulled from the cache
|
||||
* @param IDatabase $database Instance of the database interface used for looking up registrations and deployments
|
||||
* @param ICache $cache Instance of the Cache interface used to loading and storing launches. If non is provided launch data will be store in $_SESSION.
|
||||
* @param string $launch_id The launch id of the LtiMessageLaunch object that is being pulled from the cache
|
||||
* @param IDatabase $database Instance of the database interface used for looking up registrations and deployments
|
||||
* @param ICache $cache Instance of the Cache interface used to loading and storing launches. If non is provided launch data will be store in $_SESSION.
|
||||
* @return LtiMessageLaunch A populated and validated LtiMessageLaunch
|
||||
*
|
||||
* @throws LtiException Will throw an LtiException if validation fails or launch cannot be found
|
||||
*
|
||||
* @return LtiMessageLaunch A populated and validated LtiMessageLaunch
|
||||
*/
|
||||
public static function fromCache(
|
||||
$launch_id,
|
||||
@ -129,11 +125,10 @@ class LtiMessageLaunch
|
||||
/**
|
||||
* Validates all aspects of an incoming LTI message launch and caches the launch if successful.
|
||||
*
|
||||
* @param array|string $request An array of post request parameters. If not set will default to $_POST.
|
||||
* @param array|string $request An array of post request parameters. If not set will default to $_POST.
|
||||
* @return LtiMessageLaunch Will return $this if validation is successful
|
||||
*
|
||||
* @throws LtiException Will throw an LtiException if validation fails
|
||||
*
|
||||
* @return LtiMessageLaunch Will return $this if validation is successful
|
||||
*/
|
||||
public function validate(array $request = null)
|
||||
{
|
||||
@ -288,7 +283,7 @@ class LtiMessageLaunch
|
||||
return $this->launch_id;
|
||||
}
|
||||
|
||||
public static function getMissingRegistrationErrorMsg(string $issuerUrl, ?string $clientId = null): string
|
||||
public static function getMissingRegistrationErrorMsg(string $issuerUrl, string $clientId = null): string
|
||||
{
|
||||
// Guard against client ID being null
|
||||
if (!isset($clientId)) {
|
||||
@ -342,7 +337,7 @@ class LtiMessageLaunch
|
||||
}
|
||||
|
||||
// Could not find public key with a matching kid and alg.
|
||||
throw new LtiException(static::ERR_NO_PUBLIC_KEY);
|
||||
throw new LtiException(static::ERR_NO_MATCHING_PUBLIC_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -456,7 +451,8 @@ class LtiMessageLaunch
|
||||
|
||||
// Validate JWT signature
|
||||
try {
|
||||
JWT::decode($this->request['id_token'], $public_key, ['RS256']);
|
||||
$headers = new \stdClass();
|
||||
JWT::decode($this->request['id_token'], $public_key, $headers);
|
||||
} catch (ExpiredException $e) {
|
||||
// Error validating signature.
|
||||
throw new LtiException(static::ERR_INVALID_SIGNATURE);
|
||||
|
@ -9,11 +9,9 @@ use Packback\Lti1p3\Interfaces\IDatabase;
|
||||
class LtiOidcLogin
|
||||
{
|
||||
public const COOKIE_PREFIX = 'lti1p3_';
|
||||
|
||||
public const ERROR_MSG_LAUNCH_URL = 'No launch URL configured';
|
||||
public const ERROR_MSG_ISSUER = 'Could not find issuer';
|
||||
public const ERROR_MSG_LOGIN_HINT = 'Could not find login hint';
|
||||
|
||||
private $db;
|
||||
private $cache;
|
||||
private $cookie;
|
||||
@ -21,9 +19,9 @@ class LtiOidcLogin
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param IDatabase $database Instance of the Database interface used for looking up registrations and deployments
|
||||
* @param ICache $cache instance of the Cache interface used to loading and storing launches
|
||||
* @param ICookie $cookie instance of the Cookie interface used to set and read cookies
|
||||
* @param IDatabase $database Instance of the Database interface used for looking up registrations and deployments
|
||||
* @param ICache $cache instance of the Cache interface used to loading and storing launches
|
||||
* @param ICookie $cookie instance of the Cookie interface used to set and read cookies
|
||||
*/
|
||||
public function __construct(IDatabase $database, ICache $cache = null, ICookie $cookie = null)
|
||||
{
|
||||
@ -43,9 +41,8 @@ class LtiOidcLogin
|
||||
/**
|
||||
* Calculate the redirect location to return to based on an OIDC third party initiated login request.
|
||||
*
|
||||
* @param string $launch_url URL to redirect back to after the OIDC login. This URL must match exactly a URL white listed in the platform.
|
||||
* @param array|string $request An array of request parameters. If not set will default to $_REQUEST.
|
||||
*
|
||||
* @param string $launch_url URL to redirect back to after the OIDC login. This URL must match exactly a URL white listed in the platform.
|
||||
* @param array|string $request An array of request parameters. If not set will default to $_REQUEST.
|
||||
* @return Redirect returns a redirect object containing the fully formed OIDC login URL
|
||||
*/
|
||||
public function doOidcLoginRedirect($launch_url, array $request = null)
|
||||
|
@ -15,7 +15,6 @@ use Packback\Lti1p3\Interfaces\IServiceRequest;
|
||||
class LtiServiceConnector implements ILtiServiceConnector
|
||||
{
|
||||
public const NEXT_PAGE_REGEX = '/<([^>]*)>; ?rel="next"/i';
|
||||
|
||||
private $cache;
|
||||
private $client;
|
||||
private $debuggingMode = false;
|
||||
@ -213,7 +212,7 @@ class LtiServiceConnector implements ILtiServiceConnector
|
||||
|
||||
private function getNextUrl(array $headers)
|
||||
{
|
||||
$subject = $headers['Link'] ?? '';
|
||||
$subject = $headers['Link'] ?? $headers['link'] ?? '';
|
||||
preg_match(static::NEXT_PAGE_REGEX, $subject, $matches);
|
||||
|
||||
return $matches[1] ?? null;
|
||||
|
@ -7,6 +7,7 @@ use Packback\Lti1p3\Interfaces\IServiceRequest;
|
||||
class ServiceRequest implements IServiceRequest
|
||||
{
|
||||
// Request methods
|
||||
public const METHOD_DELETE = 'DELETE';
|
||||
public const METHOD_GET = 'GET';
|
||||
public const METHOD_POST = 'POST';
|
||||
public const METHOD_PUT = 'PUT';
|
||||
@ -14,21 +15,25 @@ class ServiceRequest implements IServiceRequest
|
||||
// Request types
|
||||
public const TYPE_UNSUPPORTED = 'unsupported';
|
||||
public const TYPE_AUTH = 'auth';
|
||||
|
||||
// MessageLaunch
|
||||
public const TYPE_GET_KEYSET = 'get_keyset';
|
||||
|
||||
// AGS
|
||||
public const TYPE_GET_GRADES = 'get_grades';
|
||||
public const TYPE_SYNC_GRADE = 'sync_grades';
|
||||
public const TYPE_CREATE_LINEITEM = 'create_lineitem';
|
||||
public const TYPE_DELETE_LINEITEM = 'delete_lineitem';
|
||||
public const TYPE_GET_LINEITEMS = 'get_lineitems';
|
||||
public const TYPE_GET_LINEITEM = 'get_lineitem';
|
||||
public const TYPE_UPDATE_LINEITEM = 'update_lineitem';
|
||||
|
||||
// CGS
|
||||
public const TYPE_GET_GROUPS = 'get_groups';
|
||||
public const TYPE_GET_SETS = 'get_sets';
|
||||
|
||||
// NRPS
|
||||
public const TYPE_GET_MEMBERSHIPS = 'get_memberships';
|
||||
|
||||
private $method;
|
||||
private $url;
|
||||
private $type;
|
||||
@ -125,6 +130,7 @@ class ServiceRequest implements IServiceRequest
|
||||
static::TYPE_GET_GRADES => 'Getting grades:',
|
||||
static::TYPE_SYNC_GRADE => 'Syncing grade for this lti_user_id:',
|
||||
static::TYPE_CREATE_LINEITEM => 'Creating lineitem:',
|
||||
static::TYPE_DELETE_LINEITEM => 'Deleting lineitem:',
|
||||
static::TYPE_GET_LINEITEMS => 'Getting lineitems:',
|
||||
static::TYPE_GET_LINEITEM => 'Getting a lineitem:',
|
||||
static::TYPE_UPDATE_LINEITEM => 'Updating lineitem:',
|
||||
|
@ -436,7 +436,7 @@ All rights reserved.</copyright>
|
||||
<location>lti1p3</location>
|
||||
<name>LTI 1.3 Tool Library</name>
|
||||
<description>A library used for building IMS-certified LTI 1.3 tool providers in PHP.</description>
|
||||
<version>5.2.6</version>
|
||||
<version>5.4.1</version>
|
||||
<license>Apache</license>
|
||||
<licenseversion>2.0</licenseversion>
|
||||
<repository>https://github.com/packbackbooks/lti-1-3-php-library</repository>
|
||||
|
Loading…
x
Reference in New Issue
Block a user