Skip to content

Commit

Permalink
Add permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
f1nality committed Dec 25, 2018
1 parent e6f5754 commit 7509f5e
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 0 deletions.
54 changes: 54 additions & 0 deletions jet_bridge/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from jet_bridge import settings
from jet_bridge.utils.backend import project_auth


class BasePermission(object):

def has_permission(self, view):
return True

def has_object_permission(self, view, obj):
return True


class HasProjectPermissions(BasePermission):
token_prefix = 'Token '
project_token_prefix = 'ProjectToken '

def has_permission(self, view):
token = view.request.headers.get('Authorization')
permission = getattr(view, 'required_project_permission', None)

if not token:
return False

if token[:len(self.token_prefix)] == self.token_prefix:
token = token[len(self.token_prefix):]

result = project_auth(token, permission)

if result.get('warning'):
view.headers['X-Application-Warning'] = result['warning']

return result['result']
elif token[:len(self.project_token_prefix)] == self.project_token_prefix:
token = token[len(self.project_token_prefix):]

result = project_auth(token, permission)

if result.get('warning'):
view.headers['X-Application-Warning'] = result['warning']

return result['result']
else:
return False


class ModifyNotInDemo(BasePermission):

def has_permission(self, view):
if not settings.READ_ONLY:
return True
if view.action in ['create', 'update', 'partial_update', 'destroy']:
return False
return True
1 change: 1 addition & 0 deletions jet_bridge/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ActionHandler(viewset):
for method, method_action in actions.items():
def create_action_method(action):
def action_method(inner_self, *args, **kwargs):
inner_self.action = action
return getattr(inner_self, action)(*args, **kwargs)
return action_method

Expand Down
2 changes: 2 additions & 0 deletions jet_bridge/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
define('port', default=8888, help='server port', type=int)
define('config', default=DEFAULT_CONFIG_PATH, help='config file path')
define('debug', default=False, help='debug mode', type=bool)
define('read_only', default=False, help='read only', type=bool)

define('web_base_url', default='https://app.jetadmin.io', help='Jet Admin frontend application base URL')
define('api_base_url', default='https://api.jetadmin.io/api', help='Jet Admin API base URL')
Expand Down Expand Up @@ -54,6 +55,7 @@
ADDRESS = options.address
PORT = options.port
DEBUG = options.debug
READ_ONLY = options.read_only

WEB_BASE_URL = options.web_base_url
API_BASE_URL = options.api_base_url
Expand Down
18 changes: 18 additions & 0 deletions jet_bridge/views/base/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


class APIView(tornado.web.RequestHandler):
permission_classes = []

@property
def data(self):
Expand All @@ -12,6 +13,10 @@ def data(self):
else:
return self.request.body_arguments

def prepare(self):
if self.request.method != 'OPTIONS':
self.check_permissions()

def set_default_headers(self):
ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin'
ACCESS_CONTROL_EXPOSE_HEADERS = 'Access-Control-Expose-Headers'
Expand All @@ -25,6 +30,19 @@ def set_default_headers(self):
self.set_header(ACCESS_CONTROL_EXPOSE_HEADERS, 'Content-Length,Content-Range,X-Application-Warning')
self.set_header(ACCESS_CONTROL_ALLOW_CREDENTIALS, 'true')

def get_permissions(self):
return [permission() for permission in self.permission_classes]

def check_permissions(self):
for permission in self.get_permissions():
if not permission.has_permission(self):
raise Exception(getattr(permission, 'message', None))

def check_object_permissions(self, obj):
for permission in self.get_permissions():
if not permission.has_object_permission(self, obj):
raise Exception(getattr(permission, 'message', None))

def options(self, *args, **kwargs):
self.set_status(204)
self.finish()
Expand Down
3 changes: 3 additions & 0 deletions jet_bridge/views/base/generic_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class GenericAPIView(APIView):
lookup_field = 'id'
lookup_url_kwarg = None
session = Session()
action = None

def get_model(self):
raise NotImplementedError
Expand All @@ -27,6 +28,8 @@ def get_object(self):
model_field = getattr(self.get_model(), self.lookup_field)
obj = queryset.filter(getattr(model_field, '__eq__')(self.path_kwargs[lookup_url_kwarg])).first()

self.check_object_permissions(obj)

return obj

def get_filter(self, *args, **kwargs):
Expand Down
2 changes: 2 additions & 0 deletions jet_bridge/views/message.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from jet_bridge.permissions import HasProjectPermissions
from jet_bridge.views.base.api import APIView


class MessageHandler(APIView):
permission_classes = (HasProjectPermissions,)

def post(self):
pass
21 changes: 21 additions & 0 deletions jet_bridge/views/model.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
from jet_bridge.filters.model import get_model_filter_class
from jet_bridge.permissions import HasProjectPermissions, ModifyNotInDemo
from jet_bridge.serializers.model import get_model_serializer
from jet_bridge.views.mixins.model import ModelAPIViewMixin
from jet_bridge.db import MappedBase


class ModelHandler(ModelAPIViewMixin):
model = None
permission_classes = (HasProjectPermissions, ModifyNotInDemo)

@property
def required_project_permission(self):
return {
'permission_type': 'model',
'permission_object': self.path_kwargs['model'],
'permission_actions': {
'create': 'w',
'update': 'w',
'partial_update': 'w',
'destroy': 'd',
'retrieve': 'r',
'list': 'r',
'aggregate': 'r',
'group': 'r',
'reorder': 'w',
'reset_order': 'w'
}.get(self.action, 'w')
}

def get_model(self):
if self.model:
Expand Down
2 changes: 2 additions & 0 deletions jet_bridge/views/model_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from jet_bridge.db import Session, MappedBase
from jet_bridge.models import data_types
from jet_bridge.permissions import HasProjectPermissions
from jet_bridge.responses.base import Response
from jet_bridge.serializers.model_description import ModelDescriptionSerializer
from jet_bridge.utils.db_types import map_data_type
Expand All @@ -11,6 +12,7 @@

class ModelDescriptionsHandler(APIView):
serializer_class = ModelDescriptionSerializer
permission_classes = (HasProjectPermissions,)
session = Session()

def get_queryset(self):
Expand Down
2 changes: 2 additions & 0 deletions jet_bridge/views/sql.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from jet_bridge.permissions import HasProjectPermissions
from jet_bridge.responses.base import Response
from jet_bridge.serializers.sql import SqlSerializer
from jet_bridge.views.base.api import APIView


class SqlHandler(APIView):
permission_classes = (HasProjectPermissions,)

def post(self):
serializer = SqlSerializer(data=self.data)
Expand Down

0 comments on commit 7509f5e

Please sign in to comment.