From 8cac83fc966e6bf843e8342e2e4a55713fbbb9a9 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 21 Sep 2021 14:39:27 +0200 Subject: [PATCH] add delete scopes for users, groups, servers e.g. cull-idle services do not need permission to start servers in order to be able to stop them --- jupyterhub/apihandlers/groups.py | 2 +- jupyterhub/apihandlers/users.py | 4 ++-- jupyterhub/roles.py | 1 + jupyterhub/scopes.py | 13 ++++++++++--- jupyterhub/tests/test_roles.py | 3 +++ 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/jupyterhub/apihandlers/groups.py b/jupyterhub/apihandlers/groups.py index 80f86ea7..04493796 100644 --- a/jupyterhub/apihandlers/groups.py +++ b/jupyterhub/apihandlers/groups.py @@ -129,7 +129,7 @@ class GroupAPIHandler(_GroupAPIHandler): self.write(json.dumps(self.group_model(group))) self.set_status(201) - @needs_scope('admin:groups') + @needs_scope('delete:groups') def delete(self, group_name): """Delete a group by name""" group = self.find_group(group_name) diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py index fb480df8..e36faf9e 100644 --- a/jupyterhub/apihandlers/users.py +++ b/jupyterhub/apihandlers/users.py @@ -266,7 +266,7 @@ class UserAPIHandler(APIHandler): self.write(json.dumps(self.user_model(user))) self.set_status(201) - @needs_scope('admin:users') + @needs_scope('delete:users') async def delete(self, user_name): user = self.find_user(user_name) if user is None: @@ -525,7 +525,7 @@ class UserServerAPIHandler(APIHandler): self.set_header('Content-Type', 'text/plain') self.set_status(status) - @needs_scope('servers') + @needs_scope('delete:servers') async def delete(self, user_name, server_name=''): user = self.find_user(user_name) options = self.get_json_body() diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index 9a786409..7ac5382a 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -89,6 +89,7 @@ def expand_self_scope(name): 'users:activity', 'read:users:activity', 'servers', + 'delete:servers', 'read:servers', 'tokens', 'read:tokens', diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 6884e1b4..5559f5a4 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -36,13 +36,16 @@ scope_definitions = { }, 'admin:users': { 'description': 'Read, write, create and delete users and their authentication state, not including their servers or tokens.', - 'subscopes': ['admin:auth_state', 'users', 'read:roles:users'], + 'subscopes': ['admin:auth_state', 'users', 'read:roles:users', 'delete:users'], }, 'admin:auth_state': {'description': 'Read a user’s authentication state.'}, 'users': { 'description': 'Read and write permissions to user models (excluding servers, tokens and authentication state).', 'subscopes': ['read:users', 'list:users', 'users:activity'], }, + 'delete:users': { + 'description': "Delete users.", + }, 'list:users': { 'description': 'List users, including at least their names.', 'subscopes': ['read:users:name'], @@ -76,12 +79,13 @@ scope_definitions = { 'admin:server_state': {'description': 'Read and write users’ server state.'}, 'servers': { 'description': 'Start and stop user servers.', - 'subscopes': ['read:servers'], + 'subscopes': ['read:servers', 'delete:servers'], }, 'read:servers': { 'description': 'Read users’ names and their server models (excluding the server state).', 'subscopes': ['read:users:name'], }, + 'delete:servers': {'description': "Stop and delete users' servers."}, 'tokens': { 'description': 'Read, write, create and delete user tokens.', 'subscopes': ['read:tokens'], @@ -89,7 +93,7 @@ scope_definitions = { 'read:tokens': {'description': 'Read user tokens.'}, 'admin:groups': { 'description': 'Read and write group information, create and delete groups.', - 'subscopes': ['groups', 'read:roles:groups'], + 'subscopes': ['groups', 'read:roles:groups', 'delete:groups'], }, 'groups': { 'description': 'Read and write group information, including adding/removing users to/from groups.', @@ -104,6 +108,9 @@ scope_definitions = { 'subscopes': ['read:groups:name'], }, 'read:groups:name': {'description': 'Read group names.'}, + 'delete:groups': { + 'description': "Delete groups.", + }, 'list:services': { 'description': 'List services, including at least their names.', 'subscopes': ['read:services:name'], diff --git a/jupyterhub/tests/test_roles.py b/jupyterhub/tests/test_roles.py index 543a6df0..9c6e66fb 100644 --- a/jupyterhub/tests/test_roles.py +++ b/jupyterhub/tests/test_roles.py @@ -182,6 +182,7 @@ def test_orm_roles_delete_cascade(db): 'admin:users', 'admin:auth_state', 'users', + 'delete:users', 'list:users', 'read:users', 'users:activity', @@ -218,6 +219,7 @@ def test_orm_roles_delete_cascade(db): { 'admin:groups', 'groups', + 'delete:groups', 'list:groups', 'read:groups', 'read:roles:groups', @@ -229,6 +231,7 @@ def test_orm_roles_delete_cascade(db): { 'admin:groups', 'groups', + 'delete:groups', 'list:groups', 'read:groups', 'read:roles:groups',