From 7dd4e4516ff34dc92a24e633d0e4749bb031656c Mon Sep 17 00:00:00 2001 From: Duc Trung Le Date: Wed, 1 Mar 2023 14:22:05 +0100 Subject: [PATCH] Add scope --- docs/source/_static/rest-api.yml | 3 +++ ...3c2384c5aae1_add_from_config_column_to_the_services_.py | 3 ++- jupyterhub/apihandlers/base.py | 5 ++--- jupyterhub/apihandlers/services.py | 7 ++++--- jupyterhub/app.py | 3 --- jupyterhub/handlers/base.py | 2 +- jupyterhub/roles.py | 1 + jupyterhub/scopes.py | 6 +++++- 8 files changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/source/_static/rest-api.yml b/docs/source/_static/rest-api.yml index b611f870..48e49d49 100644 --- a/docs/source/_static/rest-api.yml +++ b/docs/source/_static/rest-api.yml @@ -1498,6 +1498,9 @@ components: read:groups: Read group models. read:groups:name: Read group names. delete:groups: Delete groups. + admin:services: + Create, read, update, delete services, not including services + defined from config files. list:services: List services, including at least their names. read:services: Read service models. read:services:name: Read service names. diff --git a/jupyterhub/alembic/versions/3c2384c5aae1_add_from_config_column_to_the_services_.py b/jupyterhub/alembic/versions/3c2384c5aae1_add_from_config_column_to_the_services_.py index 31127621..4e5fe450 100644 --- a/jupyterhub/alembic/versions/3c2384c5aae1_add_from_config_column_to_the_services_.py +++ b/jupyterhub/alembic/versions/3c2384c5aae1_add_from_config_column_to_the_services_.py @@ -11,8 +11,8 @@ down_revision = '0eee8c825d24' branch_labels = None depends_on = None -from alembic import op import sqlalchemy as sa +from alembic import op def upgrade(): @@ -25,5 +25,6 @@ def upgrade(): ) op.execute('UPDATE services SET from_config = true') + def downgrade(): op.drop_column('services', sa.Column('from_config')) diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index aff0f914..f8bbd569 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -2,7 +2,6 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. import json -from typing import Union import warnings from functools import lru_cache from http.client import responses @@ -410,7 +409,7 @@ class APIHandler(BaseHandler): 'environment': dict, 'user': str, 'oauth_client_id': str, - 'oauth_redirect_uri': str + 'oauth_redirect_uri': str, } def _check_model(self, model, model_types, name): @@ -454,7 +453,7 @@ class APIHandler(BaseHandler): def _check_service_model(self, model): """Check a request-provided service model from a REST API""" self._check_model(model, self._service_model_types, 'service') - service_name = model.get('name') + service_name = model.get('name') if not isinstance(service_name, str): raise web.HTTPError( 400, ("Service name must be str, not %r", type(service_name)) diff --git a/jupyterhub/apihandlers/services.py b/jupyterhub/apihandlers/services.py index 0186c031..85c4ff95 100644 --- a/jupyterhub/apihandlers/services.py +++ b/jupyterhub/apihandlers/services.py @@ -6,9 +6,10 @@ Currently GET-only, no actions can be taken to modify services. # Distributed under the terms of the Modified BSD License. import json +from tornado import web + from ..scopes import Scope, needs_scope from .base import APIHandler -from tornado import web class ServiceListAPIHandler(APIHandler): @@ -29,7 +30,7 @@ class ServiceAPIHandler(APIHandler): service = self.services[service_name] self.write(json.dumps(self.service_model(service))) - @needs_scope('read:services', 'read:services:name', 'read:roles:services') + @needs_scope('admin:services') def post(self, service_name: str): data = self.get_json_body() service = self.find_service(service_name) @@ -39,7 +40,7 @@ class ServiceAPIHandler(APIHandler): if not data or not isinstance(data, dict): raise web.HTTPError(400, "Invalid service data") - + data['name'] = service_name self._check_service_model(data) self.service_from_spec(data) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 1e64536a..34217580 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2381,11 +2381,9 @@ class JupyterHub(Application): name = spec['name'] # get/create orm orm_service = orm.Service.find(self.db, name=name) - print('########### found', name, orm_service) if orm_service is None: # not found, create a new one orm_service = orm.Service(name=name, from_config=from_config) - print('########### adding', name, orm_service) self.db.add(orm_service) if spec.get('admin', False): self.log.warning( @@ -2396,7 +2394,6 @@ class JupyterHub(Application): ) roles.update_roles(self.db, entity=orm_service, roles=['admin']) orm_service.admin = spec.get('admin', False) - print('commiting db', name) self.db.commit() service = Service( parent=self, diff --git a/jupyterhub/handlers/base.py b/jupyterhub/handlers/base.py index 69216906..4bf7fcac 100644 --- a/jupyterhub/handlers/base.py +++ b/jupyterhub/handlers/base.py @@ -8,11 +8,11 @@ import math import random import re import time -from typing import Optional import uuid import warnings from datetime import datetime, timedelta from http.client import responses +from typing import Optional from urllib.parse import parse_qs, parse_qsl, urlencode, urlparse, urlunparse from jinja2 import TemplateNotFound diff --git a/jupyterhub/roles.py b/jupyterhub/roles.py index a53e5a53..3ae2d008 100644 --- a/jupyterhub/roles.py +++ b/jupyterhub/roles.py @@ -34,6 +34,7 @@ def get_default_roles(): 'admin-ui', 'admin:users', 'admin:servers', + 'admin:services', 'tokens', 'admin:groups', 'list:services', diff --git a/jupyterhub/scopes.py b/jupyterhub/scopes.py index 00170133..d7b91f16 100644 --- a/jupyterhub/scopes.py +++ b/jupyterhub/scopes.py @@ -123,6 +123,10 @@ scope_definitions = { 'delete:groups': { 'description': "Delete groups.", }, + 'admin:services': { + 'description': 'Create, read, update, delete services, not including services defined from config files.', + 'subscopes': ['list:services', 'read:services', 'read:roles:services'], + }, 'list:services': { 'description': 'List services, including at least their names.', 'subscopes': ['read:services:name'], @@ -435,7 +439,7 @@ def _expand_self_scope(username): @lru_cache(maxsize=65535) def _expand_scope(scope): - """Returns a scope and all all subscopes + """Returns a scope and all subscopes Arguments: scope (str): the scope to expand