mirror of https://github.com/veops/cmdb.git
208 lines
7.8 KiB
Python
208 lines
7.8 KiB
Python
# -*- coding:utf-8 -*-
|
|
|
|
import json
|
|
import re
|
|
|
|
import redis_lock
|
|
from flask import current_app
|
|
from werkzeug.exceptions import BadRequest
|
|
from werkzeug.exceptions import NotFound
|
|
|
|
from api.extensions import celery
|
|
from api.extensions import rd
|
|
from api.lib.decorator import flush_db
|
|
from api.lib.decorator import reconnect_db
|
|
from api.lib.perm.acl.audit import AuditCRUD
|
|
from api.lib.perm.acl.audit import AuditOperateSource
|
|
from api.lib.perm.acl.audit import AuditOperateType
|
|
from api.lib.perm.acl.cache import AppCache
|
|
from api.lib.perm.acl.cache import RoleCache
|
|
from api.lib.perm.acl.cache import RoleRelationCache
|
|
from api.lib.perm.acl.cache import UserCache
|
|
from api.lib.perm.acl.const import ACL_QUEUE
|
|
from api.lib.perm.acl.record import OperateRecordCRUD
|
|
from api.models.acl import Resource
|
|
from api.models.acl import Role
|
|
from api.models.acl import Trigger
|
|
|
|
|
|
@celery.task(name="acl.role_rebuild", queue=ACL_QUEUE, )
|
|
@flush_db
|
|
@reconnect_db
|
|
def role_rebuild(rids, app_id):
|
|
rids = rids if isinstance(rids, list) else [rids]
|
|
for rid in rids:
|
|
with redis_lock.Lock(rd.r, "ROLE_REBUILD_{}_{}".format(rid, app_id)):
|
|
RoleRelationCache.rebuild(rid, app_id)
|
|
|
|
current_app.logger.info("Role {0} App {1} rebuild..........".format(rids, app_id))
|
|
|
|
|
|
@celery.task(name="acl.update_resource_to_build_role", queue=ACL_QUEUE)
|
|
@reconnect_db
|
|
def update_resource_to_build_role(resource_id, app_id, group_id=None):
|
|
rids = [i.id for i in Role.get_by(__func_isnot__key_uid=None, fl='id', to_dict=False)]
|
|
rids += [i.id for i in Role.get_by(app_id=app_id, fl='id', to_dict=False)]
|
|
rids += [i.id for i in Role.get_by(__func_is___key_uid=None, __func_is___key_app_id=None, fl='id', to_dict=False)]
|
|
|
|
current_app.logger.info(rids)
|
|
for rid in rids:
|
|
if resource_id and resource_id in RoleRelationCache.get_resources(rid, app_id).get('id2perms', {}):
|
|
RoleRelationCache.rebuild2(rid, app_id)
|
|
|
|
if group_id and group_id in RoleRelationCache.get_resources(rid, app_id).get('group2perms', {}):
|
|
RoleRelationCache.rebuild2(rid, app_id)
|
|
|
|
|
|
@celery.task(name="acl.apply_trigger", queue=ACL_QUEUE)
|
|
@flush_db
|
|
@reconnect_db
|
|
def apply_trigger(_id, resource_id=None, operator_uid=None):
|
|
from api.lib.perm.acl.permission import PermissionCRUD
|
|
|
|
trigger = Trigger.get_by_id(_id)
|
|
if trigger is None:
|
|
return
|
|
|
|
uid = json.loads(trigger.uid or '[]')
|
|
if resource_id is None:
|
|
wildcard = (trigger.wildcard or '')
|
|
|
|
if wildcard and uid:
|
|
query = Resource.get_by(__func_in___key_uid=uid,
|
|
app_id=trigger.app_id,
|
|
resource_type_id=trigger.resource_type_id,
|
|
fl=['id', 'app_id'],
|
|
only_query=True)
|
|
try:
|
|
re.compile(wildcard)
|
|
|
|
resources = query.filter(Resource.name.op('regexp')(wildcard)).all()
|
|
except:
|
|
resources = query.filter(Resource.name.ilike(wildcard.replace('*', '%'))).all()
|
|
elif wildcard:
|
|
query = Resource.get_by(app_id=trigger.app_id,
|
|
resource_type_id=trigger.resource_type_id,
|
|
only_query=True)
|
|
try:
|
|
re.compile(wildcard)
|
|
|
|
resources = query.filter(Resource.name.op('regexp')(wildcard)).all()
|
|
except:
|
|
resources = query.filter(Resource.name.ilike(wildcard.replace('*', '%'))).all()
|
|
elif uid:
|
|
resources = Resource.get_by(__func_in___key_uid=uid,
|
|
app_id=trigger.app_id,
|
|
resource_type_id=trigger.resource_type_id,
|
|
to_dict=False)
|
|
else:
|
|
resources = []
|
|
else:
|
|
resources = [Resource.get_by_id(resource_id)]
|
|
|
|
perms = json.loads(trigger.permissions)
|
|
roles = json.loads(trigger.roles)
|
|
for resource in resources:
|
|
for rid in roles:
|
|
try:
|
|
PermissionCRUD.grant(rid, perms, resource.id, rebuild=False, source=AuditOperateSource.trigger)
|
|
except (NotFound, BadRequest):
|
|
pass
|
|
|
|
AuditCRUD.add_trigger_log(trigger.app_id, trigger.id, AuditOperateType.trigger_apply, {}, trigger.to_dict(),
|
|
{'uid': uid,
|
|
'resource_ids': [r.id for r in resources],
|
|
'perms': perms,
|
|
'rids': roles},
|
|
uid=operator_uid, source=AuditOperateSource.trigger)
|
|
|
|
if resources:
|
|
role_rebuild(roles, resources[0].app_id)
|
|
|
|
|
|
@celery.task(name="acl.cancel_trigger", queue=ACL_QUEUE)
|
|
@flush_db
|
|
@reconnect_db
|
|
def cancel_trigger(_id, resource_id=None, operator_uid=None):
|
|
from api.lib.perm.acl.permission import PermissionCRUD
|
|
|
|
trigger = Trigger.get_by_id(_id)
|
|
if trigger is None:
|
|
return
|
|
|
|
uid = json.loads(trigger.uid or '[]')
|
|
if resource_id is None:
|
|
wildcard = (trigger.wildcard or '')
|
|
|
|
if wildcard and uid:
|
|
query = Resource.get_by(__func_in___key_uid=uid,
|
|
app_id=trigger.app_id,
|
|
resource_type_id=trigger.resource_type_id,
|
|
fl=['id', 'app_id'],
|
|
only_query=True)
|
|
try:
|
|
re.compile(wildcard)
|
|
|
|
resources = query.filter(Resource.name.op('regexp')(wildcard)).all()
|
|
except:
|
|
resources = query.filter(Resource.name.ilike(wildcard.replace('*', '%'))).all()
|
|
elif wildcard:
|
|
query = Resource.get_by(app_id=trigger.app_id,
|
|
resource_type_id=trigger.resource_type_id,
|
|
only_query=True)
|
|
try:
|
|
re.compile(wildcard)
|
|
|
|
resources = query.filter(Resource.name.op('regexp')(wildcard)).all()
|
|
except:
|
|
resources = query.filter(Resource.name.ilike(wildcard.replace('*', '%'))).all()
|
|
elif uid:
|
|
resources = Resource.get_by(__func_in___key_uid=uid,
|
|
app_id=trigger.app_id,
|
|
resource_type_id=trigger.resource_type_id,
|
|
to_dict=False)
|
|
else:
|
|
resources = []
|
|
else:
|
|
resources = [Resource.get_by_id(resource_id)]
|
|
|
|
perms = json.loads(trigger.permissions)
|
|
roles = json.loads(trigger.roles)
|
|
for resource in resources:
|
|
if not resource:
|
|
continue
|
|
for rid in roles:
|
|
try:
|
|
PermissionCRUD.revoke(rid, perms, resource.id, rebuild=False, source=AuditOperateSource.trigger)
|
|
except (NotFound, BadRequest):
|
|
pass
|
|
|
|
AuditCRUD.add_trigger_log(trigger.app_id, trigger.id, AuditOperateType.trigger_cancel, {}, trigger.to_dict(),
|
|
{'uid': uid,
|
|
'resource_ids': [r.id for r in resources if r],
|
|
'perms': perms,
|
|
'rids': roles},
|
|
uid=operator_uid, source=AuditOperateSource.trigger)
|
|
|
|
if resources:
|
|
role_rebuild(roles, resources[0].app_id)
|
|
|
|
|
|
@celery.task(name="acl.op_record", queue=ACL_QUEUE)
|
|
@reconnect_db
|
|
def op_record(app, role_name, operate_type, obj):
|
|
if isinstance(app, int):
|
|
app = AppCache.get(app)
|
|
app = app and app.name
|
|
|
|
if isinstance(role_name, int):
|
|
u = UserCache.get(role_name)
|
|
if u:
|
|
role_name = u.username
|
|
if not u:
|
|
r = RoleCache.get(role_name)
|
|
if r:
|
|
role_name = r.name
|
|
|
|
OperateRecordCRUD.add(app, role_name, operate_type, obj)
|