mirror of https://github.com/jumpserver/jumpserver
pref: 修改 secret encrypt
parent
6a33129349
commit
9b44ed55c2
|
@ -34,6 +34,11 @@ class AccountViewSet(OrgBulkModelViewSet):
|
||||||
account = super().get_object()
|
account = super().get_object()
|
||||||
task = test_accounts_connectivity_manual.delay([account.id])
|
task = test_accounts_connectivity_manual.delay([account.id])
|
||||||
return Response(data={'task': task.id})
|
return Response(data={'task': task.id})
|
||||||
|
#
|
||||||
|
# @action(methods=['get'], detail=True, url_path='secret')
|
||||||
|
# def get_secret(self, request, *args, **kwargs):
|
||||||
|
# account = super().get_object()
|
||||||
|
# return Response(data={'secret': account.secret})
|
||||||
|
|
||||||
|
|
||||||
class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
|
class AccountSecretsViewSet(RecordViewLogMixin, AccountViewSet):
|
||||||
|
|
|
@ -35,6 +35,7 @@ class BaseType(TextChoices):
|
||||||
if choices == '__self__':
|
if choices == '__self__':
|
||||||
choices = [tp]
|
choices = [tp]
|
||||||
protocols = [{'name': name, **settings.get(name, {})} for name in choices]
|
protocols = [{'name': name, **settings.get(name, {})} for name in choices]
|
||||||
|
protocols[0]['primary'] = True
|
||||||
return protocols
|
return protocols
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -36,6 +36,13 @@ class AllTypes(ChoicesMixin):
|
||||||
cls.set_automation_methods(category, tp, constraints)
|
cls.set_automation_methods(category, tp, constraints)
|
||||||
return constraints
|
return constraints
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_primary_protocol_name(cls, category, tp):
|
||||||
|
constraints = cls.get_constraints(category, tp)
|
||||||
|
if not constraints:
|
||||||
|
return None
|
||||||
|
return constraints.get('protocols')[0]['name']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_automation_methods(cls, category, tp, constraints):
|
def set_automation_methods(cls, category, tp, constraints):
|
||||||
from assets.automations import filter_platform_methods
|
from assets.automations import filter_platform_methods
|
||||||
|
@ -189,7 +196,9 @@ class AllTypes(ChoicesMixin):
|
||||||
automation.save()
|
automation.save()
|
||||||
|
|
||||||
platform.protocols.all().delete()
|
platform.protocols.all().delete()
|
||||||
[PlatformProtocol.objects.create(**p, platform=platform) for p in protocols_data]
|
for p in protocols_data:
|
||||||
|
p.pop('primary', None)
|
||||||
|
PlatformProtocol.objects.create(**p, platform=platform)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_or_update_internal_platforms(cls):
|
def create_or_update_internal_platforms(cls):
|
||||||
|
|
|
@ -165,6 +165,15 @@ class AccountFilterSet(BaseFilterSet):
|
||||||
asset = drf_filters.CharFilter(field_name="asset_id", lookup_expr='exact')
|
asset = drf_filters.CharFilter(field_name="asset_id", lookup_expr='exact')
|
||||||
assets = drf_filters.CharFilter(field_name='asset_id', lookup_expr='in')
|
assets = drf_filters.CharFilter(field_name='asset_id', lookup_expr='in')
|
||||||
nodes = drf_filters.CharFilter(method='filter_nodes')
|
nodes = drf_filters.CharFilter(method='filter_nodes')
|
||||||
|
has_secret = drf_filters.BooleanFilter(method='filter_has_secret')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def filter_has_secret(queryset, name, has_secret):
|
||||||
|
q = Q(secret__isnull=True) | Q(secret='')
|
||||||
|
if has_secret:
|
||||||
|
return queryset.exclude(q)
|
||||||
|
else:
|
||||||
|
return queryset.filter(q)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_nodes(queryset, name, value):
|
def filter_nodes(queryset, name, value):
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-10-17 06:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0110_gatherfactsautomation'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platformprotocol',
|
||||||
|
name='default',
|
||||||
|
field=models.BooleanField(default=True, verbose_name='Default'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='platformprotocol',
|
||||||
|
name='required',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Required'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -135,7 +135,10 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def primary_protocol(self):
|
def primary_protocol(self):
|
||||||
return self.protocols.first()
|
from assets.const.types import AllTypes
|
||||||
|
primary_protocol_name = AllTypes.get_primary_protocol_name(self.category, self.type)
|
||||||
|
protocol = self.protocols.get(name=primary_protocol_name)
|
||||||
|
return protocol
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def protocol(self):
|
def protocol(self):
|
||||||
|
|
|
@ -72,18 +72,13 @@ class BaseAccount(OrgModelMixin):
|
||||||
date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated"))
|
date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated"))
|
||||||
created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
|
created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by'))
|
||||||
|
|
||||||
@property
|
|
||||||
def has_secret(self):
|
|
||||||
return bool(self.secret)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def password(self):
|
def password(self):
|
||||||
return self.secret
|
return self.secret
|
||||||
|
|
||||||
@password.setter
|
@property
|
||||||
def password(self, value):
|
def has_secret(self):
|
||||||
self.secret = value
|
return bool(self.secret)
|
||||||
self.secret_type = 'password'
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def private_key(self):
|
def private_key(self):
|
||||||
|
|
|
@ -17,6 +17,8 @@ class PlatformProtocol(models.Model):
|
||||||
'sftp_enabled': True,
|
'sftp_enabled': True,
|
||||||
'sftp_home': '/tmp'
|
'sftp_home': '/tmp'
|
||||||
}
|
}
|
||||||
|
default = models.BooleanField(default=False, verbose_name=_('Default'))
|
||||||
|
required = models.BooleanField(default=False, verbose_name=_('Required'))
|
||||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||||
port = models.IntegerField(verbose_name=_('Port'))
|
port = models.IntegerField(verbose_name=_('Port'))
|
||||||
setting = models.JSONField(verbose_name=_('Setting'), default=dict)
|
setting = models.JSONField(verbose_name=_('Setting'), default=dict)
|
||||||
|
@ -25,6 +27,13 @@ class PlatformProtocol(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '{}/{}'.format(self.name, self.port)
|
return '{}/{}'.format(self.name, self.port)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def primary(self):
|
||||||
|
primary_protocol_name = AllTypes.get_primary_protocol_name(
|
||||||
|
self.platform.category, self.platform.type
|
||||||
|
)
|
||||||
|
return self.name == primary_protocol_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def secret_types(self):
|
def secret_types(self):
|
||||||
return Protocol.settings().get(self.name, {}).get('secret_types')
|
return Protocol.settings().get(self.name, {}).get('secret_types')
|
||||||
|
@ -83,9 +92,10 @@ class Platform(models.Model):
|
||||||
)
|
)
|
||||||
return linux.id
|
return linux.id
|
||||||
|
|
||||||
@staticmethod
|
@property
|
||||||
def set_default_platforms_ops(platform_model):
|
def primary_protocol(self):
|
||||||
pass
|
primary_protocol_name = AllTypes.get_primary_protocol_name(self.category, self.type)
|
||||||
|
return self.protocols.filter(name=primary_protocol_name).first()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
|
@ -82,9 +82,7 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer):
|
||||||
class AccountSecretSerializer(SecretReadableMixin, AccountSerializer):
|
class AccountSecretSerializer(SecretReadableMixin, AccountSerializer):
|
||||||
class Meta(AccountSerializer.Meta):
|
class Meta(AccountSerializer.Meta):
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'password': {'write_only': False},
|
'secret': {'write_only': False},
|
||||||
'private_key': {'write_only': False},
|
|
||||||
'public_key': {'write_only': False},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,34 @@ class AssetSerializer(JMSWritableNestedModelSerializer):
|
||||||
if not node_id:
|
if not node_id:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def validate_protocols(self, protocols_data):
|
||||||
|
if not protocols_data:
|
||||||
|
protocols_data = []
|
||||||
|
platform_id = self.initial_data.get('platform')
|
||||||
|
if isinstance(platform_id, dict):
|
||||||
|
platform_id = platform_id.get('id') or platform_id.get('pk')
|
||||||
|
platform = Platform.objects.filter(id=platform_id).first()
|
||||||
|
if not platform:
|
||||||
|
raise serializers.ValidationError({'platform': _("Platform not exist")})
|
||||||
|
|
||||||
|
protocols_data_map = {p['name']: p for p in protocols_data}
|
||||||
|
platform_protocols = platform.protocols.all()
|
||||||
|
protocols_default = [p for p in platform_protocols if p.default]
|
||||||
|
protocols_required = [p for p in platform_protocols if p.required or p.primary]
|
||||||
|
|
||||||
|
if not protocols_data_map:
|
||||||
|
protocols_data_map = {
|
||||||
|
p.name: {'name': p.name, 'port': p.port}
|
||||||
|
for p in protocols_required + protocols_default
|
||||||
|
}
|
||||||
|
|
||||||
|
protocols_not_found = [p.name for p in protocols_required if p.name not in protocols_data_map]
|
||||||
|
if protocols_not_found:
|
||||||
|
raise serializers.ValidationError({
|
||||||
|
'protocols': _("Protocol is required: {}").format(', '.join(protocols_not_found))
|
||||||
|
})
|
||||||
|
return protocols_data_map.values()
|
||||||
|
|
||||||
@atomic
|
@atomic
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
nodes_display = validated_data.pop('nodes_display', '')
|
nodes_display = validated_data.pop('nodes_display', '')
|
||||||
|
|
|
@ -50,9 +50,9 @@ class PlatformAutomationSerializer(serializers.ModelSerializer):
|
||||||
'gather_facts_method': {'label': '收集信息方式'},
|
'gather_facts_method': {'label': '收集信息方式'},
|
||||||
'verify_account_enabled': {'label': '启用校验账号'},
|
'verify_account_enabled': {'label': '启用校验账号'},
|
||||||
'verify_account_method': {'label': '校验账号方式'},
|
'verify_account_method': {'label': '校验账号方式'},
|
||||||
'create_account_enabled': {'label': '启用创建账号'},
|
'create_account_enabled': {'label': '启用推送账号'},
|
||||||
'create_account_method': {'label': '创建账号方式'},
|
'create_account_method': {'label': '推送账号方式'},
|
||||||
'change_secret_enabled': {'label': '启用账号创建改密'},
|
'change_secret_enabled': {'label': '启用账号改密'},
|
||||||
'change_secret_method': {'label': '账号创建改密方式'},
|
'change_secret_method': {'label': '账号创建改密方式'},
|
||||||
'gather_accounts_enabled': {'label': '启用账号收集'},
|
'gather_accounts_enabled': {'label': '启用账号收集'},
|
||||||
'gather_accounts_method': {'label': '收集账号方式'},
|
'gather_accounts_method': {'label': '收集账号方式'},
|
||||||
|
@ -61,10 +61,14 @@ class PlatformAutomationSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class PlatformProtocolsSerializer(serializers.ModelSerializer):
|
class PlatformProtocolsSerializer(serializers.ModelSerializer):
|
||||||
setting = ProtocolSettingSerializer(required=False, allow_null=True)
|
setting = ProtocolSettingSerializer(required=False, allow_null=True)
|
||||||
|
primary = serializers.BooleanField(read_only=True, label=_("Primary"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PlatformProtocol
|
model = PlatformProtocol
|
||||||
fields = ['id', 'name', 'port', 'secret_types', 'setting']
|
fields = [
|
||||||
|
'id', 'name', 'port', 'primary', 'default',
|
||||||
|
'required', 'secret_types', 'setting',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class PlatformSerializer(JMSWritableNestedModelSerializer):
|
class PlatformSerializer(JMSWritableNestedModelSerializer):
|
||||||
|
|
|
@ -117,10 +117,10 @@ class EncryptMixin:
|
||||||
return signer.unsign(value) or ''
|
return signer.unsign(value) or ''
|
||||||
|
|
||||||
def from_db_value(self, value, expression, connection, context=None):
|
def from_db_value(self, value, expression, connection, context=None):
|
||||||
if value is None:
|
if not value:
|
||||||
return value
|
return value
|
||||||
value = force_text(value)
|
|
||||||
|
|
||||||
|
value = force_text(value)
|
||||||
plain_value = crypto.decrypt(value)
|
plain_value = crypto.decrypt(value)
|
||||||
|
|
||||||
# 如果没有解开,使用原来的signer解密
|
# 如果没有解开,使用原来的signer解密
|
||||||
|
@ -134,7 +134,7 @@ class EncryptMixin:
|
||||||
return plain_value
|
return plain_value
|
||||||
|
|
||||||
def get_prep_value(self, value):
|
def get_prep_value(self, value):
|
||||||
if value is None:
|
if not value:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
# 先 json 再解密
|
# 先 json 再解密
|
||||||
|
|
|
@ -86,5 +86,5 @@ class GroupedChoiceSerializer(ChoiceSerializer):
|
||||||
children = ChoiceSerializer(many=True, label=_("Children"))
|
children = ChoiceSerializer(many=True, label=_("Children"))
|
||||||
|
|
||||||
|
|
||||||
class JMSWritableNestedModelSerializer(WritableNestedModelSerializer):
|
class JMSWritableNestedModelSerializer(ModelSerializer):
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue