forked from jupyter-server/jupyter_server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decorator.py
81 lines (64 loc) · 2.58 KB
/
decorator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""Decorator for layering authorization into JupyterHandlers.
"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from functools import wraps
from typing import Callable, Optional, Union
from tornado.log import app_log
from tornado.web import HTTPError
from .utils import HTTP_METHOD_TO_AUTH_ACTION, warn_disabled_authorization
def authorized(
action: Optional[Union[str, Callable]] = None,
resource: Optional[str] = None,
message: Optional[str] = None,
) -> Callable:
"""A decorator for tornado.web.RequestHandler methods
that verifies whether the current user is authorized
to make the following request.
Helpful for adding an 'authorization' layer to
a REST API.
.. versionadded:: 2.0
Parameters
----------
action : str
the type of permission or action to check.
resource: str or None
the name of the resource the action is being authorized
to access.
message : str or none
a message for the unauthorized action.
"""
def wrapper(method):
@wraps(method)
def inner(self, *args, **kwargs):
# default values for action, resource
nonlocal action
nonlocal resource
nonlocal message
if action is None:
http_method = self.request.method.upper()
action = HTTP_METHOD_TO_AUTH_ACTION[http_method]
if resource is None:
resource = self.auth_resource
if message is None:
message = f"User is not authorized to {action} on resource: {resource}."
user = self.current_user
if not user:
app_log.warning("Attempting to authorize request without authentication!")
raise HTTPError(status_code=403, log_message=message)
# Handle the case where an authorizer wasn't attached to the handler.
if not self.authorizer:
warn_disabled_authorization()
return method(self, *args, **kwargs)
# Only return the method if the action is authorized.
if self.authorizer.is_authorized(self, user, action, resource):
return method(self, *args, **kwargs)
# Raise an exception if the method wasn't returned (i.e. not authorized)
raise HTTPError(status_code=403, log_message=message)
return inner
if callable(action):
method = action
action = None
# no-arguments `@authorized` decorator called
return wrapper(method)
return wrapper