前后端全面升级

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

@@ -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)

View 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,
)

View 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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View 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)

View File

@@ -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)