ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilLTIConsumerContentGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
31{
32 public const CMD_LAUNCH = 'launch';
33 public const CMD_SHOW_EMBEDDED = 'showEmbedded';
34
36
38
39 private \ILIAS\DI\Container $dic;
40
42
44
46 {
47 global $DIC;
48 $this->dic = $DIC;
49 $this->lng = $DIC->language();
50 $this->user = $DIC->user();
51 $this->object = $object;
52 }
53
57 public function executeCommand(): void
58 {
59 global $DIC; /* @var \ILIAS\DI\Container $DIC */
60
61 if ($this->object->getProvider()->getAvailability() == ilLTIConsumeProvider::AVAILABILITY_NONE) {
62 throw new ilLtiConsumerException('access denied!');
63 }
64 $command = $DIC->ctrl()->getCmd(self::CMD_LAUNCH);
65 $this->{$command}();
66 }
67
72 protected function launch(): void
73 {
74 if ($this->object->getProvider()->getLtiVersion() == "LTI-1p0") {
75 if ($this->object->isLaunchMethodEmbedded()) {
76 $tpl = new ilTemplate('tpl.lti_content.html', true, true, 'components/ILIAS/LTIConsumer');
77 $tpl->setVariable("EMBEDDED_IFRAME_SRC", $this->dic->ctrl()->getLinkTarget(
78 $this,
79 self::CMD_SHOW_EMBEDDED
80 ));
81 $this->dic->ui()->mainTemplate()->setContent($tpl->get());
82 } else {
83 $this->dic->toolbar()->addText($this->getStartButtonTxt11());
84 }
85 } else {
86
87 if ($this->object->isLaunchMethodEmbedded() && (ilSession::get('lti13_login_data') == null)) {
88 $tpl = new ilTemplate('tpl.lti_content.html', true, true, 'components/ILIAS/LTIConsumer');
89 $tpl->setVariable("EMBEDDED_IFRAME_SRC", $this->dic->ctrl()->getLinkTarget(
90 $this,
91 self::CMD_SHOW_EMBEDDED
92 ));
93 $this->dic->ui()->mainTemplate()->setContent($tpl->get());
94 } else {
95 if (ilSession::get('lti13_login_data') != null) {
96 $form = $this->getLoginLTI13Form();
97 if ($form == null) {
98 // $this->dic->ui()->mainTemplate()->setOnScreenMessage('failure', 'initialLogin Error: ' . $err, true);
99 $this->dic->ui()->mainTemplate()->setOnScreenMessage('failure', 'initialLogin Error: ', true);
100 } else {
101 $response = $this->dic->http()->response()->withBody(ILIAS\Filesystem\Stream\Streams::ofString($form));
102 $this->dic->http()->saveResponse($response);
103 $this->dic->http()->sendResponse();
104 $this->dic->http()->close();
105 }
106 } elseif (!$this->object->isLaunchMethodEmbedded()) {
107 $this->dic->toolbar()->addText($this->getStartButtonTxt13());
108 }
109 }
110 }
111 }
112
113 protected function getLoginLTI13Form(): ?string
114 {
115 $loginData = ilSession::get('lti13_login_data');
116 ilSession::clear('lti13_login_data');
117 $err = $this->validateLTI13InitalLogin($loginData);
118 if ($err !== null) {
119 return null;
120 } else {
121 $this->initCmixUser();
122 $params = $this->getLaunchParametersLTI13($loginData['redirect_uri'], $this->object->getProvider()->getClientId(), $this->object->getProvider()->getId(), $loginData['nonce']);
123 if (isset($loginData['state'])) {
124 $params['state'] = $loginData['state'];
125 }
126 ilSession::clear('lti_message_hint');
127 $r = '<form action="' . $loginData['redirect_uri'] . "\" name=\"ltiAuthForm\" id=\"ltiAuthForm\" " .
128 "method=\"post\" enctype=\"application/x-www-form-urlencoded\">\n";
129 if (!empty($params)) {
130 foreach ($params as $key => $value) {
131 $key = htmlspecialchars($key);
132 $value = htmlspecialchars($value);
133 $r .= " <input type=\"hidden\" name=\"{$key}\" value=\"{$value}\"/>\n";
134 }
135 }
136 $r .= "</form>\n";
137 $r .= "<script type=\"text/javascript\">\n" .
138 "//<![CDATA[\n" .
139 "document.ltiAuthForm.submit();\n" .
140 "//]]>\n" .
141 "</script>\n";
142 return $r;
143 }
144 return null;
145 }
146
147 protected function getStartButtonTxt11(): string
148 {
149 if ($this->object->getOfflineStatus() ||
150 $this->object->isLaunchMethodEmbedded() ||
151 $this->object->getProvider()->getAvailability() == ilLTIConsumeProvider::AVAILABILITY_NONE) {
152 return "";
153 }
154
156 $this->object->getId(),
157 $this->user->getId(),
158 $this->object->getProvider()->getPrivacyIdent()
159 );
160 $user_ident = $cmixUser->getUsrIdent();
161 if ($user_ident == '' || $user_ident == null) {
162 $user_ident = ilCmiXapiUser::getIdent($this->object->getProvider()->getPrivacyIdent(), $this->dic->user());
163 $cmixUser->setUsrIdent($user_ident);
164 $cmixUser->save();
165 }
166 $ilLTIConsumerLaunch = new ilLTIConsumerLaunch($this->object->getRefId());
167 $context = $ilLTIConsumerLaunch->getContext();
168 $contextType = $ilLTIConsumerLaunch::getLTIContextType($context["type"]);
169 $contextId = (string) $context["id"];
170 $contextTitle = $context["title"];
171
173 $this->dic->user()->getId(),
174 $this->object->getRefId(),
175 $this->object->getId()
176 );
177
178 $returnUrl = !$this->object->isLaunchMethodOwnWin() ? '' : str_replace(
179 '&amp;',
180 '&',
181 ilObjLTIConsumer::getIliasHttpPath() . "/" . $this->dic->ctrl()->getLinkTarget($this, "", "", false)
182 );
183
184 $launchParameters = $this->object->buildLaunchParameters(
185 $cmixUser,
186 $token,
187 $contextType,
188 $contextId,
189 $contextTitle,
190 $returnUrl
191 );
192
193 $target = $this->object->getLaunchMethod() == "newWin" ? "_blank" : "_self";
194 $button = '<input class="btn btn-default ilPre" type="button" onClick="ltilaunch()" value = "' . $this->lng->txt("show_content") . '" />';
195 $output = '<form id="lti_launch_form" name="lti_launch_form" action="' . $this->object->getProvider()->getProviderUrl() . '" method="post" target="' . $target . '" encType="application/x-www-form-urlencoded">';
196 foreach ($launchParameters as $field => $value) {
197 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', $field, $value) . "\n";
198 }
199 $output .= $button;
200 $output .= '</form>';
201 $output .= '<span id ="lti_launched" style="display:none">' . $this->lng->txt("launched") . '</span>';
202 $output .= '<script type="text/javascript">
203 function ltilaunch() {
204 document.lti_launch_form.submit();
205 document.getElementById("lti_launch_form").style.display = "none";
206 document.getElementById("lti_launched").style.display = "inline";
207 }</script>';
208 return($output);
209 }
210
211 protected function getStartButtonTxt13(): string
212 {
213 if ($this->object->getOfflineStatus() ||
214 $this->object->isLaunchMethodEmbedded() ||
215 $this->object->getProvider()->getAvailability() == ilLTIConsumeProvider::AVAILABILITY_NONE) {
216 return "";
217 }
218 $this->initCmixUser();
219 $user_ident = $this->cmixUser->getUsrIdent();
220 $ilLTIConsumerLaunch = new ilLTIConsumerLaunch($this->object->getRefId());
221 $context = $ilLTIConsumerLaunch->getContext();
222 $contextType = $ilLTIConsumerLaunch::getLTIContextType($context["type"]);
223 $contextId = $context["id"];
224 $contextTitle = $context["title"];
225
227 $this->dic->user()->getId(),
228 $this->object->getRefId(),
229 $this->object->getId()
230 );
231
232 $returnUrl = !$this->object->isLaunchMethodOwnWin() ? '' : str_replace(
233 '&amp;',
234 '&',
235 ilObjLTIConsumer::getIliasHttpPath() . "/" . $this->dic->ctrl()->getLinkTarget($this, "", "", false)
236 );
237
238 $target = $this->object->getLaunchMethod() == "newWin" ? "_blank" : "_self";
239 $button = '<input class="btn btn-default ilPre" type="button" onClick="ltilaunch()" value = "' . $this->lng->txt("show_content") . '" />';
240 $ltiMessageHint = (string) $this->object->getRefId() . ":" . CLIENT_ID;
241 ilSession::set('lti_message_hint', $ltiMessageHint);
242 $output = '<form id="lti_launch_form" name="lti_launch_form" action="' . $this->object->getProvider()->getInitiateLogin() . '" method="post" target="' . $target . '" encType="application/x-www-form-urlencoded">';
243
244 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'iss', ilObjLTIConsumer::getIliasHttpPath()) . "\n";
245 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'target_link_uri', $this->object->getProvider()->getProviderUrl()) . "\n";
246 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'login_hint', $user_ident) . "\n";
247 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'lti_message_hint', $ltiMessageHint) . "\n";
248 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'client_id', $this->object->getProvider()->getClientId()) . "\n";
249 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'lti_deployment_id', $this->object->getProvider()->getId()) . "\n";
250 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'launch_presentation_return_url', $returnUrl) . "\n";
251 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'lis_result_sourcedid', $token) . "\n";
252 $output .= $button;
253 $output .= '</form>';
254 $output .= '<span id ="lti_launched" style="display:none">' . $this->lng->txt("launched") . '</span>';
255 $output .= '<script type="text/javascript">
256 function ltilaunch() {
257 document.lti_launch_form.submit();
258 document.getElementById("lti_launch_form").style.display = "none";
259 document.getElementById("lti_launched").style.display = "inline";
260 }</script>';
261 //dump($output);exit();
262 return($output);
263 }
264
265 // TODO: merge with getStartButtonTxt13 (paramter)
266 protected function getEmbeddedAutoStartFormular(): string
267 {
268 $this->initCmixUser();
269 $user_ident = $this->cmixUser->getUsrIdent();
270 $ilLTIConsumerLaunch = new ilLTIConsumerLaunch($this->object->getRefId());
271 $context = $ilLTIConsumerLaunch->getContext();
272 $contextType = $ilLTIConsumerLaunch::getLTIContextType($context["type"]);
273 $contextId = $context["id"];
274 $contextTitle = $context["title"];
275
276 $target = "_self";
277 $output = '';
278 $ltiMessageHint = (string) $this->object->getRefId() . ":" . CLIENT_ID;
279 ilSession::set('lti_message_hint', $ltiMessageHint);
280 $output = '<form id="lti_launch_form" name="lti_launch_form" action="' . $this->object->getProvider()->getInitiateLogin() . '" method="post" target="' . $target . '" encType="application/x-www-form-urlencoded">';
281 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'iss', ilObjLTIConsumer::getIliasHttpPath()) . "\n";
282 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'target_link_uri', $this->object->getProvider()->getProviderUrl()) . "\n";
283 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'login_hint', $user_ident) . "\n";
284 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'lti_message_hint', $ltiMessageHint) . "\n";
285 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'client_id', $this->object->getProvider()->getClientId()) . "\n";
286 $output .= sprintf('<input type="hidden" name="%s" value="%s" />', 'lti_deployment_id', $this->object->getProvider()->getId()) . "\n";
287 $output .= '</form>';
288
289 $output .= "<script type=\"text/javascript\">\n" .
290 "//<![CDATA[\n" .
291 "document.lti_launch_form.submit();\n" .
292 "//]]>\n" .
293 "</script>\n";
294
295 return($output);
296 }
297
298
302 protected function showEmbedded(): void
303 {
304 if ($this->object->getProvider()->getLtiVersion() == "LTI-1p0") {
305 $this->initCmixUser();
306 $tpl = new ilTemplate('tpl.lti_embedded.html', true, true, 'components/ILIAS/LTIConsumer');
307 foreach ($this->getLaunchParameters() as $field => $value) {
308 $tpl->setCurrentBlock('launch_parameter');
309 $tpl->setVariable('LAUNCH_PARAMETER', $field);
310 $tpl->setVariable('LAUNCH_PARAM_VALUE', $value);
311 $tpl->parseCurrentBlock();
312 }
313
314 $v = DEVMODE ? '?vers=' . time() : '?vers=' . ILIAS_VERSION_NUMERIC;
315 $tpl->setVariable("DELOS_CSS_HREF", 'assets/css/delos.css' . $v);
316 $tpl->setVariable("JQUERY_SRC", 'assets/js/jquery.js' . $v);
317
318 $tpl->setVariable("LOADER_ICON_SRC", ilUtil::getImagePath("media/loader.svg"));
319 $tpl->setVariable('LAUNCH_URL', $this->object->getProvider()->getProviderUrl());
320
321 #$DIC->ui()->mainTemplate()->getStandardTemplate();
322 #$DIC->ui()->mainTemplate()->setContent($tpl->get());
323
324 echo $tpl->get();
325 exit; //TODO: no exit
326 } else {
327 $response = $this->dic->http()->response()->withBody(ILIAS\Filesystem\Stream\Streams::ofString($this->getEmbeddedAutoStartFormular()));
328 $this->dic->http()->saveResponse($response);
329 $this->dic->http()->sendResponse();
330 $this->dic->http()->close();
331 }
332 }
333
334 protected function getLaunchParameters(): array
335 {
336 $ilLTIConsumerLaunch = new ilLTIConsumerLaunch($this->object->getRefId());
337 $launchContext = $ilLTIConsumerLaunch->getContext();
338
339 $launchContextType = ilLTIConsumerLaunch::getLTIContextType($launchContext["type"]);
340 $launchContextId = (string) $launchContext["id"];
341 $launchContextTitle = $launchContext["title"];
342
344 $this->dic->user()->getId(),
345 $this->object->getRefId(),
346 $this->object->getId()
347 );
348
349 return $this->object->buildLaunchParameters(
350 $this->cmixUser,
351 $token,
352 $launchContextType,
353 $launchContextId,
354 $launchContextTitle
355 );
356 }
357
358 protected function getLaunchParametersLTI13(string $endpoint, string $clientId, int $deploymentId, string $nonce): ?array
359 {
360 $ilLTIConsumerLaunch = new ilLTIConsumerLaunch($this->object->getRefId());
361 $launchContext = $ilLTIConsumerLaunch->getContext();
362
363 $launchContextType = ilLTIConsumerLaunch::getLTIContextType($launchContext["type"]);
364 $launchContextId = (string) $launchContext["id"];
365 $launchContextTitle = $launchContext["title"];
366
368 $this->dic->user()->getId(),
369 $this->object->getRefId(),
370 $this->object->getId()
371 );
372
374 return $this->object->buildLaunchParametersLTI13(
375 $cmixUser,
376 $token,
377 $endpoint,
378 $clientId,
379 $deploymentId,
380 $nonce,
381 $launchContextType,
382 $launchContextId,
383 $launchContextTitle
384 );
385 }
386
387 public static function isEmbeddedLaunchRequest(): bool
388 {
389 global $DIC; /* @var \ILIAS\DI\Container $DIC */
390
391 if ($DIC->ctrl()->getNextClass() != strtolower(self::class)) {
392 return false;
393 }
394
395 if ($DIC->ctrl()->getCmd() != self::CMD_SHOW_EMBEDDED) {
396 return false;
397 }
398
399 return true;
400 }
401
402 protected function initCmixUser(): void
403 {
404 $this->cmixUser = new ilCmiXapiUser($this->object->getId(), $this->dic->user()->getId(), $this->object->getProvider()->getPrivacyIdent());
405 $user_ident = $this->cmixUser->getUsrIdent();
406 if ($user_ident == '' || $user_ident == null) {
407 $user_ident = ilCmiXapiUser::getIdent($this->object->getProvider()->getPrivacyIdent(), $this->dic->user());
408 $this->cmixUser->setUsrIdent($user_ident);
409 $this->cmixUser->save();
410 }
411 }
412
413 private function validateLTI13InitalLogin(array $loginData): ?string
414 {
415 $scope = $loginData['scope'];
416 $responsetype = $loginData['response_type'];
417 $clientid = $loginData['client_id'];
418 $redirecturi = $loginData['redirect_uri'];
419 $loginhint = $loginData['login_hint'];
420 $ltimessagehint = $loginData['lti_message_hint'];
421 $state = $loginData['state'];
422 $responsemode = $loginData['response_mode'];
423 $nonce = $loginData['nonce'];
424 $prompt = $loginData['prompt'];
425
426 $ok = !empty($scope) && !empty($responsetype) && !empty($clientid) &&
427 !empty($redirecturi) && !empty($loginhint) &&
428 !empty($nonce) && (ilSession::get('lti_message_hint') != null);
429
430 if (!$ok) {
431 $error = 'invalid_request';
432 }
433 if ($ok && ($scope !== 'openid')) {
434 $ok = false;
435 $error = 'invalid_scope';
436 }
437 if ($ok && ($responsetype !== 'id_token')) {
438 $ok = false;
439 $error = 'unsupported_response_type';
440 }
441 if ($ok) {
442 list($ref_id, $ilias_client_id) = explode(':', ilSession::get('lti_message_hint'), 2);
443 if ((int) $this->object->getRefId() !== (int) $ref_id) {
444 $ok = false;
445 $error = 'invalid_request';
446 }
447 if ($this->object->getProvider()->getClientId() !== $clientid) {
448 $ok = false;
449 $error = 'unauthorized_client';
450 }
451 }
452
453 if ($ok) {
455 $this->object->getId(),
456 $this->user->getId(),
457 $this->object->getProvider()->getPrivacyIdent()
458 );
459 $user_ident = $cmixUser->getUsrIdent();
460 // required?
461 if ($user_ident == '' || $user_ident == null) {
462 $user_ident = ilCmiXapiUser::getIdent($this->object->getProvider()->getPrivacyIdent(), $this->dic->user());
463 $cmixUser->setUsrIdent($user_ident);
464 $cmixUser->save();
465 }
466
467 if ((string) $loginhint !== $user_ident) {
468 $ok = false;
469 $error = 'access_denied';
470 }
471 }
472 $uris = array_map("trim", explode(",", $this->object->getProvider()->getRedirectionUris()));
473 if (!in_array($redirecturi, $uris)) {
474 $ok = false;
475 $error = 'invalid_request';
476 }
477
478 if ($ok) {
479 if (isset($responsemode)) {
480 $ok = ($responsemode === 'form_post');
481 if (!$ok) {
482 $error = 'invalid_request';
483 $desc = 'Invalid response_mode';
484 }
485 } else {
486 $ok = false;
487 $error = 'invalid_request';
488 $desc = 'Missing response_mode';
489 }
490 }
491 if ($ok && !empty($prompt) && ($prompt !== 'none')) {
492 $ok = false;
493 $error = 'invalid_request';
494 $desc = 'Invalid prompt';
495 }
496 if ($ok) {
497 return null;
498 } else {
499 return $error;
500 }
501 }
502
503 // TODO: request_wrapper?
504
510 protected function getRequestValue(string $key, $default = null)
511 {
512 global $DIC;
513 if (isset($DIC->http()->request()->getQueryParams()[$key])) {
514 return $DIC->http()->request()->getQueryParams()[$key];
515 }
516
517 if (isset($DIC->http()->request()->getParsedBody()[$key])) {
518 return $DIC->http()->request()->getParsedBody()[$key];
519 }
520
521 return $default ?? null;
522 }
523}
static fillToken(int $usrId, int $refId, int $objId, int $lrsTypeId=0)
static getIdent(int $userIdentMode, ilObjUser $user)
setUsrIdent(string $usrIdent)
__construct(ilObjLTIConsumer $object)
getRequestValue(string $key, $default=null)
getLaunchParametersLTI13(string $endpoint, string $clientId, int $deploymentId, string $nonce)
static getLTIContextType(string $a_type)
language handling
User class.
static get(string $a_var)
static clear(string $a_var)
static set(string $a_var, $a_val)
Set a value.
special template class to simplify handling of ITX/PEAR
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
const CLIENT_ID
Definition: constants.php:41
exit
const ILIAS_VERSION_NUMERIC
$ltiMessageHint
Definition: ltiauth.php:50
$ref_id
Definition: ltiauth.php:66
$clientId
Definition: ltiregend.php:26
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:31
$scope
Definition: ltiregstart.php:51
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
global $DIC
Definition: shib_login.php:26
$context
Definition: webdav.php:31
$token
Definition: xapitoken.php:70
$response
Definition: xapitoken.php:93