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

pull/9044/head
ibuler 2022-11-09 20:59:28 +08:00
commit 644f3f1783
16 changed files with 93 additions and 107 deletions

View File

@ -2,7 +2,9 @@ from django.utils.translation import ugettext as _
from rest_framework import serializers
from common.drf.serializers import BulkModelSerializer
from common.drf.serializers import MethodSerializer
from common.drf.fields import ObjectRelatedField
from jumpserver.utils import has_valid_xpack_license
from users.models import User
from ..models import LoginACL
from .rules import RuleSerializer
@ -12,8 +14,10 @@ common_help_text = _('Format for comma-delimited string, with * indicating a mat
class LoginACLSerializer(BulkModelSerializer):
user_display = serializers.ReadOnlyField(source='user.username', label=_('Username'))
reviewers_display = serializers.SerializerMethodField(label=_('Reviewers'))
user = ObjectRelatedField(queryset=User.objects, label=_('User'))
reviewers = ObjectRelatedField(
queryset=User.objects, label=_('Reviewers'), many=True, required=False
)
action_display = serializers.ReadOnlyField(source='get_action_display', label=_('Action'))
reviewers_amount = serializers.IntegerField(read_only=True, source='reviewers.count')
rules = MethodSerializer()
@ -22,13 +26,11 @@ class LoginACLSerializer(BulkModelSerializer):
model = LoginACL
fields_mini = ['id', 'name']
fields_small = fields_mini + [
'priority', 'rules', 'action', 'action_display',
'is_active', 'user', 'user_display',
'date_created', 'date_updated', 'reviewers_amount',
'comment', 'created_by'
'priority', 'rules', 'action', 'action_display', 'is_active', 'user',
'date_created', 'date_updated', 'reviewers_amount', 'comment', 'created_by',
]
fields_fk = ['user', 'user_display']
fields_m2m = ['reviewers', 'reviewers_display']
fields_fk = ['user']
fields_m2m = ['reviewers']
fields = fields_small + fields_fk + fields_m2m
extra_kwargs = {
'priority': {'default': 50},

View File

@ -111,8 +111,8 @@ class AutomationExecutionViewSet(
serializer.is_valid(raise_exception=True)
automation = serializer.validated_data.get('automation')
tp = serializer.validated_data.get('type')
model = AutomationTypes.get_model(tp)
model = AutomationTypes.get_type_model(tp)
task = execute_automation.delay(
pid=automation.ok, trigger=Trigger.manual, model=model
pid=automation.pk, trigger=Trigger.manual, model=model
)
return Response({'task': task.id}, status=status.HTTP_201_CREATED)

View File

@ -24,8 +24,8 @@ class ChangeSecretAutomationViewSet(OrgBulkModelViewSet):
class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet):
serializer_class = serializers.ChangeSecretRecordSerializer
filter_fields = ['username', 'asset', 'reason', 'execution']
search_fields = ['username', 'reason', 'asset__hostname']
filter_fields = ['asset', 'execution_id']
search_fields = ['asset__hostname']
def get_queryset(self):
return ChangeSecretRecord.objects.all()
@ -36,5 +36,5 @@ class ChangeSecretRecordViewSet(mixins.ListModelMixin, OrgGenericViewSet):
execution = get_object_or_none(AutomationExecution, pk=eid)
if execution:
queryset = queryset.filter(execution=execution)
queryset = queryset.order_by('is_success', '-date_start')
queryset = queryset.order_by('-date_start')
return queryset

View File

@ -232,5 +232,6 @@ class BasePlaybookManager:
except Exception as e:
self.on_runner_failed(runner, e)
print('\n')
self.execution.status = 'success'
self.execution.date_finished = timezone.now()
self.execution.save()

View File

@ -15,12 +15,8 @@ from assets.const import AutomationTypes
class BaseAutomation(CommonModelMixin, PeriodTaskModelMixin, OrgModelMixin):
accounts = models.JSONField(default=list, verbose_name=_("Accounts"))
nodes = models.ManyToManyField(
'assets.Node', blank=True, verbose_name=_("Nodes")
)
assets = models.ManyToManyField(
'assets.Asset', blank=True, verbose_name=_("Assets")
)
nodes = models.ManyToManyField('assets.Node', blank=True, verbose_name=_("Nodes"))
assets = models.ManyToManyField('assets.Asset', blank=True, verbose_name=_("Assets"))
type = models.CharField(max_length=16, choices=AutomationTypes.choices, verbose_name=_('Type'))
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
@ -92,7 +88,7 @@ class AutomationExecution(OrgModelMixin):
'BaseAutomation', related_name='executions', on_delete=models.CASCADE,
verbose_name=_('Automation task')
)
status = models.CharField(max_length=16, default='pending')
status = models.CharField(max_length=16, default='pending', verbose_name=_('Status'))
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
date_start = models.DateTimeField(null=True, verbose_name=_('Date start'), db_index=True)
date_finished = models.DateTimeField(null=True, verbose_name=_("Date finished"))

View File

@ -13,3 +13,7 @@ class GatherAccountsAutomation(BaseAutomation):
class Meta:
verbose_name = _("Gather asset accounts")
@property
def executed_amount(self):
return self.executions.count()

View File

@ -58,7 +58,6 @@ class AccountSerializer(AccountSerializerCreateMixin, BaseAccountSerializer):
required=False, queryset=Asset.objects,
label=_('Asset'), attrs=('id', 'name', 'address', 'platform_id')
)
secret_type = LabeledChoiceField(choices=SecretType.choices, label=_('Secret type'))
class Meta(BaseAccountSerializer.Meta):
model = Account

View File

@ -6,6 +6,8 @@ from rest_framework import serializers
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from ops.mixin import PeriodTaskSerializerMixin
from common.utils import get_logger
from common.const.choices import Trigger
from common.drf.fields import LabeledChoiceField
from assets.models import AccountBackupPlan, AccountBackupPlanExecution
@ -32,17 +34,12 @@ class AccountBackupPlanSerializer(PeriodTaskSerializerMixin, BulkOrgResourceMode
class AccountBackupPlanExecutionSerializer(serializers.ModelSerializer):
trigger_display = serializers.ReadOnlyField(
source='get_trigger_display', label=_('Trigger mode')
)
trigger = LabeledChoiceField(choices=Trigger.choices, label=_('Trigger mode'))
class Meta:
model = AccountBackupPlanExecution
fields = [
'id', 'date_start', 'timedelta', 'plan_snapshot', 'trigger', 'reason',
'is_success', 'plan', 'org_id', 'recipients', 'trigger_display'
]
read_only_fields = (
read_only_fields = [
'id', 'date_start', 'timedelta', 'plan_snapshot', 'trigger', 'reason',
'is_success', 'org_id', 'recipients'
)
]
fields = read_only_fields + ['plan']

View File

@ -1,28 +1,19 @@
# -*- coding: utf-8 -*-
from io import StringIO
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from common.utils import validate_ssh_private_key, ssh_private_key_gen
from common.drf.fields import EncryptedField
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from assets.models import BaseAccount
from assets.serializers.base import AuthValidateMixin
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
__all__ = ['BaseAccountSerializer']
class BaseAccountSerializer(BulkOrgResourceModelSerializer):
secret = EncryptedField(
label=_('Secret'), required=False, allow_blank=True,
allow_null=True, max_length=40960
)
class BaseAccountSerializer(AuthValidateMixin, BulkOrgResourceModelSerializer):
class Meta:
model = BaseAccount
fields_mini = ['id', 'name', 'username']
fields_small = fields_mini + [
'secret_type', 'secret', 'has_secret',
'secret_type', 'secret', 'has_secret', 'passphrase',
'privileged', 'is_active', 'specific',
]
fields_other = ['created_by', 'date_created', 'date_updated', 'comment']
@ -32,29 +23,5 @@ class BaseAccountSerializer(BulkOrgResourceModelSerializer):
'date_verified', 'created_by', 'date_created',
]
extra_kwargs = {
'secret': {'write_only': True},
'passphrase': {'write_only': True},
'specific': {'label': _('Specific')},
}
def validate_private_key(self, private_key):
if not private_key:
return ''
passphrase = self.initial_data.get('passphrase')
passphrase = passphrase if passphrase else None
valid = validate_ssh_private_key(private_key, password=passphrase)
if not valid:
raise serializers.ValidationError(_("private key invalid or passphrase error"))
private_key = ssh_private_key_gen(private_key, password=passphrase)
string_io = StringIO()
private_key.write_private_key(string_io)
private_key = string_io.getvalue()
return private_key
def validate_secret(self, value):
secret_type = self.initial_data.get('secret_type')
if secret_type == 'ssh_key':
value = self.validate_private_key(value)
return value

View File

@ -3,9 +3,10 @@ from rest_framework import serializers
from ops.mixin import PeriodTaskSerializerMixin
from assets.const import AutomationTypes
from assets.models import Asset, BaseAutomation, AutomationExecution
from assets.models import Asset, Node, BaseAutomation, AutomationExecution
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from common.utils import get_logger
from common.drf.fields import ObjectRelatedField
logger = get_logger(__file__)
@ -16,6 +17,9 @@ __all__ = [
class BaseAutomationSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSerializer):
assets = ObjectRelatedField(many=True, required=False, queryset=Asset.objects, label=_('Assets'))
nodes = ObjectRelatedField(many=True, required=False, queryset=Node.objects, label=_('Nodes'))
class Meta:
read_only_fields = [
'date_created', 'date_updated', 'created_by', 'periodic_display'
@ -26,6 +30,7 @@ class BaseAutomationSerializer(PeriodTaskSerializerMixin, BulkOrgResourceModelSe
]
extra_kwargs = {
'name': {'required': True},
'type': {'read_only': True},
'periodic_display': {'label': _('Periodic perform')},
}
@ -37,10 +42,10 @@ class AutomationExecutionSerializer(serializers.ModelSerializer):
class Meta:
model = AutomationExecution
fields = [
'id', 'automation', 'trigger', 'trigger_display',
'date_start', 'date_finished', 'snapshot', 'type'
read_only_fields = [
'trigger_display', 'date_start', 'date_finished', 'snapshot', 'status'
]
fields = ['id', 'automation', 'trigger', 'type'] + read_only_fields
@staticmethod
def get_snapshot(obj):

View File

@ -3,10 +3,11 @@
from django.utils.translation import ugettext as _
from rest_framework import serializers
from assets.serializers.base import AuthValidateMixin
from assets.models import ChangeSecretAutomation, ChangeSecretRecord
from assets.const import DEFAULT_PASSWORD_RULES, SecretType, SecretStrategy
from common.utils import get_logger
from common.drf.fields import LabeledChoiceField, ObjectRelatedField
from assets.serializers.base import AuthValidateMixin
from assets.const import DEFAULT_PASSWORD_RULES, SecretType, SecretStrategy, SSHKeyStrategy
from assets.models import Asset, Account, ChangeSecretAutomation, ChangeSecretRecord, AutomationExecution
from .base import BaseAutomationSerializer
@ -20,19 +21,17 @@ __all__ = [
class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializer):
secret_strategy = LabeledChoiceField(
choices=SecretStrategy.choices, required=True, label=_('Secret strategy')
)
ssh_key_change_strategy = LabeledChoiceField(
choices=SSHKeyStrategy.choices, required=False, label=_('SSH Key strategy')
)
password_rules = serializers.DictField(default=DEFAULT_PASSWORD_RULES)
secret_strategy_display = serializers.ReadOnlyField(
source='get_secret_strategy_display', label=_('Secret strategy')
)
ssh_key_change_strategy_display = serializers.ReadOnlyField(
source='get_ssh_key_strategy_display', label=_('SSH Key strategy')
)
class Meta:
model = ChangeSecretAutomation
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields + [
'secret_strategy_display', 'ssh_key_change_strategy_display'
]
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields
fields = BaseAutomationSerializer.Meta.fields + read_only_fields + [
'secret_type', 'secret_strategy', 'secret', 'password_rules',
'ssh_key_change_strategy', 'passphrase', 'recipients',
@ -84,26 +83,21 @@ class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializ
class ChangeSecretRecordSerializer(serializers.ModelSerializer):
asset_display = serializers.SerializerMethodField(label=_('Asset display'))
account_display = serializers.SerializerMethodField(label=_('Account display'))
is_success = serializers.SerializerMethodField(label=_('Is success'))
asset = ObjectRelatedField(queryset=Asset.objects, label=_('Asset'))
account = ObjectRelatedField(queryset=Account.objects, label=_('Account'))
execution = ObjectRelatedField(
queryset=AutomationExecution.objects, label=_('Automation task execution')
)
class Meta:
model = ChangeSecretRecord
fields = [
'id', 'asset', 'account', 'date_started', 'date_finished',
'is_success', 'error', 'execution', 'asset_display', 'account_display'
'id', 'asset', 'account', 'date_started',
'date_finished', 'is_success', 'error', 'execution',
]
read_only_fields = fields
@staticmethod
def get_asset_display(instance):
return str(instance.asset)
@staticmethod
def get_account_display(instance):
return str(instance.account)
@staticmethod
def get_is_success(obj):
if obj.status == 'success':

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
from assets.models import GatherAccountsAutomation
from common.utils import get_logger
@ -15,6 +16,9 @@ __all__ = [
class GatherAccountAutomationSerializer(BaseAutomationSerializer):
class Meta:
model = GatherAccountsAutomation
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields + ['executed_amount']
fields = BaseAutomationSerializer.Meta.fields + read_only_fields
extra_kwargs = BaseAutomationSerializer.Meta.extra_kwargs
extra_kwargs = {**BaseAutomationSerializer.Meta.extra_kwargs, **{
'executed_amount': {'label': _('Executed amount')}
}}

View File

@ -3,15 +3,17 @@
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from common.drf.fields import EncryptedField
from assets.const import SecretType
from common.drf.fields import EncryptedField, LabeledChoiceField
from .utils import validate_password_for_ansible, validate_ssh_key
class AuthValidateMixin(serializers.Serializer):
secret_type = serializers.CharField(label=_('Secret type'), max_length=16, required=True)
secret_type = LabeledChoiceField(
choices=SecretType.choices, required=True, label=_('Secret type')
)
secret = EncryptedField(
label=_('Secret'), required=False, max_length=16384, allow_blank=True,
label=_('Secret'), required=False, max_length=40960, allow_blank=True,
allow_null=True, write_only=True,
)
passphrase = serializers.CharField(

View File

@ -1,13 +1,15 @@
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
from ..models import GatheredUser
from common.drf.fields import ObjectRelatedField
from ..models import GatheredUser, Asset
class GatheredUserSerializer(OrgResourceModelSerializerMixin):
asset = ObjectRelatedField(queryset=Asset.objects, label=_('Asset'))
class Meta:
model = GatheredUser
fields_mini = ['id']

View File

@ -8,6 +8,7 @@ from rest_framework.response import Response
from common.drf.api import JMSModelViewSet
from common.permissions import IsServiceAccount
from common.utils import is_uuid
from orgs.utils import tmp_to_builtin_org
from rbac.permissions import RBACPermission
from terminal.models import AppletHost
@ -63,6 +64,13 @@ class AppletHostAppletViewSet(HostMixin, JMSModelViewSet):
host: AppletHost
serializer_class = AppletPublicationSerializer
def get_object(self):
pk = self.kwargs.get('pk')
if not is_uuid(pk):
return self.host.publications.get(applet__name=pk)
else:
return self.host.publications.get(pk=pk)
def get_queryset(self):
queryset = self.host.publications.all()
return queryset

View File

@ -5,21 +5,24 @@ from rest_framework import serializers
from orgs.models import Organization
from orgs.utils import get_current_org_id
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
from common.drf.fields import LabeledChoiceField
from tickets.models import TicketFlow, ApprovalRule
from tickets.const import TicketApprovalStrategy
from tickets.const import TicketApprovalStrategy, TicketType
__all__ = ['TicketFlowSerializer']
class TicketFlowApproveSerializer(serializers.ModelSerializer):
strategy_display = serializers.ReadOnlyField(source='get_strategy_display', label=_('Approve strategy'))
strategy = LabeledChoiceField(
choices=TicketApprovalStrategy.choices, required=True, label=_('Approve strategy')
)
assignees_read_only = serializers.SerializerMethodField(label=_('Assignees'))
assignees_display = serializers.SerializerMethodField(label=_('Assignees display'))
class Meta:
model = ApprovalRule
fields_small = [
'level', 'strategy', 'assignees_read_only', 'assignees_display', 'strategy_display'
'level', 'strategy', 'assignees_read_only', 'assignees_display',
]
fields_m2m = ['assignees', ]
fields = fields_small + fields_m2m
@ -46,14 +49,16 @@ class TicketFlowApproveSerializer(serializers.ModelSerializer):
class TicketFlowSerializer(OrgResourceModelSerializerMixin):
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display'))
type = LabeledChoiceField(
choices=TicketType.choices, required=True, label=_('Type')
)
rules = TicketFlowApproveSerializer(many=True, required=True)
class Meta:
model = TicketFlow
fields_mini = ['id', ]
fields_small = fields_mini + [
'type', 'type_display', 'approval_level', 'created_by', 'date_created', 'date_updated',
'type', 'approval_level', 'created_by', 'date_created', 'date_updated',
'org_id', 'org_name'
]
fields = fields_small + ['rules', ]