Closed BAOOBAP closed 11 months ago
I forgot to mention that I am using version 0.4.9.
When you set up an LTI tool in an LMS, you have to give it a few URLs provided by the tool. This sounds like Moodle is making calls to HTTP URLs... have you tried updating your configuration in the LMS to use HTTPS URLs instead?
All configured urls are https:
URL of the tool: https://1908-139-47-20-144.ngrok-free.app/back/lti
Public key set: https://1908-139-47-20-144.ngrok-free.app/back/lti/jwks
Launch login URL: https://1908-139-47-20-144.ngrok-free.app/back/lti
Redirect URI(s): https://1908-139-47-20-144.ngrok-free.app/back/lti
and I can see the contents of the path https://1908-139-47-20-144.ngrok-free.app/back/lti/jwks :
{"keys":[{"kty":"RSA","n": "yM7mK91z0OvMoXhlNA_51_qI0SyFhd- of0wEtFOBypqSaezGdjTQOfvecvecqpcm2m1s7EwKmA1vdb78DRZTQQVbcypXYvAyqyCCa9KhzeYJsMVixi4Sv5m0kRvPNVPf0WNknC25f8jbskkAwLnosl7P4eUX9xtYSZcbkUPdwoxYQQEaUUsFM9t_PzICtZ6VNlSEO2Yh1tjfVKDm8QQFAxocyHaKBWRiqqqmH- 6eao9Fcu- aH4H44BNLJt48SQssWzAypuuv6mUtuhPuauiJX86mdjTPG1Jxzfn13scK-eq72JhQmRNwzQT1bJM_80gpqqNnV8ZDDVXpsXVmRE- N8j_GXmiAVXLTnpl3bmtXbgSJfrGl1RBYl8vuI4lLLblsFtYu7PcP1pi7QX0j1pbIGpPW2g5Tp0L88z389EdcOoD5dl6pzxBLFVhhtRMCC6bLlk22Zx4NSbzMYRlvcyw2_vzJplvqsAzt9udrB5a3Luigkhy292P2rGQxvtzaXS468TMUFrd", "e": "AQAB","alg":"RS256","use":"sig","kid":"XYZ"}]} ```
If I'm understanding you right, the JWK that it's complaining about isn't the one that's provided by your app, it's the one provided by the LMS. For Moodle, that's at the URL /mod/lti/certs.php
. Check that URL, and make sure that it's accessible and returns an actual JWKS when accessed.
It is accessible and returns this:
'''
{
"keys": [
{
"kty": "RSA",
"alg": "RS256",
"kid": "591f1fac32959533c640",
"e": "AQAB",
"n": "vJXnGM8ECSlUYYYZ3pjVDrywyMlkQCF10fr2oR86XRA3DjcDmukTXmiWJHi3pFcIm27ILf0jW3_PFzxhNfkBYUoD3AbxxnEE-7LAuWbVI_ReVq6364TY2SEB2OMdCM_RO9FLcK7CfsqIvzF_tO0NNNQ_sDXvVV-". WyrlkwLVx8oMnD8y2RMpcNlFRTPOBWKyqifEAEYySXTSvU4FxodmalH9Vk0F_6_jP61an012rr1AszqVIqYZnQTtEDHSaCPeKKK0M4Yporoi4rvL16e8LJh5dh1qTSuBu9uT2ryYbA70SozwdWcSdxhFYDE6kmsoKv9c20XJM9KD7gDudonjKs5iPkw",
"use": "sig"
}
]
}
'''
Sorry for not explaining it correctly.
The LMS is hosted on a server with ssl certificate, and the project is installed on a wamp server on a local machine, but for https requests, I redirect to a domain generated by ngrok, the case is that this was all mounted locally and gave the same error that I'm having with the jwt:
JWT signature check failed - perhaps an invalid public key or timestamp
Is it possible that the locally generated certificate could be the problem?
It was generated with openssl, maybe because it is autogenerated, it is not working.
I run my development servers with a self-signed HTTPS certificate too, and it hasn't been a problem (other than needing to tell my browser to trust the cert).
You've generated an RSA public/private keypair (as described in https://github.com/longhornopen/laravel-celtic-lti/wiki/Laravel-app-setup), and edited your config/lti.php to tell your app where to find them, correct?
Yes, I have created the RSA keys, and they have been added to the project to the config/lti.php file:
'rsa_public_key' => file_get_contents(storage_path('keys/public.pem')),
'rsa_private_key' => file_get_contents(storage_path('keys/private.pem')),
Is it possible that I should also add the certificate created with these keys to the wamp server?
No, these keys aren't used for securing HTTPS, only for generating and validating JWTs.
Not sure what to tell you at this point. If you've generated proper keys, the private key should start with '-----BEGIN RSA PRIVATE KEY-----' and the public key should begin with '-----BEGIN PUBLIC KEY----'. If those are where config/lti.php says they are, everything should work fine.
Version 1.0.0 bumps us up to a newer version of the Firebase JWT library - maybe try updating and see if that helps?
I have confirmed that the headers are inside the files. I have also upgraded to the latest version of the library, but it still gives the same error.
In your database, the lti2_consumer
table describes the LMSes you're connecting to. There should be a row in there for your Moodle instance. What's in the 'settings' column?
This is the content of settings:
{"_authentication_request_url": "https:\/\/moodle.silta-dixit.com/mod\/lti\/auth.php","_oauth2_access_token_url": "https:\/\/moodle.silta-dixit.com/mod\/lti\/token.php","_jku": "https:\/\/moodle.silta-dixit.com/mod\/lti\/certs.php"}
Testing, I removed the part where the jwt is validated, and the communication is successful, I can get the data returned by the LMS, and if I make the request configuring both the external tool of the LMS and the configuration of the back with the http protocol, I have no problem.
Sorry, I updated a test back that I did not point to, it has changed the error it returned, now it returns this one:
str_replace(): Argument #3 ($subject) must be of type array|string, bool given
In function $tool->handle_request()
I have done a var_dump of the $_SERVER variable and this is what it returns:
'HTTP_HOST' => string '7002-139-47-20-144.ngrok-free.app' (length=33)
'HTTP_USER_AGENT' => string 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' (length=111)
'CONTENT_LENGTH' => string '275' (length=3)
'HTTP_ACCEPT' => string 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' (length=135)
'HTTP_ACCEPT_ENCODING' => string 'gzip, deflate, br' (length=17)
'HTTP_ACCEPT_LANGUAGE' => string 'es-ES,es;q=0.9,en;q=0.8' (length=23)
'HTTP_CACHE_CONTROL' => string 'max-age=0' (length=9)
'CONTENT_TYPE' => string 'application/x-www-form-urlencoded' (length=33)
'HTTP_COOKIE' => string 'abuse_interstitial=7002-139-47-20-144.ngrok-free.app' (length=52)
'HTTP_ORIGIN' => string 'https://moodle.silta-dixit.com' (length=30)
'HTTP_REFERER' => string 'https://moodle.silta-dixit.com/' (length=31)
'HTTP_SEC_CH_UA' => string '"Chromium";v="118", "Microsoft Edge";v="118", "Not=A?Brand";v="99"' (length=66)
'HTTP_SEC_CH_UA_MOBILE' => string '?0' (length=2)
'HTTP_SEC_CH_UA_PLATFORM' => string '"Windows"' (length=9)
'HTTP_SEC_FETCH_DEST' => string 'document' (length=8)
'HTTP_SEC_FETCH_MODE' => string 'navigate' (length=8)
'HTTP_SEC_FETCH_SITE' => string 'cross-site' (length=10)
'HTTP_UPGRADE_INSECURE_REQUESTS' => string '1' (length=1)
'HTTP_X_FORWARDED_FOR' => string '139.47.20.144' (length=13)
'HTTP_X_FORWARDED_HOST' => string '7002-139-47-20-144.ngrok-free.app' (length=33)
'HTTP_X_FORWARDED_PROTO' => string 'https' (length=5)
'PATH' => string 'C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin;C:\Program Files\Common Files\Oracle\Java\javapath;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Python311\Scripts\;C:\Python311\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\PuTTY\;C:\ProgramData\chocolatey\bin;C:\Program Files\nodejs\;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\ProgramData\ComposerSetup\bin;C:\Certbot\bin;C:\opt\j'... (length=664)
'SystemRoot' => string 'C:\WINDOWS' (length=10)
'COMSPEC' => string 'C:\WINDOWS\system32\cmd.exe' (length=27)
'PATHEXT' => string '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW' (length=62)
'WINDIR' => string 'C:\WINDOWS' (length=10)
'SERVER_SIGNATURE' => string '<address>Apache/2.4.54 (Win64) OpenSSL/1.1.1s PHP/8.1.13 mod_fcgid/2.3.10-dev Server at 7002-139-47-20-144.ngrok-free.app Port 80</address>
' (length=140)
'SERVER_SOFTWARE' => string 'Apache/2.4.54 (Win64) OpenSSL/1.1.1s PHP/8.1.13 mod_fcgid/2.3.10-dev' (length=68)
'SERVER_NAME' => string 'https://6ea4-139-47-20-144.ngrok-free.app' (length=41)
'SERVER_ADDR' => string '::1' (length=3)
'SERVER_PORT' => string '' (length=0)
'REMOTE_ADDR' => string '::1' (length=3)
'DOCUMENT_ROOT' => string 'C:/wamp64/www' (length=13)
'REQUEST_SCHEME' => string 'http' (length=4)
'CONTEXT_PREFIX' => string '/back' (length=5)
'CONTEXT_DOCUMENT_ROOT' => string 'c:/wamp64/www/Nueva_carpeta/uniadaptiveLTI-Back/public/' (length=55)
'SERVER_ADMIN' => string 'wampserver@wampserver.invalid' (length=29)
'SCRIPT_FILENAME' => string 'C:/wamp64/www/Nueva_carpeta/uniadaptiveLTI-Back/public/index.php' (length=64)
'REMOTE_PORT' => string '56880' (length=5)
'GATEWAY_INTERFACE' => string 'CGI/1.1' (length=7)
'SERVER_PROTOCOL' => string 'HTTP/1.1' (length=8)
'REQUEST_METHOD' => string 'POST' (length=4)
'QUERY_STRING' => string '' (length=0)
'REQUEST_URI' => string '/back/index.php/lti' (length=19)
'SCRIPT_NAME' => string '/back/index.php' (length=15)
'PATH_INFO' => string '/lti' (length=4)
'PATH_TRANSLATED' => string 'C:\wamp64\www\lti' (length=17)
'PHP_SELF' => string '/back/index.php/lti' (length=19)
'REQUEST_TIME_FLOAT' => float 1701514738.216
'REQUEST_TIME' => int 1701514738
'APP_NAME' => string 'uniadaptiveLTI-Back' (length=19)
'APP_ENV' => string 'prod' (length=4)
'APP_KEY' => string 'base64:EUTdkaNilbUlObr3+rfW4TLuh0nsROh51IkKIO5lsdc=' (length=51)
'APP_DEBUG' => string 'true' (length=4)
'APP_URL' => string 'back' (length=4)
'APP_PROXY' => string 'https://6ea4-139-47-20-144.ngrok-free.app' (length=41)
'APP_PROXY_PORT' => string '' (length=0)
'APP_HTTPS' => string 'on' (length=2)
'LTI13_SIGNATURE_METHOD' => string 'RS256' (length=5)
'LTI13_KEY_ID' => string 'XYZ' (length=3)
'LTI13_AUTO_REGISTER_DEPLOYMENT_ID' => string 'false' (length=5)
'LOG_CHANNEL' => string 'errorlog' (length=8)
'LOG_DEPRECATIONS_CHANNEL' => string 'null' (length=4)
'LOG_LEVEL' => string 'debug' (length=5)
'DB_CONNECTION' => string 'mysql' (length=5)
'DB_HOST' => string 'localhost' (length=9)
'DB_PORT' => string '3306' (length=4)
'DB_DATABASE' => string 'uniadaptative_back' (length=18)
'DB_USERNAME' => string 'root' (length=4)
'DB_PASSWORD' => string '' (length=0)
'BROADCAST_DRIVER' => string 'log' (length=3)
'CACHE_DRIVER' => string 'file' (length=4)
'FILESYSTEM_DISK' => string 'local' (length=5)
'QUEUE_CONNECTION' => string 'sync' (length=4)
'SESSION_DRIVER' => string 'file' (length=4)
'SESSION_LIFETIME' => string '120' (length=3)
'MEMCACHED_HOST' => string '127.0.0.1' (length=9)
'REDIS_HOST' => string '127.0.0.1' (length=9)
'REDIS_PASSWORD' => string 'null' (length=4)
'REDIS_PORT' => string '6379' (length=4)
'FRONT_URL' => string 'https://550c-139-47-20-144.ngrok-free.app/front' (length=47)
'ADMIN_PASSWORD' => string 'admin' (length=5)
'JWT_SECRET' => string 'JD897Q71UIbSBsNUSvTlKtOFqVXSGG6htu1BJJQEBWIEdzc3Udv1QPZl1RRlEaB5' (length=64))
I have noticed that the 'REQUEST_SCHEME' parameter contains http
'REQUEST_SCHEME' => string 'http'
"Request scheme contains http": I've never used ngrok in particular, but that's typical for front-end proxies. The proxy (ngrok, in this case) handles HTTPS connections, and forwards an HTTP connection to the application. If the proxy server is listed in Laravel's TrustProxies middleware, everything gets handled transparently. (I'm assuming that your APP_PROXY env var is involved in setting up your TrustProxies somehow.)
You say you've run this successfully over HTTP. Was that HTTP connection being handled by ngrok also?
Yes, I have tested the http both locally and being redirected by the ngrok.
The difference is whether moodle uses http or https.
I have used lti-example-app to test what it returns, and it returns the same error:
JWT signature check failed - perhaps an invalid public key or timestamp
I don't know what else to try
I found the solution to the problem.
I have installed the WAMP server on Windows. It appears that on Windows, you need to add a cert.pem file to validate the certificate of the server where our Moodle is hosted. To do this, I downloaded the Mozilla CA certificate and added it to the PHP server, which resolved the issue. I extracted the file from the following link: https://curl.se/docs/caextract.html
Cool, glad you're up and running again!
Good morning,
I have configured a Laravel project that uses your library to connect an external tool to Moodle on my server. With HTTP it works perfectly, the problem comes when I use HTTPS.
I have a Moodle on a server, and the project is local, but I use a domain generated with Ngrok, so far so good. When I open the external tool, it makes a request to the back, and it returns the form to fill in the data, but when it validates the JWT, it shows the following error: "JWT signature check failed - perhaps an invalid public key or timestamp". A LonghornOpenLaravelCelticLTILTILtiException exception. I have seen the content of $_SERVER and it seems that in the REQUEST_SCHEME parameter the protocol used is HTTP, I have manually forced it to be HTTPS, but it still gives the same error. In the .env file I have added the following variables:
In the boot of the project I force the requests to be HTTPS:
I've even added middleware that forces requests to HTTPS (I don't know if the latter are good for anything):
Is there anything I'm missing or not taking into account?
Thanks!