Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moodle LTI 1.3 support and guidelines #118

Open
jlanza opened this issue Nov 13, 2022 · 19 comments
Open

Moodle LTI 1.3 support and guidelines #118

jlanza opened this issue Nov 13, 2022 · 19 comments

Comments

@jlanza
Copy link

jlanza commented Nov 13, 2022

Proposed change

Is Moodle LTI 1.3 supported? Is there any information on how to integrate it with Moodle? The README is focused on Canvas. Currently I don't know where to put in JupyterHub configuration the private keys, etc. Moodle is asking for a public key.

Who would use this feature?

(just because I have to fill it) Probably quite some people trying to provide more security ;)

@welcome
Copy link

welcome bot commented Nov 13, 2022

Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! 🤗

If you haven't done so already, check out Jupyter's Code of Conduct. Also, please try to follow the issue template as it helps other other community members to contribute more effectively.
welcome
You can meet the other Jovyans by joining our Discourse forum. There is also an intro thread there where you can stop by and say Hi! 👋

Welcome to the Jupyter community! 🎉

@martinclaus
Copy link
Collaborator

Hi @jlanza, support for LTI 1.3 is currently added (#134) and will be part of the next release. But you are correct, the documentation and README really require some attention. Would be great if you are willing to contribute the Moodle specific documentation, once the PR is merged.

@jlanza
Copy link
Author

jlanza commented Mar 20, 2023

Thanks a lot for the work towards LTI 1.3. I have used you LTI 1.1 implementation at my course and I will be eager to try to integrate LTI 1.3 (first I have to read the spec and check if the Moodle of my organization is updated (I guess yes) ;)). If I have time I can do so and also contribute.

@martinclaus
Copy link
Collaborator

Hi @jlanza! LTI 1.3 support (#134) is merged into the main branch and I have updated the LTI 1.3 section of the README. I hope the configuration of the LTI13Authenticator is now more clear.

@jlanza
Copy link
Author

jlanza commented Mar 30, 2023

I really have to thank you all for the great job. I will test it as soon as I have sometime. I have integrated the functionality in my lectures, which are currently running. So I will test in a parallel deployment.

@jeflem
Copy link
Contributor

jeflem commented Apr 22, 2023

Hi @jlanza, I'm running JupyterHub with LTIAuthenticator via Moodle 4 (just when I started to think about writing the 1.3 part for LTIAuthenticator on my own a few weeks ago, @martinclaus did it, saved me many hours, really great job done, many thanks!!!). Here are some config hints from my experience and testing:

In jupyterhub_config.py:

c.LTI13Authenticator.issuer = 'https://your-moodle-domain.org'
c.LTI13Authenticator.authorize_url = 'https://your-moodle-domain.org/mod/lti/auth.php'
c.LTI13Authenticator.client_id = 'client_id_generated_by_moodle'
c.LTI13Authenticator.jwks_endpoint ='http://your-moodle-domain.org/mod/lti/certs.php'

In Moodle's external tool configuration dialog (I use manual configuration):

Important: The 'Default launch container' has to be set to 'Existing window'. All other option (even 'New window') do not work with JupyterHub because JupyterHub doesn't allow embedding into other sites (Moodle's 'New Window' first embeds JupyterHub for some reason and then opens it in a new window).

@hugokoopmans
Copy link

Hi there,
I am trying to get this to work ;-)
I have added the ltiauthenticator to my docker file, done all the steps above (moodle 4 and jupyterhub both on docker with a nginx reverse proxy running), added appropriate lines to the config file.

Both systems work fine, but I cannot get the integration working.

Seems like the lti is not available in the jupyterhub?

When I add the jupyterhub as external tool the oath url is not found...

https://my.jupyter.org/hub/lti13/oauth_login gives

404 : Not Found

Jupyter has lots of moons, but this is not one...

My dockerfile:

# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
ARG JUPYTERHUB_VERSION
FROM jupyterhub/jupyterhub:$JUPYTERHUB_VERSION
# Install dockerspawner, nativeauthenticator
# hadolint ignore=DL3013
RUN python3 -m pip install --no-cache-dir \
dockerspawner \
jupyterhub-nativeauthenticator \
jupyterhub-ltiauthenticator

CMD ["jupyterhub", "-f", "/srv/jupyterhub/jupyterhub_config.py"]`

Do i need something extra on the commandline to make the authenticator run?

All advice welcome

@hugokoopmans
Copy link

logging from jupyterhub

[I 2023-08-31 09:09:13.119 JupyterHub users:768] Server jupyter-admin is ready
[I 2023-08-31 09:09:13.120 JupyterHub log:191] 200 GET /hub/api/users/jupyter-admin/server/progress?_xsrf=[secret] ([email protected]) 2122.98ms
[I 2023-08-31 09:09:13.158 JupyterHub log:191] 302 GET /hub/spawn-pending/jupyter-admin -> /user/jupyter-admin/ ([email protected]) 3.45ms
[I 2023-08-31 09:09:13.242 JupyterHub log:191] 302 GET /hub/api/oauth2/authorize?client_id=jupyterhub-user-jupyter-admin&redirect_uri=%2Fuser%2Fjupyter-admin%2Foauth_callback&response_type=code&state=[secret] -> /user/jupyter-admin/oauth_callback?code=[secret]&state=[secret] ([email protected]) 24.23ms
[I 2023-08-31 09:09:13.291 JupyterHub log:191] 200 POST /hub/api/oauth2/token ([email protected]) 30.71ms
[I 2023-08-31 09:09:13.316 JupyterHub log:191] 200 GET /hub/api/user ([email protected]) 22.27ms
[W 2023-08-31 09:10:04.218 JupyterHub web:1869] 403 POST /hub/lti13/oauth_login (86.93.106.67): '_xsrf' argument missing from POST
[W 2023-08-31 09:10:04.255 JupyterHub log:191] 403 POST /hub/lti13/oauth_login (@86.93.106.67) 38.16ms
[W 2023-08-31 09:10:25.584 JupyterHub web:1869] 403 POST /hub/lti13/oauth_login (86.93.106.67): '_xsrf' argument missing from POST
[W 2023-08-31 09:10:25.586 JupyterHub log:191] 403 POST /hub/lti13/oauth_login (@86.93.106.67) 2.28ms
[W 2023-08-31 09:10:55.231 JupyterHub log:191] 404 GET /hub/lti13/oauth_login ([email protected]) 37.30ms
[W 2023-08-31 09:12:07.748 JupyterHub web:1869] 403 POST /hub/lti13/oauth_login (86.93.106.67): '_xsrf' argument missing from POST
[W 2023-08-31 09:12:07.750 JupyterHub log:191] 403 POST /hub/lti13/oauth_login (@86.93.106.67) 2.29ms
09:13:28.382 [ConfigProxy] info: 200 GET /api/routes 
[I 2023-08-31 09:14:04.606 JupyterHub log:191] 200 POST /hub/api/users/jupyter-admin/activity ([email protected]) 12.41ms
09:18:28.382 [ConfigProxy] info: 200 GET /api/routes 
[I 2023-08-31 09:19:16.609 JupyterHub log:191] 200 POST /hub/api/users/jupyter-admin/activity ([email protected]) 13.56ms
[I 2023-08-31 09:20:52.988 JupyterHub log:191] 200 GET /hub/api/user ([email protected]) 10.99ms
[W 2023-08-31 09:21:00.229 JupyterHub log:191] 404 GET /hub/lti13/oauth_login ([email protected]) 3.83ms
[W 2023-08-31 09:21:13.255 JupyterHub log:191] 404 GET /hub/lti13/oauth_login ([email protected]) 3.45ms
09:23:28.382 [ConfigProxy] info: 200 GET /api/routes 
[I 2023-08-31 09:24:13.586 JupyterHub log:191] 200 POST /hub/api/users/jupyter-admin/activity ([email protected]) 12.20ms
09:28:28.382 [ConfigProxy] info: 200 GET /api/routes 
[I 2023-08-31 09:28:59.096 JupyterHub log:191] 200 POST /hub/api/users/jupyter-admin/activity ([email protected]) 14.65ms```

@hugokoopmans
Copy link

hmmm i assume these two can run side by side

jupyterhub-nativeauthenticator
jupyterhub-ltiauthenticator

@hugokoopmans
Copy link

hehe

you do need to choose indeed:

#c.JupyterHub.authenticator_class = "nativeauthenticator.NativeAuthenticator"
c.JupyterHub.authenticator_class = "ltiauthenticator.lti13.auth.LTI13Authenticator"

now it works from moodle (but not anymore from outside)

@martinclaus
Copy link
Collaborator

martinclaus commented Aug 31, 2023

Hi @hugokoopmans,

you were quicker than me 😄.

Indeed, ltiauthenticator cannot run alongside another authenticator as mentioned in the README. Though, it could be mentioned in the docs too. Actually, I am not sure if multiple authenticator are supported by Jupyterhub at all. You may try to look here for some hints how to add another authenticator.

@hugokoopmans
Copy link

ok it worked fine untill a few weeks ago...

@hugokoopmans
Copy link

now I get this error : Required LTI 1.3 arg iss not in request

[I 2024-05-28 12:19:50.793 JupyterHub log:191] 200 GET /hub/login?next=%2Fhub%2Fadmin (@90.145.96.110) 2.46ms

12:20:58.516 [ConfigProxy] info: 200 GET /api/routes 

[I 2024-05-28 12:21:30.095 JupyterHub log:191] 302 GET /hub/user-redirect/git-pull?repo=https%3A%2F%2Fgithub.com%2Fstefmolin%2Fpandas-workshop&urlpath=lab%2Ftree%2Fpandas-workshop%2F -> /hub/login?next=%2Fhub%2Fuser-redirect%2Fgit-pull%3Frepo%3Dhttps%253A%252F%252Fgithub.com%252Fstefmolin%252Fpandas-workshop%26urlpath%3Dlab%252Ftree%252Fpandas-workshop%252F (@90.145.96.110) 1.38ms

[I 2024-05-28 12:21:30.134 JupyterHub log:191] 200 GET /hub/login?next=%2Fhub%2Fuser-redirect%2Fgit-pull%3Frepo%3Dhttps%253A%252F%252Fgithub.com%252Fstefmolin%252Fpandas-workshop%26urlpath%3Dlab%252Ftree%252Fpandas-workshop%252F (@90.145.96.110) 3.47ms

[W 2024-05-28 12:21:51.949 JupyterHub web:1869] 400 GET /hub/lti13/oauth_login?next=%2Fhub%2Fadmin (90.145.96.110): Required LTI 1.3 arg iss not in request

@hugokoopmans
Copy link

any suggestions?

@meffmadd
Copy link

@hugokoopmans Were you able to solve the issue with the iss arg?

@jeflem
Copy link
Contributor

jeflem commented Aug 21, 2024

Hi @hugokoopmans and @meffmadd,
tried to reproduce your problem, but without success. My guess is that there's some missconfiguration on the Moodle side, maybe related to using nbgitpuller (the GET to /hub/lti13/oauth_login looks wrong).

Here's my external tool config for Moodle+nbgitpuller (everything on current stable version):

  • "Tool URL": https://hubdomain.org/hub/user-redirect/git-pull?repo=some_repo_url&urlpath=lab/tree/some_notebook_path&branch=main
  • "Initiate login URL": https://hubdomain.org/hub/lti13/oauth_login
  • "Redirect URI(s)": https://hubdomain.org/hub/lti13/oauth_callback

Full log output from JHub would be good for discussion.

Best regards,

Jens

@meffmadd
Copy link

Hi @jeflem,
thanks for the answer! I deploy Moodle locally using https://github.com/moodlehq/moodle-docker. Maybe this helps with reproducibility if you still want to try.

Indeed, the POST request to the LTI13LoginInitHandler handler contains all the arguments necessary to pass validation (iss, login_hint and target_link_uri), but the second GET request only contains the next URL.

This has to be a misconfiguration of Moodle but this is all quite opaque to me...

@jeflem
Copy link
Contributor

jeflem commented Aug 21, 2024

I do not see any GET to /hub/lti13/oauth_login in my JHub logs. Login related log output:

Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [W 2024-08-21 11:29:22.217 JupyterHub handlers:243] Ignoring next_url None, using '/'
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.218 JupyterHub log:192] 302 POST /hub/lti13/oauth_login -> http://192.168.178.128:9090/moodle/mod/lti/auth.php?response_type=id_token&scope=openid&response_mode=form_post&prompt=none&client_id=SPhDLIochoLakRz&redirect_uri=http%3A%2F%2F192.168.178.128%3A8000%2Fhub%2Flti13%2Foauth_callback&login_hint=7&nonce=fec754f48b52c13986bf39ab516168b300f5b5691185d19f611a5fe5bd1233b7&state=[secret]&lti_message_hint=%7B%22cmid%22%3A1%2C%22launchid%22%3A%22ltilaunch1_1352468325%22%7D (@::ffff:10.0.2.100) 1.90ms
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.294 JupyterHub base:973] User logged in: u7
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.295 JupyterHub log:192] 302 POST /hub/lti13/oauth_callback -> / (u7@::ffff:10.0.2.100) 22.77ms
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.302 JupyterHub log:192] 302 GET / -> /hub/ (@::ffff:10.0.2.100) 0.70ms
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.330 JupyterHub log:192] 302 GET /hub/ -> /user/u7/ (u7@::ffff:10.0.2.100) 21.20ms
Aug 21 11:29:22 7e44488f7419 jupyterhub-singleuser[7290]: [I 2024-08-21 11:29:22.337 ServerApp] 302 GET /user/u7/ -> /user/u7/lab? (@::ffff:10.0.2.100) 0.74ms
Aug 21 11:29:22 7e44488f7419 jupyterhub-singleuser[7290]: [I 2024-08-21 11:29:22.341 ServerApp] 302 GET /user/u7/lab? -> /hub/api/oauth2/authorize?client_id=jupyterhub-user-u7&redirect_uri=%2Fuser%2Fu7%2Foauth_callback&response_type=code&state=[secret] (@::ffff:10.0.2.100) 1.12ms
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.371 JupyterHub log:192] 302 GET /hub/api/oauth2/authorize?client_id=jupyterhub-user-u7&redirect_uri=%2Fuser%2Fu7%2Foauth_callback&response_type=code&state=[secret] -> /user/u7/oauth_callback?code=[secret]&state=[secret] (u7@::ffff:10.0.2.100) 25.08ms
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.440 JupyterHub log:192] 200 POST /hub/api/oauth2/token ([email protected]) 58.35ms
Aug 21 11:29:22 7e44488f7419 jupyterhub[6977]: [I 2024-08-21 11:29:22.459 JupyterHub log:192] 200 GET /hub/api/user ([email protected]) 17.05ms
Aug 21 11:29:22 7e44488f7419 jupyterhub-singleuser[7290]: [I 2024-08-21 11:29:22.460 ServerApp] Logged-in user u7

If you post your JHub logs, I'll have a look at them.

PS: I'm testing with Moodle Podman image shipping with Ananke Jupyter Distribution instead of the official Docker images (see doc).

@meffmadd
Copy link

Hi @jeflem,
thanks for your help, my error is unrelated to the ltiauthenticator! We actually forked the implementation because we needed special handling for usernames and used a different BaseHandler, which it turns out was incompatible with the LTI handlers. Since the error today was identical to the Moodle integration problems, I jumped to early conclusions.

I tested a new Moodle LTI tool against the vanilla implementation (with JH 5.1.0) and everything worked. If the error that @hugokoopmans encountered was using the standard ltiauthenticator implementation, this error has been fixed since then.

My error was caused by checking user authentication in the prepare method of the base handler while the auth flow was executing, resulting in another redirect to the login handler without any arguments, leading to the above error message about the missing iss argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants