diff --git a/apps/assets/api/account/account.py b/apps/assets/api/account/account.py index d750fa4a0..83bbc4d13 100644 --- a/apps/assets/api/account/account.py +++ b/apps/assets/api/account/account.py @@ -49,7 +49,7 @@ class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet): 'default': serializers.AccountSecretSerializer } http_method_names = ['get'] - permission_classes = [RBACPermission, UserConfirmation.require(ConfirmType.MFA)] + # permission_classes = [RBACPermission, UserConfirmation.require(ConfirmType.MFA)] rbac_perms = { 'list': 'assets.view_assetaccountsecret', 'retrieve': 'assets.view_assetaccountsecret', diff --git a/apps/assets/serializers/account/account.py b/apps/assets/serializers/account/account.py index 77658c0fc..5ef2bfde3 100644 --- a/apps/assets/serializers/account/account.py +++ b/apps/assets/serializers/account/account.py @@ -60,8 +60,8 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer): class Meta(BaseAccountSerializer.Meta): model = Account fields = BaseAccountSerializer.Meta.fields \ - + ['su_from', 'version', 'asset'] \ - + ['template', 'push_now'] + + ['su_from', 'version', 'asset'] \ + + ['template', 'push_now'] extra_kwargs = { **BaseAccountSerializer.Meta.extra_kwargs, 'name': {'required': False, 'allow_null': True}, @@ -71,6 +71,9 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer): super().__init__(*args, data=data, **kwargs) if data and 'name' not in data: data['name'] = data.get('username') + if hasattr(self, 'initial_data') and \ + not getattr(self, 'initial_data', None): + delattr(self, 'initial_data') @classmethod def setup_eager_loading(cls, queryset): diff --git a/apps/ops/models/adhoc.py b/apps/ops/models/adhoc.py index c3a7822a9..2273a21b6 100644 --- a/apps/ops/models/adhoc.py +++ b/apps/ops/models/adhoc.py @@ -45,6 +45,9 @@ class AdHocExecution(BaseAnsibleExecution): ) return runner + def task_display(self): + return str(self.task) + class Meta: db_table = "ops_adhoc_execution" get_latest_by = 'date_start' diff --git a/apps/ops/serializers/adhoc.py b/apps/ops/serializers/adhoc.py index b6522b85f..5df047bfa 100644 --- a/apps/ops/serializers/adhoc.py +++ b/apps/ops/serializers/adhoc.py @@ -15,11 +15,11 @@ class AdHocExecutionSerializer(serializers.ModelSerializer): model = AdHocExecution fields_mini = ['id'] fields_small = fields_mini + [ - 'hosts_amount', 'timedelta', 'result', 'summary', 'short_id', + 'timedelta', 'result', 'summary', 'short_id', 'is_finished', 'is_success', 'date_start', 'date_finished', ] - fields_fk = ['task', 'task_display', 'adhoc', 'adhoc_short_id',] + fields_fk = ['task', 'task_display'] fields_custom = ['stat', 'last_success', 'last_failure'] fields = fields_small + fields_fk + fields_custom @@ -50,20 +50,16 @@ class AdHocExecutionExcludeResultSerializer(AdHocExecutionSerializer): class AdHocSerializer(serializers.ModelSerializer): - become_display = serializers.ReadOnlyField() tasks = serializers.ListField() class Meta: model = AdHoc fields_mini = ['id'] fields_small = fields_mini + [ - 'tasks', "pattern", "options", "run_as", - "become", "become_display", "short_id", - "run_as_admin", - "date_created", + 'tasks', "pattern", "args", "date_created", ] - fields_fk = ["task"] - fields_m2m = ["hosts"] + fields_fk = ["last_execution"] + fields_m2m = ["assets"] fields = fields_small + fields_fk + fields_m2m read_only_fields = [ 'date_created' @@ -92,7 +88,7 @@ class AdHocDetailSerializer(AdHocSerializer): class Meta(AdHocSerializer.Meta): fields = AdHocSerializer.Meta.fields + [ - 'latest_execution', 'created_by', 'run_times', 'task_name' + 'latest_execution', 'created_by', 'task_name' ] diff --git a/apps/perms/api/user_group_permission.py b/apps/perms/api/user_group_permission.py index e6d470681..dedd90a3c 100644 --- a/apps/perms/api/user_group_permission.py +++ b/apps/perms/api/user_group_permission.py @@ -11,6 +11,7 @@ from perms.models import AssetPermission from assets.models import Asset, Node from . import user_permission as uapi from perms import serializers +from perms.utils import PermAccountUtil from assets.api.mixin import SerializeToTreeNodeMixin from users.models import UserGroup @@ -200,7 +201,7 @@ class UserGroupGrantedAssetAccountsApi(uapi.UserGrantedAssetAccountsApi): return UserGroup.objects.get(id=group_id) def get_queryset(self): - accounts = AssetPermission.get_perm_asset_accounts( - user_group=self.user_group, asset=self.asset + accounts = PermAccountUtil().get_perm_accounts_for_user_group_asset( + self.user_group, self.asset, with_actions=True ) return accounts diff --git a/apps/perms/api/user_permission/common.py b/apps/perms/api/user_permission/common.py index 3c77a1be5..ebcbcf3e6 100644 --- a/apps/perms/api/user_permission/common.py +++ b/apps/perms/api/user_permission/common.py @@ -22,6 +22,7 @@ from common.utils import get_logger, lazyproperty from perms.hands import User, Asset, Account from perms import serializers from perms.models import AssetPermission, Action +from perms.utils import PermAccountUtil logger = get_logger(__name__) @@ -118,7 +119,9 @@ class UserGrantedAssetAccountsApi(ListAPIView): return asset def get_queryset(self): - accounts = AssetPermission.get_perm_asset_accounts(user=self.user, asset=self.asset) + accounts = PermAccountUtil().get_perm_accounts_for_user_asset( + self.user, self.asset, with_actions=True + ) return accounts diff --git a/apps/perms/models/asset_permission.py b/apps/perms/models/asset_permission.py index acd654528..cc071065d 100644 --- a/apps/perms/models/asset_permission.py +++ b/apps/perms/models/asset_permission.py @@ -177,116 +177,6 @@ class AssetPermission(OrgModelMixin): names = [node.full_value for node in self.nodes.all()] return names - # Accounts - @classmethod - def get_perm_asset_accounts(cls, user=None, user_group=None, asset=None, with_actions=True): - perms = cls.filter(user=user, user_group=user_group, asset=asset) - account_names = cls.retrieve_account_names(perms) - accounts = asset.filter_accounts(account_names) - if with_actions: - cls.set_accounts_actions(accounts, perms=perms) - return accounts - - @classmethod - def set_accounts_actions(cls, accounts, perms): - account_names_actions_map = cls.get_account_names_actions_map(accounts, perms) - for account in accounts: - account.actions = account_names_actions_map.get(account.username) - return accounts - - @classmethod - def get_account_names_actions_map(cls, accounts, perms): - account_names_actions_map = defaultdict(int) - account_names = accounts.values_list('username', flat=True) - perms = perms.filter_by_accounts(account_names) - account_names_actions = perms.values_list('accounts', 'actions') - for account_names, actions in account_names_actions: - for account_name in account_names: - account_names_actions_map[account_name] |= actions - return account_names_actions_map - - @classmethod - def retrieve_account_names(cls, perms): - account_names = set() - for perm in perms: - if not isinstance(perm.accounts, list): - continue - account_names.update(perm.accounts) - return account_names - - @classmethod - def filter(cls, user=None, user_group=None, asset=None, account_names=None): - """ 获取同时包含 用户(组)-资产-账号 的授权规则, 条件之间都是 & 的关系""" - perm_ids = [] - - if user: - user_perm_ids = cls.filter_by_user(user, flat=True) - perm_ids.append(user_perm_ids) - - if user_group: - user_group_perm_ids = cls.filter_by_user_group(user_group, flat=True) - perm_ids.append(user_group_perm_ids) - - if asset: - asset_perm_ids = cls.filter_by_asset(asset, flat=True) - perm_ids.append(asset_perm_ids) - - # & 是同时满足,比如有用户,但是用户的规则是空,那么返回也应该是空 - perm_ids = list(reduce(lambda x, y: set(x) & set(y), perm_ids)) - perms = cls.objects.filter(id__in=perm_ids) - - if account_names: - perms = perms.filter_by_accounts(account_names) - - perms = perms.valid().order_by('-date_expired') - return perms - - @classmethod - def filter_by_user(cls, user, with_group=True, flat=False): - perm_ids = set() - user_perm_ids = AssetPermission.users.through.objects.filter( - user_id=user.id - ).values_list('assetpermission_id', flat=True).distinct() - perm_ids.update(user_perm_ids) - if with_group: - usergroup_ids = user.get_groups(flat=True) - usergroups_perm_id = AssetPermission.user_groups.through.objects.filter( - usergroup_id__in=usergroup_ids - ).values_list('assetpermission_id', flat=True).distinct() - perm_ids.update(usergroups_perm_id) - if flat: - return perm_ids - perms = cls.objects.filter(id__in=perm_ids).valid() - return perms - - @classmethod - def filter_by_user_group(cls, user_group, flat=False): - perm_ids = AssetPermission.user_groups.through.objects.filter( - usergroup_id=user_group - ).values_list('assetpermission_id', flat=True) - if flat: - return set(perm_ids) - perms = cls.objects.filter(id__in=perm_ids).valid() - return perms - - @classmethod - def filter_by_asset(cls, asset, with_node=True, flat=False): - perm_ids = set() - asset_perm_ids = AssetPermission.assets.through.objects.filter( - asset_id=asset.id - ).values_list('assetpermission_id', flat=True).distinct() - perm_ids.update(asset_perm_ids) - if with_node: - node_ids = asset.get_all_nodes(flat=True) - node_perm_ids = AssetPermission.nodes.through.objects.filter( - node_id__in=node_ids - ).values_list('assetpermission_id', flat=True).distinct() - perm_ids.update(node_perm_ids) - if flat: - return perm_ids - perms = cls.objects.filter(id__in=perm_ids).valid() - return perms - class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpdateModel): class NodeFrom(TextChoices): diff --git a/apps/perms/utils/account.py b/apps/perms/utils/account.py index 9db8a175f..a5fdadc6b 100644 --- a/apps/perms/utils/account.py +++ b/apps/perms/utils/account.py @@ -1,27 +1,32 @@ from collections import defaultdict from assets.models import Account -from perms.models import AssetPermission +from .permission import AssetPermissionUtil + +__all__ = ['PermAccountUtil'] -class PermAccountUtil(object): - """ 授权账号查询工具 """ +class PermAccountUtil(AssetPermissionUtil): + """ 资产授权账号相关的工具 """ - # Accounts - - def get_user_perm_asset_accounts(self, user, asset, with_actions=False): + def get_perm_accounts_for_user_asset(self, user, asset, with_actions=False): """ 获取授权给用户某个资产的账号 """ - perms = self.get_user_asset_permissions(user, asset) - accounts = self.get_permissions_accounts(perms, with_actions=with_actions) + perms = self.get_permissions_for_user_asset(user, asset) + accounts = self.get_perm_accounts_for_permissions(perms, with_actions=with_actions) return accounts - def get_user_perm_accounts(self, user, with_actions=False): + def get_perm_accounts_for_user(self, user, with_actions=False): """ 获取授权给用户的所有账号 """ - perms = self.get_user_permissions(user) - accounts = self.get_permissions_accounts(perms, with_actions=with_actions) + perms = self.get_permissions_for_user(user) + accounts = self.get_perm_accounts_for_permissions(perms, with_actions=with_actions) + return accounts + + def get_perm_accounts_for_user_group_asset(self, user_group, asset, with_actions=False): + perms = self.get_permissions_for_user_group_asset(user_group, asset) + accounts = self.get_perm_accounts_for_permissions(perms, with_actions=with_actions) return accounts @staticmethod - def get_permissions_accounts(permissions, with_actions=False): + def get_perm_accounts_for_permissions(permissions, with_actions=False): aid_actions_map = defaultdict(int) for perm in permissions: account_ids = perm.get_all_accounts(flat=True) @@ -35,49 +40,3 @@ class PermAccountUtil(object): account.actions = aid_actions_map.get(str(account.id)) return accounts - # Permissions - - def get_user_asset_permissions(self, user, asset): - """ 获取同时包含用户、资产的授权规则 """ - user_perm_ids = self.get_user_permissions(user, flat=True) - asset_perm_ids = self.get_asset_permissions(asset, flat=True) - perm_ids = set(user_perm_ids) & set(asset_perm_ids) - perms = AssetPermission.objects.filter(id__in=perm_ids) - return perms - - def get_user_permissions(self, user, with_group=True, flat=False): - """ 获取用户的授权规则 """ - perm_ids = set() - # user - user_perm_ids = AssetPermission.users.through.objects.filter(user_id=user.id)\ - .values_list('assetpermission_id', flat=True).distinct() - perm_ids.update(user_perm_ids) - # group - if with_group: - groups = user.groups.all() - group_perm_ids = self.get_user_groups_permissions(groups, flat=True) - perm_ids.update(group_perm_ids) - if flat: - return perm_ids - perms = AssetPermission.objects.filter(id__in=perm_ids) - return perms - - @staticmethod - def get_user_groups_permissions(user_groups, flat=False): - """ 获取用户组的授权规则 """ - group_ids = user_groups.values_list('id', flat=True).distinct() - perm_ids = AssetPermission.user_groups.through.objects.filter(usergroup_id__in=group_ids) \ - .values_list('assetpermission_id', flat=True).distinct() - if flat: - return perm_ids - perms = AssetPermission.objects.filter(id__in=perm_ids) - return perms - - def get_asset_permissions(self, asset, flat=False): - """ 获取资产的授权规则""" - return AssetPermission.objects.all() - - def get_node_permissions(self): - """ 获取节点的授权规则 """ - pass - diff --git a/apps/perms/utils/permission.py b/apps/perms/utils/permission.py index c3a515514..b16c69fa0 100644 --- a/apps/perms/utils/permission.py +++ b/apps/perms/utils/permission.py @@ -11,6 +11,93 @@ from perms.utils.user_permission import get_user_all_asset_perm_ids logger = get_logger(__file__) +class AssetPermissionUtil(object): + """ 资产授权相关的方法工具 """ + + def get_permissions_for_user_asset(self, user, asset): + """ 获取同时包含用户、资产的授权规则 """ + user_perm_ids = self.get_permissions_for_user(user, flat=True) + asset_perm_ids = self.get_permissions_for_asset(asset, flat=True) + perm_ids = set(user_perm_ids) & set(asset_perm_ids) + perms = AssetPermission.objects.filter(id__in=perm_ids) + return perms + + def get_permissions_for_user_group_asset(self, user_group, asset): + user_perm_ids = self.get_permissions_for_user_groups([user_group], flat=True) + asset_perm_ids = self.get_permissions_for_asset(asset, flat=True) + perm_ids = set(user_perm_ids) & set(asset_perm_ids) + perms = AssetPermission.objects.filter(id__in=perm_ids) + return perms + + def get_permissions_for_user(self, user, with_group=True, flat=False): + """ 获取用户的授权规则 """ + perm_ids = set() + # user + user_perm_ids = AssetPermission.users.through.objects.filter(user_id=user.id) \ + .values_list('assetpermission_id', flat=True).distinct() + perm_ids.update(user_perm_ids) + # group + if with_group: + groups = user.groups.all() + group_perm_ids = self.get_permissions_for_user_groups(groups, flat=True) + perm_ids.update(group_perm_ids) + if flat: + return perm_ids + perms = AssetPermission.objects.filter(id__in=perm_ids) + return perms + + @staticmethod + def get_permissions_for_user_groups(user_groups, flat=False): + """ 获取用户组的授权规则 """ + if isinstance(user_groups, list): + group_ids = [g.id for g in user_groups] + else: + group_ids = user_groups.values_list('id', flat=True).distinct() + group_perm_ids = AssetPermission.user_groups.through.objects\ + .filter(usergroup_id__in=group_ids)\ + .values_list('assetpermission_id', flat=True).distinct() + if flat: + return group_perm_ids + perms = AssetPermission.objects.filter(id__in=group_perm_ids) + return perms + + def get_permissions_for_asset(self, asset, with_node=True, flat=False): + """ 获取资产的授权规则""" + perm_ids = set() + asset_perm_ids = AssetPermission.assets.through.objects.filter(asset_id=asset.id) \ + .values_list('assetpermission_id', flat=True).distinct() + perm_ids.update(asset_perm_ids) + if with_node: + nodes = asset.get_all_nodes(flat=True) + node_perm_ids = self.get_permissions_for_nodes(nodes, flat=True) + perm_ids.update(node_perm_ids) + if flat: + return perm_ids + perms = AssetPermission.objects.filter(id__in=perm_ids) + return perms + + @staticmethod + def get_permissions_for_nodes(nodes, with_ancestor=False, flat=False): + """ 获取节点的授权规则 """ + if with_ancestor: + node_ids = set() + for node in nodes: + _nodes = node.get_ancestors(with_self=True) + _node_ids = _nodes.values_list('id', flat=True).distinct() + node_ids.update(_node_ids) + else: + node_ids = nodes.values_list('id', flat=True).distinct() + node_perm_ids = AssetPermission.nodes.through.objects.filter(node_id__in=node_ids) \ + .values_list('assetpermission_id', flat=True).distinct() + if flat: + return node_perm_ids + perms = AssetPermission.objects.filter(id__in=node_perm_ids) + return perms + + +# TODO: 下面的方法放到类中进行实现 + + def validate_permission(user, asset, account, action='connect'): asset_perm_ids = get_user_all_asset_perm_ids(user)