diff --git a/jupyterhub_config.py b/jupyterhub_config.py index dd838ea..bde26fe 100644 --- a/jupyterhub_config.py +++ b/jupyterhub_config.py @@ -3,8 +3,6 @@ and overrides some of the default values from the plugin. """ -import getpass - from jupyterhub.auth import DummyAuthenticator from tljh.configurer import apply_config, load_config from tljh_repo2docker import tljh_custom_jupyterhub_config @@ -31,8 +29,6 @@ c.JupyterHub.authenticator_class = DummyAuthenticator -user = getpass.getuser() -c.Authenticator.admin_users = {user, "alice"} c.JupyterHub.allow_named_servers = True c.JupyterHub.ip = "0.0.0.0" @@ -55,19 +51,21 @@ ] ) + c.JupyterHub.load_roles = [ { "description": "Role for tljh_repo2docker service", - "name": "tljh_repo2docker_role", + "name": "tljh-repo2docker-service", "scopes": ["read:users", "read:servers", "read:roles:users"], "services": ["tljh_repo2docker"], }, + {"name": "tljh-repo2docker-service-admin", "users": ["alice"]}, { - "name": "env-user", + "name": "user", "scopes": [ + "self", # access to the env page - "access:services" + "access:services!service=tljh_repo2docker", ], - "users": ["trung"], }, ] diff --git a/tljh_repo2docker/__init__.py b/tljh_repo2docker/__init__.py index edcedb1..3204a4a 100644 --- a/tljh_repo2docker/__init__.py +++ b/tljh_repo2docker/__init__.py @@ -14,6 +14,8 @@ # See: https://docs.docker.com/config/containers/resource_constraints/#limit-a-containers-access-to-memory#configure-the-default-cfs-scheduler CPU_PERIOD = 100_000 +TLJH_R2D_ADMIN_ROLE = 'tljh-repo2docker-service-admin' + class SpawnerMixin(Configurable): """ diff --git a/tljh_repo2docker/base.py b/tljh_repo2docker/base.py index d835e15..902bff6 100644 --- a/tljh_repo2docker/base.py +++ b/tljh_repo2docker/base.py @@ -6,7 +6,9 @@ from jupyterhub.services.auth import HubOAuthenticated from jupyterhub.utils import url_path_join from tornado import web -from jupyterhub.scopes import needs_scope + +from tljh_repo2docker import TLJH_R2D_ADMIN_ROLE + from .model import UserModel @@ -35,8 +37,16 @@ async def fetch_user(self) -> UserModel: user_model: dict = response.json() user_model.setdefault("name", user["name"]) user_model.setdefault("servers", {}) + user_model.setdefault("roles", []) user_model.setdefault("admin", False) + if not user_model["admin"]: + if ( + "admin" in user_model["roles"] + or TLJH_R2D_ADMIN_ROLE in user_model["roles"] + ): + user_model["admin"] = True + return UserModel.from_dict(user_model) def get_template(self, name: str) -> Template: @@ -48,7 +58,7 @@ def get_template(self, name: str) -> Template: """ return self.settings["jinja2_env"].get_template(name) - def render_template(self, name: str, **kwargs) -> str: + async def render_template(self, name: str, **kwargs) -> str: """Render the given template with the provided arguments Args: name: Template name @@ -56,15 +66,17 @@ def render_template(self, name: str, **kwargs) -> str: Returns: The generated template """ - user = self.current_user + user = await self.fetch_user() + base_url = self.settings.get("base_url", "/") template_ns = dict( service_prefix=self.settings.get("service_prefix", "/"), hub_prefix=self.settings.get("hub_prefix", "/"), - base_url=self.settings.get("base_url", "/"), + base_url=base_url, + logout_url=self.settings.get("logout_url", url_path_join(base_url, 'logout')), static_url=self.static_url, xsrf_token=self.xsrf_token.decode("ascii"), user=user, - admin_access=user["admin"], + admin_access=user.admin, ) template_ns.update(kwargs) template = self.get_template(name) diff --git a/tljh_repo2docker/environments.py b/tljh_repo2docker/environments.py index 1925c05..70a2a73 100644 --- a/tljh_repo2docker/environments.py +++ b/tljh_repo2docker/environments.py @@ -1,6 +1,7 @@ from inspect import isawaitable from tornado import web + from .base import BaseHandler from .docker import list_containers, list_images @@ -12,9 +13,9 @@ class EnvironmentsHandler(BaseHandler): @web.authenticated async def get(self): - user = self.current_user + user = await self.fetch_user() - if not user["admin"]: + if not user.admin: raise web.HTTPError(status_code=404, reason="Unauthorized.") images = await list_images() containers = await list_containers() diff --git a/tljh_repo2docker/model.py b/tljh_repo2docker/model.py index 04de93d..b06343e 100644 --- a/tljh_repo2docker/model.py +++ b/tljh_repo2docker/model.py @@ -7,6 +7,7 @@ class UserModel: name: str admin: bool servers: dict + roles: list @classmethod def from_dict(self, kwargs_dict: dict): @@ -30,3 +31,4 @@ def all_spawners(self) -> list: } ) return sp + diff --git a/tljh_repo2docker/templates/page.html b/tljh_repo2docker/templates/page.html index 4dcac67..3e2a194 100644 --- a/tljh_repo2docker/templates/page.html +++ b/tljh_repo2docker/templates/page.html @@ -18,7 +18,7 @@ base_url: "{{base_url}}", hub_prefix: "{{hub_prefix}}", {% if user %} - user: "{{ user['name'] | safe }}", + user: "{{ user.name | safe }}", {% endif %} {% if admin_access %} admin_access: true, @@ -86,7 +86,7 @@ {% block login_widget %} {% if user %} - +