diff --git a/.htaccess b/.htaccess index e91ea78d63..13d1bfadcb 100755 --- a/.htaccess +++ b/.htaccess @@ -64,6 +64,9 @@ RewriteRule ^main/newscorm/(.*)$ main/lp/$1 [QSA,L] # service Information RewriteRule ^service/(\d{1,})$ plugin/buycourses/src/service_information.php?service_id=$1 [L] +# LTI outcome service +RewriteRule ^ims_lti/outcome_service/(\d{1,})$ plugin/ims_lti/outcome_service.php?t=$1 [L] + # This rule is very generic and should always remain at the bottom of .htaccess # http://my.chamilo.net/jdoe to http://my.chamilo.net/user.php?jdoe RewriteRule ^([^/.]+)/?$ user.php?$1 [L] diff --git a/plugin/ims_lti/OAuthSimple.php b/plugin/ims_lti/OAuthSimple.php index 265aae3154..76501f267c 100644 --- a/plugin/ims_lti/OAuthSimple.php +++ b/plugin/ims_lti/OAuthSimple.php @@ -539,6 +539,45 @@ class OAuthSimple break; } } + + /** + * @param $string + * + * @return string + */ + public static function generateBodyHash($string) + { + $hash = sha1($string, true); + + return base64_encode($hash); + } + + /** + * @param string $authorizationHeader + * + * @return array + */ + public static function getAuthorizationParams($authorizationHeader) + { + if ('OAuth ' !== substr($authorizationHeader, 0, 6)) { + return []; + } + + $params = []; + $authString = str_replace('OAuth ', '', $authorizationHeader); + $authParts = explode(',', $authString); + + foreach ($authParts as $authPart) { + list($key, $value) = explode('=', $authPart, 2); + + $key = trim($key); + $value = trim($value, " \""); + + $params[$key] = urldecode($value); + } + + return $params; + } } /** diff --git a/plugin/ims_lti/form.php b/plugin/ims_lti/form.php index 12ade82773..0f0a3d42a6 100644 --- a/plugin/ims_lti/form.php +++ b/plugin/ims_lti/form.php @@ -15,7 +15,9 @@ api_block_anonymous_users(false); $em = Database::getManager(); /** @var ImsLtiTool $tool */ -$tool = isset($_GET['id']) ? $em->find('ChamiloPluginBundle:ImsLti\ImsLtiTool', intval($_GET['id'])) : 0; +$tool = isset($_GET['id']) + ? $em->find('ChamiloPluginBundle:ImsLti\ImsLtiTool', (int) $_GET['id']) + : null; if (!$tool) { api_not_allowed(true); @@ -30,6 +32,7 @@ $course = $em->find('ChamiloCoreBundle:Course', api_get_course_int_id()); /** @var User $user */ $user = $em->find('ChamiloUserBundle:User', api_get_user_id()); +$pluginPath = api_get_path(WEB_PLUGIN_PATH).'ims_lti/'; $toolUserId = ImsLtiPlugin::generateToolUserId($user->getId()); $platformDomain = str_replace(['https://', 'http://'], '', api_get_setting('InstitutionUrl')); @@ -38,7 +41,7 @@ $params['lti_version'] = 'LTI-1p0'; if ($tool->isActiveDeepLinking()) { $params['lti_message_type'] = 'ContentItemSelectionRequest'; - $params['content_item_return_url'] = api_get_path(WEB_PLUGIN_PATH).'ims_lti/item_return.php'; + $params['content_item_return_url'] = $pluginPath.'item_return.php'; $params['accept_media_types'] = '*/*'; $params['accept_presentation_document_targets'] = 'iframe'; //$params['accept_unsigned']; @@ -58,7 +61,7 @@ if ($tool->isActiveDeepLinking()) { if (!empty($toolEval)) { $params['lis_result_sourcedid'] = $toolEval->getId().':'.$user->getId(); - $params['lis_outcome_service_url'] = api_get_path(WEB_PLUGIN_PATH).'ims_lti/outcome_service.php'; + $params['lis_outcome_service_url'] = api_get_path(WEB_PATH).'ims_lti/outcome_service/'.$tool->getId(); $params['lis_person_sourcedid'] = "$platformDomain:$toolUserId"; $params['lis_course_offering_sourcedid'] = "$platformDomain:".$course->getId(); diff --git a/plugin/ims_lti/outcome_service.php b/plugin/ims_lti/outcome_service.php index c547c2e7d8..9c78e32cb9 100644 --- a/plugin/ims_lti/outcome_service.php +++ b/plugin/ims_lti/outcome_service.php @@ -1,10 +1,62 @@ find('ChamiloPluginBundle:ImsLti\ImsLtiTool', (int) $_GET['t']); + +if (empty($tool)) { + exit; +} + +$body = file_get_contents('php://input'); +$bodyHash = OAuthSimple::generateBodyHash($body); + +$url = api_get_path(WEB_PATH).'ims_lti/outcome_service/'.$tool->getId(); +$headers = getallheaders(); + +$params = OAuthSimple::getAuthorizationParams($headers['Authorization']); + +if (empty($params)) { + exit; +} + +$oauth = new OAuthSimple( + $params['oauth_consumer_key'], + $tool->getSharedSecret() +); +$oauth->setAction('POST'); +$oauth->setSignatureMethod('HMAC-SHA1'); +$result = $oauth->sign( + [ + 'path' => $url, + 'parameters' => [ + 'oauth_body_hash' => $params['oauth_body_hash'], + 'oauth_nonce' => $params['oauth_nonce'], + 'oauth_timestamp' => $params['oauth_timestamp'], + 'oauth_signature_method' => $params['oauth_signature_method'], + ], + ] +); + +$signatureValid = urldecode($result['signature']) == $params['oauth_signature']; +$bodyHashValid = $bodyHash === $params['oauth_body_hash']; + +if (!$signatureValid || !$bodyHashValid) { + exit; +} + $plugin = ImsLtiPlugin::create(); $process = $plugin->processServiceRequest();