mirror of https://github.com/jumpserver/jumpserver
fix: 修复swagger
parent
05f913ab18
commit
fe4df4b179
|
@ -7,5 +7,6 @@ from .node import *
|
|||
from .domain import *
|
||||
from .gathered_user import *
|
||||
from .favorite_asset import *
|
||||
from .account_template import *
|
||||
from .account_backup import *
|
||||
from .account_history import *
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
from orgs.mixins.api import OrgBulkModelViewSet
|
||||
from ..models import AccountTemplate
|
||||
from .. import serializers
|
||||
|
||||
|
||||
class AccountTemplateViewSet(OrgBulkModelViewSet):
|
||||
model = AccountTemplate
|
||||
filterset_fields = ("username", 'name')
|
||||
search_fields = ('username', 'name')
|
||||
serializer_classes = {
|
||||
'default': serializers.AccountTemplateSerializer
|
||||
}
|
|
@ -16,5 +16,5 @@ class GatheredUserViewSet(OrgModelViewSet):
|
|||
serializer_class = GatheredUserSerializer
|
||||
extra_filter_backends = [AssetRelatedByNodeFilterBackend]
|
||||
|
||||
filterset_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__hostname', 'asset_id']
|
||||
search_fields = ['username', 'asset__ip', 'asset__hostname']
|
||||
filterset_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__name', 'asset_id']
|
||||
search_fields = ['username', 'asset__ip', 'asset__name']
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# Generated by Django 3.2.13 on 2022-08-19 07:23
|
||||
|
||||
import assets.models.base
|
||||
import common.db.fields
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0110_auto_20220817_1716'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AccountTemplate',
|
||||
fields=[
|
||||
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('connectivity', models.CharField(choices=[('unknown', 'Unknown'), ('ok', 'Ok'), ('failed', 'Failed')], default='unknown', max_length=16, verbose_name='Connectivity')),
|
||||
('date_verified', models.DateTimeField(null=True, verbose_name='Date verified')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
|
||||
('password', common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
|
||||
('private_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
|
||||
('public_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
|
||||
('comment', models.TextField(blank=True, verbose_name='Comment')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
|
||||
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
|
||||
('token', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Token')),
|
||||
('privileged', models.BooleanField(default=False, verbose_name='Privileged account')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Account template',
|
||||
},
|
||||
bases=(models.Model, assets.models.base.AuthMixin),
|
||||
)
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 3.2.13 on 2022-08-19 07:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0111_auto_20220819_1523'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='protocols_default',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='protocols_enabled',
|
||||
field=models.BooleanField(default=True, verbose_name='Protocols enabled'),
|
||||
),
|
||||
]
|
|
@ -5,7 +5,7 @@ from simple_history.models import HistoricalRecords
|
|||
from common.db import fields
|
||||
from .base import BaseAccount, AbsConnectivity
|
||||
|
||||
__all__ = ['Account']
|
||||
__all__ = ['Account', 'AccountTemplate']
|
||||
|
||||
|
||||
class Account(BaseAccount, AbsConnectivity):
|
||||
|
@ -27,3 +27,14 @@ class Account(BaseAccount, AbsConnectivity):
|
|||
|
||||
def __str__(self):
|
||||
return '{}@{}'.format(self.username, self.asset.name)
|
||||
|
||||
|
||||
class AccountTemplate(BaseAccount, AbsConnectivity):
|
||||
token = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Token'))
|
||||
privileged = models.BooleanField(verbose_name=_("Privileged account"), default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Account template')
|
||||
|
||||
def __str__(self):
|
||||
return '{}@{}'.format(self.username, self.name)
|
||||
|
|
|
@ -98,6 +98,11 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
|||
return False, warning
|
||||
return True, warning
|
||||
|
||||
def domain_display(self):
|
||||
if self.domain:
|
||||
return self.domain.name
|
||||
return ''
|
||||
|
||||
def nodes_display(self):
|
||||
names = []
|
||||
for n in self.nodes.all():
|
||||
|
@ -114,10 +119,18 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
|||
def type(self):
|
||||
return self.platform.type
|
||||
|
||||
@property
|
||||
def type_display(self):
|
||||
return self.platform.type
|
||||
|
||||
@property
|
||||
def category(self):
|
||||
return self.platform.category
|
||||
|
||||
@property
|
||||
def category_display(self):
|
||||
return self.platform.category
|
||||
|
||||
def as_node(self):
|
||||
from assets.models import Node
|
||||
fake_node = Node()
|
||||
|
|
|
@ -9,5 +9,6 @@ from .gathered_user import *
|
|||
from .favorite_asset import *
|
||||
from .account import *
|
||||
from .account_history import *
|
||||
from .account_template import *
|
||||
from .backup import *
|
||||
from .platform import *
|
||||
|
|
|
@ -6,7 +6,6 @@ from assets.models import Account
|
|||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
|
||||
from .base import AuthSerializerMixin
|
||||
from common.utils.encode import ssh_pubkey_gen
|
||||
from common.drf.serializers import SecretReadableMixin
|
||||
|
||||
|
||||
|
@ -33,17 +32,6 @@ class AccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
}
|
||||
ref_name = 'AssetAccountSerializer'
|
||||
|
||||
def _validate_gen_key(self, attrs):
|
||||
private_key = attrs.get('private_key')
|
||||
if not private_key:
|
||||
return attrs
|
||||
|
||||
password = attrs.get('passphrase')
|
||||
username = attrs.get('username')
|
||||
public_key = ssh_pubkey_gen(private_key, password=password, username=username)
|
||||
attrs['public_key'] = public_key
|
||||
return attrs
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs = self._validate_gen_key(attrs)
|
||||
return attrs
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
from assets.models import AccountTemplate
|
||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
|
||||
from .base import AuthSerializerMixin
|
||||
from .account import AccountSerializer
|
||||
|
||||
|
||||
class AccountTemplateSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||
class Meta:
|
||||
model = AccountTemplate
|
||||
fields_mini = ['id', 'privileged', 'username']
|
||||
fields_write_only = AccountSerializer.Meta.fields_write_only
|
||||
fields_other = AccountSerializer.Meta.fields_other
|
||||
fields = fields_mini + fields_write_only + fields_other
|
||||
extra_kwargs = AccountSerializer.Meta.extra_kwargs
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs = self._validate_gen_key(attrs)
|
||||
return attrs
|
|
@ -31,7 +31,7 @@ class DatabaseSerializer(AssetSerializer):
|
|||
class Meta(AssetSerializer.Meta):
|
||||
model = Database
|
||||
fields_mini = [
|
||||
'id', 'name', 'ip', 'port', 'db_name',
|
||||
'id', 'name', 'ip', 'db_name',
|
||||
]
|
||||
fields_small = fields_mini + [
|
||||
'is_active', 'comment',
|
||||
|
|
|
@ -13,7 +13,8 @@ from .utils import validate_password_for_ansible
|
|||
|
||||
class AuthSerializer(serializers.ModelSerializer):
|
||||
password = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=1024, label=_('Password'))
|
||||
private_key = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=16384, label=_('Private key'))
|
||||
private_key = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=16384,
|
||||
label=_('Private key'))
|
||||
|
||||
def gen_keys(self, private_key=None, password=None):
|
||||
if private_key is None:
|
||||
|
@ -74,6 +75,17 @@ class AuthSerializerMixin(serializers.ModelSerializer):
|
|||
validated_data.pop(field, None)
|
||||
validated_data.pop('passphrase', None)
|
||||
|
||||
def _validate_gen_key(self, attrs):
|
||||
private_key = attrs.get('private_key')
|
||||
if not private_key:
|
||||
return attrs
|
||||
|
||||
password = attrs.get('passphrase')
|
||||
username = attrs.get('username')
|
||||
public_key = ssh_pubkey_gen(private_key, password=password, username=username)
|
||||
attrs['public_key'] = public_key
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
self.clean_auth_fields(validated_data)
|
||||
return super().create(validated_data)
|
||||
|
|
|
@ -14,6 +14,7 @@ router.register(r'assets', api.AssetViewSet, 'asset')
|
|||
router.register(r'hosts', api.HostViewSet, 'host')
|
||||
router.register(r'databases', api.DatabaseViewSet, 'database')
|
||||
router.register(r'accounts', api.AccountViewSet, 'account')
|
||||
router.register(r'account-templates', api.AccountTemplateViewSet, 'account-template')
|
||||
router.register(r'account-secrets', api.AccountSecretsViewSet, 'account-secret')
|
||||
router.register(r'accounts-history', api.AccountHistoryViewSet, 'account-history')
|
||||
router.register(r'account-history-secrets', api.AccountHistorySecretsViewSet, 'account-history-secret')
|
||||
|
|
|
@ -107,11 +107,11 @@ class CommandExecutionViewSet(ListModelMixin, OrgGenericViewSet):
|
|||
]
|
||||
filterset_fields = [
|
||||
'user__name', 'user__username', 'command',
|
||||
'run_as__name', 'run_as__username', 'is_finished'
|
||||
'account', 'is_finished'
|
||||
]
|
||||
search_fields = [
|
||||
'command', 'user__name', 'user__username',
|
||||
'run_as__name', 'run_as__username',
|
||||
'account__username',
|
||||
]
|
||||
ordering = ['-date_created']
|
||||
|
||||
|
@ -121,7 +121,7 @@ class CommandExecutionViewSet(ListModelMixin, OrgGenericViewSet):
|
|||
return queryset.model.objects.none()
|
||||
if current_org.is_root():
|
||||
return queryset
|
||||
queryset = queryset.filter(run_as__org_id=current_org.org_id())
|
||||
# queryset = queryset.filter(run_as__org_id=current_org.org_id())
|
||||
return queryset
|
||||
|
||||
|
||||
|
@ -131,7 +131,7 @@ class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet)
|
|||
filterset_fields = [
|
||||
'id', 'asset', 'commandexecution'
|
||||
]
|
||||
search_fields = ('asset__hostname', )
|
||||
search_fields = ('asset__name', )
|
||||
http_method_names = ['options', 'get']
|
||||
rbac_perms = {
|
||||
'GET': 'ops.view_commandexecution',
|
||||
|
@ -142,7 +142,7 @@ class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet)
|
|||
queryset = super().get_queryset()
|
||||
queryset = queryset.annotate(
|
||||
asset_display=Concat(
|
||||
F('asset__hostname'), Value('('),
|
||||
F('asset__name'), Value('('),
|
||||
F('asset__ip'), Value(')')
|
||||
)
|
||||
)
|
||||
|
|
|
@ -88,24 +88,22 @@ class CommandExecutionSerializer(serializers.ModelSerializer):
|
|||
model = CommandExecution
|
||||
fields_mini = ['id']
|
||||
fields_small = fields_mini + [
|
||||
'run_as', 'command', 'is_finished', 'user',
|
||||
'command', 'is_finished', 'user',
|
||||
'date_start', 'result', 'is_success', 'org_id'
|
||||
]
|
||||
fields = fields_small + ['hosts', 'hosts_display', 'run_as_display', 'user_display']
|
||||
fields = fields_small + ['hosts', 'hosts_display', 'user_display']
|
||||
extra_kwargs = {
|
||||
'result': {'label': _('Result')}, # model 上的方法,只能在这修改
|
||||
'is_success': {'label': _('Is success')},
|
||||
'hosts': {'label': _('Hosts')}, # 外键,会生成 sql。不在 model 上修改
|
||||
'run_as': {'label': _('Run as')},
|
||||
'user': {'label': _('User')},
|
||||
'run_as_display': {'label': _('Run as display')},
|
||||
'user_display': {'label': _('User display')},
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def setup_eager_loading(cls, queryset):
|
||||
""" Perform necessary eager loading of data. """
|
||||
queryset = queryset.prefetch_related('user', 'run_as', 'hosts')
|
||||
queryset = queryset.prefetch_related('user', 'hosts')
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -45,18 +45,12 @@ class ConnectionTokenMixin:
|
|||
@staticmethod
|
||||
def check_user_has_resource_permission(user, asset, application, system_user):
|
||||
from perms.utils.asset import has_asset_system_permission
|
||||
from perms.utils.application import has_application_system_permission
|
||||
|
||||
if asset and not has_asset_system_permission(user, asset, system_user):
|
||||
error = f'User not has this asset and system user permission: ' \
|
||||
f'user={user.id} system_user={system_user.id} asset={asset.id}'
|
||||
raise PermissionDenied(error)
|
||||
|
||||
if application and not has_application_system_permission(user, application, system_user):
|
||||
error = f'User not has this application and system user permission: ' \
|
||||
f'user={user.id} system_user={system_user.id} application={application.id}'
|
||||
raise PermissionDenied(error)
|
||||
|
||||
def get_smart_endpoint(self, protocol, asset=None, application=None):
|
||||
if asset:
|
||||
target_ip = asset.get_target_ip()
|
||||
|
@ -204,8 +198,7 @@ class ConnectionTokenMixin:
|
|||
|
||||
class ConnectionTokenViewSet(ConnectionTokenMixin, RootOrgViewMixin, JMSModelViewSet):
|
||||
filterset_fields = (
|
||||
'type',
|
||||
'user_display', 'system_user_display', 'application_display', 'asset_display'
|
||||
'type', 'user_display', 'asset_display'
|
||||
)
|
||||
search_fields = filterset_fields
|
||||
serializer_classes = {
|
||||
|
|
|
@ -25,7 +25,6 @@ class CommandExecutionViewSet(RootOrgViewMixin, viewsets.ModelViewSet):
|
|||
def check_hosts(self, serializer):
|
||||
data = serializer.validated_data
|
||||
assets = data["hosts"]
|
||||
system_user = data["run_as"]
|
||||
user = self.request.user
|
||||
|
||||
# TOdo:
|
||||
|
|
|
@ -47,10 +47,6 @@ class CommandExecution(OrgModelMixin):
|
|||
inv = JMSInventory(self.allow_assets, run_as=username, system_user=self.run_as)
|
||||
return inv
|
||||
|
||||
@lazyproperty
|
||||
def run_as_display(self):
|
||||
return str(self.run_as)
|
||||
|
||||
@lazyproperty
|
||||
def user_display(self):
|
||||
return str(self.user)
|
||||
|
|
|
@ -138,9 +138,8 @@ class CommandExecutionSerializer(serializers.ModelSerializer):
|
|||
'command', 'result', 'log_url',
|
||||
'is_finished', 'date_created', 'date_finished'
|
||||
]
|
||||
fields_fk = ['run_as']
|
||||
fields_m2m = ['hosts']
|
||||
fields = fields_small + fields_fk + fields_m2m
|
||||
fields = fields_small + fields_m2m
|
||||
read_only_fields = [
|
||||
'result', 'is_finished', 'log_url', 'date_created',
|
||||
'date_finished'
|
||||
|
|
|
@ -80,12 +80,12 @@ class AssetPermissionAssetRelationViewSet(RelationMixin):
|
|||
filterset_fields = [
|
||||
'id', 'asset', 'assetpermission',
|
||||
]
|
||||
search_fields = ["id", "asset__hostname", "asset__ip", "assetpermission__name"]
|
||||
search_fields = ["id", "asset__name", "asset__ip", "assetpermission__name"]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
queryset = queryset \
|
||||
.annotate(asset_display=F('asset__hostname'))
|
||||
.annotate(asset_display=F('asset__name'))
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = Asset
|
||||
only_fields = [
|
||||
"id", "name", "ip", "protocols", "os", 'domain',
|
||||
"id", "name", "ip", "protocols", 'domain',
|
||||
"platform", "comment", "org_id", "is_active"
|
||||
]
|
||||
fields = only_fields + ['org_name']
|
||||
|
|
Loading…
Reference in New Issue