diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index c8b2dc9e..0012ea96 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -83,6 +83,7 @@ class BaseHandler(RequestHandler): except Exception: self.log.exception("Failed to get current user") self._jupyterhub_user = None + self.scopes = [] return await maybe_future(super().prepare()) @@ -426,6 +427,10 @@ class BaseHandler(RequestHandler): # don't let errors here raise more than once self._jupyterhub_user = None self.log.exception("Error getting current user") + if self._jupyterhub_user is not None: + self.scopes = self.settings.get("mock_scopes", []) + else: + self.scopes = [] return self._jupyterhub_user @property diff --git a/jupyterhub/tests/mocking.py b/jupyterhub/tests/mocking.py index 47b38f87..6d6a3adf 100644 --- a/jupyterhub/tests/mocking.py +++ b/jupyterhub/tests/mocking.py @@ -53,6 +53,7 @@ from ..spawner import SimpleLocalProcessSpawner from ..utils import random_port from ..utils import url_path_join from .utils import async_requests +from .utils import get_all_scopes from .utils import public_host from .utils import public_url from .utils import ssl_setup @@ -299,6 +300,7 @@ class MockHub(JupyterHub): super().init_tornado_application() # reconnect tornado_settings so that mocks can update the real thing self.tornado_settings = self.users.settings = self.tornado_application.settings + self.tornado_settings['mock_scopes'] = get_all_scopes() def init_services(self): # explicitly expire services before reinitializing diff --git a/jupyterhub/tests/utils.py b/jupyterhub/tests/utils.py index 09aeb196..9f81d5f0 100644 --- a/jupyterhub/tests/utils.py +++ b/jupyterhub/tests/utils.py @@ -194,3 +194,25 @@ def public_url(app, user_or_service=None, path=''): return host + ujoin(prefix, path) else: return host + prefix + + +def get_all_scopes(): + scopes = [ + 'all', + 'all', + 'users', + 'users:name', + 'users:groups', + 'users:activity', + 'users:servers', + 'users:tokens', + 'admin:users', + 'admin:users:servers', + 'groups', + 'admin:groups', + 'read:services', + 'proxy', + 'shutdown', + ] + read_only = ["read:%s" % el for el in scopes] + return scopes + read_only diff --git a/jupyterhub/utils.py b/jupyterhub/utils.py index a3f324ad..133c0fd4 100644 --- a/jupyterhub/utils.py +++ b/jupyterhub/utils.py @@ -305,12 +305,12 @@ def needs_scope(scope): def scope_decorator(func): @functools.wraps(func) def _auth_func(self, *args, **kwargs): - if scope not in self.current_scopes: + self.log.warning("Scope needed: " + scope) + self.log.warning("Scope possessed: %s" % ", ".join(self.scopes)) + if scope not in self.scopes: # Check if access is not restricted to user/server/group match_string = re.compile("^" + re.escape(scope) + r"!.+=.+$") - subscopes = filter( - lambda s: re.search(match_string, s), self.current_scopes - ) + subscopes = filter(lambda s: re.search(match_string, s), self.scopes) subset = [subscope.split('=')[1] for subscope in subscopes] if not subset: raise web.HTTPError(