check some permissions

This commit is contained in:
Daniel Tsvetkov 2021-05-14 23:37:30 +02:00
parent 878a7c5947
commit a56bdf135a
5 changed files with 69 additions and 30 deletions

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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",
)

View File

@ -1,3 +1,3 @@
{% if has_permission('[[ name|camel_to_snake ]]', 'create', instance) %}
{% if has_permission('[[ name|camel_to_snake ]]', 'create') %}
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">{{ _("Create") }}</a>
{% endif %}