mirror of
https://github.com/veops/cmdb.git
synced 2025-08-08 12:37:14 +08:00
前后端全面升级
This commit is contained in:
78
cmdb-api/api/views/acl/app.py
Normal file
78
cmdb-api/api/views/acl/app.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import abort
|
||||
from flask import request
|
||||
|
||||
from api.lib.decorator import args_required
|
||||
from api.lib.decorator import args_validate
|
||||
from api.lib.perm.acl.acl import is_app_admin
|
||||
from api.lib.perm.acl.app import AppCRUD
|
||||
from api.lib.perm.acl.resp_format import ErrFormat
|
||||
from api.lib.perm.auth import auth_abandoned
|
||||
from api.lib.utils import get_page
|
||||
from api.lib.utils import get_page_size
|
||||
from api.resource import APIView
|
||||
|
||||
|
||||
class AppView(APIView):
|
||||
url_prefix = ('/apps', '/apps/<int:_id>')
|
||||
|
||||
def get(self, _id=None):
|
||||
if _id is not None:
|
||||
if not is_app_admin('acl'):
|
||||
return abort(403, ErrFormat.no_permission)
|
||||
|
||||
app = AppCRUD.get(_id)
|
||||
app = app and app.to_dict() or {}
|
||||
|
||||
return self.jsonify(**app)
|
||||
|
||||
page = get_page(request.values.get('page', 1))
|
||||
page_size = get_page_size(request.values.get('page_size'))
|
||||
q = request.values.get('q')
|
||||
|
||||
numfound, res = AppCRUD.search(q, page, page_size)
|
||||
|
||||
res = [i.to_dict() for i in res]
|
||||
for i in res:
|
||||
i.pop('app_id', None)
|
||||
i.pop('secret_key', None)
|
||||
|
||||
return self.jsonify(page=page,
|
||||
page_size=page_size,
|
||||
numfound=numfound,
|
||||
total=len(res),
|
||||
apps=res)
|
||||
|
||||
@args_required('name')
|
||||
@args_validate(AppCRUD.cls)
|
||||
def post(self):
|
||||
name = request.values.get('name')
|
||||
description = request.values.get('description')
|
||||
|
||||
app = AppCRUD.add(name, description)
|
||||
|
||||
return self.jsonify(app.to_dict())
|
||||
|
||||
@args_validate(AppCRUD.cls)
|
||||
def put(self, _id):
|
||||
app = AppCRUD.update(_id, **request.values)
|
||||
|
||||
return self.jsonify(app.to_dict())
|
||||
|
||||
def delete(self, _id):
|
||||
AppCRUD.delete(_id)
|
||||
|
||||
return self.jsonify(id=_id)
|
||||
|
||||
|
||||
class AppAccessTokenView(APIView):
|
||||
url_prefix = '/apps/token'
|
||||
|
||||
@args_required('app_id')
|
||||
@args_required('secret_key')
|
||||
@auth_abandoned
|
||||
def post(self):
|
||||
token = AppCRUD.gen_token(request.values.get('app_id'), request.values.get('secret_key'))
|
||||
|
||||
return self.jsonify(token=token)
|
39
cmdb-api/api/views/acl/audit.py
Normal file
39
cmdb-api/api/views/acl/audit.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import request, abort
|
||||
|
||||
from api.lib.perm.acl.audit import AuditCRUD
|
||||
from api.lib.utils import get_page
|
||||
from api.lib.utils import get_page_size
|
||||
from api.resource import APIView
|
||||
|
||||
|
||||
class AuditLogView(APIView):
|
||||
url_prefix = ("/audit_log/<string:name>",)
|
||||
|
||||
def get(self, name):
|
||||
page = get_page(request.values.get("page", 1))
|
||||
page_size = get_page_size(request.values.get("page_size"))
|
||||
app_id = request.values.get('app_id')
|
||||
q = request.values.get('q')
|
||||
start = request.values.get('start')
|
||||
end = request.values.get('end')
|
||||
|
||||
func_map = {
|
||||
'permission': AuditCRUD.search_permission,
|
||||
'role': AuditCRUD.search_role,
|
||||
'trigger': AuditCRUD.search_trigger,
|
||||
'resource': AuditCRUD.search_resource,
|
||||
}
|
||||
if name not in func_map:
|
||||
abort(400, f'wrong {name}, please use {func_map.keys()}')
|
||||
|
||||
_func = func_map[name]
|
||||
|
||||
data = _func(app_id, q, page, page_size, start, end)
|
||||
|
||||
return self.jsonify(
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
**data,
|
||||
)
|
179
cmdb-api/api/views/acl/login.py
Normal file
179
cmdb-api/api/views/acl/login.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import datetime
|
||||
|
||||
import jwt
|
||||
import six
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import request
|
||||
from flask import session
|
||||
from flask_login import login_user, logout_user
|
||||
|
||||
from api.lib.decorator import args_required
|
||||
from api.lib.decorator import args_validate
|
||||
from api.lib.perm.acl.acl import ACLManager
|
||||
from api.lib.perm.acl.cache import RoleCache
|
||||
from api.lib.perm.acl.cache import User
|
||||
from api.lib.perm.acl.cache import UserCache
|
||||
from api.lib.perm.acl.resp_format import ErrFormat
|
||||
from api.lib.perm.auth import auth_abandoned
|
||||
from api.lib.perm.auth import auth_with_app_token
|
||||
from api.models.acl import Role
|
||||
from api.resource import APIView
|
||||
|
||||
|
||||
class LoginView(APIView):
|
||||
url_prefix = "/login"
|
||||
|
||||
@args_required("username")
|
||||
@args_required("password")
|
||||
@auth_abandoned
|
||||
@args_validate(User)
|
||||
def post(self):
|
||||
username = request.values.get("username") or request.values.get("email")
|
||||
password = request.values.get("password")
|
||||
_role = None
|
||||
if current_app.config.get('AUTH_WITH_LDAP'):
|
||||
user, authenticated = User.query.authenticate_with_ldap(username, password)
|
||||
else:
|
||||
user, authenticated = User.query.authenticate(username, password)
|
||||
if not user:
|
||||
_role, authenticated = Role.query.authenticate(username, password)
|
||||
|
||||
if not user and not _role:
|
||||
return abort(401, ErrFormat.user_not_found.format(username))
|
||||
|
||||
if not authenticated:
|
||||
return abort(401, ErrFormat.invalid_password)
|
||||
|
||||
if user:
|
||||
login_user(user)
|
||||
user.update(has_logined=True, last_login=datetime.datetime.now())
|
||||
|
||||
token = jwt.encode({
|
||||
'sub': user.email,
|
||||
'iat': datetime.datetime.now(),
|
||||
'exp': datetime.datetime.now() + datetime.timedelta(minutes=24 * 60 * 7)},
|
||||
current_app.config['SECRET_KEY'])
|
||||
|
||||
username = username.split("@")[0]
|
||||
user_info = ACLManager.get_user_info(username)
|
||||
|
||||
session["acl"] = dict(uid=user_info.get("uid"),
|
||||
avatar=user.avatar if user else user_info.get("avatar"),
|
||||
userId=user_info.get("uid"),
|
||||
rid=user_info.get("rid"),
|
||||
userName=user_info.get("username"),
|
||||
nickName=user_info.get("nickname"),
|
||||
parentRoles=user_info.get("parents"),
|
||||
childRoles=user_info.get("children"),
|
||||
roleName=user_info.get("role"))
|
||||
session["uid"] = user_info.get("uid")
|
||||
|
||||
return self.jsonify(token=token.decode() if six.PY2 else token, username=username)
|
||||
else:
|
||||
return self.jsonify(username=username)
|
||||
|
||||
|
||||
class AuthWithKeyView(APIView):
|
||||
url_prefix = "/auth_with_key"
|
||||
|
||||
@args_required("key")
|
||||
@args_required("secret")
|
||||
@args_required("path")
|
||||
@auth_abandoned
|
||||
def post(self):
|
||||
key = request.values.get('key')
|
||||
secret = request.values.get('secret')
|
||||
path = six.moves.urllib.parse.urlparse(request.values.get('path')).path
|
||||
payload = request.values.get('payload') or {}
|
||||
|
||||
payload.pop('_key', None)
|
||||
payload.pop('_secret', None)
|
||||
|
||||
req_args = [str(payload[k]) for k in sorted(payload.keys())]
|
||||
user, authenticated = User.query.authenticate_with_key(key, secret, req_args, path)
|
||||
if user:
|
||||
role = RoleCache.get_by_name(None, user.username)
|
||||
role or abort(404, ErrFormat.role_not_found.format(user.username))
|
||||
user = user.to_dict()
|
||||
else:
|
||||
role, authenticated = Role.query.authenticate_with_key(key, secret, req_args, path)
|
||||
user = role and role.to_dict() or {}
|
||||
|
||||
can_proxy = True if role and role.is_app_admin else False
|
||||
|
||||
if can_proxy and request.values.get('proxy'):
|
||||
role = RoleCache.get_by_name(None, request.values.get('proxy'))
|
||||
role or abort(404, ErrFormat.role_not_found.format(request.values.get('proxy')))
|
||||
user = role and role.to_dict() or {}
|
||||
|
||||
user['rid'] = role and role.id
|
||||
user.pop('password', None)
|
||||
user.pop('key', None)
|
||||
user.pop('secret', None)
|
||||
|
||||
if not user.get('username'):
|
||||
user['username'] = user.get('name')
|
||||
|
||||
return self.jsonify(user=user,
|
||||
authenticated=authenticated,
|
||||
rid=role and role.id,
|
||||
can_proxy=can_proxy)
|
||||
|
||||
|
||||
class AuthWithTokenView(APIView):
|
||||
url_prefix = ("/auth_with_token", "/req_token")
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
username = request.values.get('username')
|
||||
|
||||
token = jwt.encode({
|
||||
'sub': username,
|
||||
'iat': datetime.datetime.now(),
|
||||
'exp': datetime.datetime.now() + datetime.timedelta(minutes=2 * 60)},
|
||||
current_app.config['SECRET_KEY'])
|
||||
|
||||
return self.jsonify(token=token)
|
||||
|
||||
@args_required("token")
|
||||
@auth_with_app_token
|
||||
def post(self):
|
||||
token = request.values.get('token')
|
||||
|
||||
user = None
|
||||
try:
|
||||
data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])
|
||||
authenticated = True
|
||||
user = UserCache.get(data.get('sub'))
|
||||
if not user:
|
||||
authenticated = False
|
||||
except jwt.ExpiredSignatureError:
|
||||
authenticated = False
|
||||
except (jwt.InvalidTokenError, Exception) as e:
|
||||
current_app.logger.error(str(e))
|
||||
authenticated = False
|
||||
|
||||
if user is not None:
|
||||
role = RoleCache.get_by_name(None, user.username)
|
||||
role or abort(404, ErrFormat.role_not_found.format(user.username))
|
||||
user = user.to_dict()
|
||||
|
||||
user['rid'] = role and role.id
|
||||
user.pop('password', None)
|
||||
user.pop('key', None)
|
||||
user.pop('secret', None)
|
||||
|
||||
return self.jsonify(user=user,
|
||||
authenticated=authenticated)
|
||||
|
||||
|
||||
class LogoutView(APIView):
|
||||
url_prefix = "/logout"
|
||||
|
||||
@auth_abandoned
|
||||
def post(self):
|
||||
logout_user()
|
||||
self.jsonify(code=200)
|
@@ -1,10 +1,17 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import request
|
||||
|
||||
from api.lib.decorator import args_required
|
||||
from api.lib.perm.acl.acl import ACLManager
|
||||
from api.lib.perm.acl.cache import AppCache
|
||||
from api.lib.perm.acl.permission import PermissionCRUD
|
||||
from api.lib.perm.acl.resp_format import ErrFormat
|
||||
from api.lib.perm.auth import auth_only_for_acl
|
||||
from api.lib.perm.auth import auth_with_app_token
|
||||
from api.lib.utils import handle_arg_list
|
||||
from api.resource import APIView
|
||||
|
||||
@@ -12,29 +19,149 @@ from api.resource import APIView
|
||||
class ResourcePermissionView(APIView):
|
||||
url_prefix = ("/resources/<int:resource_id>/permissions", "/resource_groups/<int:group_id>/permissions")
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self, resource_id=None, group_id=None):
|
||||
return self.jsonify(PermissionCRUD.get_all(resource_id, group_id))
|
||||
need_users = request.values.get('need_users', 1) in current_app.config.get('BOOL_TRUE')
|
||||
return self.jsonify(PermissionCRUD.get_all(resource_id, group_id, need_users=need_users))
|
||||
|
||||
|
||||
class ResourcePermission2View(APIView):
|
||||
url_prefix = "/resource/permissions"
|
||||
|
||||
@args_required('resource_name')
|
||||
@args_required('resource_type_name')
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
resource_name = request.values.get('resource_name')
|
||||
resource_type_name = request.values.get('resource_type_name')
|
||||
app_id = request.values.get('app_id')
|
||||
|
||||
return self.jsonify(PermissionCRUD.get_all2(resource_name, resource_type_name, app_id))
|
||||
|
||||
|
||||
class RolePermissionGrantView(APIView):
|
||||
url_prefix = ('/roles/<int:rid>/resources/<int:resource_id>/grant',
|
||||
'/roles/<int:rid>/resource_groups/<int:group_id>/grant')
|
||||
'/roles/<int:rid>/resource_groups/<int:group_id>/grant',
|
||||
'/roles/<int:rid>/resources/batch/grant2', # by names
|
||||
)
|
||||
|
||||
@args_required('perms')
|
||||
@auth_only_for_acl
|
||||
def post(self, rid, resource_id=None, group_id=None):
|
||||
perms = handle_arg_list(request.values.get("perms"))
|
||||
|
||||
if "batch" in request.url:
|
||||
resource_ids = request.values.get('resource_ids')
|
||||
perm_map = request.values.get('perm_map')
|
||||
resource_names = request.values.get('resource_names')
|
||||
resource_type_id = request.values.get('resource_type_id')
|
||||
app = AppCache.get(request.values.get('app_id'))
|
||||
PermissionCRUD.batch_grant_by_resource_names(rid, perms, resource_type_id, resource_names,
|
||||
resource_ids, perm_map, app_id=app and app.id)
|
||||
|
||||
return self.jsonify(rid=rid, resource_names=resource_names, resource_type_id=resource_type_id, perms=perms)
|
||||
|
||||
PermissionCRUD.grant(rid, perms, resource_id=resource_id, group_id=group_id)
|
||||
|
||||
return self.jsonify(rid=rid, resource_id=resource_id, group_id=group_id, perms=perms)
|
||||
|
||||
|
||||
class RolePermissionGrant2View(APIView):
|
||||
url_prefix = ('/roles/<int:rid>/resources/<int:resource_id>/grant2',)
|
||||
|
||||
def post(self, rid, resource_id):
|
||||
if not ACLManager(request.values.get('app_id')).has_permission(None, None, 'grant', resource_id):
|
||||
return abort(403, ErrFormat.no_permission2)
|
||||
|
||||
perms = handle_arg_list(request.values.get("perms"))
|
||||
|
||||
PermissionCRUD.grant(rid, perms, resource_id=resource_id)
|
||||
|
||||
return self.jsonify(rid=rid, resource_id=resource_id, perms=perms)
|
||||
|
||||
|
||||
class RolePermissionBatchGrantView(APIView):
|
||||
url_prefix = ('/roles/<int:rid>/resources/batch/grant',
|
||||
'/roles/<int:rid>/resource_groups/batch/grant')
|
||||
|
||||
@auth_only_for_acl
|
||||
def post(self, rid):
|
||||
resource_ids = request.values.get('resource_ids')
|
||||
group_ids = request.values.get('group_ids')
|
||||
|
||||
perms = handle_arg_list(request.values.get("perms"))
|
||||
|
||||
if resource_ids and isinstance(resource_ids, list):
|
||||
for resource_id in resource_ids[:-1]:
|
||||
PermissionCRUD.grant(rid, perms, resource_id=resource_id, group_id=None, rebuild=False)
|
||||
PermissionCRUD.grant(rid, perms, resource_id=resource_ids[-1], group_id=None, rebuild=True)
|
||||
|
||||
if group_ids and isinstance(group_ids, list):
|
||||
for group_id in group_ids[:-1]:
|
||||
PermissionCRUD.grant(rid, perms, resource_id=None, group_id=group_id, rebuild=False)
|
||||
PermissionCRUD.grant(rid, perms, resource_id=None, group_id=group_ids[-1], rebuild=True)
|
||||
|
||||
return self.jsonify(rid=rid, resource_ids=resource_ids, group_ids=group_ids, perms=perms)
|
||||
|
||||
|
||||
class RolePermissionRevokeView(APIView):
|
||||
url_prefix = ('/roles/<int:rid>/resources/<int:resource_id>/revoke',
|
||||
'/roles/<int:rid>/resource_groups/<int:group_id>/revoke')
|
||||
'/roles/<int:rid>/resource_groups/<int:group_id>/revoke',
|
||||
'/roles/<int:rid>/resources/batch/revoke2', # by names
|
||||
)
|
||||
|
||||
@args_required('perms')
|
||||
@auth_only_for_acl
|
||||
def post(self, rid, resource_id=None, group_id=None):
|
||||
perms = handle_arg_list(request.values.get("perms"))
|
||||
if "batch" in request.url:
|
||||
resource_names = request.values.get('resource_names')
|
||||
resource_type_id = request.values.get('resource_type_id')
|
||||
resource_ids = request.values.get('resource_ids')
|
||||
perm_map = request.values.get('perm_map')
|
||||
app = AppCache.get(request.values.get('app_id'))
|
||||
PermissionCRUD.batch_revoke_by_resource_names(rid, perms, resource_type_id, resource_names,
|
||||
resource_ids, perm_map, app_id=app and app.id)
|
||||
|
||||
return self.jsonify(rid=rid, resource_names=resource_names, resource_type_id=resource_type_id, perms=perms)
|
||||
|
||||
PermissionCRUD.revoke(rid, perms, resource_id=resource_id, group_id=group_id)
|
||||
|
||||
return self.jsonify(rid=rid, resource_id=resource_id, group_id=group_id, perms=perms)
|
||||
|
||||
|
||||
class RolePermissionRevoke2View(APIView):
|
||||
url_prefix = ('/roles/<int:rid>/resources/<int:resource_id>/revoke2',
|
||||
'/roles/<int:rid>/resource_groups/<int:group_id>/revoke2',)
|
||||
|
||||
def post(self, rid, resource_id=None, group_id=None):
|
||||
if not ACLManager(request.values.get('app_id')).has_permission(None, None, 'grant', resource_id):
|
||||
return abort(403, ErrFormat.no_permission2)
|
||||
|
||||
perms = handle_arg_list(request.values.get("perms"))
|
||||
|
||||
PermissionCRUD.revoke(rid, perms, resource_id=resource_id, group_id=group_id)
|
||||
|
||||
return self.jsonify(rid=rid, resource_id=resource_id, perms=perms)
|
||||
|
||||
|
||||
class RolePermissionBatchRevokeView(APIView):
|
||||
url_prefix = ('/roles/<int:rid>/resources/batch/revoke',
|
||||
'/roles/<int:rid>/resource_groups/batch/revoke')
|
||||
|
||||
@auth_only_for_acl
|
||||
def post(self, rid):
|
||||
resource_ids = request.values.get('resource_ids')
|
||||
group_ids = request.values.get('group_ids')
|
||||
|
||||
perms = handle_arg_list(request.values.get("perms"))
|
||||
|
||||
if resource_ids and isinstance(resource_ids, list):
|
||||
for resource_id in resource_ids[:-1]:
|
||||
PermissionCRUD.revoke(rid, perms, resource_id=resource_id, group_id=None, rebuild=False)
|
||||
PermissionCRUD.revoke(rid, perms, resource_id=resource_ids[-1], group_id=None, rebuild=True)
|
||||
|
||||
if group_ids and isinstance(group_ids, list):
|
||||
for group_id in group_ids[:-1]:
|
||||
PermissionCRUD.revoke(rid, perms, resource_id=None, group_id=group_id, rebuild=False)
|
||||
PermissionCRUD.revoke(rid, perms, resource_id=None, group_id=group_ids[-1], rebuild=True)
|
||||
|
||||
return self.jsonify(rid=rid, resource_ids=resource_ids, group_ids=group_ids, perms=perms)
|
||||
|
@@ -1,12 +1,16 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import g
|
||||
from flask import request
|
||||
|
||||
from api.lib.decorator import args_required
|
||||
from api.lib.decorator import args_validate
|
||||
from api.lib.perm.acl import validate_app
|
||||
from api.lib.perm.acl.resource import ResourceCRUD
|
||||
from api.lib.perm.acl.resource import ResourceGroupCRUD
|
||||
from api.lib.perm.acl.resource import ResourceTypeCRUD
|
||||
from api.lib.perm.auth import auth_only_for_acl
|
||||
from api.lib.perm.auth import auth_with_app_token
|
||||
from api.lib.utils import get_page
|
||||
from api.lib.utils import get_page_size
|
||||
from api.lib.utils import handle_arg_list
|
||||
@@ -16,8 +20,8 @@ from api.resource import APIView
|
||||
class ResourceTypeView(APIView):
|
||||
url_prefix = ("/resource_types", "/resource_types/<int:type_id>")
|
||||
|
||||
@args_required('app_id')
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
page = get_page(request.values.get("page", 1))
|
||||
page_size = get_page_size(request.values.get("page_size"))
|
||||
@@ -33,9 +37,10 @@ class ResourceTypeView(APIView):
|
||||
id2perms=id2perms)
|
||||
|
||||
@args_required('name')
|
||||
@args_required('app_id')
|
||||
@args_required('perms')
|
||||
@validate_app
|
||||
@auth_only_for_acl
|
||||
@args_validate(ResourceTypeCRUD.cls, exclude_args=['app_id'])
|
||||
def post(self):
|
||||
name = request.values.get('name')
|
||||
app_id = request.values.get('app_id')
|
||||
@@ -46,11 +51,14 @@ class ResourceTypeView(APIView):
|
||||
|
||||
return self.jsonify(rt.to_dict())
|
||||
|
||||
@auth_only_for_acl
|
||||
@args_validate(ResourceTypeCRUD.cls, exclude_args=['app_id'])
|
||||
def put(self, type_id):
|
||||
rt = ResourceTypeCRUD.update(type_id, **request.values)
|
||||
|
||||
return self.jsonify(rt.to_dict())
|
||||
|
||||
@auth_only_for_acl
|
||||
def delete(self, type_id):
|
||||
ResourceTypeCRUD.delete(type_id)
|
||||
|
||||
@@ -60,6 +68,7 @@ class ResourceTypeView(APIView):
|
||||
class ResourceTypePermsView(APIView):
|
||||
url_prefix = "/resource_types/<int:type_id>/perms"
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self, type_id):
|
||||
return self.jsonify(ResourceTypeCRUD.get_perms(type_id))
|
||||
|
||||
@@ -67,36 +76,43 @@ class ResourceTypePermsView(APIView):
|
||||
class ResourceView(APIView):
|
||||
url_prefix = ("/resources", "/resources/<int:resource_id>")
|
||||
|
||||
@args_required('app_id')
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
page = get_page(request.values.get("page", 1))
|
||||
page_size = get_page_size(request.values.get("page_size"))
|
||||
q = request.values.get('q')
|
||||
u = request.values.get('u')
|
||||
resource_type_id = request.values.get('resource_type_id')
|
||||
app_id = request.values.get('app_id')
|
||||
|
||||
numfound, res = ResourceCRUD.search(q, app_id, resource_type_id, page, page_size)
|
||||
numfound, res = ResourceCRUD.search(q, u, app_id, resource_type_id, page, page_size)
|
||||
|
||||
return self.jsonify(numfound=numfound,
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
resources=[i.to_dict() for i in res])
|
||||
resources=res)
|
||||
|
||||
@args_required('name')
|
||||
@args_required('type_id')
|
||||
@args_required('app_id')
|
||||
@validate_app
|
||||
@auth_only_for_acl
|
||||
@args_validate(ResourceCRUD.cls, exclude_args=['app_id'])
|
||||
def post(self):
|
||||
name = request.values.get('name')
|
||||
type_id = request.values.get('type_id')
|
||||
app_id = request.values.get('app_id')
|
||||
uid = request.values.get('uid')
|
||||
if not uid and hasattr(g, "user") and hasattr(g.user, "uid"):
|
||||
uid = g.user.uid
|
||||
|
||||
resource = ResourceCRUD.add(name, type_id, app_id)
|
||||
resource = ResourceCRUD.add(name, type_id, app_id, uid)
|
||||
|
||||
return self.jsonify(resource.to_dict())
|
||||
|
||||
@args_required('name')
|
||||
@auth_only_for_acl
|
||||
@args_validate(ResourceCRUD.cls, exclude_args=['app_id'])
|
||||
def put(self, resource_id):
|
||||
name = request.values.get('name')
|
||||
|
||||
@@ -104,6 +120,7 @@ class ResourceView(APIView):
|
||||
|
||||
return self.jsonify(resource.to_dict())
|
||||
|
||||
@auth_only_for_acl
|
||||
def delete(self, resource_id):
|
||||
ResourceCRUD.delete(resource_id)
|
||||
|
||||
@@ -113,15 +130,16 @@ class ResourceView(APIView):
|
||||
class ResourceGroupView(APIView):
|
||||
url_prefix = ("/resource_groups", "/resource_groups/<int:group_id>")
|
||||
|
||||
@args_required('app_id')
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
page = get_page(request.values.get("page", 1))
|
||||
page_size = get_page_size(request.values.get("page_size"))
|
||||
q = request.values.get('q')
|
||||
app_id = request.values.get('app_id')
|
||||
resource_type_id = request.values.get('resource_type_id')
|
||||
|
||||
numfound, res = ResourceGroupCRUD.search(q, app_id, page, page_size)
|
||||
numfound, res = ResourceGroupCRUD.search(q, app_id, resource_type_id, page, page_size)
|
||||
|
||||
return self.jsonify(numfound=numfound,
|
||||
page=page,
|
||||
@@ -130,8 +148,9 @@ class ResourceGroupView(APIView):
|
||||
|
||||
@args_required('name')
|
||||
@args_required('type_id')
|
||||
@args_required('app_id')
|
||||
@validate_app
|
||||
@auth_only_for_acl
|
||||
@args_validate(ResourceGroupCRUD.cls, exclude_args=['app_id'])
|
||||
def post(self):
|
||||
name = request.values.get('name')
|
||||
type_id = request.values.get('type_id')
|
||||
@@ -142,6 +161,8 @@ class ResourceGroupView(APIView):
|
||||
return self.jsonify(group.to_dict())
|
||||
|
||||
@args_required('items')
|
||||
@auth_only_for_acl
|
||||
@args_validate(ResourceGroupCRUD.cls, exclude_args=['app_id'])
|
||||
def put(self, group_id):
|
||||
items = handle_arg_list(request.values.get("items"))
|
||||
|
||||
@@ -151,6 +172,7 @@ class ResourceGroupView(APIView):
|
||||
|
||||
return self.jsonify(items)
|
||||
|
||||
@auth_only_for_acl
|
||||
def delete(self, group_id):
|
||||
ResourceGroupCRUD.delete(group_id)
|
||||
|
||||
@@ -160,6 +182,7 @@ class ResourceGroupView(APIView):
|
||||
class ResourceGroupItemsView(APIView):
|
||||
url_prefix = "/resource_groups/<int:group_id>/items"
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self, group_id):
|
||||
items = ResourceGroupCRUD.get_items(group_id)
|
||||
|
||||
|
@@ -1,12 +1,21 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from flask import request
|
||||
|
||||
from api.lib.decorator import args_required
|
||||
from api.lib.decorator import args_validate
|
||||
from api.lib.perm.acl import validate_app
|
||||
from api.lib.perm.acl.acl import is_app_admin
|
||||
from api.lib.perm.acl.cache import AppCache
|
||||
from api.lib.perm.acl.cache import RoleCache
|
||||
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.lib.perm.auth import auth_only_for_acl
|
||||
from api.lib.perm.auth import auth_with_app_token
|
||||
from api.lib.utils import get_page
|
||||
from api.lib.utils import get_page_size
|
||||
from api.resource import APIView
|
||||
@@ -15,43 +24,56 @@ from api.resource import APIView
|
||||
class RoleView(APIView):
|
||||
url_prefix = ("/roles", "/roles/<int:rid>")
|
||||
|
||||
@args_required('app_id')
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
page = get_page(request.values.get("page", 1))
|
||||
page_size = get_page_size(request.values.get("page_size"))
|
||||
q = request.values.get('q')
|
||||
app_id = request.values.get('app_id')
|
||||
is_all = request.values.get('is_all', True)
|
||||
is_all = True if is_all in current_app.config.get("BOOL_TRUE") else False
|
||||
user_role = request.values.get('user_role', True)
|
||||
user_only = request.values.get('user_only', False)
|
||||
user_role = True if user_role in current_app.config.get("BOOL_TRUE") else False
|
||||
user_only = True if user_only in current_app.config.get("BOOL_TRUE") else False
|
||||
|
||||
numfound, roles = RoleCRUD.search(q, app_id, page, page_size, user_role)
|
||||
numfound, roles = RoleCRUD.search(q, app_id, page, page_size, user_role, is_all, user_only)
|
||||
|
||||
id2parents = RoleRelationCRUD.get_parents([i.id for i in roles])
|
||||
id2parents = RoleRelationCRUD.get_parents([i.id for i in roles], app_id=app_id)
|
||||
|
||||
roles = [i.to_dict() for i in roles]
|
||||
for i in roles:
|
||||
i.pop('password', None)
|
||||
|
||||
return self.jsonify(numfound=numfound,
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
id2parents=id2parents,
|
||||
roles=[i.to_dict() for i in roles])
|
||||
roles=roles)
|
||||
|
||||
@args_required('name')
|
||||
@args_required('app_id')
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
@args_validate(RoleCRUD.cls, exclude_args=['app_id'])
|
||||
def post(self):
|
||||
name = request.values.get('name')
|
||||
app_id = request.values.get('app_id')
|
||||
is_app_admin = request.values.get('is_app_admin', False)
|
||||
password = request.values.get('password')
|
||||
_is_app_admin = request.values.get('is_app_admin', False)
|
||||
|
||||
role = RoleCRUD.add_role(name, app_id, is_app_admin=is_app_admin)
|
||||
role = RoleCRUD.add_role(name, app_id, password=password, is_app_admin=_is_app_admin)
|
||||
|
||||
return self.jsonify(role.to_dict())
|
||||
|
||||
@auth_only_for_acl
|
||||
@args_validate(RoleCRUD.cls, exclude_args=['app_id'])
|
||||
def put(self, rid):
|
||||
role = RoleCRUD.update_role(rid, **request.values)
|
||||
|
||||
return self.jsonify(role.to_dict())
|
||||
|
||||
@auth_only_for_acl
|
||||
def delete(self, rid):
|
||||
RoleCRUD.delete_role(rid)
|
||||
|
||||
@@ -59,19 +81,97 @@ class RoleView(APIView):
|
||||
|
||||
|
||||
class RoleRelationView(APIView):
|
||||
url_prefix = "/roles/<int:child_id>/parents"
|
||||
url_prefix = ("/roles/<int:rid>/parents", "/roles/<int:rid>/users", "/roles/<int:rid>/children")
|
||||
|
||||
@auth_with_app_token
|
||||
@validate_app
|
||||
def get(self, rid):
|
||||
app_id = request.values.get('app_id')
|
||||
app = AppCache.get(app_id)
|
||||
if app and app.name == "acl":
|
||||
app_id = None # global
|
||||
|
||||
users = RoleRelationCRUD.get_users_by_rid(rid, app_id)
|
||||
|
||||
return self.jsonify(users=users)
|
||||
|
||||
@auth_only_for_acl
|
||||
@validate_app
|
||||
@args_validate(RoleRelationCRUD.cls, exclude_args=['app_id'])
|
||||
def post(self, rid):
|
||||
|
||||
app_id = request.values.get('app_id')
|
||||
app = AppCache.get(app_id)
|
||||
if app and app.name == "acl":
|
||||
app_id = None # global
|
||||
|
||||
role = RoleCache.get(rid) or abort(400, ErrFormat.role_not_found.format("id={}".format(rid)))
|
||||
|
||||
if request.values.get('parent_id'):
|
||||
parent_id = request.values.get('parent_id')
|
||||
|
||||
res = RoleRelationCRUD.add(role, parent_id, [rid], app_id)
|
||||
|
||||
return self.jsonify(res)
|
||||
elif request.values.get("child_ids") and isinstance(request.values['child_ids'], list):
|
||||
res = RoleRelationCRUD.add(role, rid, request.values['child_ids'], app_id)
|
||||
|
||||
return self.jsonify(res)
|
||||
|
||||
else:
|
||||
return abort(400, ErrFormat.invalid_request)
|
||||
|
||||
@args_required('parent_id')
|
||||
def post(self, child_id):
|
||||
parent_id = request.values.get('parent_id')
|
||||
res = RoleRelationCRUD.add(parent_id, child_id)
|
||||
|
||||
return self.jsonify(res.to_dict())
|
||||
|
||||
@args_required('parent_id')
|
||||
def delete(self, child_id):
|
||||
@auth_only_for_acl
|
||||
@validate_app
|
||||
def delete(self, rid):
|
||||
parent_id = request.values.get('parent_id')
|
||||
|
||||
RoleRelationCRUD.delete2(parent_id, child_id)
|
||||
app_id = request.values.get('app_id')
|
||||
app = AppCache.get(app_id)
|
||||
if app and app.name == "acl":
|
||||
app_id = None # global
|
||||
|
||||
return self.jsonify(parent_id=parent_id, child_id=child_id)
|
||||
RoleRelationCRUD.delete2(parent_id, rid, app_id)
|
||||
|
||||
return self.jsonify(parent_id=parent_id, child_id=rid)
|
||||
|
||||
|
||||
class RoleResourcesView(APIView):
|
||||
url_prefix = "/roles/<int:rid>/resources"
|
||||
|
||||
@auth_with_app_token
|
||||
@validate_app
|
||||
def get(self, rid):
|
||||
resource_type_id = request.values.get('resource_type_id')
|
||||
group_flat = request.values.get('group_flat', True)
|
||||
res = RoleCRUD.recursive_resources(rid, request.values['app_id'], resource_type_id, group_flat, to_record=True)
|
||||
|
||||
return self.jsonify(res)
|
||||
|
||||
|
||||
class RoleHasPermissionView(APIView):
|
||||
url_prefix = "/roles/has_perm"
|
||||
|
||||
@args_required('resource_name')
|
||||
@args_required('resource_type_name')
|
||||
@args_required('perm')
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
if not request.values.get('rid'):
|
||||
role = RoleCache.get_by_name(None, g.user.username)
|
||||
role or abort(404, ErrFormat.role_not_found.format(g.user.username))
|
||||
else:
|
||||
role = RoleCache.get(int(request.values.get('rid')))
|
||||
|
||||
app_id = request.values.get('app_id')
|
||||
if is_app_admin(app_id):
|
||||
return self.jsonify(result=True)
|
||||
|
||||
resource_name = request.values.get('resource_name')
|
||||
resource_type_name = request.values.get('resource_type_name')
|
||||
perm = request.values.get('perm')
|
||||
result = RoleCRUD.has_permission(role.id, resource_name, resource_type_name, app_id, perm)
|
||||
|
||||
return self.jsonify(result=result)
|
||||
|
92
cmdb-api/api/views/acl/trigger.py
Normal file
92
cmdb-api/api/views/acl/trigger.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import request
|
||||
|
||||
from api.lib.decorator import args_required
|
||||
from api.lib.decorator import args_validate
|
||||
from api.lib.perm.acl import validate_app
|
||||
from api.lib.perm.acl.trigger import TriggerCRUD
|
||||
from api.lib.perm.auth import auth_only_for_acl
|
||||
from api.lib.perm.auth import auth_with_app_token
|
||||
from api.resource import APIView
|
||||
|
||||
|
||||
class TriggerView(APIView):
|
||||
url_prefix = ("/triggers", "/triggers/<int:_id>")
|
||||
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
return self.jsonify(TriggerCRUD.get(request.values.get('app_id')))
|
||||
|
||||
@args_required('name')
|
||||
@args_required('resource_type_id')
|
||||
@args_required('roles')
|
||||
@args_required('permissions')
|
||||
@validate_app
|
||||
@auth_only_for_acl
|
||||
@args_validate(TriggerCRUD.cls, exclude_args=['app_id'])
|
||||
def post(self):
|
||||
request.values.pop('_key', None)
|
||||
request.values.pop('_secret', None)
|
||||
trigger = TriggerCRUD.add(request.values.pop('app_id', None), **request.values)
|
||||
|
||||
return self.jsonify(trigger.to_dict())
|
||||
|
||||
@args_required('resource_type_id')
|
||||
@args_required('roles')
|
||||
@args_required('permissions')
|
||||
@validate_app
|
||||
@auth_only_for_acl
|
||||
@args_validate(TriggerCRUD.cls, exclude_args=['app_id'])
|
||||
def put(self, _id):
|
||||
request.values.pop('_key', None)
|
||||
request.values.pop('_secret', None)
|
||||
|
||||
trigger = TriggerCRUD.update(_id, **request.values)
|
||||
|
||||
return self.jsonify(trigger.to_dict())
|
||||
|
||||
@auth_only_for_acl
|
||||
def delete(self, _id):
|
||||
TriggerCRUD.delete(_id)
|
||||
|
||||
return self.jsonify(id=_id)
|
||||
|
||||
|
||||
class TriggerResourceView(APIView):
|
||||
url_prefix = "/triggers/resources"
|
||||
|
||||
@validate_app
|
||||
@auth_with_app_token
|
||||
@args_required("resource_type_id")
|
||||
def post(self):
|
||||
app_id = request.values.get('app_id')
|
||||
resource_type_id = request.values.get('resource_type_id')
|
||||
wildcard = request.values.get('pattern')
|
||||
uid = request.values.get('owner')
|
||||
|
||||
resources = TriggerCRUD.get_resources(app_id, resource_type_id, wildcard, uid)
|
||||
resources = [i.to_dict() for i in resources]
|
||||
|
||||
return self.jsonify(resources)
|
||||
|
||||
|
||||
class TriggerApplyView(APIView):
|
||||
url_prefix = "/triggers/<int:_id>/apply"
|
||||
|
||||
@auth_only_for_acl
|
||||
def post(self, _id):
|
||||
TriggerCRUD.apply(_id)
|
||||
|
||||
return self.jsonify(id=_id)
|
||||
|
||||
|
||||
class TriggerCancelView(APIView):
|
||||
url_prefix = "/triggers/<int:_id>/cancel"
|
||||
|
||||
@auth_only_for_acl
|
||||
def post(self, _id):
|
||||
TriggerCRUD.cancel(_id)
|
||||
|
||||
return self.jsonify(id=_id)
|
@@ -1,13 +1,25 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
import requests
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from flask import request
|
||||
from flask import session
|
||||
from flask_login import current_user
|
||||
|
||||
from api.lib.decorator import args_required
|
||||
from api.lib.decorator import args_validate
|
||||
from api.lib.perm.acl.acl import ACLManager
|
||||
from api.lib.perm.acl.acl import role_required
|
||||
from api.lib.perm.acl.audit import AuditCRUD, AuditOperateType
|
||||
from api.lib.perm.acl.cache import AppCache
|
||||
from api.lib.perm.acl.cache import UserCache
|
||||
from api.lib.perm.acl.resp_format import ErrFormat
|
||||
from api.lib.perm.acl.role import RoleRelationCRUD
|
||||
from api.lib.perm.acl.user import UserCRUD
|
||||
from api.lib.perm.auth import auth_with_app_token
|
||||
from api.lib.utils import get_page
|
||||
from api.lib.utils import get_page_size
|
||||
from api.resource import APIView
|
||||
@@ -16,25 +28,57 @@ from api.resource import APIView
|
||||
class GetUserInfoView(APIView):
|
||||
url_prefix = "/users/info"
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
name = session.get("CAS_USERNAME") or current_user.nickname
|
||||
role = dict(permissions=session.get("acl", {}).get("parentRoles", []))
|
||||
avatar = current_user.avatar
|
||||
app_id = request.values.get('app_id')
|
||||
if not app_id:
|
||||
name = session.get("acl", {}).get("userName") or session.get("CAS_USERNAME") or \
|
||||
current_user.username or request.values.get('username')
|
||||
else:
|
||||
|
||||
return self.jsonify(result=dict(name=name,
|
||||
role=role,
|
||||
avatar=avatar))
|
||||
name = request.values.get('username')
|
||||
|
||||
current_app.logger.info("get user info for1: app_id: {0}, name: {1}".format(request.values.get('app_id'), name))
|
||||
user_info = ACLManager().get_user_info(name, request.values.get('app_id'))
|
||||
current_app.logger.info("get user info for2: {}".format(user_info))
|
||||
|
||||
result = dict(name=user_info.get('nickname') or name,
|
||||
username=user_info.get('username') or name,
|
||||
email=user_info.get('email'),
|
||||
uid=user_info.get('uid'),
|
||||
rid=user_info.get('rid'),
|
||||
role=dict(permissions=user_info.get('parents')),
|
||||
avatar=user_info.get('avatar'))
|
||||
|
||||
current_app.logger.info("get user info for3: {}".format(result))
|
||||
return self.jsonify(result=result)
|
||||
|
||||
|
||||
class GetUserKeySecretView(APIView):
|
||||
url_prefix = "/users/secret"
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
if not request.values.get('app_id'):
|
||||
name = session.get("acl", {}).get("userName") or session.get("CAS_USERNAME") or current_user.username
|
||||
else:
|
||||
name = request.values.get('username')
|
||||
|
||||
user = UserCache.get(name) or abort(404, ErrFormat.user_not_found.format(name))
|
||||
|
||||
return self.jsonify(key=user.key, secret=user.secret)
|
||||
|
||||
|
||||
class UserView(APIView):
|
||||
url_prefix = ("/users", "/users/<int:uid>")
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
page = get_page(request.values.get('page', 1))
|
||||
page_size = get_page_size(request.values.get('page_size'))
|
||||
q = request.values.get("q")
|
||||
numfound, users = UserCRUD.search(q, page, page_size)
|
||||
id2parents = RoleRelationCRUD.get_parents(uids=[i.uid for i in users])
|
||||
id2parents = RoleRelationCRUD.get_parents(uids=[i.uid for i in users], all_app=True)
|
||||
|
||||
users = [i.to_dict() for i in users]
|
||||
for u in users:
|
||||
@@ -50,22 +94,49 @@ class UserView(APIView):
|
||||
|
||||
@args_required('username')
|
||||
@args_required('email')
|
||||
@role_required("acl_admin")
|
||||
@args_validate(UserCRUD.cls)
|
||||
def post(self):
|
||||
request.values.pop('_key', None)
|
||||
request.values.pop('_secret', None)
|
||||
|
||||
user = UserCRUD.add(**request.values)
|
||||
|
||||
return self.jsonify(user.to_dict())
|
||||
|
||||
@role_required("acl_admin")
|
||||
@args_validate(UserCRUD.cls)
|
||||
def put(self, uid):
|
||||
request.values.pop('_key', None)
|
||||
request.values.pop('_secret', None)
|
||||
|
||||
user = UserCRUD.update(uid, **request.values)
|
||||
|
||||
return self.jsonify(user.to_dict())
|
||||
|
||||
@role_required("acl_admin")
|
||||
def delete(self, uid):
|
||||
if g.user.uid == uid:
|
||||
return abort(400, ErrFormat.invalid_operation)
|
||||
UserCRUD.delete(uid)
|
||||
|
||||
return self.jsonify(uid=uid)
|
||||
|
||||
|
||||
class UserOnTheJobView(APIView):
|
||||
url_prefix = ("/users/employee",)
|
||||
|
||||
@auth_with_app_token
|
||||
def get(self):
|
||||
if current_app.config.get('HR_URI'):
|
||||
try:
|
||||
return self.jsonify(requests.get(current_app.config["HR_URI"]).json())
|
||||
except:
|
||||
return abort(400, ErrFormat.invalid_request)
|
||||
else:
|
||||
return self.jsonify(UserCRUD.get_employees())
|
||||
|
||||
|
||||
class UserResetKeySecretView(APIView):
|
||||
url_prefix = "/users/reset_key_secret"
|
||||
|
||||
@@ -76,3 +147,31 @@ class UserResetKeySecretView(APIView):
|
||||
|
||||
def put(self):
|
||||
return self.post()
|
||||
|
||||
|
||||
class UserResetPasswordView(APIView):
|
||||
url_prefix = "/users/reset_password"
|
||||
|
||||
@auth_with_app_token
|
||||
@args_required('username')
|
||||
@args_required('password')
|
||||
@args_validate(UserCRUD.cls, exclude_args=['app_id'])
|
||||
def post(self):
|
||||
if request.values.get('app_id'):
|
||||
app = AppCache.get(request.values['app_id'])
|
||||
if app.name not in ('cas-server', 'acl'):
|
||||
return abort(403, ErrFormat.invalid_request)
|
||||
|
||||
elif hasattr(g, 'user'):
|
||||
if g.user.username != request.values['username']:
|
||||
return abort(403, ErrFormat.invalid_request)
|
||||
|
||||
else:
|
||||
return abort(400, ErrFormat.invalid_operation)
|
||||
|
||||
user = UserCache.get(request.values['username'])
|
||||
user or abort(404, ErrFormat.user_not_found.format(request.values['username']))
|
||||
|
||||
UserCRUD.update(user.uid, password=request.values['password'])
|
||||
|
||||
return self.jsonify(code=200)
|
||||
|
Reference in New Issue
Block a user