前后端全面升级

This commit is contained in:
pycook
2023-07-10 17:42:15 +08:00
parent f57ff80099
commit 98cc853dbc
641 changed files with 97789 additions and 23995 deletions

View File

@@ -1,37 +1,69 @@
# -*- coding:utf-8 -*-
import functools
import hashlib
import requests
import six
from flask import current_app, g, request
from flask import session, abort
from api.lib.cmdb.const import ResourceTypeEnum as CmdbResourceType
from api.lib.cmdb.const import RoleEnum
from api.extensions import cache
from api.lib.perm.acl.audit import AuditCRUD
from api.lib.perm.acl.cache import AppCache
from api.lib.perm.acl.cache import RoleCache
from api.lib.perm.acl.cache import UserCache
from api.lib.perm.acl.permission import PermissionCRUD
from api.lib.perm.acl.resource import ResourceCRUD
from api.lib.perm.acl.resp_format import ErrFormat
from api.lib.perm.acl.role import RoleCRUD
from api.lib.perm.acl.role import RoleRelationCRUD
from api.models.acl import App
from api.models.acl import Resource
from api.models.acl import ResourceGroup
from api.models.acl import ResourceType
from api.models.acl import Role
CMDB_RESOURCE_TYPES = CmdbResourceType.all()
def get_access_token():
url = "{0}/acl/apps/token".format(current_app.config.get('ACL_URI'))
payload = dict(app_id=current_app.config.get('APP_ID'),
secret_key=hashlib.md5(current_app.config.get('APP_SECRET_KEY').encode('utf-8')).hexdigest())
try:
res = requests.post(url, data=payload).json()
return res.get("token")
except Exception as e:
current_app.logger.error(str(e))
class AccessTokenCache(object):
TOKEN_KEY = 'TICKET::AccessToken'
@classmethod
def get(cls):
if cache.get(cls.TOKEN_KEY) is not None and cache.get(cls.TOKEN_KEY) != "":
return cache.get(cls.TOKEN_KEY)
res = get_access_token() or ""
cache.set(cls.TOKEN_KEY, res, timeout=60 * 60)
return res
@classmethod
def clean(cls):
cache.clear(cls.TOKEN_KEY)
class ACLManager(object):
def __init__(self):
self.app_id = AppCache.get('cmdb')
if not self.app_id:
raise Exception("cmdb not in acl apps")
self.app_id = self.app_id.id
def __init__(self, app=None):
self.app = AppCache.get(app or 'cmdb')
if not self.app:
raise Exception(ErrFormat.app_not_found.format(app))
self.app_id = self.app.id
def _get_resource(self, name, resource_type_name):
resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False)
resource_type or abort(404, "ResourceType <{0}> cannot be found".format(resource_type_name))
resource_type or abort(404, ErrFormat.resource_type_not_found.format(resource_type_name))
return Resource.get_by(resource_type_id=resource_type.id,
app_id=self.app_id,
@@ -52,13 +84,23 @@ class ACLManager(object):
if user:
return Role.get_by(name=name, uid=user.uid, first=True, to_dict=False)
return Role.get_by(name=name, app_id=self.app_id, first=True, to_dict=False)
return Role.get_by(name=name, app_id=self.app_id, first=True, to_dict=False) or \
Role.get_by(name=name, first=True, to_dict=False)
def add_resource(self, name, resource_type_name=None):
resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False)
resource_type or abort(404, "ResourceType <{0}> cannot be found".format(resource_type_name))
resource_type or abort(404, ErrFormat.resource_type_not_found.format(resource_type_name))
ResourceCRUD.add(name, resource_type.id, self.app_id)
uid = AuditCRUD.get_current_operate_uid()
ResourceCRUD.add(name, resource_type.id, self.app_id, uid)
def update_resource(self, name, new_name, resource_type_name=None):
resource = self._get_resource(name, resource_type_name)
if resource is None:
self.add_resource(new_name, resource_type_name)
else:
ResourceCRUD.update(resource.id, new_name)
def grant_resource_to_role(self, name, role, resource_type_name=None, permissions=None):
resource = self._get_resource(name, resource_type_name)
@@ -72,21 +114,103 @@ class ACLManager(object):
if group:
PermissionCRUD.grant(role.id, permissions, group_id=group.id)
def grant_resource_to_role_by_rid(self, name, rid, resource_type_name=None, permissions=None):
resource = self._get_resource(name, resource_type_name)
if resource:
PermissionCRUD.grant(rid, permissions, resource_id=resource.id)
else:
group = self._get_resource_group(name)
if group:
PermissionCRUD.grant(rid, permissions, group_id=group.id)
def revoke_resource_from_role(self, name, role, resource_type_name=None, permissions=None):
resource = self._get_resource(name, resource_type_name)
role = self._get_role(role)
if resource:
PermissionCRUD.revoke(role.id, permissions, resource_id=resource.id)
else:
group = self._get_resource_group(name)
if group:
PermissionCRUD.revoke(role.id, permissions, group_id=group.id)
def revoke_resource_from_role_by_rid(self, name, rid, resource_type_name=None, permissions=None):
resource = self._get_resource(name, resource_type_name)
if resource:
PermissionCRUD.revoke(rid, permissions, resource_id=resource.id)
else:
group = self._get_resource_group(name)
if group:
PermissionCRUD.revoke(rid, permissions, group_id=group.id)
def del_resource(self, name, resource_type_name=None):
resource = self._get_resource(name, resource_type_name)
if resource:
ResourceCRUD.delete(resource.id)
def has_permission(self, resource_name, resource_type, perm):
def has_permission(self, resource_name, resource_type, perm, resource_id=None):
if is_app_admin(self.app_id):
return True
role = self._get_role(g.user.username)
role or abort(404, "Role <{0}> is not found".format(g.user.username))
role or abort(404, ErrFormat.role_not_found.format(g.user.username))
return RoleCRUD.has_permission(role.id, resource_name, resource_type, self.app_id, perm)
return RoleCRUD.has_permission(role.id, resource_name, resource_type, self.app_id, perm,
resource_id=resource_id)
@staticmethod
def get_user_info(username, app_id=None):
user = UserCache.get(username)
if not user:
user = RoleCache.get_by_name(app_id, username) or RoleCache.get_by_name(None, username) # FIXME
if not user:
return abort(404, ErrFormat.user_not_found.format(username))
user = user.to_dict()
role = Role.get_by(uid=user['uid'], first=True, to_dict=False) if user.get('uid') else None
if role is not None:
user["rid"] = role.id
if app_id is None:
parent_ids = []
apps = App.get_by(to_dict=False)
for app in apps:
parent_ids.extend(RoleRelationCRUD.recursive_parent_ids(role.id, app.id))
else:
parent_ids = RoleRelationCRUD.recursive_parent_ids(role.id, app_id)
user['parents'] = [RoleCache.get(rid).name for rid in set(parent_ids) if RoleCache.get(rid)]
else:
user['parents'] = []
user['rid'] = user['id'] if user.get('id') else None
if user['rid']:
parent_ids = RoleRelationCRUD.recursive_parent_ids(user['rid'], app_id)
user['parents'] = [RoleCache.get(rid).name for rid in set(parent_ids) if RoleCache.get(rid)]
return user
def get_resources(self, resource_type_name=None):
role = self._get_role(g.user.username)
role or abort(404, ErrFormat.role_not_found.format(g.user.username))
rid = role.id
return RoleCRUD.recursive_resources(rid, self.app_id, resource_type_name).get('resources')
@staticmethod
def authenticate_with_token(token):
url = "{0}/acl/auth_with_token".format(current_app.config.get('ACL_URI'))
try:
return requests.post(url, json={"token": token},
headers={'App-Access-Token': AccessTokenCache.get()}).json()
except:
return {}
def validate_permission(resources, resource_type, perm):
def validate_permission(resources, resource_type, perm, app=None):
if not resources:
return
@@ -96,11 +220,11 @@ def validate_permission(resources, resource_type, perm):
resources = [resources] if isinstance(resources, six.string_types) else resources
for resource in resources:
if not ACLManager().has_permission(resource, resource_type, perm):
return abort(403, "has no permission")
if not ACLManager(app).has_permission(resource, resource_type, perm):
return abort(403, ErrFormat.resource_no_permission.format(resource, perm))
def has_perm(resources, resource_type, perm):
def has_perm(resources, resource_type, perm, app=None):
def decorator_has_perm(func):
@functools.wraps(func)
def wrapper_has_perm(*args, **kwargs):
@@ -108,10 +232,10 @@ def has_perm(resources, resource_type, perm):
return
if current_app.config.get("USE_ACL"):
if is_app_admin():
if is_app_admin(app):
return func(*args, **kwargs)
validate_permission(resources, resource_type, perm)
validate_permission(resources, resource_type, perm, app)
return func(*args, **kwargs)
@@ -121,11 +245,14 @@ def has_perm(resources, resource_type, perm):
def is_app_admin(app=None):
if RoleEnum.CONFIG in session.get("acl", {}).get("parentRoles", []):
return True
app = app or 'cmdb'
app_id = AppCache.get(app).id
app = AppCache.get(app)
if app is None:
return False
app_id = app.id
if 'acl_admin' in session.get("acl", {}).get("parentRoles", []):
return True
for role_name in session.get("acl", {}).get("parentRoles", []):
role = RoleCache.get_by_name(app_id, role_name)
@@ -135,7 +262,27 @@ def is_app_admin(app=None):
return False
def has_perm_from_args(arg_name, resource_type, perm, callback=None):
def is_admin():
if 'acl_admin' in session.get("acl", {}).get("parentRoles", []):
return True
return False
def admin_required(app=None):
def decorator_admin_required(func):
@functools.wraps(func)
def wrapper_admin_required(*args, **kwargs):
if is_app_admin(app):
return func(*args, **kwargs)
return abort(403, ErrFormat.admin_required)
return wrapper_admin_required
return decorator_admin_required
def has_perm_from_args(arg_name, resource_type, perm, callback=None, app=None):
def decorator_has_perm(func):
@functools.wraps(func)
def wrapper_has_perm(*args, **kwargs):
@@ -146,10 +293,10 @@ def has_perm_from_args(arg_name, resource_type, perm, callback=None):
resource = callback(resource)
if current_app.config.get("USE_ACL") and resource:
if is_app_admin():
if is_app_admin(app):
return func(*args, **kwargs)
validate_permission(resource, resource_type, perm)
validate_permission(resource, resource_type, perm, app)
return func(*args, **kwargs)
@@ -158,7 +305,7 @@ def has_perm_from_args(arg_name, resource_type, perm, callback=None):
return decorator_has_perm
def role_required(role_name):
def role_required(role_name, app=None):
def decorator_role_required(func):
@functools.wraps(func)
def wrapper_role_required(*args, **kwargs):
@@ -166,8 +313,11 @@ def role_required(role_name):
return
if current_app.config.get("USE_ACL"):
if role_name not in session.get("acl", {}).get("parentRoles", []) and not is_app_admin():
return abort(403, "Role {0} is required".format(role_name))
if getattr(g.user, 'username', None) == "worker":
return func(*args, **kwargs)
if role_name not in session.get("acl", {}).get("parentRoles", []) and not is_app_admin(app):
return abort(403, ErrFormat.role_required.format(role_name))
return func(*args, **kwargs)
return wrapper_role_required