From 1343a1e0229ad17a1a210ebd48e82a8a8b42d8a1 Mon Sep 17 00:00:00 2001 From: Zsailer Date: Fri, 10 Jan 2020 11:09:27 -0800 Subject: [PATCH] update authorized wrapper with resource --- jupyter_server/edit/handlers.py | 2 +- jupyter_server/files/handlers.py | 4 ++-- jupyter_server/kernelspecs/handlers.py | 4 ++-- jupyter_server/nbconvert/handlers.py | 5 +++++ jupyter_server/services/api/handlers.py | 6 +++-- jupyter_server/services/config/handlers.py | 9 ++++---- jupyter_server/services/contents/handlers.py | 22 +++++++++---------- jupyter_server/services/kernels/handlers.py | 14 ++++++------ .../services/kernelspecs/handlers.py | 4 ++-- jupyter_server/services/nbconvert/handlers.py | 5 +++-- jupyter_server/services/security/handlers.py | 4 +++- jupyter_server/services/sessions/handlers.py | 11 +++++----- jupyter_server/services/shutdown.py | 3 ++- jupyter_server/terminal/api_handlers.py | 10 ++++++--- jupyter_server/terminal/handlers.py | 6 +++-- jupyter_server/view/handlers.py | 5 +++-- 16 files changed, 65 insertions(+), 49 deletions(-) diff --git a/jupyter_server/edit/handlers.py b/jupyter_server/edit/handlers.py index 008c2c2d1b..598779eab4 100644 --- a/jupyter_server/edit/handlers.py +++ b/jupyter_server/edit/handlers.py @@ -14,7 +14,7 @@ class EditorHandler(JupyterHandler): """Render the text editor interface.""" @web.authenticated - @authorized('read') + @authorized("read", resource="editor") def get(self, path): path = path.strip('/') if not self.contents_manager.file_exists(path): diff --git a/jupyter_server/files/handlers.py b/jupyter_server/files/handlers.py index d8b39c25df..fd96b13da5 100644 --- a/jupyter_server/files/handlers.py +++ b/jupyter_server/files/handlers.py @@ -28,12 +28,12 @@ def content_security_policy(self): "; sandbox allow-scripts" @web.authenticated - @authorized('read') + @authorized("read", resource="files") def head(self, path): self.get(path, include_body=False) @web.authenticated - @authorized('read') + @authorized("read", resource="files") @gen.coroutine def get(self, path, include_body=True): cm = self.contents_manager diff --git a/jupyter_server/kernelspecs/handlers.py b/jupyter_server/kernelspecs/handlers.py index 73a9f61fa9..5677d4d94d 100644 --- a/jupyter_server/kernelspecs/handlers.py +++ b/jupyter_server/kernelspecs/handlers.py @@ -11,7 +11,7 @@ def initialize(self): web.StaticFileHandler.initialize(self, path='') @web.authenticated - @authorized("read") + @authorized("read", resource="kernelspecs") def get(self, kernel_name, path, include_body=True): ksm = self.kernel_spec_manager try: @@ -22,7 +22,7 @@ def get(self, kernel_name, path, include_body=True): return web.StaticFileHandler.get(self, path, include_body=include_body) @web.authenticated - @authorized("read") + @authorized("read", resource="kernelspecs") def head(self, kernel_name, path): return self.get(kernel_name, path, include_body=False) diff --git a/jupyter_server/nbconvert/handlers.py b/jupyter_server/nbconvert/handlers.py index fc8d9c961b..ca600047f4 100644 --- a/jupyter_server/nbconvert/handlers.py +++ b/jupyter_server/nbconvert/handlers.py @@ -19,6 +19,9 @@ from ipython_genutils.py3compat import cast_bytes from ipython_genutils import text +from jupyter_server.utils import authorized + + def find_resource_files(output_files_dir): files = [] for dirpath, dirnames, filenames in os.walk(output_files_dir): @@ -80,6 +83,7 @@ class NbconvertFileHandler(JupyterHandler): SUPPORTED_METHODS = ('GET',) @web.authenticated + @authorized("read", resource="nbconvert") def get(self, format, path): exporter = get_exporter(format, config=self.config, log=self.log) @@ -149,6 +153,7 @@ class NbconvertPostHandler(JupyterHandler): SUPPORTED_METHODS = ('POST',) @web.authenticated + @authorized("write", resource="nbconvert") def post(self, format): exporter = get_exporter(format, config=self.config) diff --git a/jupyter_server/services/api/handlers.py b/jupyter_server/services/api/handlers.py index c5859ab527..753842b7ce 100644 --- a/jupyter_server/services/api/handlers.py +++ b/jupyter_server/services/api/handlers.py @@ -8,9 +8,9 @@ from tornado import gen, web -from ...base.handlers import JupyterHandler, APIHandler +from jupyter_server.base.handlers import JupyterHandler, APIHandler from jupyter_server._tz import utcfromtimestamp, isoformat -from jupyter_server.utils import maybe_future +from jupyter_server.utils import maybe_future, authorized class APISpecHandler(web.StaticFileHandler, JupyterHandler): @@ -19,6 +19,7 @@ def initialize(self): web.StaticFileHandler.initialize(self, path=os.path.dirname(__file__)) @web.authenticated + @authorized("read", resource="api") def get(self): self.log.warning("Serving api spec (experimental, incomplete)") return web.StaticFileHandler.get(self, 'api.yaml') @@ -32,6 +33,7 @@ class APIStatusHandler(APIHandler): _track_activity = False @web.authenticated + @authorized("read", resource="api") @gen.coroutine def get(self): # if started was missing, use unix epoch diff --git a/jupyter_server/services/config/handlers.py b/jupyter_server/services/config/handlers.py index 6a42b151db..873055b0e6 100644 --- a/jupyter_server/services/config/handlers.py +++ b/jupyter_server/services/config/handlers.py @@ -9,28 +9,27 @@ from tornado import web from ipython_genutils.py3compat import PY3 -from ...base.handlers import APIHandler - +from jupyter_server.base.handlers import APIHandler from jupyter_server.utils import authorized class ConfigHandler(APIHandler): @web.authenticated - @authorized('read') + @authorized("read", resource="config") def get(self, section_name): self.set_header("Content-Type", 'application/json') self.finish(json.dumps(self.config_manager.get(section_name))) @web.authenticated - @authorized('write') + @authorized("write", resource="config") def put(self, section_name): data = self.get_json_body() # Will raise 400 if content is not valid JSON self.config_manager.set(section_name, data) self.set_status(204) @web.authenticated - @authorized('write') + @authorized("write", resource="config") def patch(self, section_name): new_data = self.get_json_body() section = self.config_manager.update(section_name, new_data) diff --git a/jupyter_server/services/contents/handlers.py b/jupyter_server/services/contents/handlers.py index f8915cf353..e06c79813a 100644 --- a/jupyter_server/services/contents/handlers.py +++ b/jupyter_server/services/contents/handlers.py @@ -16,9 +16,9 @@ from jupyter_server.base.handlers import ( JupyterHandler, APIHandler, path_regex, ) - from jupyter_server.utils import authorized + def validate_model(model, expect_content): """ Validate a model returned by a ContentsManager method. @@ -89,7 +89,7 @@ def _finish_model(self, model, location=True): self.finish(json.dumps(model, default=date_default)) @web.authenticated - @authorized('read', resource='contents') + @authorized("read", resource="contents") @gen.coroutine def get(self, path=''): """Return a model for a file or directory. @@ -117,7 +117,7 @@ def get(self, path=''): self._finish_model(model, location=False) @web.authenticated - @authorized('write', resource='contents') + @authorized("write", resource="contents") @gen.coroutine def patch(self, path=''): """PATCH renames a file or directory without re-uploading content.""" @@ -170,7 +170,7 @@ def _save(self, model, path): self._finish_model(model) @web.authenticated - @authorized('write', resource='contents') + @authorized("write", resource="contents") @gen.coroutine def post(self, path=''): """Create a new file in the specified path. @@ -208,7 +208,7 @@ def post(self, path=''): yield self._new_untitled(path) @web.authenticated - @authorized('write', resource='contents') + @authorized("write", resource="contents") @gen.coroutine def put(self, path=''): """Saves the file in the location specified by name and path. @@ -234,7 +234,7 @@ def put(self, path=''): yield maybe_future(self._new_untitled(path)) @web.authenticated - @authorized('write', resource='contents') + @authorized("write", resource="contents") @gen.coroutine def delete(self, path=''): """delete a file in the given path""" @@ -248,7 +248,7 @@ def delete(self, path=''): class CheckpointsHandler(APIHandler): @web.authenticated - @authorized('read', resource='checkpoints') + @authorized("read", resource="contents") @gen.coroutine def get(self, path=''): """get lists checkpoints for a file""" @@ -258,7 +258,7 @@ def get(self, path=''): self.finish(data) @web.authenticated - @authorized('write', resource='checkpoints') + @authorized("write", resource="contents") @gen.coroutine def post(self, path=''): """post creates a new checkpoint""" @@ -275,7 +275,7 @@ def post(self, path=''): class ModifyCheckpointsHandler(APIHandler): @web.authenticated - @authorized('write', resource='checkpoints') + @authorized("write", resource="contents") @gen.coroutine def post(self, path, checkpoint_id): """post restores a file from a checkpoint""" @@ -285,7 +285,7 @@ def post(self, path, checkpoint_id): self.finish() @web.authenticated - @authorized('write', resource='checkpoints') + @authorized("write", resource="contents") @gen.coroutine def delete(self, path, checkpoint_id): """delete clears a checkpoint for a given file""" @@ -314,7 +314,7 @@ class TrustNotebooksHandler(JupyterHandler): """ Handles trust/signing of notebooks """ @web.authenticated - @authorized('write', resource='trust_notebook') + @authorized("write", resource="contents") @gen.coroutine def post(self,path=''): cm = self.contents_manager diff --git a/jupyter_server/services/kernels/handlers.py b/jupyter_server/services/kernels/handlers.py index 6fa16f3d94..655e9cb3db 100644 --- a/jupyter_server/services/kernels/handlers.py +++ b/jupyter_server/services/kernels/handlers.py @@ -19,15 +19,15 @@ from ipython_genutils.py3compat import cast_unicode from jupyter_server.utils import url_path_join, url_escape, maybe_future -from ...base.handlers import APIHandler -from ...base.zmqhandlers import AuthenticatedZMQStreamHandler, deserialize_binary_message +from jupyter_server.base.handlers import APIHandler +from jupyter_server.base.zmqhandlers import AuthenticatedZMQStreamHandler, deserialize_binary_message from jupyter_server.utils import authorized class MainKernelHandler(APIHandler): @web.authenticated - @authorized('read', resource='kernels') + @authorized("read", resource="kernels") @gen.coroutine def get(self): km = self.kernel_manager @@ -35,7 +35,7 @@ def get(self): self.finish(json.dumps(kernels, default=date_default)) @web.authenticated - @authorized('write', resource='kernels') + @authorized("write", resource="kernels") @gen.coroutine def post(self): km = self.kernel_manager @@ -58,14 +58,14 @@ def post(self): class KernelHandler(APIHandler): @web.authenticated - @authorized('read', resource='kernels') + @authorized("read", resource="kernels") def get(self, kernel_id): km = self.kernel_manager model = km.kernel_model(kernel_id) self.finish(json.dumps(model, default=date_default)) @web.authenticated - @authorized('write', resource='kernels') + @authorized("write", resource="kernels") @gen.coroutine def delete(self, kernel_id): km = self.kernel_manager @@ -77,7 +77,7 @@ def delete(self, kernel_id): class KernelActionHandler(APIHandler): @web.authenticated - @authorized('write', resource='kernels') + @authorized("write", resource="kernels") @gen.coroutine def post(self, kernel_id, action): km = self.kernel_manager diff --git a/jupyter_server/services/kernelspecs/handlers.py b/jupyter_server/services/kernelspecs/handlers.py index abb8412631..fe6a1bccf5 100644 --- a/jupyter_server/services/kernelspecs/handlers.py +++ b/jupyter_server/services/kernelspecs/handlers.py @@ -56,7 +56,7 @@ def is_kernelspec_model(spec_dict): class MainKernelSpecHandler(APIHandler): @web.authenticated - @authorized('read', resource='kernelspecs') + @authorized("read", resource="kernelspecs") @gen.coroutine def get(self): ksm = self.kernel_spec_manager @@ -82,7 +82,7 @@ def get(self): class KernelSpecHandler(APIHandler): @web.authenticated - @authorized('read', resource='kernelspecs') + @authorized("read", resource="kernelspecs") @gen.coroutine def get(self, kernel_name): ksm = self.kernel_spec_manager diff --git a/jupyter_server/services/nbconvert/handlers.py b/jupyter_server/services/nbconvert/handlers.py index 63e731238f..bab2a9d726 100644 --- a/jupyter_server/services/nbconvert/handlers.py +++ b/jupyter_server/services/nbconvert/handlers.py @@ -2,12 +2,13 @@ from tornado import web -from ...base.handlers import APIHandler - +from jupyter_server.base.handlers import APIHandler +from jupyter_server.utils import authorized class NbconvertRootHandler(APIHandler): @web.authenticated + @authorized("read", resource="nbconvert") def get(self): try: from nbconvert.exporters import base diff --git a/jupyter_server/services/security/handlers.py b/jupyter_server/services/security/handlers.py index 82a00d234b..d0629bf8d0 100644 --- a/jupyter_server/services/security/handlers.py +++ b/jupyter_server/services/security/handlers.py @@ -5,7 +5,8 @@ from tornado import web -from ...base.handlers import APIHandler +from jupyter_server.base.handlers import APIHandler +from jupyter_server.utils import authorized from . import csp_report_uri class CSPReportHandler(APIHandler): @@ -22,6 +23,7 @@ def check_xsrf_cookie(self): return @web.authenticated + @authorized("write", resource="csp") def post(self): '''Log a content security policy violation report''' self.log.warning("Content security violation: %s", diff --git a/jupyter_server/services/sessions/handlers.py b/jupyter_server/services/sessions/handlers.py index 60182db384..e888e26699 100644 --- a/jupyter_server/services/sessions/handlers.py +++ b/jupyter_server/services/sessions/handlers.py @@ -14,14 +14,13 @@ from jupyter_client.jsonutil import date_default from jupyter_server.utils import maybe_future, url_path_join from jupyter_client.kernelspec import NoSuchKernel - from jupyter_server.utils import authorized class SessionRootHandler(APIHandler): @web.authenticated - @authorized('read', resource='sessions') + @authorized("read", resource="sessions") @gen.coroutine def get(self): # Return a list of running sessions @@ -30,7 +29,7 @@ def get(self): self.finish(json.dumps(sessions, default=date_default)) @web.authenticated - @authorized('write', resource='sessions') + @authorized("write", resource="sessions") @gen.coroutine def post(self): # Creates a new session @@ -92,7 +91,7 @@ def post(self): class SessionHandler(APIHandler): @web.authenticated - @authorized('read', resource='sessions') + @authorized("read", resource="sessions") @gen.coroutine def get(self, session_id): # Returns the JSON model for a single session @@ -101,7 +100,7 @@ def get(self, session_id): self.finish(json.dumps(model, default=date_default)) @web.authenticated - @authorized('write', resource='sessions') + @authorized("write", resource="sessions") @gen.coroutine def patch(self, session_id): """Patch updates sessions: @@ -155,7 +154,7 @@ def patch(self, session_id): self.finish(json.dumps(model, default=date_default)) @web.authenticated - @authorized('write', resource='sessions') + @authorized("write", resource="sessions") @gen.coroutine def delete(self, session_id): # Deletes the session with given session_id diff --git a/jupyter_server/services/shutdown.py b/jupyter_server/services/shutdown.py index c7f5361c42..586d0683f5 100644 --- a/jupyter_server/services/shutdown.py +++ b/jupyter_server/services/shutdown.py @@ -2,10 +2,11 @@ """ from tornado import web, ioloop from jupyter_server.base.handlers import JupyterHandler - +from jupyter_server.utils import authorized class ShutdownHandler(JupyterHandler): @web.authenticated + @authorized("write", resource="shutdown") def post(self): self.log.info("Shutting down on /api/shutdown request.") ioloop.IOLoop.current().stop() diff --git a/jupyter_server/terminal/api_handlers.py b/jupyter_server/terminal/api_handlers.py index d64e1acb3f..59aec8189c 100644 --- a/jupyter_server/terminal/api_handlers.py +++ b/jupyter_server/terminal/api_handlers.py @@ -1,13 +1,14 @@ import json from tornado import web, gen -from ..base.handlers import APIHandler -from ..prometheus.metrics import TERMINAL_CURRENTLY_RUNNING_TOTAL - +from jupyter_server.base.handlers import APIHandler +from jupyter_server.prometheus.metrics import TERMINAL_CURRENTLY_RUNNING_TOTAL +from jupyter_server.utils import authorized class TerminalRootHandler(APIHandler): @web.authenticated + @authorized("read", resource="terminal") def get(self): tm = self.terminal_manager terms = [{'name': name} for name in tm.terminals] @@ -19,6 +20,7 @@ def get(self): ) @web.authenticated + @authorized("write", resource="terminal") def post(self): """POST /terminals creates a new terminal and redirects to it""" name, _ = self.terminal_manager.new_named_terminal() @@ -32,6 +34,7 @@ class TerminalHandler(APIHandler): SUPPORTED_METHODS = ('GET', 'DELETE') @web.authenticated + @authorized("read", resource="terminal") def get(self, name): tm = self.terminal_manager if name in tm.terminals: @@ -40,6 +43,7 @@ def get(self, name): raise web.HTTPError(404, "Terminal not found: %r" % name) @web.authenticated + @authorized("write", resource="terminal") @gen.coroutine def delete(self, name): tm = self.terminal_manager diff --git a/jupyter_server/terminal/handlers.py b/jupyter_server/terminal/handlers.py index 231ede1f39..fcf7170326 100644 --- a/jupyter_server/terminal/handlers.py +++ b/jupyter_server/terminal/handlers.py @@ -7,13 +7,15 @@ from tornado import web import terminado from jupyter_server._tz import utcnow -from ..base.handlers import JupyterHandler -from ..base.zmqhandlers import WebSocketMixin +from jupyter_server.utils import authorized +from jupyter_server.base.handlers import JupyterHandler +from jupyter_server.base.zmqhandlers import WebSocketMixin class TerminalHandler(JupyterHandler): """Render the terminal interface.""" @web.authenticated + @authorized("read", resource="terminal") def get(self, term_name): self.write(self.render_template('terminal.html', ws_path="terminals/websocket/%s" % term_name)) diff --git a/jupyter_server/view/handlers.py b/jupyter_server/view/handlers.py index 5663d4db3a..5f761a3d93 100644 --- a/jupyter_server/view/handlers.py +++ b/jupyter_server/view/handlers.py @@ -5,13 +5,14 @@ # Distributed under the terms of the Modified BSD License. from tornado import web -from ..base.handlers import JupyterHandler, path_regex -from ..utils import url_escape, url_path_join +from jupyter_server.base.handlers import JupyterHandler, path_regex +from jupyter_server.utils import url_escape, url_path_join, authorized class ViewHandler(JupyterHandler): """Render HTML files within an iframe.""" @web.authenticated + @authorized("read", resource="view") def get(self, path): path = path.strip('/') if not self.contents_manager.file_exists(path):