From a56bdf135a1fefd70fd0480b6fb541ceb5e05a85 Mon Sep 17 00:00:00 2001 From: Daniel Tsvetkov Date: Fri, 14 May 2021 23:37:30 +0200 Subject: [PATCH] check some permissions --- oshipka.sh | 1 + oshipka/persistance/__init__.py | 29 +++-------- oshipka/webapp/views.py | 60 ++++++++++++++++++++--- vm_gen/templates/_hooks.py | 7 +++ vm_gen/templates/html/_action_create.html | 2 +- 5 files changed, 69 insertions(+), 30 deletions(-) diff --git a/oshipka.sh b/oshipka.sh index e412212..4558eac 100755 --- a/oshipka.sh +++ b/oshipka.sh @@ -155,6 +155,7 @@ bootstrap() { init_venv link_dev_oshipka source venv/bin/activate + model python manager.py db init python manager.py db migrate -m "001" _post_migrate diff --git a/oshipka/persistance/__init__.py b/oshipka/persistance/__init__.py index d454338..b88b0f4 100644 --- a/oshipka/persistance/__init__.py +++ b/oshipka/persistance/__init__.py @@ -328,27 +328,9 @@ def init_db(app): SENSITIVE_PREFIX = "__SENSITIVE__." -""" -role,1,permission.get,models.song,,1 -role,1,permission.add_user,models.song,,1 -role,1,permission.add_role,models.song,,1 -role,1,permission.update,models.song,,1 -role,1,permission.delete_user,models.song,,1 -role,1,permission.delete_user_self,models.song,,1 -role,1,permission.delete_role,models.song,,1 -role,1,permission.change_owner,models.song,,1 -role,1,model.get,models.song,,1 -role,1,model.list,models.song,,1 -role,1,model.create,models.song,,1 -role,1,model.update,models.song,,1 -role,1,model.delete,models.song,,1 -public,,column.get,columns.song.audio_filename.read,,1 -public,,column.get,columns.song.audio_filename.write,,1 -""" - -DEFAULT_PERMISSION_PERMISSIONS = ['get', 'add_user', 'add_role', 'delete_user', 'delete_role'] -DEFAULT_MODEL_PERMISSIONS = ['get', 'list', 'create', 'update', 'delete'] +DEFAULT_PERMISSION_PERMISSIONS = ['get', 'add_user', 'add_role', 'remove_user', 'remove_role'] +DEFAULT_MODEL_PERMISSIONS = ['get', 'list', 'search', 'create', 'update', 'delete'] DEFAULT_COLUMN_PERMISSIONS = ['read', 'write'] DEFAULT_SUBJECTS = ['public', 'logged'] @@ -364,14 +346,14 @@ def generate_permissions(): continue is_ownable = 'Ownable' in model_view.definitions.get('inherits', []) subjects = DEFAULT_SUBJECTS + ['owner']if is_ownable else DEFAULT_SUBJECTS + f.write("role,1,permission.update,models.{},,1\n".format(model)) + f.write("role,1,permission.remove_user_self,models.{},,1\n".format(model)) for subject in subjects: for permission in DEFAULT_PERMISSION_PERMISSIONS: f.write("{},,permission.{},models.{},,0\n".format(subject, permission, model)) f.write("role,1,permission.{},models.{},,1\n".format(permission, model)) f.write("{},,permission.update,models.{},,0\n".format(subject, model)) - f.write("role,1,permission.update,models.{},,1\n".format(subject, model)) - f.write("{},,permission.delete_user_self,models.{},,0\n".format(subject, model)) - f.write("role,1,permission.delete_user_self,models.{},,1\n".format(subject, model)) + f.write("{},,permission.remove_user_self,models.{},,0\n".format(subject, model)) if is_ownable: f.write("{},,permission.change_owner,models.{},,1\n".format(subject, model)) for permission in DEFAULT_MODEL_PERMISSIONS: @@ -380,6 +362,7 @@ def generate_permissions(): column_name = column.get('name') for permission in DEFAULT_COLUMN_PERMISSIONS: f.write("{},,column.{}.{},columns.{},,1\n".format(subject, column_name, permission, model)) + f.write("role,1,column.{}.{},columns.{},,1\n".format(subject, column_name, permission, model)) def populate_static(app): diff --git a/oshipka/webapp/views.py b/oshipka/webapp/views.py index a7b2143..1fd90f4 100644 --- a/oshipka/webapp/views.py +++ b/oshipka/webapp/views.py @@ -6,7 +6,7 @@ from copy import copy from functools import wraps import inflect -from flask import flash, render_template, redirect, request, url_for, jsonify +from flask import flash, render_template, redirect, request, url_for, jsonify, abort from flask_login import current_user from flask_security import login_required, roles_required from sqlalchemy_filters import apply_filters @@ -14,10 +14,13 @@ from sqlalchemy_filters import apply_filters from oshipka.persistance import db, filter_m_n, update_m_ns, SHARING_TYPE_TYPES_TYPE_PUBLIC, \ SHARING_TYPE_TYPES_TYPE_AUTHZ, SHARING_TYPE_TYPES_TYPE_AUTHN from oshipka.util.strings import camel_case_to_snake_case -from config import MEDIA_DIR +from config import MEDIA_DIR, SECURITY_ENABLED webapp_models = importlib.import_module("webapp.models") +if SECURITY_ENABLED: + from webapp.models import Permission + MODEL_VIEWS = dict() @@ -29,9 +32,50 @@ def has_permission(model, verb, instance=None): model_view = MODEL_VIEWS.get(model, {}) if not model_view: return False - if '.' in verb: - return check_instance_perm(model_view, verb, instance) - return True + if current_user.is_anonymous: + permission = Permission.query.filter(Permission.object == "models.{}".format(model), + Permission.action == "model.{}".format(verb), + Permission.subject == "public").first() + if permission and permission.is_allowed: + return True + return False + + if instance is not None: + inherits = model_view.definitions.get('inherits', []) + if "Ownable" in inherits: + permission = Permission.query.filter(Permission.object == "models.{}".format(model), + Permission.object_id == instance.id, + Permission.action == "model.{}".format(verb), + Permission.subject == "owner").first() + if permission and permission.is_allowed: + return True + + # LOGGED IN USER + permission = Permission.query.filter(Permission.object == "models.{}".format(model), + Permission.action == "model.{}".format(verb), + Permission.subject == "logged").first() + if permission and permission.is_allowed: + return True + + # ROLE PERMISSIONS + roles_ids = [r.id for r in current_user.roles] + role_permissions = Permission.query.filter(Permission.object == "models.{}".format(model), + Permission.action == "model.{}".format(verb), + Permission.subject == "user", + Permission.subject_id.in_(roles_ids)).all() + for role_permission in role_permissions: + if role_permission.is_allowed: + return True + + # USER PERMISSIONS + user_id = current_user.id + user_permission = Permission.query.filter(Permission.object == "models.{}".format(model), + Permission.action == "model.{}".format(verb), + Permission.subject == "user", + Permission.subject_id == user_id).first() + if user_permission: + return user_permission.is_allowed + return False def default_get_args_func(view_context): @@ -181,7 +225,7 @@ class ViewContext(object): jsonify_func=None, render_func=None, template_func=None, template_ctx_func=None, should_redirect_no_instances_func=None, should_redirect_at_end_func=None, - is_json=False, model_view=None, **kwargs): + is_json=False, model_view=None, verb=None, **kwargs): self.args_get_func = args_get_func or default_get_args_func self.args_process_func = args_process_func or default_none_func self.filter_func = filter_func or default_none_func @@ -199,6 +243,7 @@ class ViewContext(object): self.should_redirect_at_end_func = should_redirect_at_end_func or default_none_func self.is_json = is_json self.model_view = model_view + self.verb = verb self.serialized_args = {} self.url_args = {} @@ -224,6 +269,9 @@ def create_view(model_view, view_context_kwargs, is_login_required=False, the_ro def inner(**kwargs): view_context = ViewContext(**view_context_kwargs) + model_name = view_context.model_view.model_name + if not has_permission(model_name, view_context.verb): + abort(403) view_context.url_args = kwargs view_context.args_get_func(view_context) view_context.args_process_func(view_context) diff --git a/vm_gen/templates/_hooks.py b/vm_gen/templates/_hooks.py index 164439a..e30a883 100644 --- a/vm_gen/templates/_hooks.py +++ b/vm_gen/templates/_hooks.py @@ -33,27 +33,32 @@ def delete_template(vc): get_view_context = ViewContext( filter_func=default_get_func, template_func=get_template, + verb="get", ) list_view_context = ViewContext( filter_func=default_list_func, template_func=list_template, + verb="list", ) table_view_context = ViewContext( filter_func=default_list_func, template_func=table_template, + verb="list", ) search_view_context = ViewContext( filter_func=default_search_func, template_func=list_template, + verb="search", ) create_view_context = ViewContext( args_get_func=default_get_form_func, template_func=create_template, execute_func=default_create_func, + verb="create", ) update_view_context = ViewContext( @@ -61,6 +66,7 @@ update_view_context = ViewContext( filter_func=default_get_func, template_func=update_template, execute_func=default_update_func, + verb="update", ) delete_view_context = ViewContext( @@ -68,4 +74,5 @@ delete_view_context = ViewContext( filter_func=default_get_func, template_func=delete_template, execute_func=default_delete_func, + verb="delete", ) diff --git a/vm_gen/templates/html/_action_create.html b/vm_gen/templates/html/_action_create.html index ae27d9c..91b1a22 100644 --- a/vm_gen/templates/html/_action_create.html +++ b/vm_gen/templates/html/_action_create.html @@ -1,3 +1,3 @@ -{% if has_permission('[[ name|camel_to_snake ]]', 'create', instance) %} +{% if has_permission('[[ name|camel_to_snake ]]', 'create') %} {{ _("Create") }} {% endif %} \ No newline at end of file