mirror of https://github.com/jumpserver/jumpserver
fix: 修复用户授权资产账号API及Model处理逻辑
parent
e3b138be3a
commit
351d3b297d
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
|
@ -54,6 +55,11 @@ class Account(BaseAccount):
|
|||
""" @USER 动态用户的账号(self) """
|
||||
return cls(name=cls.InnerAccount.USER.value, username=username)
|
||||
|
||||
@classmethod
|
||||
def filter(cls, asset_ids, account_usernames):
|
||||
queries = Q(asset_id__in=asset_ids) & Q(username__in=account_usernames)
|
||||
return cls.objects.filter(queries)
|
||||
|
||||
|
||||
class AccountTemplate(BaseAccount):
|
||||
class Meta:
|
||||
|
|
|
@ -183,7 +183,8 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
|||
return self.accounts.all()
|
||||
if AssetPermission.SpecialAccount.ALL in account_names:
|
||||
return self.accounts.all()
|
||||
queries = Q(name__in=account_names) | Q(username__in=account_names)
|
||||
# queries = Q(name__in=account_names) | Q(username__in=account_names)
|
||||
queries = Q(username__in=account_names)
|
||||
accounts = self.accounts.filter(queries)
|
||||
return accounts
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#
|
||||
import uuid
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.decorators import method_decorator
|
||||
from rest_framework.views import APIView, Response
|
||||
|
@ -21,7 +21,7 @@ from common.utils import get_logger, lazyproperty
|
|||
|
||||
from perms.hands import User, Asset, Account
|
||||
from perms import serializers
|
||||
from perms.models import AssetPermission
|
||||
from perms.models import AssetPermission, Action
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
@ -162,15 +162,19 @@ class UserGrantedAssetAccounts(ListAPIView):
|
|||
return asset
|
||||
|
||||
def get_queryset(self):
|
||||
# 获取用户-资产的授权规则
|
||||
assetperms = AssetPermission.filter(self.user, self.asset)
|
||||
account_names = AssetPermission.get_account_names(assetperms)
|
||||
accounts = list(self.asset.filter_accounts(account_names))
|
||||
accounts = AssetPermission.get_user_perm_asset_accounts(
|
||||
self.user, self.asset, with_actions=True
|
||||
)
|
||||
return accounts
|
||||
# @INPUT @USER
|
||||
inner_accounts = [Account.get_input_account(), Account.get_user_account(self.user.username)]
|
||||
all_accounts = accounts + inner_accounts
|
||||
# inner_accounts = [
|
||||
# Account.get_input_account(), Account.get_user_account(self.user.username)
|
||||
# ]
|
||||
# for inner_account in inner_accounts:
|
||||
# inner_account.actions = Action.ALL
|
||||
# accounts = accounts + inner_accounts
|
||||
# 构造默认包含的账号,如: @INPUT @USER
|
||||
return all_accounts
|
||||
# return accounts
|
||||
|
||||
|
||||
class MyGrantedAssetAccounts(UserGrantedAssetAccounts):
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.utils import timezone
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db import models
|
||||
from django.db.models import F, Q, TextChoices
|
||||
from collections import defaultdict
|
||||
|
||||
from assets.models import Asset, Node, FamilyMixin, Account
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
|
@ -76,6 +77,11 @@ class AssetPermissionQuerySet(models.QuerySet):
|
|||
q = (Q(is_active=False) | Q(date_start__gt=now) | Q(date_expired__lt=now))
|
||||
return self.filter(q)
|
||||
|
||||
def filter_by_accounts(self, accounts):
|
||||
q = Q(accounts__contains=accounts) | \
|
||||
Q(accounts__contains=AssetPermission.SpecialAccount.ALL.value)
|
||||
return self.filter(q)
|
||||
|
||||
|
||||
class AssetPermissionManager(OrgManager):
|
||||
def valid(self):
|
||||
|
@ -212,94 +218,96 @@ class AssetPermission(OrgModelMixin):
|
|||
names = [node.full_value for node in self.nodes.all()]
|
||||
return names
|
||||
|
||||
# Related accounts
|
||||
def get_asset_accounts(self):
|
||||
asset_ids = self.get_all_assets(flat=True)
|
||||
queries = Q(asset_id__in=asset_ids) \
|
||||
& (Q(username__in=self.accounts) | Q(name__in=self.accounts))
|
||||
accounts = Account.objects.filter(queries)
|
||||
accounts = Account.filter(asset_ids, self.accounts)
|
||||
return accounts
|
||||
|
||||
@classmethod
|
||||
def get_account_names(cls, perms):
|
||||
def get_user_perm_asset_accounts(cls, user, asset: Asset, with_actions=False):
|
||||
perms = cls.filter(user, asset)
|
||||
all_account_names = cls.retrieve_account_names(perms)
|
||||
accounts = asset.filter_accounts(all_account_names)
|
||||
if with_actions:
|
||||
cls.set_accounts_actions(accounts, perms=perms)
|
||||
return accounts
|
||||
|
||||
@classmethod
|
||||
def set_accounts_actions(cls, accounts, perms):
|
||||
# set account actions
|
||||
account_names = accounts.values_list('username', flat=True)
|
||||
perms = perms.filter_by_accounts(account_names)
|
||||
account_names_actions_map = defaultdict(set)
|
||||
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
|
||||
for account in accounts:
|
||||
account.actions = account_names_actions_map.get(account.username)
|
||||
return accounts
|
||||
|
||||
@classmethod
|
||||
def retrieve_account_names(cls, perms):
|
||||
account_names = set()
|
||||
for perm in perms:
|
||||
perm: cls
|
||||
if not isinstance(perm.accounts, list):
|
||||
continue
|
||||
account_names.update(perm.accounts)
|
||||
return account_names
|
||||
|
||||
@classmethod
|
||||
def filter(cls, user=None, asset=None, account=None):
|
||||
def filter(cls, user=None, asset=None, account_names=None):
|
||||
""" 获取同时包含 用户-资产-账号 的授权规则 """
|
||||
assetperm_ids = []
|
||||
perm_ids = []
|
||||
if user:
|
||||
user_assetperm_ids = cls.filter_by_user(user, flat=True)
|
||||
assetperm_ids.append(user_assetperm_ids)
|
||||
perm_ids.append(user_assetperm_ids)
|
||||
if asset:
|
||||
asset_assetperm_ids = cls.filter_by_asset(asset, flat=True)
|
||||
assetperm_ids.append(asset_assetperm_ids)
|
||||
if account:
|
||||
account_assetperm_ids = cls.filter_by_account(account, flat=True)
|
||||
assetperm_ids.append(account_assetperm_ids)
|
||||
perm_ids.append(asset_assetperm_ids)
|
||||
# & 是同时满足,比如有用户,但是用户的规则是空,那么返回也应该是空
|
||||
assetperm_ids = list(reduce(lambda x, y: set(x) & set(y), assetperm_ids))
|
||||
assetperms = cls.objects.filter(id__in=assetperm_ids).valid().order_by('-date_expired')
|
||||
return assetperms
|
||||
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)
|
||||
return perms.valid().order_by('-date_expired')
|
||||
|
||||
@classmethod
|
||||
def filter_by_user(cls, user, with_group=True, flat=False):
|
||||
assetperm_ids = set()
|
||||
user_assetperm_ids = AssetPermission.users.through.objects \
|
||||
.filter(user_id=user.id) \
|
||||
.values_list('assetpermission_id', flat=True) \
|
||||
.distinct()
|
||||
assetperm_ids.update(user_assetperm_ids)
|
||||
|
||||
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_assetperm_id = AssetPermission.user_groups.through.objects \
|
||||
.filter(usergroup_id__in=usergroup_ids) \
|
||||
.values_list('assetpermission_id', flat=True) \
|
||||
.distinct()
|
||||
assetperm_ids.update(usergroups_assetperm_id)
|
||||
|
||||
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 assetperm_ids
|
||||
else:
|
||||
assetperms = cls.objects.filter(id__in=assetperm_ids).valid()
|
||||
return assetperms
|
||||
return 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):
|
||||
assetperm_ids = set()
|
||||
asset_assetperm_ids = AssetPermission.assets.through.objects \
|
||||
.filter(asset_id=asset.id) \
|
||||
.values_list('assetpermission_id', flat=True)
|
||||
assetperm_ids.update(asset_assetperm_ids)
|
||||
|
||||
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_assetperm_ids = AssetPermission.nodes.through.objects \
|
||||
.filter(node_id__in=node_ids) \
|
||||
.values_list('assetpermission_id', flat=True)
|
||||
assetperm_ids.update(node_assetperm_ids)
|
||||
|
||||
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 assetperm_ids
|
||||
else:
|
||||
assetperms = cls.objects.filter(id__in=assetperm_ids).valid()
|
||||
return assetperms
|
||||
|
||||
@classmethod
|
||||
def filter_by_account(cls, account, flat=False):
|
||||
queries = Q(accounts__contains=account) | Q(accounts__contains=cls.SpecialAccount.ALL.value)
|
||||
assetperms = cls.objects.filter(queries).valid()
|
||||
if flat:
|
||||
assetperm_ids = assetperms.values_list('id', flat=True)
|
||||
return assetperm_ids
|
||||
else:
|
||||
return assetperms
|
||||
return perm_ids
|
||||
perms = cls.objects.filter(id__in=perm_ids).valid()
|
||||
return perms
|
||||
|
||||
|
||||
class UserAssetGrantedTreeNodeRelation(OrgModelMixin, FamilyMixin, BaseCreateUpdateModel):
|
||||
|
|
|
@ -49,8 +49,9 @@ class AccountsGrantedSerializer(serializers.ModelSerializer):
|
|||
|
||||
# Todo: 添加前端登录逻辑中需要的一些字段,比如:是否需要手动输入密码
|
||||
# need_manual = serializers.BooleanField(label=_('Need manual input'))
|
||||
actions = ActionsField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Account
|
||||
fields = ['id', 'name', 'username']
|
||||
fields = ['id', 'name', 'username', 'actions']
|
||||
read_only_fields = fields
|
||||
|
|
|
@ -58,14 +58,15 @@ user_permission_urlpatterns = [
|
|||
# 收藏的资产
|
||||
path('<uuid:pk>/nodes/favorite/assets/', api.UserFavoriteGrantedAssetsApi.as_view(), name='user-ungrouped-assets'),
|
||||
path('nodes/favorite/assets/', api.MyFavoriteGrantedAssetsApi.as_view(), name='my-ungrouped-assets'),
|
||||
# v3 中上面的 API 基本不用动
|
||||
|
||||
# Todo: 删除
|
||||
# Todo: v3 删除
|
||||
# Asset System users
|
||||
path('<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersForAdminApi.as_view(), name='user-asset-system-users'),
|
||||
path('assets/<uuid:asset_id>/system-users/', api.MyGrantedAssetSystemUsersApi.as_view(), name='my-asset-system-users'),
|
||||
|
||||
# Todo: 增加
|
||||
# 获取所有和资产相关联的账号列表
|
||||
# Todo: v3 增加
|
||||
# 获取所有和资产-用户关联的账号列表
|
||||
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccounts.as_view(), name='user-asset-accounts'),
|
||||
path('assets/<uuid:asset_id>/accounts/', api.MyGrantedAssetAccounts.as_view(), name='my-asset-accounts')
|
||||
]
|
||||
|
@ -77,17 +78,21 @@ user_group_permission_urlpatterns = [
|
|||
path('<uuid:pk>/nodes/children/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes-children'),
|
||||
path('<uuid:pk>/nodes/children/tree/', api.UserGroupGrantedNodeChildrenAsTreeApi.as_view(), name='user-group-nodes-children-as-tree'),
|
||||
path('<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(), name='user-group-node-assets'),
|
||||
|
||||
# Todo: v3 删除
|
||||
path('<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGroupGrantedAssetSystemUsersApi.as_view(), name='user-group-asset-system-users'),
|
||||
# Todo: v3 增加
|
||||
# 获取所有和资产-用户组关联的账号列表
|
||||
path('<uuid:pk>/assets/<uuid:asset_id>/accounts/', api.UserGrantedAssetAccounts.as_view(), name='user-asset-accounts'),
|
||||
]
|
||||
|
||||
permission_urlpatterns = [
|
||||
# Todo: 获取规则中授权的所有账号列表
|
||||
#
|
||||
# 授权规则中授权的资产
|
||||
path('<uuid:pk>/assets/all/', api.AssetPermissionAllAssetListApi.as_view(), name='asset-permission-all-assets'),
|
||||
path('<uuid:pk>/users/all/', api.AssetPermissionAllUserListApi.as_view(), name='asset-permission-all-users'),
|
||||
|
||||
# 验证用户是否有某个资产和系统用户的权限
|
||||
# Todo: API 需要修改,验证用户有某个账号的权限
|
||||
path('user/validate/', api.ValidateUserAssetPermissionApi.as_view(), name='validate-user-asset-permission'),
|
||||
path('user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'),
|
||||
|
||||
|
|
Loading…
Reference in New Issue