mirror of https://github.com/jumpserver/jumpserver
perf: 账号管理api
parent
389094f615
commit
108ccf5a8b
|
@ -1,45 +1,19 @@
|
||||||
from django_filters import rest_framework as filters
|
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.generics import CreateAPIView
|
from rest_framework.generics import CreateAPIView
|
||||||
|
|
||||||
from orgs.mixins.api import OrgBulkModelViewSet
|
from orgs.mixins.api import OrgBulkModelViewSet
|
||||||
from rbac.permissions import RBACPermission
|
from rbac.permissions import RBACPermission
|
||||||
from common.drf.filters import BaseFilterSet, UUIDInFilter
|
|
||||||
from common.mixins import RecordViewLogMixin
|
from common.mixins import RecordViewLogMixin
|
||||||
from common.permissions import UserConfirmation
|
from common.permissions import UserConfirmation
|
||||||
from authentication.const import ConfirmType
|
from authentication.const import ConfirmType
|
||||||
|
from assets.models import Account
|
||||||
|
from assets.filters import AccountFilterSet
|
||||||
from assets.tasks.account_connectivity import test_accounts_connectivity_manual
|
from assets.tasks.account_connectivity import test_accounts_connectivity_manual
|
||||||
from assets.models import Account, Node
|
|
||||||
from assets import serializers
|
from assets import serializers
|
||||||
|
|
||||||
__all__ = ['AccountFilterSet', 'AccountViewSet', 'AccountSecretsViewSet', 'AccountTaskCreateAPI']
|
__all__ = ['AccountViewSet', 'AccountSecretsViewSet', 'AccountTaskCreateAPI']
|
||||||
|
|
||||||
|
|
||||||
class AccountFilterSet(BaseFilterSet):
|
|
||||||
ip = filters.CharFilter(field_name='ip', lookup_expr='exact')
|
|
||||||
hostname = filters.CharFilter(field_name='name', lookup_expr='exact')
|
|
||||||
username = filters.CharFilter(field_name="username", lookup_expr='exact')
|
|
||||||
assets = UUIDInFilter(field_name='asset_id', lookup_expr='in')
|
|
||||||
nodes = UUIDInFilter(method='filter_nodes')
|
|
||||||
|
|
||||||
def filter_nodes(self, queryset, name, value):
|
|
||||||
nodes = Node.objects.filter(id__in=value)
|
|
||||||
if not nodes:
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
node_qs = Node.objects.none()
|
|
||||||
for node in nodes:
|
|
||||||
node_qs |= node.get_all_children(with_self=True)
|
|
||||||
node_ids = list(node_qs.values_list('id', flat=True))
|
|
||||||
queryset = queryset.filter(asset__nodes__in=node_ids)
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Account
|
|
||||||
fields = [
|
|
||||||
'asset', 'id'
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class AccountViewSet(OrgBulkModelViewSet):
|
class AccountViewSet(OrgBulkModelViewSet):
|
||||||
|
@ -52,7 +26,7 @@ class AccountViewSet(OrgBulkModelViewSet):
|
||||||
'verify': serializers.AssetTaskSerializer
|
'verify': serializers.AssetTaskSerializer
|
||||||
}
|
}
|
||||||
rbac_perms = {
|
rbac_perms = {
|
||||||
'verify': 'assets.test_authbook',
|
'verify': 'assets.test_account',
|
||||||
'partial_update': 'assets.change_assetaccountsecret',
|
'partial_update': 'assets.change_assetaccountsecret',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
from .account import (
|
|
||||||
AccountFilterSet, AccountViewSet, AccountSecretsViewSet
|
|
||||||
)
|
|
||||||
from common.mixins import RecordViewLogMixin
|
|
||||||
from assets import serializers
|
from assets import serializers
|
||||||
from assets.models import Account
|
from assets.models import Account
|
||||||
|
from assets.filters import AccountFilterSet
|
||||||
|
from common.mixins import RecordViewLogMixin
|
||||||
|
from .account import AccountViewSet, AccountSecretsViewSet
|
||||||
|
|
||||||
__all__ = ['AccountHistoryViewSet', 'AccountHistorySecretsViewSet']
|
__all__ = ['AccountHistoryViewSet', 'AccountHistorySecretsViewSet']
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
|
||||||
from rest_framework.compat import coreapi, coreschema
|
|
||||||
from rest_framework import filters
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from rest_framework import filters
|
||||||
|
from rest_framework.compat import coreapi, coreschema
|
||||||
|
|
||||||
from .models import Label
|
from common.drf.filters import BaseFilterSet, UUIDInFilter
|
||||||
from assets.utils import is_query_node_all_assets, get_node_from_request
|
from assets.utils import is_query_node_all_assets, get_node_from_request
|
||||||
|
from .models import Label, Node, Account
|
||||||
|
|
||||||
|
|
||||||
class AssetByNodeFilterBackend(filters.BaseFilterBackend):
|
class AssetByNodeFilterBackend(filters.BaseFilterBackend):
|
||||||
|
@ -109,7 +109,7 @@ class LabelFilterBackend(filters.BaseFilterBackend):
|
||||||
q = Q(name=key, value=value)
|
q = Q(name=key, value=value)
|
||||||
if not q:
|
if not q:
|
||||||
return []
|
return []
|
||||||
labels = Label.objects.filter(q, is_active=True)\
|
labels = Label.objects.filter(q, is_active=True) \
|
||||||
.values_list('id', flat=True)
|
.values_list('id', flat=True)
|
||||||
return labels
|
return labels
|
||||||
|
|
||||||
|
@ -154,3 +154,30 @@ class IpInFilterBackend(filters.BaseFilterBackend):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class AccountFilterSet(BaseFilterSet):
|
||||||
|
from django_filters import rest_framework as filters
|
||||||
|
ip = filters.CharFilter(field_name='ip', lookup_expr='exact')
|
||||||
|
hostname = filters.CharFilter(field_name='name', lookup_expr='exact')
|
||||||
|
username = filters.CharFilter(field_name="username", lookup_expr='exact')
|
||||||
|
assets = UUIDInFilter(field_name='asset_id', lookup_expr='in')
|
||||||
|
nodes = UUIDInFilter(method='filter_nodes')
|
||||||
|
|
||||||
|
def filter_nodes(self, queryset, name, value):
|
||||||
|
nodes = Node.objects.filter(id__in=value)
|
||||||
|
if not nodes:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
node_qs = Node.objects.none()
|
||||||
|
for node in nodes:
|
||||||
|
node_qs |= node.get_all_children(with_self=True)
|
||||||
|
node_ids = list(node_qs.values_list('id', flat=True))
|
||||||
|
queryset = queryset.filter(asset__nodes__in=node_ids)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Account
|
||||||
|
fields = [
|
||||||
|
'asset', 'id'
|
||||||
|
]
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from django.db.models import F
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
@ -21,20 +20,20 @@ class AccountSerializerCreateMixin(serializers.ModelSerializer):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_template(value):
|
def validate_template(value):
|
||||||
AccountTemplate.objects.get_or_create()
|
|
||||||
model = AccountTemplate
|
|
||||||
try:
|
try:
|
||||||
return model.objects.get(id=value)
|
return AccountTemplate.objects.get(id=value)
|
||||||
except AccountTemplate.DoesNotExist:
|
except AccountTemplate.DoesNotExist:
|
||||||
raise serializers.ValidationError(_('Account template not found'))
|
raise serializers.ValidationError(_('Account template not found'))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def replace_attrs(account_template: AccountTemplate, attrs: dict):
|
def replace_attrs(account_template: AccountTemplate, attrs: dict):
|
||||||
exclude_fields = [
|
exclude_fields = [
|
||||||
'_state', 'org_id', 'date_verified', 'id',
|
'_state', 'org_id', 'id', 'date_created', 'date_updated'
|
||||||
'date_created', 'date_updated', 'created_by'
|
|
||||||
]
|
]
|
||||||
template_attrs = {k: v for k, v in account_template.__dict__.items() if k not in exclude_fields}
|
template_attrs = {
|
||||||
|
k: v for k, v in account_template.__dict__.items()
|
||||||
|
if k not in exclude_fields
|
||||||
|
}
|
||||||
for k, v in template_attrs.items():
|
for k, v in template_attrs.items():
|
||||||
attrs.setdefault(k, v)
|
attrs.setdefault(k, v)
|
||||||
|
|
||||||
|
@ -48,17 +47,19 @@ class AccountSerializerCreateMixin(serializers.ModelSerializer):
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
instance = super().create(validated_data)
|
instance = super().create(validated_data)
|
||||||
if self.push_now:
|
if self.push_now:
|
||||||
print("Start push account to asset")
|
|
||||||
# Todo: push it
|
# Todo: push it
|
||||||
pass
|
print("Start push account to asset")
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class AccountSerializer(AuthValidateMixin,
|
class AccountSerializer(
|
||||||
AccountSerializerCreateMixin,
|
AuthValidateMixin, AccountSerializerCreateMixin,
|
||||||
AccountFieldsSerializerMixin,
|
AccountFieldsSerializerMixin, BulkOrgResourceModelSerializer
|
||||||
BulkOrgResourceModelSerializer):
|
):
|
||||||
asset = ObjectRelatedField(required=False, queryset=Asset.objects, label=_('Asset'), attrs=('id', 'name', 'ip'))
|
asset = ObjectRelatedField(
|
||||||
|
required=False, queryset=Asset.objects,
|
||||||
|
label=_('Asset'), attrs=('id', 'name', 'ip')
|
||||||
|
)
|
||||||
platform = serializers.ReadOnlyField(label=_("Platform"))
|
platform = serializers.ReadOnlyField(label=_("Platform"))
|
||||||
|
|
||||||
class Meta(AccountFieldsSerializerMixin.Meta):
|
class Meta(AccountFieldsSerializerMixin.Meta):
|
||||||
|
|
|
@ -74,7 +74,7 @@ def test_user_connectivity(task_name, asset, username, password=None, private_ke
|
||||||
@org_aware_func("account")
|
@org_aware_func("account")
|
||||||
def test_account_connectivity_util(account, task_name):
|
def test_account_connectivity_util(account, task_name):
|
||||||
"""
|
"""
|
||||||
:param account: <AuthBook>对象
|
:param account: <Account>对象
|
||||||
:param task_name:
|
:param task_name:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
@ -101,7 +101,7 @@ def test_account_connectivity_util(account, task_name):
|
||||||
@shared_task(queue="ansible")
|
@shared_task(queue="ansible")
|
||||||
def test_accounts_connectivity_manual(accounts):
|
def test_accounts_connectivity_manual(accounts):
|
||||||
"""
|
"""
|
||||||
:param accounts: <AuthBook>对象
|
:param accounts: <Account>对象
|
||||||
"""
|
"""
|
||||||
for account in accounts:
|
for account in accounts:
|
||||||
task_name = gettext_noop("Test account connectivity: ") + str(account)
|
task_name = gettext_noop("Test account connectivity: ") + str(account)
|
||||||
|
|
|
@ -35,14 +35,14 @@ exclude_permissions = (
|
||||||
('assets', 'assetgroup', '*', '*'),
|
('assets', 'assetgroup', '*', '*'),
|
||||||
('assets', 'cluster', '*', '*'),
|
('assets', 'cluster', '*', '*'),
|
||||||
('assets', 'favoriteasset', '*', '*'),
|
('assets', 'favoriteasset', '*', '*'),
|
||||||
('assets', 'historicalauthbook', '*', '*'),
|
('assets', 'historicalaccount', '*', '*'),
|
||||||
('assets', 'assetuser', '*', '*'),
|
('assets', 'assetuser', '*', '*'),
|
||||||
('assets', 'gathereduser', 'add,delete,change', 'gathereduser'),
|
('assets', 'gathereduser', 'add,delete,change', 'gathereduser'),
|
||||||
('assets', 'accountbackupplanexecution', 'delete,change', 'accountbackupplanexecution'),
|
('assets', 'accountbackupplanexecution', 'delete,change', 'accountbackupplanexecution'),
|
||||||
('assets', 'authbook', 'change', 'authbook'),
|
('assets', 'account', 'change', 'account'),
|
||||||
# TODO 暂时去掉历史账号的权限
|
# TODO 暂时去掉历史账号的权限
|
||||||
('assets', 'authbook', '*', 'assethistoryaccount'),
|
('assets', 'account', '*', 'assethistoryaccount'),
|
||||||
('assets', 'authbook', '*', 'assethistoryaccountsecret'),
|
('assets', 'account', '*', 'assethistoryaccountsecret'),
|
||||||
|
|
||||||
('perms', 'userassetgrantedtreenoderelation', '*', '*'),
|
('perms', 'userassetgrantedtreenoderelation', '*', '*'),
|
||||||
('perms', 'usergrantedmappingnode', '*', '*'),
|
('perms', 'usergrantedmappingnode', '*', '*'),
|
||||||
|
|
|
@ -61,7 +61,7 @@ extra_nodes_data = [
|
||||||
# 将 model 放到其它节点下,而不是本来的 app 中
|
# 将 model 放到其它节点下,而不是本来的 app 中
|
||||||
special_pid_mapper = {
|
special_pid_mapper = {
|
||||||
'common.permission': 'view_other',
|
'common.permission': 'view_other',
|
||||||
"assets.authbook": "accounts",
|
"assets.account": "accounts",
|
||||||
"applications.account": "accounts",
|
"applications.account": "accounts",
|
||||||
'xpack.account': 'cloud_import',
|
'xpack.account': 'cloud_import',
|
||||||
'xpack.syncinstancedetail': 'cloud_import',
|
'xpack.syncinstancedetail': 'cloud_import',
|
||||||
|
|
Loading…
Reference in New Issue