fix media perms
This commit is contained in:
parent
3a539d698d
commit
79d02aee72
@ -248,42 +248,7 @@ def register_filters(app):
|
|||||||
def bool_filter(v):
|
def bool_filter(v):
|
||||||
return bool(v)
|
return bool(v)
|
||||||
|
|
||||||
def check_instance_perm(model_view, verb, instance):
|
from oshipka.webapp.views import has_permission
|
||||||
model_acl = model_view.model_acl
|
|
||||||
# Anonymous user -> check public ACL
|
|
||||||
if current_user.is_anonymous:
|
|
||||||
instance_acl = model_acl.query.filter_by(instance=instance,
|
|
||||||
acl_type=SHARING_TYPE_TYPES_TYPE_PUBLIC).first()
|
|
||||||
else:
|
|
||||||
# Logged in user -> find (user, instance) pair
|
|
||||||
instance_acl = model_acl.query.filter_by(user=current_user, instance=instance,
|
|
||||||
acl_type=SHARING_TYPE_TYPES_TYPE_AUTHZ).first()
|
|
||||||
if not instance_acl:
|
|
||||||
# If not (user, instance) pair -> check authN ACL
|
|
||||||
instance_acl = model_acl.query.filter_by(user=current_user, instance=instance,
|
|
||||||
acl_type=SHARING_TYPE_TYPES_TYPE_AUTHN).first()
|
|
||||||
column = verb.replace('.', '__')
|
|
||||||
return getattr(instance_acl, column)
|
|
||||||
|
|
||||||
def has_permission(model, verb, instance=None):
|
|
||||||
model_view = MODEL_VIEWS.get(model, {})
|
|
||||||
if '.' in verb:
|
|
||||||
return check_instance_perm(model_view, verb, instance)
|
|
||||||
acl = model_view.model.model_acls.get(verb)
|
|
||||||
# Anonymous user -> do we require AuthN?
|
|
||||||
if current_user.is_anonymous:
|
|
||||||
return not acl.get('authn')
|
|
||||||
# Not Anonymous user -> Check roles
|
|
||||||
roles = acl.get('authz')
|
|
||||||
# No roles required -> has permission
|
|
||||||
if not roles:
|
|
||||||
return True
|
|
||||||
# One role is enough to grant permission
|
|
||||||
for role in roles:
|
|
||||||
if current_user.has_role(role):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
app.jinja_env.globals.update(has_permission=has_permission)
|
app.jinja_env.globals.update(has_permission=has_permission)
|
||||||
|
|
||||||
|
|
||||||
@ -379,7 +344,10 @@ def populate_static(app):
|
|||||||
model = getattr(models, model_name)
|
model = getattr(models, model_name)
|
||||||
model_acl = getattr(models, model_name + 'Acl')
|
model_acl = getattr(models, model_name + 'Acl')
|
||||||
with open(os.path.join(STATIC_DATA_DIR, "{}.csv".format(model_name))) as f:
|
with open(os.path.join(STATIC_DATA_DIR, "{}.csv".format(model_name))) as f:
|
||||||
|
if issubclass(model, Ownable):
|
||||||
user = User.query.first()
|
user = User.query.first()
|
||||||
|
else:
|
||||||
|
user = None
|
||||||
reader = csv.DictReader(f)
|
reader = csv.DictReader(f)
|
||||||
for row in reader:
|
for row in reader:
|
||||||
row_updates = dict()
|
row_updates = dict()
|
||||||
@ -427,6 +395,6 @@ def create_model(model, model_acl, user, serialized_args):
|
|||||||
for key, ids in m_ns.items():
|
for key, ids in m_ns.items():
|
||||||
m_ns[key] = ids.split(',')
|
m_ns[key] = ids.split(',')
|
||||||
update_m_ns(instance, m_ns)
|
update_m_ns(instance, m_ns)
|
||||||
if model_acl and user:
|
if model_acl:
|
||||||
create_acls(model_acl, instance, user)
|
create_acls(model_acl, instance, user)
|
||||||
return instance
|
return instance
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from flask import send_from_directory, redirect, request, url_for, session, jsonify
|
from flask import send_from_directory, redirect, request, url_for, session, jsonify, abort
|
||||||
from flask_security import login_user
|
from flask_security import login_user
|
||||||
|
|
||||||
from oshipka.util.strings import random_string_generator
|
from oshipka.util.strings import random_string_generator
|
||||||
@ -9,15 +9,27 @@ from oshipka.webapp import oshipka_bp, app
|
|||||||
from config import MEDIA_DIR, APP_BASE_URL, SECURITY_ENABLED, SSO_BASE_URL, SSO_CLIENT_ID
|
from config import MEDIA_DIR, APP_BASE_URL, SECURITY_ENABLED, SSO_BASE_URL, SSO_CLIENT_ID
|
||||||
from sensitive import SSO_CLIENT_SECRET
|
from sensitive import SSO_CLIENT_SECRET
|
||||||
|
|
||||||
|
from oshipka.webapp.views import MODEL_VIEWS, has_permission
|
||||||
|
|
||||||
# TODO: VULNZ - EVERYONE HAS ACCESS TO THIS
|
|
||||||
@oshipka_bp.route('/media/<path:filepath>')
|
@oshipka_bp.route('/media/<model_name>/<int:instance_id>/<column>/<path:filepath>')
|
||||||
def get_media(filepath):
|
def get_media(model_name, instance_id, column, filepath):
|
||||||
|
model_view = MODEL_VIEWS.get(model_name)
|
||||||
|
if not model_view:
|
||||||
|
abort(404)
|
||||||
|
model = model_view.model
|
||||||
|
instance = model.query.filter_by(id=instance_id).first()
|
||||||
|
if not instance:
|
||||||
|
abort(404)
|
||||||
|
verb = "{}.read".format(column)
|
||||||
|
if not has_permission(model_name, verb, instance):
|
||||||
|
abort(401)
|
||||||
return send_from_directory(MEDIA_DIR, filepath)
|
return send_from_directory(MEDIA_DIR, filepath)
|
||||||
|
|
||||||
|
|
||||||
if SECURITY_ENABLED:
|
if SECURITY_ENABLED:
|
||||||
from oshipka.persistance import User, db
|
from oshipka.persistance import User, db
|
||||||
|
|
||||||
app.config['SSO_BASE_URL'] = SSO_BASE_URL
|
app.config['SSO_BASE_URL'] = SSO_BASE_URL
|
||||||
|
|
||||||
SSO_AUTH_URL = '/oidc/auth'
|
SSO_AUTH_URL = '/oidc/auth'
|
||||||
|
@ -21,6 +21,52 @@ webapp_models = importlib.import_module("webapp.models")
|
|||||||
MODEL_VIEWS = dict()
|
MODEL_VIEWS = dict()
|
||||||
|
|
||||||
|
|
||||||
|
def check_instance_perm(model_view, verb, instance):
|
||||||
|
model_acl = model_view.model_acl
|
||||||
|
# Anonymous user -> check public ACL
|
||||||
|
if current_user.is_anonymous:
|
||||||
|
instance_acl = model_acl.query.filter_by(instance=instance,
|
||||||
|
acl_type=SHARING_TYPE_TYPES_TYPE_PUBLIC).first()
|
||||||
|
else:
|
||||||
|
# Logged in user -> find (user, instance) pair
|
||||||
|
instance_acl = model_acl.query.filter_by(user=current_user, instance=instance,
|
||||||
|
acl_type=SHARING_TYPE_TYPES_TYPE_AUTHZ).first()
|
||||||
|
if not instance_acl:
|
||||||
|
# If not (user, instance) pair -> check authN ACL
|
||||||
|
instance_acl = model_acl.query.filter_by(user=current_user, instance=instance,
|
||||||
|
acl_type=SHARING_TYPE_TYPES_TYPE_AUTHN).first()
|
||||||
|
if not instance_acl:
|
||||||
|
# finally, try public
|
||||||
|
instance_acl = model_acl.query.filter_by(instance=instance,
|
||||||
|
acl_type=SHARING_TYPE_TYPES_TYPE_PUBLIC).first()
|
||||||
|
if not instance_acl:
|
||||||
|
return False
|
||||||
|
column = verb.replace('.', '__')
|
||||||
|
return getattr(instance_acl, column)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
acl = model_view.model.model_acls.get(verb)
|
||||||
|
# Anonymous user -> do we require AuthN?
|
||||||
|
if current_user.is_anonymous:
|
||||||
|
return not acl.get('authn')
|
||||||
|
# Not Anonymous user -> Check roles
|
||||||
|
roles = acl.get('authz')
|
||||||
|
# No roles required -> has permission
|
||||||
|
if not roles:
|
||||||
|
return True
|
||||||
|
# One role is enough to grant permission
|
||||||
|
for role in roles:
|
||||||
|
if current_user.has_role(role):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def default_get_args_func(view_context):
|
def default_get_args_func(view_context):
|
||||||
view_context.serialized_args = request.args
|
view_context.serialized_args = request.args
|
||||||
|
|
||||||
@ -129,14 +175,16 @@ def default_create_func(vc):
|
|||||||
instance = vc.instances or vc.model_view.model()
|
instance = vc.instances or vc.model_view.model()
|
||||||
vc.instances = [instance]
|
vc.instances = [instance]
|
||||||
default_update_func(vc)
|
default_update_func(vc)
|
||||||
create_acls(vc.model_view.model_acl, instance, current_user)
|
user = current_user if not current_user.is_anonymous else None
|
||||||
|
create_acls(vc.model_view.model_acl, instance, user)
|
||||||
|
|
||||||
|
|
||||||
def create_acls(model_acl, instance, user):
|
def create_acls(model_acl, instance, user):
|
||||||
instance_public_acl = model_acl(user=user, instance=instance, acl_type=SHARING_TYPE_TYPES_TYPE_PUBLIC)
|
instance_public_acl = model_acl(user=user, instance=instance, acl_type=SHARING_TYPE_TYPES_TYPE_PUBLIC)
|
||||||
|
db.session.add(instance_public_acl)
|
||||||
|
if user:
|
||||||
instance_authn_acl = model_acl(user=user, instance=instance, acl_type=SHARING_TYPE_TYPES_TYPE_AUTHN)
|
instance_authn_acl = model_acl(user=user, instance=instance, acl_type=SHARING_TYPE_TYPES_TYPE_AUTHN)
|
||||||
instance_authz_acl = model_acl(user=user, instance=instance, acl_type=SHARING_TYPE_TYPES_TYPE_AUTHZ)
|
instance_authz_acl = model_acl(user=user, instance=instance, acl_type=SHARING_TYPE_TYPES_TYPE_AUTHZ)
|
||||||
db.session.add(instance_public_acl)
|
|
||||||
db.session.add(instance_authn_acl)
|
db.session.add(instance_authn_acl)
|
||||||
db.session.add(instance_authz_acl)
|
db.session.add(instance_authz_acl)
|
||||||
|
|
||||||
|
@ -10,14 +10,14 @@
|
|||||||
[%- endif %]
|
[%- endif %]
|
||||||
[%- endif %]
|
[%- endif %]
|
||||||
[%- if column.type in ['picture', 'image', 'img'] %]
|
[%- if column.type in ['picture', 'image', 'img'] %]
|
||||||
<img src="{{ url_for('oshipka_bp.get_media', filepath=instance.[[ column.name ]]) }}" id="display-[[ name|camel_to_snake ]]-[[ column.name ]]" />
|
<img src="{{ url_for('oshipka_bp.get_media', model_name='[[ name|camel_to_snake ]]', instance_id=instance.id, column='[[ column.name ]]', filepath=instance.[[ column.name ]]) }}" id="display-[[ name|camel_to_snake ]]-[[ column.name ]]" />
|
||||||
[%- elif column.type in ['video'] %]
|
[%- elif column.type in ['video'] %]
|
||||||
<video src="{{ url_for('oshipka_bp.get_media', filepath=instance.[[ column.name ]]) }}" controls class="video-inline" id="display-[[ name|camel_to_snake ]]-[[ column.name ]]">
|
<video src="{{ url_for('oshipka_bp.get_media', model_name='[[ name|camel_to_snake ]]', instance_id=instance.id, column='[[ column.name ]]', filepath=instance.[[ column.name ]]) }}" controls class="video-inline" id="display-[[ name|camel_to_snake ]]-[[ column.name ]]">
|
||||||
<source src="{{ url_for('oshipka_bp.get_media', filepath=instance.[[ column.name ]]) }}" type="video/mp4">
|
<source src="{{ url_for('oshipka_bp.get_media', model_name='[[ name|camel_to_snake ]]', instance_id=instance.id, column='[[ column.name ]]', filepath=instance.[[ column.name ]]) }}" type="video/mp4">
|
||||||
<source src="{{ url_for('oshipka_bp.get_media', filepath=instance.[[ column.name ]]) }}" type="video/webm">
|
<source src="{{ url_for('oshipka_bp.get_media', model_name='[[ name|camel_to_snake ]]', instance_id=instance.id, column='[[ column.name ]]', filepath=instance.[[ column.name ]]) }}" type="video/webm">
|
||||||
</video>
|
</video>
|
||||||
[%- elif column.type in ['audio'] %]
|
[%- elif column.type in ['audio'] %]
|
||||||
<audio src="{{ url_for('oshipka_bp.get_media', filepath=instance.[[ column.name ]]) }}" controls id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"></audio>
|
<audio src="{{ url_for('oshipka_bp.get_media', model_name='[[ name|camel_to_snake ]]', instance_id=instance.id, column='[[ column.name ]]', filepath=instance.[[ column.name ]]) }}" controls id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"></audio>
|
||||||
[%- elif column.type in ['relationship'] %]
|
[%- elif column.type in ['relationship'] %]
|
||||||
[%- if column.multiple %]
|
[%- if column.multiple %]
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from oshipka.persistance import db, ModelController, index_service, LiberalBoolean[% for inherit in interits %], [[ inherit ]][% endfor %]
|
from oshipka.persistance import db, ModelController, index_service, LiberalBoolean, Ownable
|
||||||
|
|
||||||
[%- if imports %]
|
[%- if imports %]
|
||||||
[%- for import in imports %]
|
[%- for import in imports %]
|
||||||
[[ import ]]
|
[[ import ]]
|
||||||
|
Loading…
Reference in New Issue
Block a user