Cvmcosta / ltijs

Turn your application into a fully integratable LTI 1.3 tool provider.
https://cvmcosta.github.io/ltijs/
Apache License 2.0
299 stars 67 forks source link

Submitting Grade Results in 400 (Bad Request) #83

Closed markvitapoly closed 3 years ago

markvitapoly commented 3 years ago

Describe the bug

  1. Setup https://github.com/Cvmcosta/ltijs-demo-server and add to Moodle
  2. Click on Grade Services
  3. Submit Grade

It seems to error out here: const accessToken = await platform.platformAccessToken('https://purl.imsglobal.org/spec/lti-ags/scope/lineitem https://purl.imsglobal.org/spec/lti-ags/scope/score');

https://purl.imsglobal.org/spec/lti-ags/scope/lineitem returns 404?

Expected behavior Successfully Submit Grade

Provider logs (1) ['Receiving request at path: /grade'] (1) ['Path does not match reserved endpoints'] (1) ['Cookies received: '] (1) [{…}] (1) ['Ltik found'] (1) ['Ltik successfully verified'] (1) ['Attempting to retrieve matching session cookie'] (1) ['Dev Mode enabled: Missing session cookies will be ignored'] (1) ['Valid session found'] (1) ['Passing request to next handler'] (1) ['Target platform: https://testmoodle.com'] (1) ['Attempting to retrieve platform access_token for [https://testmoodle.com]'] (1) ['Valid access_token for https://testmoodle.com not found']

Ltijs version

Platform used

Additional context Add any other context about the problem here.

Cvmcosta commented 3 years ago

Hello! Are you hosting both Moodle and LTIJS on localhost? Or both on a VPS? If LTIJS is hosted locally a VPS hosted Moodle can't retrieve Access tokens because moodle will try to reach its own localhost.

markvitapoly commented 3 years ago

LTIJS is local. Moodle is a personal remote server but I also have the same results at https://sandbox.moodledemo.net/

LTIJS is running localhost, none https.

markvitapoly commented 3 years ago

Settings on sandbox.moodledemo.net, url: https://sandbox.moodledemo.net/mod/lti/instructor_edit_tool_type.php?sesskey=IF6rRf1rL2&course=2&action=edit&typeid=1

image

Code changes in the index.js of the server:


const setup = async () => {
  await lti.deploy({ port: process.env.PORT })

  host="https://sandbox.moodledemo.net";
  client='JLRqDHJ2VoViWMq';

  await lti.registerPlatform({
    url: host,
    name: 'Platform',
    clientId: client,
    authenticationEndpoint: host + '/mod/lti/auth.php',
    accesstokenEndpoint: host + '/mod/lti/token.php',
    authConfig: { method: 'JWK_SET', key: host + '/mod/lti/certs.php' }
  })

}
Cvmcosta commented 3 years ago

Yes, that is the issue. Moodle is trying to make a call to localhost:3000/keys to validate the access token request. But since it is reaching its own localhost, instead of your machine. You can only test the Services if both are accessible from the web or both are locally hosted.

markvitapoly commented 3 years ago

ok, i moved the server to an external facing VPS and also created some self signed certs for SSL. I have a slightly different issue, it's failing at a similar spot with a different error:


provider:auth Valid session found +2s
  provider:main Passing request to next handler +8ms
  provider:main Receiving request at path: /grade +4s
  provider:main Path does not match reserved endpoints +1ms
  provider:main Cookies received:  +0ms
  provider:main [Object: null prototype] {} +0ms
  provider:main Ltik found +0ms
  provider:main Ltik successfully verified +0ms
  provider:main Attempting to retrieve matching session cookie +1ms
  provider:main Dev Mode enabled: Missing session cookies will be ignored +0ms
  provider:auth Valid session found +4s
  provider:main Passing request to next handler +6ms
  provider:gradeService Target platform: https://sandbox.moodledemo.net +56s
  provider:gradeService Attempting to retrieve platform access_token for [https://sandbox.moodledemo.net] +21ms
  provider:platform Valid access_token for https://sandbox.moodledemo.net not found +56s
  provider:platform Attempting to generate new access_token for https://sandbox.moodledemo.net +1ms
  provider:platform With scopes: https://purl.imsglobal.org/spec/lti-ags/scope/lineitem https://purl.imsglobal.org/spec/lti-ags/scope/score +0ms
  provider:auth Awaiting return from the platform +6s
Response code 404 (Not Found)

index.js::

lti.setup(process.env.LTI_KEY,
  {
    url: 'mongodb://' + process.env.DB_HOST + '/' + process.env.DB_NAME,
    connection: { user: process.env.DB_USER, pass: process.env.DB_PASS }
  }, {
    staticPath: path.join(__dirname, './public'), // Path to static files
    cookies: {
      secure: true, // Set secure to true if the testing platform is in a different domain and https is being used
      sameSite: 'None' // Set sameSite to 'None' if the testing platform is in a different domain and https is being used
    },
    https: true,
    ssl:{
      key:fs.readFileSync("/etc/ssl/private/apache-selfsigned.key").toString(),
      cert:fs.readFileSync("/etc/ssl/certs/apache-selfsigned.crt").toString()
    },
    devMode: true // Set DevMode to true if the testing platform is in a different domain and https is not being used
  })
Cvmcosta commented 3 years ago

That is weird. Did you update the Public Keyset field in the Tool Registration on Moodle? It seems Moodle still ca't find the Keyset URL.

markvitapoly commented 3 years ago

https://sandbox.moodledemo.net/mod/lti/view.php?id=4&forceview=1

The keyset field is set to https://192.155.87.222:3000/keys

image

BTW, I just noticed that the moodle instance never hit the /keys route. If it did, the server will print out: provider:main Receiving request at path: /keys +1m provider:keyset Generating JWK keyset +0ms

UPDATE: ok, so the key string from the /keys URL isn't the format that moodle 3.10 is expecting. I extracted the key.pem and pasted it into moodle and was able to successfully submit a grade for the student.

I do not know if ltijs's /keys is the problem or if moodle 3.10 is the problem but there is some incompatibility there with specifying the keys url. The workaround was to modify the node_modules/ltijs/dist/Utils/Keyset.js to print out key.pem for manual entry into moodle. Perhaps there another way to convert /keys json output to the correct format?

Thanks for your help.

Cvmcosta commented 3 years ago

Hello! So Moodle was not hitting the /keys endpoint, right?

Regarding the key format. Keyset URLs serve keys in the JWK format. When using a single key instead of a keyset Moodle accepts keys in the RSA format. In ltijs, to get the RSA version of a given platform key you have to do it by code:

const platform = await lti.getPlatform('https://platform.url.com', 'CLIENTID')
const rsaKey = await platform.platformPublicKey()
Cvmcosta commented 3 years ago

I'll close this issue since it seems you managed to submit grades and the issue was that Moodle could not reach the /keys endpoint to validate the access token request.

Laktus commented 4 months ago

Hello @Cvmcosta,

I have the exact same problem with the /keys endpoint. It only works when i paste in the retrieved RSA key, like you defined it with your code. Do you have any idea how this problem may happen? The interesting thing is that when i try to access the keys endpoint directly via the browser (http://127.0.0.1:3000/keys) then it works. I specified the exact same URL in my moodle configs.

image