Show More
@@ -43,15 +43,23 b' sys_info = json.dumps(get_sys_info())' | |||||
43 | class AuthenticatedHandler(web.RequestHandler): |
|
43 | class AuthenticatedHandler(web.RequestHandler): | |
44 | """A RequestHandler with an authenticated user.""" |
|
44 | """A RequestHandler with an authenticated user.""" | |
45 |
|
45 | |||
|
46 | @property | |||
|
47 | def content_security_policy(self): | |||
|
48 | """The default Content-Security-Policy header | |||
|
49 | ||||
|
50 | Can be overridden by defining Content-Security-Policy in settings['headers'] | |||
|
51 | """ | |||
|
52 | return '; '.join([ | |||
|
53 | "frame-ancestors 'self'", | |||
|
54 | # Make sure the report-uri is relative to the base_url | |||
|
55 | "report-uri " + url_path_join(self.base_url, csp_report_uri), | |||
|
56 | ]) | |||
|
57 | ||||
46 | def set_default_headers(self): |
|
58 | def set_default_headers(self): | |
47 | headers = self.settings.get('headers', {}) |
|
59 | headers = self.settings.get('headers', {}) | |
48 |
|
60 | |||
49 | if "Content-Security-Policy" not in headers: |
|
61 | if "Content-Security-Policy" not in headers: | |
50 |
headers["Content-Security-Policy"] = |
|
62 | headers["Content-Security-Policy"] = self.content_security_policy | |
51 | "frame-ancestors 'self'; " |
|
|||
52 | # Make sure the report-uri is relative to the base_url |
|
|||
53 | "report-uri " + url_path_join(self.base_url, csp_report_uri) + ";" |
|
|||
54 | ) |
|
|||
55 |
|
63 | |||
56 | # Allow for overriding headers |
|
64 | # Allow for overriding headers | |
57 | for header_name,value in headers.items() : |
|
65 | for header_name,value in headers.items() : | |
@@ -309,6 +317,21 b' class IPythonHandler(AuthenticatedHandler):' | |||||
309 | self.write(html) |
|
317 | self.write(html) | |
310 |
|
318 | |||
311 |
|
319 | |||
|
320 | class APIHandler(IPythonHandler): | |||
|
321 | """Base class for API handlers""" | |||
|
322 | ||||
|
323 | @property | |||
|
324 | def content_security_policy(self): | |||
|
325 | csp = '; '.join([ | |||
|
326 | super(APIHandler, self).content_security_policy, | |||
|
327 | "default-src 'none'", | |||
|
328 | ]) | |||
|
329 | return csp | |||
|
330 | ||||
|
331 | def finish(self, *args, **kwargs): | |||
|
332 | self.set_header('Content-Type', 'application/json') | |||
|
333 | return super(APIHandler, self).finish(*args, **kwargs) | |||
|
334 | ||||
312 |
|
335 | |||
313 | class Template404(IPythonHandler): |
|
336 | class Template404(IPythonHandler): | |
314 | """Render our 404 template""" |
|
337 | """Render our 404 template""" | |
@@ -370,6 +393,7 b' def json_errors(method):' | |||||
370 | try: |
|
393 | try: | |
371 | result = yield gen.maybe_future(method(self, *args, **kwargs)) |
|
394 | result = yield gen.maybe_future(method(self, *args, **kwargs)) | |
372 | except web.HTTPError as e: |
|
395 | except web.HTTPError as e: | |
|
396 | self.set_header('Content-Type', 'application/json') | |||
373 | status = e.status_code |
|
397 | status = e.status_code | |
374 | message = e.log_message |
|
398 | message = e.log_message | |
375 | self.log.warn(message) |
|
399 | self.log.warn(message) | |
@@ -377,6 +401,7 b' def json_errors(method):' | |||||
377 | reply = dict(message=message, reason=e.reason) |
|
401 | reply = dict(message=message, reason=e.reason) | |
378 | self.finish(json.dumps(reply)) |
|
402 | self.finish(json.dumps(reply)) | |
379 | except Exception: |
|
403 | except Exception: | |
|
404 | self.set_header('Content-Type', 'application/json') | |||
380 | self.log.error("Unhandled error in API request", exc_info=True) |
|
405 | self.log.error("Unhandled error in API request", exc_info=True) | |
381 | status = 500 |
|
406 | status = 500 | |
382 | message = "Unknown server error" |
|
407 | message = "Unknown server error" | |
@@ -399,7 +424,7 b' def json_errors(method):' | |||||
399 | # to minimize subclass changes: |
|
424 | # to minimize subclass changes: | |
400 | HTTPError = web.HTTPError |
|
425 | HTTPError = web.HTTPError | |
401 |
|
426 | |||
402 | class FileFindHandler(web.StaticFileHandler): |
|
427 | class FileFindHandler(IPythonHandler, web.StaticFileHandler): | |
403 | """subclass of StaticFileHandler for serving files from a search path""" |
|
428 | """subclass of StaticFileHandler for serving files from a search path""" | |
404 |
|
429 | |||
405 | # cache search results, don't search for files more than once |
|
430 | # cache search results, don't search for files more than once | |
@@ -453,7 +478,7 b' class FileFindHandler(web.StaticFileHandler):' | |||||
453 | return super(FileFindHandler, self).validate_absolute_path(root, absolute_path) |
|
478 | return super(FileFindHandler, self).validate_absolute_path(root, absolute_path) | |
454 |
|
479 | |||
455 |
|
480 | |||
456 |
class A |
|
481 | class APIVersionHandler(APIHandler): | |
457 |
|
482 | |||
458 | @json_errors |
|
483 | @json_errors | |
459 | def get(self): |
|
484 | def get(self): | |
@@ -524,5 +549,5 b' path_regex = r"(?P<path>(?:(?:/[^/]+)+|/?))"' | |||||
524 |
|
549 | |||
525 | default_handlers = [ |
|
550 | default_handlers = [ | |
526 | (r".*/", TrailingSlashHandler), |
|
551 | (r".*/", TrailingSlashHandler), | |
527 |
(r"api", A |
|
552 | (r"api", APIVersionHandler) | |
528 | ] |
|
553 | ] |
@@ -7,28 +7,28 b' import json' | |||||
7 |
|
7 | |||
8 | from tornado import web |
|
8 | from tornado import web | |
9 |
|
9 | |||
10 |
from ...base.handlers import |
|
10 | from ...base.handlers import APIHandler | |
11 |
|
11 | |||
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 | # Cluster handlers |
|
13 | # Cluster handlers | |
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 |
|
15 | |||
16 |
|
16 | |||
17 |
class MainClusterHandler( |
|
17 | class MainClusterHandler(APIHandler): | |
18 |
|
18 | |||
19 | @web.authenticated |
|
19 | @web.authenticated | |
20 | def get(self): |
|
20 | def get(self): | |
21 | self.finish(json.dumps(self.cluster_manager.list_profiles())) |
|
21 | self.finish(json.dumps(self.cluster_manager.list_profiles())) | |
22 |
|
22 | |||
23 |
|
23 | |||
24 |
class ClusterProfileHandler( |
|
24 | class ClusterProfileHandler(APIHandler): | |
25 |
|
25 | |||
26 | @web.authenticated |
|
26 | @web.authenticated | |
27 | def get(self, profile): |
|
27 | def get(self, profile): | |
28 | self.finish(json.dumps(self.cluster_manager.profile_info(profile))) |
|
28 | self.finish(json.dumps(self.cluster_manager.profile_info(profile))) | |
29 |
|
29 | |||
30 |
|
30 | |||
31 |
class ClusterActionHandler( |
|
31 | class ClusterActionHandler(APIHandler): | |
32 |
|
32 | |||
33 | @web.authenticated |
|
33 | @web.authenticated | |
34 | def post(self, profile, action): |
|
34 | def post(self, profile, action): |
@@ -9,9 +9,9 b' import errno' | |||||
9 | from tornado import web |
|
9 | from tornado import web | |
10 |
|
10 | |||
11 | from IPython.utils.py3compat import PY3 |
|
11 | from IPython.utils.py3compat import PY3 | |
12 |
from ...base.handlers import |
|
12 | from ...base.handlers import APIHandler, json_errors | |
13 |
|
13 | |||
14 |
class ConfigHandler( |
|
14 | class ConfigHandler(APIHandler): | |
15 | SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH') |
|
15 | SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH') | |
16 |
|
16 | |||
17 | @web.authenticated |
|
17 | @web.authenticated |
@@ -11,7 +11,7 b' from IPython.html.utils import url_path_join, url_escape' | |||||
11 | from IPython.utils.jsonutil import date_default |
|
11 | from IPython.utils.jsonutil import date_default | |
12 |
|
12 | |||
13 | from IPython.html.base.handlers import ( |
|
13 | from IPython.html.base.handlers import ( | |
14 | IPythonHandler, json_errors, path_regex, |
|
14 | IPythonHandler, APIHandler, json_errors, path_regex, | |
15 | ) |
|
15 | ) | |
16 |
|
16 | |||
17 |
|
17 | |||
@@ -75,7 +75,7 b' def validate_model(model, expect_content):' | |||||
75 | ) |
|
75 | ) | |
76 |
|
76 | |||
77 |
|
77 | |||
78 |
class ContentsHandler( |
|
78 | class ContentsHandler(APIHandler): | |
79 |
|
79 | |||
80 | SUPPORTED_METHODS = (u'GET', u'PUT', u'PATCH', u'POST', u'DELETE') |
|
80 | SUPPORTED_METHODS = (u'GET', u'PUT', u'PATCH', u'POST', u'DELETE') | |
81 |
|
81 | |||
@@ -257,7 +257,7 b' class ContentsHandler(IPythonHandler):' | |||||
257 | self.finish() |
|
257 | self.finish() | |
258 |
|
258 | |||
259 |
|
259 | |||
260 |
class CheckpointsHandler( |
|
260 | class CheckpointsHandler(APIHandler): | |
261 |
|
261 | |||
262 | SUPPORTED_METHODS = ('GET', 'POST') |
|
262 | SUPPORTED_METHODS = ('GET', 'POST') | |
263 |
|
263 | |||
@@ -286,7 +286,7 b' class CheckpointsHandler(IPythonHandler):' | |||||
286 | self.finish(data) |
|
286 | self.finish(data) | |
287 |
|
287 | |||
288 |
|
288 | |||
289 |
class ModifyCheckpointsHandler( |
|
289 | class ModifyCheckpointsHandler(APIHandler): | |
290 |
|
290 | |||
291 | SUPPORTED_METHODS = ('POST', 'DELETE') |
|
291 | SUPPORTED_METHODS = ('POST', 'DELETE') | |
292 |
|
292 |
@@ -13,12 +13,12 b' from IPython.utils.jsonutil import date_default' | |||||
13 | from IPython.utils.py3compat import cast_unicode |
|
13 | from IPython.utils.py3compat import cast_unicode | |
14 | from IPython.html.utils import url_path_join, url_escape |
|
14 | from IPython.html.utils import url_path_join, url_escape | |
15 |
|
15 | |||
16 | from ...base.handlers import IPythonHandler, json_errors |
|
16 | from ...base.handlers import IPythonHandler, APIHandler, json_errors | |
17 | from ...base.zmqhandlers import AuthenticatedZMQStreamHandler, deserialize_binary_message |
|
17 | from ...base.zmqhandlers import AuthenticatedZMQStreamHandler, deserialize_binary_message | |
18 |
|
18 | |||
19 | from IPython.core.release import kernel_protocol_version |
|
19 | from IPython.core.release import kernel_protocol_version | |
20 |
|
20 | |||
21 |
class MainKernelHandler( |
|
21 | class MainKernelHandler(APIHandler): | |
22 |
|
22 | |||
23 | @web.authenticated |
|
23 | @web.authenticated | |
24 | @json_errors |
|
24 | @json_errors | |
@@ -46,7 +46,7 b' class MainKernelHandler(IPythonHandler):' | |||||
46 | self.finish(json.dumps(model)) |
|
46 | self.finish(json.dumps(model)) | |
47 |
|
47 | |||
48 |
|
48 | |||
49 |
class KernelHandler( |
|
49 | class KernelHandler(APIHandler): | |
50 |
|
50 | |||
51 | SUPPORTED_METHODS = ('DELETE', 'GET') |
|
51 | SUPPORTED_METHODS = ('DELETE', 'GET') | |
52 |
|
52 | |||
@@ -67,7 +67,7 b' class KernelHandler(IPythonHandler):' | |||||
67 | self.finish() |
|
67 | self.finish() | |
68 |
|
68 | |||
69 |
|
69 | |||
70 |
class KernelActionHandler( |
|
70 | class KernelActionHandler(APIHandler): | |
71 |
|
71 | |||
72 | @web.authenticated |
|
72 | @web.authenticated | |
73 | @json_errors |
|
73 | @json_errors |
@@ -68,6 +68,7 b' class KernelAPITest(NotebookTestBase):' | |||||
68 | self.assertEqual(r.headers['Content-Security-Policy'], ( |
|
68 | self.assertEqual(r.headers['Content-Security-Policy'], ( | |
69 | "frame-ancestors 'self'; " |
|
69 | "frame-ancestors 'self'; " | |
70 | "report-uri /api/security/csp-report;" |
|
70 | "report-uri /api/security/csp-report; " | |
|
71 | "default-src 'none'" | |||
71 | )) |
|
72 | )) | |
72 |
|
73 | |||
73 | def test_main_kernel_handler(self): |
|
74 | def test_main_kernel_handler(self): | |
@@ -81,6 +82,7 b' class KernelAPITest(NotebookTestBase):' | |||||
81 | self.assertEqual(r.headers['Content-Security-Policy'], ( |
|
82 | self.assertEqual(r.headers['Content-Security-Policy'], ( | |
82 | "frame-ancestors 'self'; " |
|
83 | "frame-ancestors 'self'; " | |
83 | "report-uri /api/security/csp-report;" |
|
84 | "report-uri /api/security/csp-report; " | |
|
85 | "default-src 'none'" | |||
84 | )) |
|
86 | )) | |
85 |
|
87 | |||
86 | # GET request |
|
88 | # GET request |
@@ -10,7 +10,7 b' pjoin = os.path.join' | |||||
10 |
|
10 | |||
11 | from tornado import web |
|
11 | from tornado import web | |
12 |
|
12 | |||
13 |
from ...base.handlers import |
|
13 | from ...base.handlers import APIHandler, json_errors | |
14 | from ...utils import url_path_join |
|
14 | from ...utils import url_path_join | |
15 |
|
15 | |||
16 | def kernelspec_model(handler, name): |
|
16 | def kernelspec_model(handler, name): | |
@@ -40,7 +40,7 b' def kernelspec_model(handler, name):' | |||||
40 | ) |
|
40 | ) | |
41 | return d |
|
41 | return d | |
42 |
|
42 | |||
43 |
class MainKernelSpecHandler( |
|
43 | class MainKernelSpecHandler(APIHandler): | |
44 | SUPPORTED_METHODS = ('GET',) |
|
44 | SUPPORTED_METHODS = ('GET',) | |
45 |
|
45 | |||
46 | @web.authenticated |
|
46 | @web.authenticated | |
@@ -62,7 +62,7 b' class MainKernelSpecHandler(IPythonHandler):' | |||||
62 | self.finish(json.dumps(model)) |
|
62 | self.finish(json.dumps(model)) | |
63 |
|
63 | |||
64 |
|
64 | |||
65 |
class KernelSpecHandler( |
|
65 | class KernelSpecHandler(APIHandler): | |
66 | SUPPORTED_METHODS = ('GET',) |
|
66 | SUPPORTED_METHODS = ('GET',) | |
67 |
|
67 | |||
68 | @web.authenticated |
|
68 | @web.authenticated |
@@ -2,9 +2,9 b' import json' | |||||
2 |
|
2 | |||
3 | from tornado import web |
|
3 | from tornado import web | |
4 |
|
4 | |||
5 |
from ...base.handlers import |
|
5 | from ...base.handlers import APIHandler, json_errors | |
6 |
|
6 | |||
7 |
class NbconvertRootHandler( |
|
7 | class NbconvertRootHandler(APIHandler): | |
8 | SUPPORTED_METHODS = ('GET',) |
|
8 | SUPPORTED_METHODS = ('GET',) | |
9 |
|
9 | |||
10 | @web.authenticated |
|
10 | @web.authenticated |
@@ -5,10 +5,10 b'' | |||||
5 |
|
5 | |||
6 | from tornado import gen, web |
|
6 | from tornado import gen, web | |
7 |
|
7 | |||
8 |
from ...base.handlers import |
|
8 | from ...base.handlers import APIHandler, json_errors | |
9 | from . import csp_report_uri |
|
9 | from . import csp_report_uri | |
10 |
|
10 | |||
11 |
class CSPReportHandler( |
|
11 | class CSPReportHandler(APIHandler): | |
12 | '''Accepts a content security policy violation report''' |
|
12 | '''Accepts a content security policy violation report''' | |
13 | @web.authenticated |
|
13 | @web.authenticated | |
14 | @json_errors |
|
14 | @json_errors |
@@ -7,13 +7,13 b' import json' | |||||
7 |
|
7 | |||
8 | from tornado import web |
|
8 | from tornado import web | |
9 |
|
9 | |||
10 |
from ...base.handlers import |
|
10 | from ...base.handlers import APIHandler, json_errors | |
11 | from IPython.utils.jsonutil import date_default |
|
11 | from IPython.utils.jsonutil import date_default | |
12 | from IPython.html.utils import url_path_join, url_escape |
|
12 | from IPython.html.utils import url_path_join, url_escape | |
13 | from IPython.kernel.kernelspec import NoSuchKernel |
|
13 | from IPython.kernel.kernelspec import NoSuchKernel | |
14 |
|
14 | |||
15 |
|
15 | |||
16 |
class SessionRootHandler( |
|
16 | class SessionRootHandler(APIHandler): | |
17 |
|
17 | |||
18 | @web.authenticated |
|
18 | @web.authenticated | |
19 | @json_errors |
|
19 | @json_errors | |
@@ -65,7 +65,7 b' class SessionRootHandler(IPythonHandler):' | |||||
65 | self.set_status(201) |
|
65 | self.set_status(201) | |
66 | self.finish(json.dumps(model, default=date_default)) |
|
66 | self.finish(json.dumps(model, default=date_default)) | |
67 |
|
67 | |||
68 |
class SessionHandler( |
|
68 | class SessionHandler(APIHandler): | |
69 |
|
69 | |||
70 | SUPPORTED_METHODS = ('GET', 'PATCH', 'DELETE') |
|
70 | SUPPORTED_METHODS = ('GET', 'PATCH', 'DELETE') | |
71 |
|
71 |
@@ -1,9 +1,9 b'' | |||||
1 | import json |
|
1 | import json | |
2 | from tornado import web, gen |
|
2 | from tornado import web, gen | |
3 |
from ..base.handlers import |
|
3 | from ..base.handlers import APIHandler, json_errors | |
4 | from ..utils import url_path_join |
|
4 | from ..utils import url_path_join | |
5 |
|
5 | |||
6 |
class TerminalRootHandler( |
|
6 | class TerminalRootHandler(APIHandler): | |
7 | @web.authenticated |
|
7 | @web.authenticated | |
8 | @json_errors |
|
8 | @json_errors | |
9 | def get(self): |
|
9 | def get(self): | |
@@ -19,7 +19,7 b' class TerminalRootHandler(IPythonHandler):' | |||||
19 | self.finish(json.dumps({'name': name})) |
|
19 | self.finish(json.dumps({'name': name})) | |
20 |
|
20 | |||
21 |
|
21 | |||
22 |
class TerminalHandler( |
|
22 | class TerminalHandler(APIHandler): | |
23 | SUPPORTED_METHODS = ('GET', 'DELETE') |
|
23 | SUPPORTED_METHODS = ('GET', 'DELETE') | |
24 |
|
24 | |||
25 | @web.authenticated |
|
25 | @web.authenticated |
General Comments 0
You need to be logged in to leave comments.
Login now