Merge branch 'v3' of github.com:jumpserver/jumpserver into v3

pull/8991/head
ibuler 2022-10-18 20:38:03 +08:00
commit 8c92a9934b
9 changed files with 126 additions and 184 deletions

View File

@ -49,7 +49,7 @@ class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
'default': serializers.AccountSecretSerializer 'default': serializers.AccountSecretSerializer
} }
http_method_names = ['get'] http_method_names = ['get']
permission_classes = [RBACPermission, UserConfirmation.require(ConfirmType.MFA)] # permission_classes = [RBACPermission, UserConfirmation.require(ConfirmType.MFA)]
rbac_perms = { rbac_perms = {
'list': 'assets.view_assetaccountsecret', 'list': 'assets.view_assetaccountsecret',
'retrieve': 'assets.view_assetaccountsecret', 'retrieve': 'assets.view_assetaccountsecret',

View File

@ -60,8 +60,8 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer):
class Meta(BaseAccountSerializer.Meta): class Meta(BaseAccountSerializer.Meta):
model = Account model = Account
fields = BaseAccountSerializer.Meta.fields \ fields = BaseAccountSerializer.Meta.fields \
+ ['su_from', 'version', 'asset'] \ + ['su_from', 'version', 'asset'] \
+ ['template', 'push_now'] + ['template', 'push_now']
extra_kwargs = { extra_kwargs = {
**BaseAccountSerializer.Meta.extra_kwargs, **BaseAccountSerializer.Meta.extra_kwargs,
'name': {'required': False, 'allow_null': True}, 'name': {'required': False, 'allow_null': True},
@ -71,6 +71,9 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer):
super().__init__(*args, data=data, **kwargs) super().__init__(*args, data=data, **kwargs)
if data and 'name' not in data: if data and 'name' not in data:
data['name'] = data.get('username') data['name'] = data.get('username')
if hasattr(self, 'initial_data') and \
not getattr(self, 'initial_data', None):
delattr(self, 'initial_data')
@classmethod @classmethod
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):

View File

@ -45,6 +45,9 @@ class AdHocExecution(BaseAnsibleExecution):
) )
return runner return runner
def task_display(self):
return str(self.task)
class Meta: class Meta:
db_table = "ops_adhoc_execution" db_table = "ops_adhoc_execution"
get_latest_by = 'date_start' get_latest_by = 'date_start'

View File

@ -15,11 +15,11 @@ class AdHocExecutionSerializer(serializers.ModelSerializer):
model = AdHocExecution model = AdHocExecution
fields_mini = ['id'] fields_mini = ['id']
fields_small = fields_mini + [ fields_small = fields_mini + [
'hosts_amount', 'timedelta', 'result', 'summary', 'short_id', 'timedelta', 'result', 'summary', 'short_id',
'is_finished', 'is_success', 'is_finished', 'is_success',
'date_start', 'date_finished', '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_custom = ['stat', 'last_success', 'last_failure']
fields = fields_small + fields_fk + fields_custom fields = fields_small + fields_fk + fields_custom
@ -50,20 +50,16 @@ class AdHocExecutionExcludeResultSerializer(AdHocExecutionSerializer):
class AdHocSerializer(serializers.ModelSerializer): class AdHocSerializer(serializers.ModelSerializer):
become_display = serializers.ReadOnlyField()
tasks = serializers.ListField() tasks = serializers.ListField()
class Meta: class Meta:
model = AdHoc model = AdHoc
fields_mini = ['id'] fields_mini = ['id']
fields_small = fields_mini + [ fields_small = fields_mini + [
'tasks', "pattern", "options", "run_as", 'tasks', "pattern", "args", "date_created",
"become", "become_display", "short_id",
"run_as_admin",
"date_created",
] ]
fields_fk = ["task"] fields_fk = ["last_execution"]
fields_m2m = ["hosts"] fields_m2m = ["assets"]
fields = fields_small + fields_fk + fields_m2m fields = fields_small + fields_fk + fields_m2m
read_only_fields = [ read_only_fields = [
'date_created' 'date_created'
@ -92,7 +88,7 @@ class AdHocDetailSerializer(AdHocSerializer):
class Meta(AdHocSerializer.Meta): class Meta(AdHocSerializer.Meta):
fields = AdHocSerializer.Meta.fields + [ fields = AdHocSerializer.Meta.fields + [
'latest_execution', 'created_by', 'run_times', 'task_name' 'latest_execution', 'created_by', 'task_name'
] ]

View File

@ -11,6 +11,7 @@ from perms.models import AssetPermission
from assets.models import Asset, Node from assets.models import Asset, Node
from . import user_permission as uapi from . import user_permission as uapi
from perms import serializers from perms import serializers
from perms.utils import PermAccountUtil
from assets.api.mixin import SerializeToTreeNodeMixin from assets.api.mixin import SerializeToTreeNodeMixin
from users.models import UserGroup from users.models import UserGroup
@ -200,7 +201,7 @@ class UserGroupGrantedAssetAccountsApi(uapi.UserGrantedAssetAccountsApi):
return UserGroup.objects.get(id=group_id) return UserGroup.objects.get(id=group_id)
def get_queryset(self): def get_queryset(self):
accounts = AssetPermission.get_perm_asset_accounts( accounts = PermAccountUtil().get_perm_accounts_for_user_group_asset(
user_group=self.user_group, asset=self.asset self.user_group, self.asset, with_actions=True
) )
return accounts return accounts

View File

@ -22,6 +22,7 @@ from common.utils import get_logger, lazyproperty
from perms.hands import User, Asset, Account from perms.hands import User, Asset, Account
from perms import serializers from perms import serializers
from perms.models import AssetPermission, Action from perms.models import AssetPermission, Action
from perms.utils import PermAccountUtil
logger = get_logger(__name__) logger = get_logger(__name__)
@ -118,7 +119,9 @@ class UserGrantedAssetAccountsApi(ListAPIView):
return asset return asset
def get_queryset(self): 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 return accounts

View File

@ -177,116 +177,6 @@ class AssetPermission(OrgModelMixin):
names = [node.full_value for node in self.nodes.all()] names = [node.full_value for node in self.nodes.all()]
return names 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 UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpdateModel):
class NodeFrom(TextChoices): class NodeFrom(TextChoices):

View File

@ -1,27 +1,32 @@
from collections import defaultdict from collections import defaultdict
from assets.models import Account 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_perm_accounts_for_user_asset(self, user, asset, with_actions=False):
def get_user_perm_asset_accounts(self, user, asset, with_actions=False):
""" 获取授权给用户某个资产的账号 """ """ 获取授权给用户某个资产的账号 """
perms = self.get_user_asset_permissions(user, asset) perms = self.get_permissions_for_user_asset(user, asset)
accounts = self.get_permissions_accounts(perms, with_actions=with_actions) accounts = self.get_perm_accounts_for_permissions(perms, with_actions=with_actions)
return accounts 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) perms = self.get_permissions_for_user(user)
accounts = self.get_permissions_accounts(perms, with_actions=with_actions) 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 return accounts
@staticmethod @staticmethod
def get_permissions_accounts(permissions, with_actions=False): def get_perm_accounts_for_permissions(permissions, with_actions=False):
aid_actions_map = defaultdict(int) aid_actions_map = defaultdict(int)
for perm in permissions: for perm in permissions:
account_ids = perm.get_all_accounts(flat=True) account_ids = perm.get_all_accounts(flat=True)
@ -35,49 +40,3 @@ class PermAccountUtil(object):
account.actions = aid_actions_map.get(str(account.id)) account.actions = aid_actions_map.get(str(account.id))
return accounts 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

View File

@ -11,6 +11,93 @@ from perms.utils.user_permission import get_user_all_asset_perm_ids
logger = get_logger(__file__) 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'): def validate_permission(user, asset, account, action='connect'):
asset_perm_ids = get_user_all_asset_perm_ids(user) asset_perm_ids = get_user_all_asset_perm_ids(user)