security conditional

This commit is contained in:
Daniel Tsvetkov 2021-05-09 14:44:11 +02:00
parent 517bdc32fe
commit b1b7b4017b
7 changed files with 131 additions and 116 deletions

View File

@ -25,3 +25,4 @@ MAKEDIRS = [
] ]
APP_BASE_URL = "http://localhost:5000" APP_BASE_URL = "http://localhost:5000"
SECURITY_ENABLED = True

View File

@ -27,7 +27,7 @@ from tww.lib import solve_query, resolve_timezone, dt_tz_translation, time_ago
from whooshalchemy import IndexService from whooshalchemy import IndexService
from config import SQLALCHEMY_DATABASE_URI, MAKEDIRS, DATABASE_FILE, SEARCH_INDEX_PATH, STATIC_DATA_DIR, MEDIA_DIR, \ from config import SQLALCHEMY_DATABASE_URI, MAKEDIRS, DATABASE_FILE, SEARCH_INDEX_PATH, STATIC_DATA_DIR, MEDIA_DIR, \
basepath basepath, SECURITY_ENABLED
from oshipka.util.strings import camel_case_to_snake_case from oshipka.util.strings import camel_case_to_snake_case
from vm_gen.vm_gen import order_from_process_order from vm_gen.vm_gen import order_from_process_order
@ -61,11 +61,6 @@ class Datable(object):
updated_dt = db.Column(db.UnicodeText()) updated_dt = db.Column(db.UnicodeText())
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class ModelJsonEncoder(JSONEncoder): class ModelJsonEncoder(JSONEncoder):
def default(self, o): def default(self, o):
if isinstance(o, datetime.datetime): if isinstance(o, datetime.datetime):
@ -168,6 +163,12 @@ class ModelController(ModelJsonEncoder):
return fields return fields
if SECURITY_ENABLED:
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, ModelController, RoleMixin): class Role(db.Model, ModelController, RoleMixin):
name = db.Column(db.Unicode, unique=True) name = db.Column(db.Unicode, unique=True)
description = db.Column(db.Unicode) description = db.Column(db.Unicode)
@ -337,6 +338,7 @@ def init_db(app):
db.init_app(app) db.init_app(app)
csrf.init_app(app) csrf.init_app(app)
migrate.init_app(app, db) migrate.init_app(app, db)
if SECURITY_ENABLED:
security.init_app(app, user_datastore) security.init_app(app, user_datastore)
_init_translations(app) _init_translations(app)
@ -370,7 +372,7 @@ def populate_static(app):
sensitive = import_module("sensitive") sensitive = import_module("sensitive")
ordered_model_names = order_from_process_order('csv', STATIC_DATA_DIR) ordered_model_names = order_from_process_order('csv', STATIC_DATA_DIR)
for model_name in ordered_model_names: for model_name in ordered_model_names:
if model_name in ['User', 'Role']: if SECURITY_ENABLED and model_name in ['User', 'Role']:
model = eval(model_name) model = eval(model_name)
else: else:
model = getattr(models, model_name) model = getattr(models, model_name)
@ -385,16 +387,6 @@ def populate_static(app):
row_updates[key] = sensitive_value row_updates[key] = sensitive_value
if row_updates: if row_updates:
row.update(row_updates) row.update(row_updates)
if model_name == "User":
if 'role_names' in row:
role_names = row.pop('role_names')
else:
role_names = ""
user = user_datastore.create_user(**row)
for role_name in role_names.split(';'):
role = Role.query.filter_by(name=role_name).first()
user_datastore.add_role_to_user(user, role)
else:
instance = create_model(model, row) instance = create_model(model, row)
db.session.add(instance) db.session.add(instance)
db.session.commit() db.session.commit()

View File

@ -4,10 +4,9 @@ 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
from flask_security import login_user from flask_security import login_user
from oshipka.persistance import User, db
from oshipka.util.strings import random_string_generator from oshipka.util.strings import random_string_generator
from oshipka.webapp import oshipka_bp, app from oshipka.webapp import oshipka_bp, app
from config import MEDIA_DIR, APP_BASE_URL from config import MEDIA_DIR, APP_BASE_URL, SECURITY_ENABLED
from sensitive import SSO_CLIENT_ID, SSO_CLIENT_SECRET from sensitive import SSO_CLIENT_ID, SSO_CLIENT_SECRET
@ -16,7 +15,8 @@ from sensitive import SSO_CLIENT_ID, SSO_CLIENT_SECRET
def get_media(filepath): def get_media(filepath):
return send_from_directory(MEDIA_DIR, filepath) return send_from_directory(MEDIA_DIR, filepath)
if SECURITY_ENABLED:
from oshipka.persistance import User, db
SSO_BASE_URL = 'http://sso.localhost:5008' SSO_BASE_URL = 'http://sso.localhost:5008'
SSO_AUTH_URL = '/oidc/auth' SSO_AUTH_URL = '/oidc/auth'
SSO_TOKEN_URL = '/oidc/token' SSO_TOKEN_URL = '/oidc/token'

View File

@ -257,7 +257,7 @@ def create_view(model_view, view_context_kwargs, is_login_required=False, the_ro
class ModelView(object): class ModelView(object):
def __init__(self, app, model, model_acl): def __init__(self, app, model, model_acl=None):
self.app = app self.app = app
self.model = model self.model = model
self.model_acl = model_acl self.model_acl = model_acl

View File

@ -6,7 +6,11 @@ from sqlalchemy_utils import ChoiceType
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
[%- endif %] [%- endif %]
class [[ name ]](db.Model, ModelController[% for inherit in interits %], [[ inherit ]][% endfor %]): [% for inherit_import in inherits_imports %]
[[ inherit_import ]]
[% endfor %]
class [[ name ]](db.Model, ModelController[% for inherit in inherits %], [[ inherit ]][% endfor %]):
[%- include "_model_choice_header_py" %] [%- include "_model_choice_header_py" %]
[%- include "_model_searchable_header_py" %] [%- include "_model_searchable_header_py" %]

View File

@ -6,10 +6,20 @@ Edit the hooks in webapp/routes/[[ name|camel_to_snake ]]_hooks.py instead
from oshipka.webapp import app from oshipka.webapp import app
from oshipka.webapp.views import ModelView from oshipka.webapp.views import ModelView
from webapp.models import [[ name ]], [[ name ]]Acl
from webapp.routes.[[ name|camel_to_snake ]]_hooks import * from webapp.routes.[[ name|camel_to_snake ]]_hooks import *
[%- if name == "User" %]
from webapp.models import [[ name ]]
[[ name|camel_to_snake ]] = ModelView(app, [[name]])
[%- else %]
from webapp.models import [[ name ]], [[ name ]]Acl
[[ name|camel_to_snake ]] = ModelView(app, [[name]], [[ name ]]Acl) [[ name|camel_to_snake ]] = ModelView(app, [[name]], [[ name ]]Acl)
[%- endif %]
[% for verb, verb_values in _verbs.items() %] [% for verb, verb_values in _verbs.items() %]
[[ name|camel_to_snake ]].register_verb(view_context=[[ verb ]]_view_context, [[ name|camel_to_snake ]].register_verb(view_context=[[ verb ]]_view_context,
verb="[[ verb ]]", verb="[[ verb ]]",

View File

@ -163,23 +163,27 @@ def process_navigation(view_models):
def process_model(view_model): def process_model(view_model):
template = env.get_template('model_py') template = env.get_template('model_py')
view_model['acls'] = {} view_model['acls'] = {}
for verb, acl in view_model['_verbs'].items():
view_model['acls'][verb] = {'authn': acl['is_login_required'], 'authz': acl['the_roles_required']}
model = autopep8.fix_code(template.render(**view_model), options=pep_options)
_model_name = view_model.get('name') _model_name = view_model.get('name')
template_acl = env.get_template('model_acl_py')
model_acl = autopep8.fix_code(template_acl.render(**view_model), options=pep_options)
model_camel = _model_name.split('.yaml')[0] model_camel = _model_name.split('.yaml')[0]
model_snake = camel_case_to_snake_case(_model_name.split('.yaml')[0]) model_snake = camel_case_to_snake_case(_model_name.split('.yaml')[0])
for verb, acl in view_model['_verbs'].items():
view_model['acls'][verb] = {'authn': acl['is_login_required'], 'authz': acl['the_roles_required']}
model = autopep8.fix_code(template.render(**view_model), options=pep_options)
with open(os.path.join(MODELS_PATH, "_{}.py".format(model_snake)), 'w+') as f: with open(os.path.join(MODELS_PATH, "_{}.py".format(model_snake)), 'w+') as f:
f.write(model) f.write(model)
if model_camel not in ['User']:
template_acl = env.get_template('model_acl_py')
model_acl = autopep8.fix_code(template_acl.render(**view_model), options=pep_options)
with open(os.path.join(MODELS_PATH, "_{}_acl.py".format(model_snake)), 'w+') as f: with open(os.path.join(MODELS_PATH, "_{}_acl.py".format(model_snake)), 'w+') as f:
f.write(model_acl) f.write(model_acl)
public_model = os.path.join(MODELS_PATH, "{}.py".format(model_snake)) public_model = os.path.join(MODELS_PATH, "{}.py".format(model_snake))
if not os.path.exists(public_model): if not os.path.exists(public_model):
with open(public_model, 'w+') as f: with open(public_model, 'w+') as f:
if model_camel not in ['User']:
f.write("from webapp.models._{}_acl import {}Acl\n".format(model_snake, model_camel)) f.write("from webapp.models._{}_acl import {}Acl\n".format(model_snake, model_camel))
f.write("from webapp.models._{} import {}\n".format(model_snake, model_camel)) f.write("from webapp.models._{} import {}\n".format(model_snake, model_camel))
@ -229,8 +233,12 @@ def main():
process_routes(view_model) process_routes(view_model)
view_model_name = view_model.get('name', '') view_model_name = view_model.get('name', '')
model_snake_name = camel_case_to_snake_case(view_model_name) model_snake_name = camel_case_to_snake_case(view_model_name)
if view_model_name not in ['User']:
all_model_imports.append('from webapp.models.{s} import {c}, {c}Acl'.format( all_model_imports.append('from webapp.models.{s} import {c}, {c}Acl'.format(
s=model_snake_name, c=view_model_name)) s=model_snake_name, c=view_model_name))
else:
all_model_imports.append('from webapp.models.{s} import {c}'.format(
s=model_snake_name, c=view_model_name))
process_html_templates(view_model) process_html_templates(view_model)
all_route_imports.append('from webapp.routes.{} import *'.format( all_route_imports.append('from webapp.routes.{} import *'.format(
model_snake_name model_snake_name