This came up while I was trying to find a way for Hub users to share notebooks with one another. As an example, if I share http://<host>:<port>/user/me/notebooks/hello-world.ipynb with another user, the other user should be able to view this notebook by visiting this link.
In that case, my server at /user/me first tries to authorize the access, and upon successful authorization, redirect the other user to my notebook.
What’s interesting though is that ONLY admins are able to view other users’ notebooks, not regular Jupyterhub users. In this example, if this other user is an admin, then he/she would be able to view my notebook, but otherwise, a 403 page is displayed.
So I turned on --debug mode and screened through the logs as I ran through 2 scenarios as different users.
-
admin user viewing non-admin user’s notebook via direct link. Log shows:
[D 2020-04-23 09:35:17.269 SingleUserNotebookApp zmqhandlers:296] Initializing websocket connection /user/NonAdminUser/api/kernels/60e17652-6cf8-4a48-b9e1-55f4b20f3f27/channels
[D 2020-04-23 09:35:17.271 SingleUserNotebookApp auth:857] Allowing Hub admin AdminUser
-
non-admin user viewing other user’s notebook via direct link. Log shows:
[I 2020-04-23 09:39:03.150 SingleUserNotebookApp log:174] 302 GET /user/AAAA/oauth_callback?code=[secret]&state=[secret] -> /user/****/notebooks/hello-world.ipynb (@::ffff:135.210.10.9) 120.81ms
[W 2020-04-23 09:39:03.248 SingleUserNotebookApp auth:883] Not allowing Hub user NonAdminUser
Log confirms the behavior that I am seeing in the GUI. Digging a little deeper, I see this log is generated by jupyterhub/services/auth.py
module --> HubAuthenticated.check_hub_user()
method. Code snippet here for reference:
def check_hub_user(self, model): """Check whether Hub-authenticated user or service should be allowed. Returns the input if the user should be allowed, None otherwise. Override if you want to check anything other than the username's presence in hub_users list. Args: model (dict): the user or service model returned from :class:`HubAuth` Returns: user_model (dict): The user model if the user should be allowed, None otherwise. """ name = model['name'] kind = model.setdefault('kind', 'user') if self.allow_all: app_log.debug( "Allowing Hub %s %s (all Hub users and services allowed)", kind, name ) return model if self.allow_admin and model.get('admin', False): app_log.debug("Allowing Hub admin %s", name) return model if kind == 'service': # it's a service, check hub_services if self.hub_services and name in self.hub_services: app_log.debug("Allowing whitelisted Hub service %s", name) return model else: app_log.warning("Not allowing Hub service %s", name) raise UserNotAllowed(model) if self.hub_users and name in self.hub_users: # user in whitelist app_log.debug("Allowing whitelisted Hub user %s", name) return model elif self.hub_groups and set(model['groups']).intersection(self.hub_groups): allowed_groups = set(model['groups']).intersection(self.hub_groups) app_log.debug( "Allowing Hub user %s in group(s) %s", name, ','.join(sorted(allowed_groups)), ) # group in whitelist return model else: app_log.warning("Not allowing Hub user %s", name) raise UserNotAllowed(model)
Now what really confuses me is that …
in scenario 1, I hit the if self.allow_admin and model.get(‘admin’,False)
check and returned a model, meaning successful authorization.
but in scenario 2, I should have hit the first if statement if self.allow_all
, because self.allow_all
is True
at this point. Here’s the snippet:
hub_services = None # set of allowed services hub_users = None # set of allowed users hub_groups = None # set of allowed groups allow_admin = False # allow any admin user access @property def allow_all(self): """Property indicating that all successfully identified user or service should be allowed. """ return ( self.hub_services is None and self.hub_users is None and self.hub_groups is None )
and more importantly, I didnt whitelist any users in the jupyterhub_config.py file. So ending up in the last if > elif > else check doesnt make a lot of sense.
In addition, when I log in as a non-admin user and viewing my own notebooks, log shows that
‘Allowing whitelisted Hub user [user-name]’
, but again, NO users were whitelisted in the config file. And logging in as self doesn’t mean I’m a whitelisted user.
Apologies for the lengthy post. If anyone has any insights, hmu!