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

pull/8931/head
ibuler 2022-09-22 15:25:12 +08:00
commit 68ed3ac1a8
18 changed files with 75 additions and 181 deletions

View File

@ -90,7 +90,7 @@ class LoginAssetACL(BaseACL, OrgModelMixin):
'applicant': user,
'apply_login_user': user,
'apply_login_asset': asset,
'apply_login_account': account,
'apply_login_account': str(account),
'org_id': org_id,
}
ticket = ApplyLoginAssetTicket.objects.create(**data)

View File

@ -2,8 +2,7 @@ from rest_framework import serializers
from orgs.utils import tmp_to_root_org
from common.utils import get_object_or_none, lazyproperty
from users.models import User
from assets.models import Asset
from assets.models import Asset, Account
__all__ = ['LoginAssetCheckSerializer']
@ -18,7 +17,7 @@ class LoginAssetCheckSerializer(serializers.Serializer):
super().__init__(*args, **kwargs)
self.user = None
self.asset = None
self._account = None
self.account = None
self._account_username = None
def validate_user_id(self, user_id):
@ -29,6 +28,10 @@ class LoginAssetCheckSerializer(serializers.Serializer):
self.asset = self.validate_object_exist(Asset, asset_id)
return asset_id
def validate_account_id(self, account_id):
self.account = self.validate_object_exist(Account, account_id)
return account_id
@staticmethod
def validate_object_exist(model, field_id):
with tmp_to_root_org():

View File

@ -16,5 +16,5 @@ class GatheredUserViewSet(OrgModelViewSet):
serializer_class = GatheredUserSerializer
extra_filter_backends = [AssetRelatedByNodeFilterBackend]
filterset_fields = ['asset', 'username', 'present', 'asset__ip', 'asset__name', 'asset_id']
search_fields = ['username', 'asset__ip', 'asset__name']
filterset_fields = ['asset', 'username', 'present', 'asset__address', 'asset__name', 'asset_id']
search_fields = ['username', 'asset__address', 'asset__name']

View File

@ -98,7 +98,7 @@ class Asset(AbsConnectivity, NodesRelationMixin, JMSOrgBaseModel):
objects = AssetManager.from_queryset(AssetQuerySet)()
def __str__(self):
return '{0.name}({0.ip})'.format(self)
return '{0.name}({0.address})'.format(self)
def get_target_ip(self):
return self.address

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
import uuid
import re
import uuid
from django.db import models
from django.db.models import Q
@ -9,10 +9,9 @@ from django.core.validators import MinValueValidator, MaxValueValidator
from django.utils.translation import ugettext_lazy as _
from users.models import User, UserGroup
from ..models import Asset
from common.utils import lazyproperty, get_logger, get_object_or_none
from orgs.mixins.models import OrgModelMixin
from common.utils import lazyproperty, get_logger, get_object_or_none
from ..models import Asset, Account
logger = get_logger(__file__)
@ -167,7 +166,7 @@ class CommandFilterRule(OrgModelMixin):
'applicant': session.user_obj,
'apply_run_user_id': session.user_id,
'apply_run_asset': str(session.asset),
'apply_run_system_user_id': session.system_user_id,
'apply_run_account': str(session.account),
'apply_run_command': run_command[:4090],
'apply_from_session_id': str(session.id),
'apply_from_cmd_filter_rule_id': str(cmd_filter_rule.id),
@ -180,9 +179,10 @@ class CommandFilterRule(OrgModelMixin):
return ticket
@classmethod
def get_queryset(cls, user_id=None, user_group_id=None, system_user_id=None,
asset_id=None, application_id=None, org_id=None):
from applications.models import Application
def get_queryset(
cls, user_id=None, user_group_id=None, system_user_id=None,
asset_id=None, org_id=None
):
user_groups = []
user = get_object_or_none(User, pk=user_id)
if user:
@ -191,23 +191,19 @@ class CommandFilterRule(OrgModelMixin):
if user_group:
org_id = user_group.org_id
user_groups.append(user_group)
system_user = get_object_or_none(SystemUser, pk=system_user_id)
account = get_object_or_none(Account, pk=system_user_id)
asset = get_object_or_none(Asset, pk=asset_id)
application = get_object_or_none(Application, pk=application_id)
q = Q()
if user:
q |= Q(users=user)
if user_groups:
q |= Q(user_groups__in=set(user_groups))
if system_user:
org_id = system_user.org_id
q |= Q(system_users=system_user)
if account:
org_id = account.org_id
q |= Q(accounts=account)
if asset:
org_id = asset.org_id
q |= Q(assets=asset)
if application:
org_id = application.org_id
q |= Q(applications=application)
if q:
cmd_filters = CommandFilter.objects.filter(q).filter(is_active=True)
if org_id:

View File

@ -144,7 +144,7 @@ class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet)
queryset = queryset.annotate(
asset_display=Concat(
F('asset__name'), Value('('),
F('asset__ip'), Value(')')
F('asset__address'), Value(')')
)
)
return queryset

View File

@ -49,7 +49,7 @@ class CommandExecutionFilter(BaseFilterSet):
queryset = queryset.annotate(
hostname_ip=Concat(
F('asset__hostname'), Value('('),
F('asset__ip'), Value(')')
F('asset__address'), Value(')')
)
).filter(hostname_ip__icontains=value)
return queryset

View File

@ -78,7 +78,7 @@ class AssetPermissionAssetRelationViewSet(RelationMixin):
filterset_fields = [
'id', 'asset', 'assetpermission',
]
search_fields = ["id", "asset__name", "asset__ip", "assetpermission__name"]
search_fields = ["id", "asset__name", "asset__address", "assetpermission__name"]
def get_queryset(self):
queryset = super().get_queryset()

View File

@ -8,7 +8,6 @@ class TicketType(TextChoices):
general = 'general', _("General")
login_confirm = 'login_confirm', _("Login confirm")
apply_asset = 'apply_asset', _('Apply for asset')
apply_application = 'apply_application', _('Apply for application')
login_asset_confirm = 'login_asset_confirm', _('Login asset confirm')
command_confirm = 'command_confirm', _('Command confirm')

View File

@ -1,67 +0,0 @@
from django.utils.translation import ugettext as _
from orgs.utils import tmp_to_org
from perms.models import ApplicationPermission
from tickets.models import ApplyApplicationTicket
from .base import BaseHandler
class Handler(BaseHandler):
ticket: ApplyApplicationTicket
def _on_step_approved(self, step):
is_finished = super()._on_step_approved(step)
if is_finished:
self._create_application_permission()
# permission
def _create_application_permission(self):
org_id = self.ticket.org_id
with tmp_to_org(org_id):
application_permission = ApplicationPermission.objects.filter(id=self.ticket.id).first()
if application_permission:
return application_permission
apply_applications = self.ticket.apply_applications.all()
apply_system_users = self.ticket.apply_system_users.all()
apply_permission_name = self.ticket.apply_permission_name
apply_actions = self.ticket.apply_actions
apply_category = self.ticket.apply_category
apply_type = self.ticket.apply_type
apply_date_start = self.ticket.apply_date_start
apply_date_expired = self.ticket.apply_date_expired
permission_created_by = '{}:{}'.format(
str(self.ticket.__class__.__name__), str(self.ticket.id)
)
permission_comment = _(
'Created by the ticket, '
'ticket title: {}, '
'ticket applicant: {}, '
'ticket processor: {}, '
'ticket ID: {}'
).format(
self.ticket.title,
self.ticket.applicant,
','.join([i['processor_display'] for i in self.ticket.process_map]),
str(self.ticket.id)
)
permissions_data = {
'id': self.ticket.id,
'name': apply_permission_name,
'from_ticket': True,
'category': apply_category,
'actions': apply_actions,
'type': apply_type,
'comment': str(permission_comment),
'created_by': permission_created_by,
'date_start': apply_date_start,
'date_expired': apply_date_expired,
}
with tmp_to_org(self.ticket.org_id):
application_permission = ApplicationPermission.objects.create(**permissions_data)
application_permission.users.add(self.ticket.applicant)
application_permission.applications.set(apply_applications)
application_permission.system_users.set(apply_system_users)
return application_permission

View File

@ -1,7 +1,7 @@
from django.utils.translation import ugettext as _
from perms.models import AssetPermission
from orgs.utils import tmp_to_org, tmp_to_root_org
from orgs.utils import tmp_to_org
from tickets.models import ApplyAssetTicket
from .base import BaseHandler
@ -24,7 +24,6 @@ class Handler(BaseHandler):
apply_nodes = self.ticket.apply_nodes.all()
apply_assets = self.ticket.apply_assets.all()
apply_system_users = self.ticket.apply_system_users.all()
apply_permission_name = self.ticket.apply_permission_name
apply_actions = self.ticket.apply_actions
@ -61,6 +60,5 @@ class Handler(BaseHandler):
asset_permission.users.add(self.ticket.applicant)
asset_permission.nodes.set(apply_nodes)
asset_permission.assets.set(apply_assets)
asset_permission.system_users.set(apply_system_users)
return asset_permission

View File

@ -65,7 +65,7 @@ class BaseHandler:
if state != TicketState.approved:
return diff_context
if self.ticket.type not in [TicketType.apply_asset, TicketType.apply_application]:
if self.ticket.type == TicketType.apply_asset:
return diff_context
# 企业微信钉钉审批不做diff

View File

@ -0,0 +1,34 @@
# Generated by Django 3.2.13 on 2022-09-21 10:14
from django.db import migrations, models
def migrate_remove_application_flow(apps, schema_editor):
flow_model = apps.get_model('tickets', 'TicketFlow')
flow_model.objects.filter(type='apply_application').delete()
class Migration(migrations.Migration):
dependencies = [
('tickets', '0020_auto_20220817_1346'),
]
operations = [
migrations.AlterField(
model_name='ticket',
name='type',
field=models.CharField(
choices=[('general', 'General'), ('login_confirm', 'Login confirm'), ('apply_asset', 'Apply for asset'),
('login_asset_confirm', 'Login asset confirm'), ('command_confirm', 'Command confirm')],
default='general', max_length=64, verbose_name='Type'),
),
migrations.AlterField(
model_name='ticketflow',
name='type',
field=models.CharField(
choices=[('general', 'General'), ('login_confirm', 'Login confirm'), ('apply_asset', 'Apply for asset'),
('login_asset_confirm', 'Login asset confirm'), ('command_confirm', 'Command confirm')],
default='general', max_length=64, verbose_name='Type'),
),
migrations.RunPython(migrate_remove_application_flow),
]

View File

@ -1,65 +0,0 @@
from django.utils.translation import ugettext as _
from rest_framework import serializers
from perms.models import ApplicationPermission
from perms.serializers.permission import ActionsField
from orgs.utils import tmp_to_org
from applications.models import Application
from tickets.models import ApplyApplicationTicket
from .ticket import TicketApplySerializer
from .common import BaseApplyAssetApplicationSerializer
__all__ = ['ApplyApplicationSerializer', 'ApplyApplicationDisplaySerializer', 'ApproveApplicationSerializer']
class ApplyApplicationSerializer(BaseApplyAssetApplicationSerializer, TicketApplySerializer):
apply_actions = ActionsField(required=True, allow_empty=False)
permission_model = ApplicationPermission
class Meta:
model = ApplyApplicationTicket
writeable_fields = [
'id', 'title', 'type', 'apply_category',
'apply_type', 'apply_applications', 'apply_system_users',
'apply_actions', 'apply_date_start', 'apply_date_expired', 'org_id'
]
fields = TicketApplySerializer.Meta.fields + \
writeable_fields + ['apply_permission_name', 'apply_actions_display']
read_only_fields = list(set(fields) - set(writeable_fields))
ticket_extra_kwargs = TicketApplySerializer.Meta.extra_kwargs
extra_kwargs = {
'apply_applications': {'required': False, 'allow_empty': True},
'apply_system_users': {'required': False, 'allow_empty': True},
}
extra_kwargs.update(ticket_extra_kwargs)
def validate_apply_applications(self, applications):
if self.is_final_approval and not applications:
raise serializers.ValidationError(_('This field is required.'))
tp = self.initial_data.get('apply_type')
return self.filter_many_to_many_field(Application, applications, type=tp)
class ApproveApplicationSerializer(ApplyApplicationSerializer):
class Meta(ApplyApplicationSerializer.Meta):
read_only_fields = ApplyApplicationSerializer.Meta.read_only_fields + ['title', 'type']
class ApplyApplicationDisplaySerializer(ApplyApplicationSerializer):
apply_applications = serializers.SerializerMethodField()
apply_system_users = serializers.SerializerMethodField()
class Meta:
model = ApplyApplicationSerializer.Meta.model
fields = ApplyApplicationSerializer.Meta.fields
read_only_fields = fields
@staticmethod
def get_apply_applications(instance):
with tmp_to_org(instance.org_id):
return instance.apply_applications.values_list('id', flat=True)
@staticmethod
def get_apply_system_users(instance):
with tmp_to_org(instance.org_id):
return instance.apply_system_users.values_list('id', flat=True)

View File

@ -23,17 +23,18 @@ class ApplyAssetSerializer(BaseApplyAssetApplicationSerializer, TicketApplySeria
model = ApplyAssetTicket
writeable_fields = [
'id', 'title', 'type', 'apply_nodes', 'apply_assets',
'apply_system_users', 'apply_actions',
'apply_date_start', 'apply_date_expired', 'org_id'
'apply_accounts', 'apply_actions', 'org_id',
'apply_date_start', 'apply_date_expired'
]
fields = TicketApplySerializer.Meta.fields + writeable_fields + [
'apply_permission_name', 'apply_actions_display'
]
fields = TicketApplySerializer.Meta.fields + \
writeable_fields + ['apply_permission_name', 'apply_actions_display']
read_only_fields = list(set(fields) - set(writeable_fields))
ticket_extra_kwargs = TicketApplySerializer.Meta.extra_kwargs
extra_kwargs = {
'apply_nodes': {'required': False, 'allow_empty': True},
'apply_assets': {'required': False, 'allow_empty': True},
'apply_system_users': {'required': False, 'allow_empty': True},
'apply_accounts': {'required': False, 'allow_empty': True},
}
extra_kwargs.update(ticket_extra_kwargs)
@ -58,13 +59,14 @@ class ApplyAssetSerializer(BaseApplyAssetApplicationSerializer, TicketApplySeria
class ApproveAssetSerializer(ApplyAssetSerializer):
class Meta(ApplyAssetSerializer.Meta):
read_only_fields = ApplyAssetSerializer.Meta.read_only_fields + ['title', 'type']
read_only_fields = ApplyAssetSerializer.Meta.read_only_fields + [
'title', 'type'
]
class ApplyAssetDisplaySerializer(ApplyAssetSerializer):
apply_nodes = serializers.SerializerMethodField()
apply_assets = serializers.SerializerMethodField()
apply_system_users = serializers.SerializerMethodField()
class Meta:
model = ApplyAssetSerializer.Meta.model
@ -80,8 +82,3 @@ class ApplyAssetDisplaySerializer(ApplyAssetSerializer):
def get_apply_assets(instance):
with tmp_to_org(instance.org_id):
return instance.apply_assets.values_list('id', flat=True)
@staticmethod
def get_apply_system_users(instance):
with tmp_to_org(instance.org_id):
return instance.apply_system_users.values_list('id', flat=True)

View File

@ -10,7 +10,7 @@ class ApplyCommandConfirmSerializer(TicketApplySerializer):
class Meta:
model = ApplyCommandTicket
fields = TicketApplySerializer.Meta.fields + [
'apply_run_user', 'apply_run_asset', 'apply_run_system_user',
'apply_run_user', 'apply_run_asset', 'apply_run_account',
'apply_run_command', 'apply_from_session', 'apply_from_cmd_filter',
'apply_from_cmd_filter_rule'
]

View File

@ -53,17 +53,16 @@ class BaseApplyAssetApplicationSerializer(serializers.Serializer):
qs = model.objects.filter(id__in=ids, **kwargs).values_list('id', flat=True)
return list(qs)
def validate_apply_account(self, system_users):
if self.is_final_approval and not system_users:
def validate_apply_accounts(self, accounts):
if self.is_final_approval and not accounts:
raise serializers.ValidationError(_('This field is required.'))
return self.filter_many_to_many_field(SystemUser, system_users)
return accounts
def validate(self, attrs):
attrs = super().validate(attrs)
apply_date_start = attrs['apply_date_start'].strftime('%Y-%m-%d %H:%M:%S')
apply_date_expired = attrs['apply_date_expired'].strftime('%Y-%m-%d %H:%M:%S')
if apply_date_expired <= apply_date_start:
error = _('The expiration date should be greater than the start date')
raise serializers.ValidationError({'apply_date_expired': error})

View File

@ -10,5 +10,5 @@ class LoginAssetConfirmSerializer(TicketApplySerializer):
class Meta:
model = ApplyLoginAssetTicket
fields = TicketApplySerializer.Meta.fields + [
'apply_login_user', 'apply_login_asset', 'apply_login_system_user'
'apply_login_user', 'apply_login_asset', 'apply_login_account'
]