diff --git a/admin/processltiqueue.php b/admin/processltiqueue.php index afea76e986..3cca12198d 100644 --- a/admin/processltiqueue.php +++ b/admin/processltiqueue.php @@ -126,7 +126,8 @@ function debuglog($str) { 'platformid' => $platformid, 'grade' => max(0, $row['grade']), 'isstu' => $row['isstu'], - 'addedon' => $row['addedon'] + 'addedon' => $row['addedon'], + 'keyseturl' => $row['keyseturl'], ), null, //no special callback array( //user-data; will get passed to response @@ -149,7 +150,8 @@ function debuglog($str) { 'ver' => 'LTI1.3', 'action' => 'gettoken', 'platformid' => $platformid, - 'platforminfo' => $platforminfo + 'platforminfo' => $platforminfo, + 'keyseturl' => $row['keyseturl'], ), null, //no special callback array( //user-data; will get passed to response @@ -276,7 +278,7 @@ function LTIqueuePostdataCallback($data) { if ($updater1p3->have_token($data['platformid']) && $updater1p3->token_valid($data['platformid']) ) { // double check we have a valid token - $token = $updater1p3->get_access_token($data['platformid']); + $token = $updater1p3->get_access_token($data['platformid'], '', '', '', $data['keyseturl']); return $updater1p3->get_update_body($token, $data['grade'], $data['ltiuserid'], $data['isstu'], $data['addedon']); } else { return false; diff --git a/includes/ltioutcomes.php b/includes/ltioutcomes.php index 9e70c05e19..ee7a360ac2 100644 --- a/includes/ltioutcomes.php +++ b/includes/ltioutcomes.php @@ -19,10 +19,11 @@ function addToLTIQueue($sourcedid, $key, $grade, $sendnow=false, $isstu=true) { global $DBH, $CFG; $LTIdelay = 60*(isset($CFG['LTI']['queuedelay'])?$CFG['LTI']['queuedelay']:5); + $keyseturl = $GLOBALS['basesiteurl'] . '/lti/jwks.php'; - $query = 'INSERT INTO imas_ltiqueue (hash, sourcedid, grade, failures, sendon, isstu, addedon) '; - $query .= 'VALUES (:hash, :sourcedid, :grade, 0, :sendon, :isstu, :addedon) ON DUPLICATE KEY UPDATE '; - $query .= 'grade=VALUES(grade),sendon=VALUES(sendon),sourcedid=VALUES(sourcedid),failures=0,isstu=GREATEST(isstu,VALUES(isstu)) '; + $query = 'INSERT INTO imas_ltiqueue (hash, sourcedid, grade, failures, sendon, isstu, addedon, keyseturl) '; + $query .= 'VALUES (:hash, :sourcedid, :grade, 0, :sendon, :isstu, :addedon, :keyseturl) ON DUPLICATE KEY UPDATE '; + $query .= 'grade=VALUES(grade),sendon=VALUES(sendon),sourcedid=VALUES(sourcedid),failures=0,isstu=GREATEST(isstu,VALUES(isstu)),keyseturl=VALUES(keyseturl) '; $stm = $DBH->prepare($query); $stm->execute(array( @@ -31,7 +32,8 @@ function addToLTIQueue($sourcedid, $key, $grade, $sendnow=false, $isstu=true) { ':grade' => $grade, ':sendon' => (time() + ($sendnow?0:$LTIdelay)), ':isstu' => $isstu ? 1 : 0, - ':addedon' => time() + ':addedon' => time(), + ':keyseturl' => $keyseturl, )); return ($stm->rowCount()>0); diff --git a/lti/LTI_Grade_Update.php b/lti/LTI_Grade_Update.php index 9648dadac0..582b471292 100644 --- a/lti/LTI_Grade_Update.php +++ b/lti/LTI_Grade_Update.php @@ -21,7 +21,7 @@ class LTI_Grade_Update { private $dbh; private $access_tokens = []; - private $private_key = ''; + private $private_key = []; private $failures = []; private $debug = false; @@ -210,9 +210,12 @@ public function get_update_body(string $token, float $score, string $ltiuserid, * @param string $client_id optional if known - the client_id * @param string $token_server optional if known - the token_server_url * @param string $auth_server optional if known - the aud for token request + * @param string|null $keyseturl optional if known - the keyset url * @return false|string access token, or false on failure */ - public function get_access_token(int $platform_id, string $client_id='', string $token_server='', string $auth_server='') { + public function get_access_token(int $platform_id, string $client_id='', string $token_server='', string $auth_server='', + ?string $keyseturl = null + ) { // see if we already have the token in our private variable cache if (isset($this->access_tokens[$platform_id]) && $this->access_tokens[$platform_id]['expires'] < time() @@ -248,7 +251,7 @@ public function get_access_token(int $platform_id, string $client_id='', string list($client_id, $token_server, $auth_server) = $stm->fetch(PDO::FETCH_NUM); } $this->debuglog('requesting a token from '.$platform_id); - $request_post = $this->get_token_request_post($platform_id, $client_id, $token_server, $auth_server); + $request_post = $this->get_token_request_post($platform_id, $client_id, $token_server, $auth_server, $keyseturl); // Make request to get auth token $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $token_server); @@ -306,11 +309,16 @@ public function store_access_token(int $platform_id, array $token_data): void { * @param string $client_id * @param string $token_server * @param string $auth_server + * @param string|null $keyseturl * @return string output of http_build_query */ public function get_token_request_post(int $platform_id, string $client_id, - string $token_server, string $auth_server + string $token_server, string $auth_server, ?string $keyseturl = null ): string { + if (empty($keyseturl)) { + $keyseturl = TOOL_HOST . '/lti/jwks.php'; + } + // Build up JWT to exchange for an auth token $jwt_claim = [ "iss" => $client_id, @@ -322,10 +330,10 @@ public function get_token_request_post(int $platform_id, string $client_id, ]; // Get tool private key from our JWKS - $private_key = $this->get_tool_private_key(); + $private_key[$keyseturl] = $this->get_tool_private_key($keyseturl); // Sign the JWT with our private key (given by the platform on registration) - $jwt = JWT::encode($jwt_claim, $private_key['privatekey'], 'RS256', $private_key['kid']); + $jwt = JWT::encode($jwt_claim, $private_key[$keyseturl]['privatekey'], 'RS256', $private_key[$keyseturl]['kid']); // Build auth token request headers $auth_request = [ @@ -390,14 +398,15 @@ public function update_sendon(string $hash, int $platform_id): void { /** * Get tool's private key + * @param string $keyseturl * @return array */ - private function get_tool_private_key(): array { - if (!empty($this->private_key)) { - return $this->private_key; + private function get_tool_private_key(string $keyseturl): array { + if (!empty($this->private_key[$keyseturl])) { + return $this->private_key[$keyseturl]; } $stm = $this->dbh->prepare('SELECT * FROM imas_lti_keys WHERE key_set_url=? AND privatekey != "" ORDER BY created_at DESC LIMIT 1'); - $stm->execute(array(TOOL_HOST.'/lti/jwks.php')); + $stm->execute(array($keyseturl)); $row = $stm->fetch(PDO::FETCH_ASSOC); $this->private_key = $row; return $row; diff --git a/migrations/20230321_add_keyseturl_to_ltiqueue.php b/migrations/20230321_add_keyseturl_to_ltiqueue.php new file mode 100644 index 0000000000..4730e2737c --- /dev/null +++ b/migrations/20230321_add_keyseturl_to_ltiqueue.php @@ -0,0 +1,22 @@ +beginTransaction(); + +$query = "ALTER TABLE `imas_ltiqueue` + ADD COLUMN `keyseturl` VARCHAR(256) NULL, + ALGORITHM=INPLACE, + LOCK=NONE;"; +$res = $DBH->query($query); +if ($res===false) { + echo "

Query failed: ($query) : ".print_r($DBH->errorInfo(),true)."

"; + $DBH->rollBack(); + return false; +} + + +$DBH->commit(); +echo '

Add keyseturl columnn to imas_ltiqueue.

'; + +return true;