diff --git a/config/jupyterhub/02-jhub-apps.py b/config/jupyterhub/02-jhub-apps.py index 5a8c0c8..31acc0f 100644 --- a/config/jupyterhub/02-jhub-apps.py +++ b/config/jupyterhub/02-jhub-apps.py @@ -73,6 +73,28 @@ # Install jhub-apps (sets up service, roles, etc.) c = install_jhub_apps(c, spawner_to_subclass=KubeSpawner) +# Extend the `user` role with the scopes the jhub-apps sharing dropdown +# ("Individuals and group access") needs: the dropdown is (other hub users + +# hub groups) filtered by the requesting user's token scopes, and without +# read:users:name / read:groups:name it is empty for every user - admins +# included (#188). This MUST extend, in place, the `user` role that +# install_jhub_apps just appended to load_roles: defining a second role via +# z2jh's hub.loadRoles (which runs before this file) makes JupyterHub abort +# startup with "Role user multiply defined". Mirrors jhub-apps' reference +# jupyterhub_config.py. +# +# NOTE: read:users:name lets any authenticated user enumerate all usernames, +# inherent to sharing by name. Opt out via +# ``jupyterhub.custom.sharing-scopes-enabled: false``. +if get_config("custom.sharing-scopes-enabled", True): + for _role in c.JupyterHub.load_roles: + if _role.get("name") == "user": + _role["scopes"] = sorted( + set(_role["scopes"]) + | {"read:users:name", "read:groups:name", "shares!user"} + ) + break + # Forward JUPYTERHUB_OIDC_CLIENT_SECRET to the jhub-apps subprocess so that # 03-nebi-envs.py (which is re-evaluated inside the subprocess via # get_jupyterhub_config()) can read it for Keycloak token exchange. diff --git a/values.yaml b/values.yaml index 2ba3062..43300cc 100644 --- a/values.yaml +++ b/values.yaml @@ -531,6 +531,16 @@ jupyterhub: # For production, use GenericOAuthenticator with Keycloak (see below) authenticator_class: dummy + # Mirror each user's Keycloak groups into JupyterHub groups at login so + # groups can be jhub-apps share targets (#188) - without this the hub + # has no groups at all and the "Individuals and group access" dropdown + # can never list one. Standard oauthenticator trait (the pack's + # KeyCloakOAuthenticator subclasses GenericOAuthenticator); inert under + # the dummy authenticator. A group appears once one of its members + # logs in. Opt out by overriding to false. + KeyCloakOAuthenticator: + manage_groups: true + # ============================================================ # Optional: Keycloak/OAuth Configuration # ============================================================