From 97fb36d4985d6efa2bfbc23a640476d8e1ca2edf Mon Sep 17 00:00:00 2001 From: Mustafa Yontar Date: Mon, 1 Feb 2021 19:49:33 +0300 Subject: [PATCH] permission system updated --- resource.py | 10 +++++-- views.py | 86 +++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/resource.py b/resource.py index c66ce7e..fbc37cb 100644 --- a/resource.py +++ b/resource.py @@ -104,10 +104,14 @@ class Resource: data.get(**{self.as_pk: pk}) return data - def to_json(self, pk: str = None) -> tuple: + def to_json(self, pk: str = None, qs=None) -> tuple: + + if qs is None: + if self.mongo_qs is None: + self.mongo_qs = self.to_qs(pk) + else: + self.mongo_qs = qs - if self.mongo_qs is None: - self.mongo_qs = self.to_qs(pk) data = self.mongo_qs count = data.count() diff --git a/views.py b/views.py index f2175ee..39f4830 100644 --- a/views.py +++ b/views.py @@ -5,7 +5,7 @@ import mongoengine from flask import jsonify, request from flask_views.base import View from mongoengine import ValidationError, DoesNotExist, InvalidQueryError -from werkzeug.exceptions import Unauthorized, NotFound +from werkzeug.exceptions import Unauthorized, NotFound, Forbidden from restapi.resource import Resource @@ -14,7 +14,7 @@ class ApiView(View): model = None authentication_methods = [] - def __init__(self, model,authentication_methods): + def __init__(self, model, authentication_methods): self.start = time.time() self.model = model self.resource = Resource(self.model) @@ -28,22 +28,28 @@ class ApiView(View): def _dispatch_request(self, *args, **kwargs): authorized = True if len(self.authentication_methods) == 0 else False + autherror = None for authentication_method in self.authentication_methods: - if authentication_method().authorized(): + authclass = authentication_method() + if authclass.authorized(): authorized = True + else: + autherror = authclass.get_error() if not authorized: - return {'error': 'Unauthorized'}, '401 Unauthorized' + return {'error': 'Unauthorized', "message": str(autherror), "status": False}, '401 Unauthorized' try: return super(ApiView, self).dispatch_request(*args, **kwargs) except mongoengine.queryset.DoesNotExist as e: - return {'error': 'Empty query: ' + str(e)}, '404 Not Found' + return {'error': 'empty_query', "message": str(e), "status": False}, '404 Not Found' except ValidationError as e: - return e.args[0], '400 Bad Request' + return {"error": "bad_request", "message": e.args, "status": False}, '400 Bad Request' except Unauthorized: - return {'error': 'Unauthorized'}, '401 Unauthorized' + return {'error': 'Unauthorized', "status": False}, '401 Unauthorized' + except Forbidden: + return {'error': 'Access_Denied', "status": False}, '403 Access Denied' except NotFound as e: - return {'error': str(e)}, '404 Not Found' + return {'error': str(e), "status": False}, '404 Not Found' def get(self, *args, **kwargs): """ @@ -55,7 +61,8 @@ class ApiView(View): if 'pk' in kwargs: try: qs = self.resource.to_qs(pk=kwargs.get('pk')) - count, data = self.resource.to_json(pk=kwargs.get('pk')) + qs = self.has_read_permission(qs) + count, data = self.resource.to_json(pk=kwargs.get('pk'), qs=qs) response = { 'response': data, 'status': True, @@ -73,7 +80,9 @@ class ApiView(View): if "query" in request.args and self.model._meta.get('can_query'): self.resource.external_query(json.loads(request.args.get('query'))) qs = self.resource.to_qs() - count, data = self.resource.to_json() + qs = self.has_read_permission(qs) + + count, data = self.resource.to_json(qs=qs) response = { 'response': data, 'info': { @@ -89,8 +98,6 @@ class ApiView(View): def post(self, *args, **kwargs): """ - TODO: check permissions - :param args: :param kwargs: :return: @@ -109,8 +116,20 @@ class ApiView(View): 'status': False, 'errors': str(e) }), 400 - data = item.save() - return self.get(pk=data.id, code=201) + resp, obj = self.has_add_permission(item) + from flask import current_app + + if resp: + try: + item = obj + data = item.save() + except Exception as e: + current_app.logger.error(e) + current_app.logger.info(item.pk) + + return self.get(pk=item.pk, code=201) + else: + raise Forbidden() def put(self, *args, **kwargs): """ @@ -127,7 +146,15 @@ class ApiView(View): }), 403 else: try: - self.model.objects(id=kwargs.get('pk')).update(**request.json) + item = self.model.objects.get(id=kwargs.get('pk')) + updata = request.json + resp, obj = self.has_change_permission(item, updata) + from flask import current_app + if resp: + updata = obj + item.update(**updata) + else: + raise Forbidden() return self.get(pk=kwargs.get('pk')) except ValidationError as v: print(v.__dict__) @@ -141,16 +168,31 @@ class ApiView(View): 'errors': str(e) }), 400 - def has_read_permission(self, request, qs): + def has_read_permission(self, qs): + for authentication_method in self.authentication_methods: + authclass = authentication_method() + qs = authclass.has_model_read_permission(qs) return qs - def has_add_permission(self, request, obj): - return True - - def has_change_permission(self, request, obj): - return True + def has_add_permission(self, obj): + has_ret = False + for authentication_method in self.authentication_methods: + authclass = authentication_method() + resp, obj = authclass.has_model_write_permission(obj) + if resp: + has_ret = True + return has_ret, obj + + def has_change_permission(self, obj, update): + has_ret = False + for authentication_method in self.authentication_methods: + authclass = authentication_method() + resp, obj = authclass.has_model_update_permission(obj, update) + if resp: + has_ret = True + return has_ret, update - def has_delete_permission(self, request, obj): + def has_delete_permission(self, obj): return True def delete(self, *args, **kwargs):