/** * Set up the form definition. */ public function definition() { global $CFG; $mform =& $this->_form; $mform->addElement('header', 'setup', get_string('registration_options', 'lti')); // Tool Provider name. $mform->addElement('text', 'lti_registrationname', get_string('registrationname', 'lti')); $mform->setType('lti_registrationname', PARAM_TEXT); $mform->addHelpButton('lti_registrationname', 'registrationname', 'lti'); $mform->addRule('lti_registrationname', null, 'required', null, 'client'); // Registration URL. $mform->addElement('text', 'lti_registrationurl', get_string('registrationurl', 'lti'), array('size' => '64')); $mform->setType('lti_registrationurl', PARAM_TEXT); $mform->addHelpButton('lti_registrationurl', 'registrationurl', 'lti'); // LTI Capabilities. $options = array_keys(lti_get_capabilities()); natcasesort($options); $attributes = array( 'multiple' => 1, 'size' => min(count($options), 10) ); $mform->addElement('select', 'lti_capabilities', get_string('capabilities', 'lti'), array_combine($options, $options), $attributes); $mform->setType('lti_capabilities', PARAM_TEXT); $mform->addHelpButton('lti_capabilities', 'capabilities', 'lti'); // LTI Services. $services = lti_get_services(); $options = array(); foreach ($services as $service) { $options[$service->get_id()] = $service->get_name(); } $attributes = array( 'multiple' => 1, 'size' => min(count($options), 10) ); $mform->addElement('select', 'lti_services', get_string('services', 'lti'), $options, $attributes); $mform->setType('lti_services', PARAM_TEXT); $mform->addHelpButton('lti_services', 'services', 'lti'); $mform->addElement('hidden', 'toolproxyid'); $mform->setType('toolproxyid', PARAM_INT); $tab = optional_param('tab', '', PARAM_ALPHAEXT); $mform->addElement('hidden', 'tab', $tab); $mform->setType('tab', PARAM_ALPHAEXT); $courseid = optional_param('course', 1, PARAM_INT); $mform->addElement('hidden', 'course', $courseid); $mform->setType('course', PARAM_INT); // Add standard buttons, common to all modules. $this->add_action_buttons(); }
*/ define('NO_DEBUG_DISPLAY', true); define('NO_MOODLE_COOKIES', true); require_once dirname(__FILE__) . '/../../config.php'; require_once $CFG->dirroot . '/mod/lti/locallib.php'; $response = new \mod_lti\local\ltiservice\response(); $isget = $response->get_request_method() == 'GET'; if ($isget) { $response->set_accept(isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : ''); } else { $response->set_content_type(isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : ''); } $ok = false; $path = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ''; $accept = $response->get_accept(); $services = lti_get_services(); foreach ($services as $service) { $resources = $service->get_resources(); foreach ($resources as $resource) { if ($isget && !empty($accept) && strpos($accept, '*/*') === false && !in_array($accept, $resource->get_formats()) || !$isget && !in_array($response->get_content_type(), $resource->get_formats())) { continue; } $template = $resource->get_template(); $template = preg_replace('/\\{[a-zA-Z_]+\\}/', '[^/]+', $template); $template = preg_replace('/\\{\\?[0-9a-zA-Z_\\-,]+\\}$/', '', $template); $template = str_replace('/', '\\/', $template); if (preg_match("/{$template}/", $path) === 1) { $ok = true; break 2; } }
/** * Update the database with a tool proxy instance * * @param object $config Tool proxy definition * * @return int Record id number */ function lti_add_tool_proxy($config) { global $USER, $DB; $toolproxy = new \stdClass(); if (isset($config->lti_registrationname)) { $toolproxy->name = trim($config->lti_registrationname); } if (isset($config->lti_registrationurl)) { $toolproxy->regurl = trim($config->lti_registrationurl); } if (isset($config->lti_capabilities)) { $toolproxy->capabilityoffered = implode("\n", $config->lti_capabilities); } else { $toolproxy->capabilityoffered = implode("\n", array_keys(lti_get_capabilities())); } if (isset($config->lti_services)) { $toolproxy->serviceoffered = implode("\n", $config->lti_services); } else { $func = function ($s) { return $s->get_id(); }; $servicenames = array_map($func, lti_get_services()); $toolproxy->serviceoffered = implode("\n", $servicenames); } if (isset($config->toolproxyid) && !empty($config->toolproxyid)) { $toolproxy->id = $config->toolproxyid; if (!isset($toolproxy->state) || $toolproxy->state != LTI_TOOL_PROXY_STATE_ACCEPTED) { $toolproxy->state = LTI_TOOL_PROXY_STATE_CONFIGURED; $toolproxy->guid = random_string(); $toolproxy->secret = random_string(); } $id = lti_update_tool_proxy($toolproxy); } else { $toolproxy->state = LTI_TOOL_PROXY_STATE_CONFIGURED; $toolproxy->timemodified = time(); $toolproxy->timecreated = $toolproxy->timemodified; if (!isset($toolproxy->createdby)) { $toolproxy->createdby = $USER->id; } $toolproxy->guid = random_string(); $toolproxy->secret = random_string(); $id = $DB->insert_record('lti_tool_proxies', $toolproxy); } return $id; }
/** * Parse a custom parameter to replace any substitution variables * * @param object $toolproxy Tool proxy instance object * @param object $tool Tool instance object * @param array $params LTI launch parameters * @param string $value Custom parameter value * @param boolean $islti2 True if an LTI 2 tool is being launched * * @return Parsed value of custom parameter */ function lti_parse_custom_parameter($toolproxy, $tool, $params, $value, $islti2) { global $USER, $COURSE; if ($value) { if (substr($value, 0, 1) == '\\') { $value = substr($value, 1); } else { if (substr($value, 0, 1) == '$') { $value1 = substr($value, 1); $enabledcapabilities = lti_get_enabled_capabilities($tool); if (!$islti2 || in_array($value1, $enabledcapabilities)) { $capabilities = lti_get_capabilities(); if (array_key_exists($value1, $capabilities)) { $val = $capabilities[$value1]; if ($val) { if (substr($val, 0, 1) != '$') { $value = $params[$val]; } else { $valarr = explode('->', substr($val, 1), 2); $value = "{${$valarr[0]}->{$valarr[1]}}"; $value = str_replace('<br />', ' ', $value); $value = str_replace('<br>', ' ', $value); $value = format_string($value); } } } else { if ($islti2) { $val = $value; $services = lti_get_services(); foreach ($services as $service) { $service->set_tool_proxy($toolproxy); $value = $service->parse_value($val); if ($val != $value) { break; } } } } } } } } return $value; }
/** * Execute the request for this resource. * * @param mod_lti\local\ltiservice\response $response Response object for this request. */ public function execute($response) { $ok = $this->check_tool_proxy(null, $response->get_request_data()); if ($ok) { $toolproxy = $this->get_service()->get_tool_proxy(); } else { $toolproxy = null; $response->set_code(401); } $tools = array(); // Ensure all required elements are present in the Tool Proxy. if ($ok) { $toolproxyjson = json_decode($response->get_request_data()); $ok = !empty($toolproxyjson); if (!$ok) { debugging('Tool proxy is not properly formed JSON'); } else { $ok = isset($toolproxyjson->tool_profile->product_instance->product_info->product_family->vendor->code); $ok = $ok && isset($toolproxyjson->security_contract->shared_secret); $ok = $ok && isset($toolproxyjson->tool_profile->resource_handler); if (!$ok) { debugging('One or more missing elements from tool proxy: vendor code, shared secret or resource handlers'); } } } // Check all capabilities requested were offered. if ($ok) { $offeredcapabilities = explode("\n", $toolproxy->capabilityoffered); $resources = $toolproxyjson->tool_profile->resource_handler; $errors = array(); foreach ($resources as $resource) { if (isset($resource->message)) { foreach ($resource->message as $message) { if (!in_array($message->message_type, $offeredcapabilities)) { $errors[] = $message->message_type; } else { if (isset($resource->parameter)) { foreach ($message->parameter as $parameter) { if (isset($parameter->variable) && !in_array($parameter->variable, $offeredcapabilities)) { $errors[] = $parameter->variable; } } } } } } } if (count($errors) > 0) { $ok = false; debugging('Tool proxy contains capabilities which were not offered: ' . implode(', ', $errors)); } } // Check all services requested were offered (only tool services currently supported). if ($ok && isset($toolproxyjson->security_contract->tool_service)) { $contexts = lti_get_contexts($toolproxyjson); $profileservice = lti_get_service_by_name('profile'); $profileservice->set_tool_proxy($toolproxy); $context = $profileservice->get_service_path() . $profileservice->get_resources()[0]->get_path() . '#'; $offeredservices = explode("\n", $toolproxy->serviceoffered); $services = lti_get_services(); $tpservices = $toolproxyjson->security_contract->tool_service; $errors = array(); foreach ($tpservices as $service) { $fqid = lti_get_fqid($contexts, $service->service); if (substr($fqid, 0, strlen($context)) !== $context) { $errors[] = $service->service; } else { $id = explode('#', $fqid, 2); $aservice = lti_get_service_by_resource_id($services, $id[1]); $classname = explode('\\', get_class($aservice)); if (empty($aservice) || !in_array($classname[count($classname) - 1], $offeredservices)) { $errors[] = $service->service; } } } if (count($errors) > 0) { $ok = false; debugging('Tool proxy contains services which were not offered: ' . implode(', ', $errors)); } } // Extract all launchable tools from the resource handlers. if ($ok) { $resources = $toolproxyjson->tool_profile->resource_handler; foreach ($resources as $resource) { $found = false; $tool = new \stdClass(); foreach ($resource->message as $message) { if ($message->message_type == 'basic-lti-launch-request') { $found = true; $tool->path = $message->path; $tool->enabled_capability = $message->enabled_capability; $tool->parameter = $message->parameter; break; } } if (!$found) { continue; } $tool->name = $resource->resource_name->default_value; $tools[] = $tool; } $ok = count($tools) > 0; if (!$ok) { debugging('No launchable messages found in tool proxy'); } } // Add tools and custom parameters. if ($ok) { $baseurl = ''; if (isset($toolproxyjson->tool_profile->base_url_choice[0]->default_base_url)) { $baseurl = $toolproxyjson->tool_profile->base_url_choice[0]->default_base_url; } $securebaseurl = ''; if (isset($toolproxyjson->tool_profile->base_url_choice[0]->secure_base_url)) { $securebaseurl = $toolproxyjson->tool_profile->base_url_choice[0]->secure_base_url; } foreach ($tools as $tool) { $config = new \stdClass(); $config->lti_toolurl = "{$baseurl}{$tool->path}"; $config->lti_typename = $tool->name; $config->lti_coursevisible = 1; $config->lti_forcessl = 0; $type = new \stdClass(); $type->state = LTI_TOOL_STATE_PENDING; $type->toolproxyid = $toolproxy->id; $type->enabledcapability = implode("\n", $tool->enabled_capability); $type->parameter = self::lti_extract_parameters($tool->parameter); if (isset($resource->icon_info[0]->default_location->path)) { $iconpath = $resource->icon_info[0]->default_location->path; $type->icon = "{$baseurl}{$iconpath}"; if (!empty($securebaseurl)) { $type->secureicon = "{$securebaseurl}{$iconpath}"; } } $ok = $ok && lti_add_type($type, $config) !== false; } if (isset($toolproxyjson->custom)) { lti_set_tool_settings($toolproxyjson->custom, $toolproxy->id); } } if (!empty($toolproxy)) { if ($ok) { // If all went OK accept the tool proxy. $toolproxy->state = LTI_TOOL_PROXY_STATE_ACCEPTED; $toolproxy->toolproxy = $response->get_request_data(); $toolproxy->secret = $toolproxyjson->security_contract->shared_secret; $toolproxy->vendorcode = $toolproxyjson->tool_profile->product_instance->product_info->product_family->vendor->code; $url = $this->get_endpoint(); $body = <<<EOD { "@context" : "http://purl.imsglobal.org/ctx/lti/v2/ToolProxyId", "@type" : "ToolProxy", "@id" : "{$url}", "tool_proxy_guid" : "{$toolproxy->guid}" } EOD; $response->set_code(201); $response->set_content_type('application/vnd.ims.lti.v2.toolproxy.id+json'); $response->set_body($body); } else { // Otherwise reject the tool proxy. $toolproxy->state = LTI_TOOL_PROXY_STATE_REJECTED; $response->set_code(400); } lti_update_tool_proxy($toolproxy); } else { $response->set_code(400); } }