ACL: permission management [doing]

This commit is contained in:
pycook 2019-12-04 18:14:09 +08:00
parent e73810b456
commit 6973cc68ed
6 changed files with 68 additions and 44 deletions

View File

@ -3,52 +3,47 @@
import functools import functools
import six import six
from flask import current_app, g, request from flask import current_app, g, request
from flask import session, abort from flask import session, abort
from api.extensions import cache from api.lib.perm.acl.cache import AppCache
from api.models.acl import ResourceType
from api.models.acl import Resource
def get_access_token(): from api.lib.perm.acl.resource import ResourceCRUD
return
class AccessTokenCache(object):
@classmethod
def get(cls):
if cache.get("AccessToken") is not None:
return cache.get("AccessToken")
res = get_access_token() or ""
cache.set("AccessToken", res, timeout=60 * 60)
return res
@classmethod
def clean(cls):
cache.clear("AccessToken")
class ACLManager(object): class ACLManager(object):
def __init__(self): def __init__(self):
self.access_token = AccessTokenCache.get()
self.acl_session = dict(uid=session.get("uid"),
token=self.access_token)
self.user_info = session["acl"] if "acl" in session else {} self.user_info = session["acl"] if "acl" in session else {}
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 add_resource(self, name, resource_type_name=None): def add_resource(self, name, resource_type_name=None):
pass resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False)
if resource_type:
return abort(400, "ResourceType <{0}> cannot be found".format(resource_type_name))
ResourceCRUD.add(name, resource_type.id, self.app_id)
def grant_resource_to_role(self, name, role, resource_type_name=None): def grant_resource_to_role(self, name, role, resource_type_name=None):
pass resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False)
if resource_type:
return abort(400, "ResourceType <{0}> cannot be found".format(resource_type_name))
def del_resource(self, name, resource_type_name=None): def del_resource(self, name, resource_type_name=None):
pass resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False)
if resource_type:
return abort(400, "ResourceType <{0}> cannot be found".format(resource_type_name))
def get_user_info(self, username): resource = Resource.get_by(resource_type_id=resource_type.id,
return dict() app_id=self.app_id,
name=name,
first=True,
to_dict=False)
if resource:
ResourceCRUD.delete(resource.id)
def get_resources(self, resource_type_name=None): def get_resources(self, resource_type_name=None):
if "acl" not in session: if "acl" not in session:
@ -87,7 +82,9 @@ def can_access_resources(resource_type):
else: else:
g.resources = {resource_type: result} g.resources = {resource_type: result}
return func(*args, **kwargs) return func(*args, **kwargs)
return wrapper_can_access_resources return wrapper_can_access_resources
return decorator_can_access_resources return decorator_can_access_resources
@ -102,7 +99,9 @@ def has_perm(resources, resource_type, perm):
validate_permission(resources, resource_type, perm) validate_permission(resources, resource_type, perm)
return func(*args, **kwargs) return func(*args, **kwargs)
return wrapper_has_perm return wrapper_has_perm
return decorator_has_perm return decorator_has_perm
@ -120,7 +119,9 @@ def has_perm_from_args(arg_name, resource_type, perm, callback=None):
validate_permission(resource, resource_type, perm) validate_permission(resource, resource_type, perm)
return func(*args, **kwargs) return func(*args, **kwargs)
return wrapper_has_perm return wrapper_has_perm
return decorator_has_perm return decorator_has_perm
@ -135,5 +136,7 @@ def role_required(role_name):
if role_name not in session.get("acl", {}).get("parentRoles", []): if role_name not in session.get("acl", {}).get("parentRoles", []):
return abort(403, "Role {0} is required".format(role_name)) return abort(403, "Role {0} is required".format(role_name))
return func(*args, **kwargs) return func(*args, **kwargs)
return wrapper_role_required return wrapper_role_required
return decorator_role_required return decorator_role_required

View File

@ -36,11 +36,11 @@ class ResourceTypeCRUD(object):
return [i.to_dict() for i in perms] return [i.to_dict() for i in perms]
@classmethod @classmethod
def add(cls, app_id, name, perms): def add(cls, app_id, name, description, perms):
ResourceType.get_by(name=name, app_id=app_id) and abort( ResourceType.get_by(name=name, app_id=app_id) and abort(
400, "ResourceType <{0}> is already existed".format(name)) 400, "ResourceType <{0}> is already existed".format(name))
rt = ResourceType.create(name=name, app_id=app_id) rt = ResourceType.create(name=name, description=description, app_id=app_id)
cls.update_perms(rt.id, perms, app_id) cls.update_perms(rt.id, perms, app_id)

View File

@ -23,8 +23,8 @@ class RoleRelationCRUD(object):
if uids is not None: if uids is not None:
uids = [uids] if isinstance(uids, six.integer_types) else uids uids = [uids] if isinstance(uids, six.integer_types) else uids
rids = db.session.query(Role).filter(Role.deleted.is_(False)).filter(Role.uid.in_(uids)) rids = db.session.query(Role).filter(Role.deleted.is_(False)).filter(Role.uid.in_(uids))
rid2uid = {i.rid: i.uid for i in rids} rid2uid = {i.id: i.uid for i in rids}
rids = [i.rid for i in rids] rids = [i.id for i in rids]
else: else:
rids = [rids] if isinstance(rids, six.integer_types) else rids rids = [rids] if isinstance(rids, six.integer_types) else rids
@ -98,9 +98,12 @@ class RoleRelationCRUD(object):
class RoleCRUD(object): class RoleCRUD(object):
@staticmethod @staticmethod
def search(q, app_id, page=1, page_size=None): def search(q, app_id, page=1, page_size=None, user_role=False):
query = db.session.query(Role).filter(Role.deleted.is_(False)).filter( query = db.session.query(Role).filter(Role.deleted.is_(False)).filter(Role.app_id == app_id)
Role.app_id == app_id).filter(Role.uid.is_(None))
if not user_role:
query = query.filter(Role.uid.is_(None))
if q: if q:
query = query.filter(Role.name.ilike('%{0}%'.format(q))) query = query.filter(Role.name.ilike('%{0}%'.format(q)))
@ -109,7 +112,7 @@ class RoleCRUD(object):
return numfound, query.offset((page - 1) * page_size).limit(page_size) return numfound, query.offset((page - 1) * page_size).limit(page_size)
@staticmethod @staticmethod
def add_role(name, app_id, is_app_admin=False, uid=None): def add_role(name, app_id=None, is_app_admin=False, uid=None):
Role.get_by(name=name, app_id=app_id) and abort(400, "Role <{0}> is already existed".format(name)) Role.get_by(name=name, app_id=app_id) and abort(400, "Role <{0}> is already existed".format(name))
return Role.create(name=name, return Role.create(name=name,

View File

@ -1,15 +1,17 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
import uuid
import string
import random import random
import string
import uuid
from flask import abort from flask import abort
from flask import g from flask import g
from api.extensions import db from api.extensions import db
from api.lib.perm.acl.cache import UserCache from api.lib.perm.acl.cache import UserCache
from api.lib.perm.acl.role import RoleCRUD
from api.models.acl import Role
from api.models.acl import User from api.models.acl import User
@ -40,14 +42,28 @@ class UserCRUD(object):
kwargs['block'] = 0 kwargs['block'] = 0
kwargs['key'], kwargs['secret'] = cls._gen_key_secret() kwargs['key'], kwargs['secret'] = cls._gen_key_secret()
return User.create(**kwargs) user = User.create(**kwargs)
RoleCRUD.add_role(user.username, uid=user.uid)
return user
@staticmethod @staticmethod
def update(uid, **kwargs): def update(uid, **kwargs):
user = User.get_by(uid=uid, to_dict=False, first=True) or abort(404, "User <{0}> does not exist".format(uid)) user = User.get_by(uid=uid, to_dict=False, first=True) or abort(404, "User <{0}> does not exist".format(uid))
if kwargs.get("username"):
other = User.get_by(username=kwargs['username'], first=True, to_dict=False)
if other is not None and other.uid != user.uid:
return abort(400, "User <{0}> cannot be duplicated".format(kwargs['username']))
UserCache.clean(user) UserCache.clean(user)
if kwargs.get("username") and kwargs['username'] != user.username:
role = Role.get_by(name=user.username, first=True, to_dict=False)
if role is not None:
RoleCRUD.update_role(role.id, **dict(name=kwargs['name']))
return user.update(**kwargs) return user.update(**kwargs)
@classmethod @classmethod

View File

@ -39,9 +39,10 @@ class ResourceTypeView(APIView):
def post(self): def post(self):
name = request.values.get('name') name = request.values.get('name')
app_id = request.values.get('app_id') app_id = request.values.get('app_id')
description = request.values.get('description', '')
perms = request.values.get('perms') perms = request.values.get('perms')
rt = ResourceTypeCRUD.add(app_id, name, perms) rt = ResourceTypeCRUD.add(app_id, name, description, perms)
return self.jsonify(rt.to_dict()) return self.jsonify(rt.to_dict())

View File

@ -21,8 +21,9 @@ class RoleView(APIView):
page_size = get_page_size(request.values.get("page_size")) page_size = get_page_size(request.values.get("page_size"))
q = request.values.get('q') q = request.values.get('q')
app_id = request.values.get('app_id') app_id = request.values.get('app_id')
user_role = request.values.get('user_role', False)
numfound, roles = RoleCRUD.search(q, app_id, page, page_size) numfound, roles = RoleCRUD.search(q, app_id, page, page_size, user_role)
id2parents = RoleRelationCRUD.get_parents([i.id for i in roles]) id2parents = RoleRelationCRUD.get_parents([i.id for i in roles])