diff --git a/config/clusters/earthscope/common.values.yaml b/config/clusters/earthscope/common.values.yaml index 4aebac876e..4b7063c660 100644 --- a/config/clusters/earthscope/common.values.yaml +++ b/config/clusters/earthscope/common.values.yaml @@ -90,6 +90,92 @@ basehub: c.Spawner.auth_state_hook = populate_token c.JupyterHub.authenticator_class = CustomGenericOAuthenticator + + 06-gh-teams: | + # Re-assignes c.KubeSpawner.profile_list to a callable that filters the + # initial configuration of profile_list based on the user's github + # org/team membership as declared via "allowed_teams" read from + # profile_list profiles. + # + # This only has effect if: + # + # - GitHubOAuthenticator is used. + # - GitHubOAuthenticator.populate_teams_in_auth_state is True, that + # requires Authenticator.enable_auth_state to be True as well. + # - The user is a normal user, and not "deployment-service-check". + # + import copy + + from textwrap import dedent + from tornado import web + from oauthenticator.github import GitHubOAuthenticator + + original_profile_list = c.KubeSpawner.profile_list + + def user_groups(user_info): + print("Hello") + print(user_info, flush=True) + return set() + + c.GenericOAuthenticator.manage_groups = True + c.GenericOAuthenticator.claim_groups_key = user_groups + print(c.GenericOAuthenticator.claim_groups_key) + + async def profile_list_allowed_groups_filter(spawner): + """ + Returns the initially configured profile_list filtered based on the + user's membership in each profile's `allowed_groups`. If + `allowed_groups` isn't set for a profile, its not filtered out. + + `allowed_groups` is a list of JupyterHub groups. + + If the returned profile_list is filtered to not include a profile, + an error is raised and the user isn't allowed to start a server. + """ + if spawner.user.name == "deployment-service-check": + print("Ignoring allowed_teams check for deployment-service-check") + return original_profile_list + + groups = {g.name.casefold() for g in spawner.user.groups} + print(f"User {spawner.user.name} is part of groups {groups}") + + # Filter out profiles with allowed_groups set if the user isn't part of any. + allowed_profiles = [] + for profile in copy.deepcopy(original_profile_list): + allowed_groups = profile.get("allowed_groups") + if allowed_groups is None: + # If no allowed_groups are set, allow access to everything + allowed_profiles.append(profile) + continue + + if allowed_groups & groups: + print(f"Allowing profile {profile['display_name']} for user {spawner.user.name} based on group membership") + allowed_profiles.append(profile) + continue + + if len(allowed_profiles) == 0: + # If no profiles are allowed, user should not be able to spawn anything! + # If we don't explicitly stop this, user will be logged into the 'default' settings + # set in singleuser, without any profile overrides. Not desired behavior + # FIXME: User doesn't actually see this error message, just the generic 403. + error_msg = dedent(f""" + Your Group team membership is insufficient to launch any server profiles. + + GitHub teams you are a member of that this JupyterHub knows about are {', '.join(groups)}. + + If you are part of additional teams, log out of this JupyterHub and log back in to refresh that information. + """) + raise web.HTTPError(403, error_msg) + + return allowed_profiles + + # Only set this customized profile_list *if* we already have a profile_list set + # otherwise, we'll show users a blank server options form and they won't be able to + # start their server + if c.KubeSpawner.profile_list: + # Customize list of profiles dynamically, rather than override options form. + # This is more secure, as users can't override the options available to them via the hub API + c.KubeSpawner.profile_list = profile_list_allowed_groups_filter config: # JupyterHub: # authenticator_class: auth0 @@ -110,7 +196,7 @@ basehub: username_claim: sub # Convert 'scope' from the OAuth2 response into JupyterHub groups manage_groups: true - claim_groups_key: 'scope' + # claim_groups_key: 'scope' CILogonOAuthenticator: allowed_idps: http://github.com/login/oauth/authorize: