28 'ContentItemSelection',
163 private $accessToken =
null;
187 $this->secret =
null;
188 $this->signatureMethod =
'HMAC-SHA1';
189 $this->encryptionMethod =
null;
190 $this->rsaKey =
null;
193 $this->platformId =
null;
194 $this->clientId =
null;
195 $this->deploymentId =
null;
196 $this->ltiVersion =
null;
197 $this->consumerName =
null;
198 $this->consumerVersion =
null;
199 $this->consumerGuid =
null;
200 $this->profile =
null;
201 $this->toolProxy =
null;
202 $this->settings = array();
203 $this->
protected =
false;
204 $this->enabled =
false;
205 $this->enableFrom =
null;
206 $this->enableUntil =
null;
207 $this->lastAccess =
null;
209 $this->defaultEmail =
'';
210 $this->created =
null;
211 $this->updated =
null;
229 public function save()
231 return $this->dataConnector->savePlatform($this);
239 public function delete()
241 return $this->dataConnector->deletePlatform($this);
251 public function getId()
253 if (!empty($this->key)) {
255 } elseif (!empty($this->platformId)) {
257 if (!empty($this->clientId)) {
260 if (!empty($this->deploymentId)) {
278 if (!empty($this->consumerVersion)) {
280 $pos = strpos($familyCode,
'-');
281 if ($pos !==
false) {
282 $familyCode = substr($familyCode, 0, $pos);
306 return $this->accessToken;
316 $this->accessToken = $accessToken;
329 if (
$ok && !is_null($this->enableFrom)) {
330 $ok = $this->enableFrom <= $now;
332 if (
$ok && !is_null($this->enableUntil)) {
333 $ok = $this->enableUntil > $now;
346 $has = !empty($this->
getSetting(
'custom_system_setting_url'));
348 $has = self::hasConfiguredApiHook(self::$TOOL_SETTINGS_SERVICE_HOOK, $this->
getFamilyCode(), $this);
364 if (!empty($this->
getSetting(
'custom_system_setting_url'))) {
365 $url = $this->
getSetting(
'custom_system_setting_url');
367 $settings = $service->get();
368 $this->lastServiceRequest = $service->getHttpMessage();
369 $ok = $settings !==
false;
371 if (!
$ok && $this->hasConfiguredApiHook(self::$TOOL_SETTINGS_SERVICE_HOOK, $this->
getFamilyCode(), $this)) {
372 $className = $this->getApiHook(self::$TOOL_SETTINGS_SERVICE_HOOK, $this->
getFamilyCode());
373 $hook =
new $className($this);
374 $settings = $hook->getToolSettings($simple);
390 if (!empty($this->
getSetting(
'custom_system_setting_url'))) {
391 $url = $this->
getSetting(
'custom_system_setting_url');
393 $ok = $service->set($settings);
394 $this->lastServiceRequest = $service->getHttpMessage();
396 if (!
$ok && $this->hasConfiguredApiHook(self::$TOOL_SETTINGS_SERVICE_HOOK, $this->
getFamilyCode(), $this)) {
397 $className = $this->getApiHook(self::$TOOL_SETTINGS_SERVICE_HOOK, $this->
getFamilyCode());
398 $hook =
new $className($this);
399 $ok = $hook->setToolSettings($settings);
412 return $this->dataConnector->getTools();
422 $has = !empty($this->
getSetting(
'custom_oauth2_access_token_url'));
424 $has = self::hasConfiguredApiHook(self::$ACCESS_TOKEN_SERVICE_HOOK, $this->
getFamilyCode(), $this);
436 if ($this->ok && is_null($this->messageParameters)) {
437 $this->parseMessage(
true,
true,
false);
449 if ($this->debugMode) {
453 if (!empty($parameters[
'client_id'])) {
455 $this->handleAuthenticationRequest();
459 if ($this->ok && $this->authenticate()) {
468 $errorMessage =
"Request failed with reason: '{$this->reason}'";
469 if (!empty($this->details)) {
470 $errorMessage .= PHP_EOL .
'Debug information:';
471 foreach ($this->details as $detail) {
472 $errorMessage .= PHP_EOL .
" {$detail}";
491 $platform->key = $key;
494 if (
$ok && $autoEnable) {
495 $platform->enabled =
true;
521 $platform->enabled =
true;
539 $platform->setRecordId($id);
552 $javascript = <<< EOD
554 let storageData = {};
556 window.addEventListener(
'message',
function (event) {
558 if (typeof event.data !==
"object") {
560 event.source.postMessage({
561 subject:
'.response',
565 message:
'Event data is not an object'
570 if (event.data.message_id) {
571 messageid =
event.data.message_id;
573 if (!event.data.subject) {
575 event.source.postMessage({
576 subject:
'.response',
577 message_id: messageid,
580 message:
'There is no subject specified'
583 }
else if (!event.data.message_id) {
585 event.source.postMessage({
586 subject:
event.data.subject +
'.response',
587 message_id: messageid,
590 message:
'There is no message ID specified'
595 switch (event.data.subject) {
596 case 'lti.capabilities':
597 event.source.postMessage({
598 subject:
'lti.capabilities.response',
599 message_id:
event.data.message_id,
600 supported_messages: [
602 subject:
'lti.capabilities'
605 subject:
'lti.get_data'
608 subject:
'lti.put_data'
614 if (!event.data.key) {
615 event.source.postMessage({
616 subject:
event.data.subject +
'.response',
617 message_id: messageid,
620 message:
'There is no key specified'
623 }
else if (!event.data.value) {
624 event.source.postMessage({
625 subject:
event.data.subject +
'.response',
626 message_id: messageid,
629 message:
'There is no value specified'
633 if (!storageData[event.origin]) {
634 storageData[
event.origin] = {};
636 storageData[
event.origin][
event.data.key] =
event.data.value;
637 event.source.postMessage({
638 subject:
'lti.put_data.response',
639 message_id:
event.data.message_id,
641 value:
event.data.value
646 if (!event.data.key) {
647 event.source.postMessage({
648 subject:
event.data.subject +
'.response',
649 message_id: messageid,
652 message:
'There is no key specified'
655 }
else if (storageData[event.origin] && storageData[event.origin][event.data.key]) {
656 event.source.postMessage({
657 subject:
'lti.get_data.response',
658 message_id:
event.data.message_id,
660 value: storageData[
event.origin][
event.data.key]
663 console.log(
'There is no value stored with origin/key of \'' + event.origin +
'/' + event.data.key +
'\'');
664 event.source.postMessage({
665 subject:
'lti.get_data.response',
666 message_id:
event.data.message_id,
669 message:
'There is no value stored for this key'
675 event.source.postMessage({
676 subject:
event.data.subject +
'.response',
677 message_id:
event.data.message_id,
679 code:
'unsupported_subject',
680 message:
'Subject \'' +
event.data.subject +
'\' not recognised
'
708 protected function onInitiateLogin(&$url, &$loginHint, &$ltiMessageHint, $params)
710 $hasSession = !empty(session_id());
714 $_SESSION['ceLTIc_lti_initiated_login
'] = array(
715 'messageUrl
' => $url,
716 'login_hint
' => $loginHint,
717 'lti_message_hint
' => $ltiMessageHint,
721 session_write_close();
730 protected function onAuthenticate()
732 $hasSession = !empty(session_id());
736 if (isset($_SESSION['ceLTIc_lti_initiated_login
'])) {
737 $login = $_SESSION['ceLTIc_lti_initiated_login
'];
738 $parameters = Util::getRequestParameters();
739 if ($parameters['login_hint
'] !== $login['login_hint
'] ||
740 (isset($login['lti_message_hint
']) && (!isset($parameters['lti_message_hint
']) || ($parameters['lti_message_hint
'] !== $login['lti_message_hint
'])))) {
742 $this->messageParameters['error
'] = 'access_denied
';
744 Tool::$defaultTool->messageUrl = $login['messageUrl
'];
745 $this->messageParameters = $login['params
'];
747 unset($_SESSION['ceLTIc_lti_initiated_login
']);
750 session_write_close();
757 protected function onContentItem()
759 $this->reason = 'No
onContentItem method found
for platform
';
766 protected function onLtiStartAssessment()
775 protected function onError()
791 private function authenticate()
793 $this->ok = $this->checkMessage();
795 $this->ok = $this->verifySignature();
806 private function handleAuthenticationRequest()
808 $this->messageParameters = array();
809 $parameters = Util::getRequestParameters();
810 $this->ok = isset($parameters['scope
']) && isset($parameters['response_type
']) &&
811 isset($parameters['client_id
']) && isset($parameters['redirect_uri
']) &&
812 isset($parameters['login_hint
']) && isset($parameters['nonce
']);
814 $this->messageParameters['error
'] = 'invalid_request
';
817 $scopes = explode(' ', $parameters['scope
']);
818 $this->ok = in_array('openid
', $scopes);
820 $this->messageParameters['error
'] = 'invalid_scope
';
823 if ($this->ok && ($parameters['response_type
'] !== 'id_token
')) {
825 $this->messageParameters['error
'] = 'unsupported_response_type
';
827 if ($this->ok && ($parameters['client_id
'] !== $this->clientId)) {
829 $this->messageParameters['error
'] = 'unauthorized_client
';
832 $this->ok = in_array($parameters['redirect_uri
'], Tool::$defaultTool->redirectionUris);
834 $this->messageParameters['error
'] = 'invalid_request
';
835 $this->messageParameters['error_description
'] = 'Unregistered redirect_uri
';
839 if (isset($parameters['response_mode
'])) {
840 $this->ok = ($parameters['response_mode
'] === 'form_post
');
845 $this->messageParameters['error
'] = 'invalid_request
';
846 $this->messageParameters['error_description
'] = 'Invalid response_mode
';
849 if ($this->ok && (!isset($parameters['prompt
']) || ($parameters['prompt
'] !== 'none
'))) {
851 $this->messageParameters['error
'] = 'invalid_request
';
852 $this->messageParameters['error_description
'] = 'Invalid prompt
';
856 $this->onAuthenticate();
859 $this->messageParameters = $this->addSignature(Tool::$defaultTool->messageUrl, $this->messageParameters, 'POST
', null,
860 $parameters['nonce
']);
862 if (isset($parameters['state
'])) {
863 $this->messageParameters['state
'] = $parameters['state
'];
865 if (!empty(static::$browserStorageFrame)) {
866 if (strpos($parameters['redirect_uri
'], '?
') === false) {
871 $parameters['redirect_uri
'] .= "{$sep}lti_storage_target=" . static::$browserStorageFrame;
873 $html = Util::sendForm($parameters['redirect_uri
'], $this->messageParameters);
Trait to handle API hook registrations.
getDataConnector()
Get the data connector.
Class to provide a connection to a persistent store for LTI objects.
Class to represent an HTTP message request.
Class to implement a service.
Class to represent an LTI system.
$enabled
Whether the system instance is enabled to accept connection requests.
$dataConnector
Data connector object.
$messageParameters
LTI message parameters.
$ok
True if the last request was successful.
getSetting($name, $default='')
Get a setting value.
static logRequest($debugLevel=false)
Log a request received.
static $logLevel
Current logging level.
static logError($message, $showSource=true)
Log an error message.
static getRequestParameters()
Return GET and POST request parameters (POST parameters take precedence).
const LOGLEVEL_DEBUG
Log all messages.