mirror of https://github.com/jumpserver/jumpserver
perf: 修改系统用户
parent
fb0fb71ea3
commit
0dc3d43ee5
|
@ -9,7 +9,7 @@ from orgs.mixins.models import OrgModelMixin
|
|||
from common.mixins import CommonModelMixin
|
||||
from common.tree import TreeNode
|
||||
from common.utils import is_uuid
|
||||
from assets.models import Asset, SystemUser
|
||||
from assets.models import Asset
|
||||
|
||||
from ..utils import KubernetesTree
|
||||
from .. import const
|
||||
|
|
|
@ -1,176 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from common.utils import get_logger, get_object_or_none
|
||||
from common.mixins.api import SuggestionMixin
|
||||
from orgs.mixins.api import OrgBulkModelViewSet
|
||||
from orgs.mixins import generics
|
||||
from ..models import SystemUser, CommandFilterRule, Account
|
||||
from .. import serializers
|
||||
|
||||
logger = get_logger(__file__)
|
||||
__all__ = [
|
||||
'SystemUserViewSet', 'SystemUserAuthInfoApi',
|
||||
'SystemUserCommandFilterRuleListApi',
|
||||
'SystemUserAssetAccountApi',
|
||||
'SystemUserAssetAccountSecretApi',
|
||||
]
|
||||
|
||||
|
||||
class SystemUserViewSet(SuggestionMixin, OrgBulkModelViewSet):
|
||||
"""
|
||||
System user api set, for add,delete,update,list,retrieve resource
|
||||
"""
|
||||
model = SystemUser
|
||||
filterset_fields = {
|
||||
'name': ['exact'],
|
||||
'username': ['exact'],
|
||||
'protocol': ['exact', 'in'],
|
||||
}
|
||||
search_fields = filterset_fields
|
||||
serializer_class = serializers.SystemUserSerializer
|
||||
serializer_classes = {
|
||||
'default': serializers.SystemUserSerializer,
|
||||
'suggestion': serializers.MiniSystemUserSerializer
|
||||
}
|
||||
ordering_fields = ('name', 'protocol', 'login_mode')
|
||||
ordering = ('name', )
|
||||
rbac_perms = {
|
||||
'su_from': 'assets.view_systemuser',
|
||||
'su_to': 'assets.view_systemuser',
|
||||
'match': 'assets.match_systemuser'
|
||||
}
|
||||
|
||||
@action(methods=['get'], detail=False, url_path='su-from')
|
||||
def su_from(self, request, *args, **kwargs):
|
||||
""" API 获取可选的 su_from 系统用户"""
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
queryset = queryset.filter(
|
||||
protocol=SystemUser.Protocol.ssh, login_mode=SystemUser.LOGIN_AUTO
|
||||
)
|
||||
return self.get_paginate_response_if_need(queryset)
|
||||
|
||||
@action(methods=['get'], detail=True, url_path='su-to')
|
||||
def su_to(self, request, *args, **kwargs):
|
||||
""" 获取系统用户的所有 su_to 系统用户 """
|
||||
pk = kwargs.get('pk')
|
||||
system_user = get_object_or_404(SystemUser, pk=pk)
|
||||
queryset = system_user.su_to.all()
|
||||
queryset = self.filter_queryset(queryset)
|
||||
return self.get_paginate_response_if_need(queryset)
|
||||
|
||||
def get_paginate_response_if_need(self, queryset):
|
||||
page = self.paginate_queryset(queryset)
|
||||
if page is not None:
|
||||
serializer = self.get_serializer(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class SystemUserAccountViewSet(GenericViewSet):
|
||||
model = Account
|
||||
serializer_classes = {
|
||||
'default': serializers.AccountSerializer,
|
||||
'account_secret': serializers.AccountSecretSerializer,
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
system_user_id = self.kwargs.get('pk')
|
||||
asset_id = self.kwargs.get('asset_id')
|
||||
user_id = self.kwargs.get("user_id")
|
||||
system_user = SystemUser.objects.get(id=system_user_id)
|
||||
account = system_user.get_account(user_id, asset_id)
|
||||
return account
|
||||
|
||||
@action(methods=['get'], detail=False, url_path='account')
|
||||
def account(self, request, *args, **kwargs):
|
||||
pass
|
||||
|
||||
@action(methods=['get'], detail=False, url_path='account-secret')
|
||||
def account_secret(self):
|
||||
pass
|
||||
|
||||
@action(methods=['put'], detail=False, url_path='manual-account')
|
||||
def manual_account(self, request, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class SystemUserAssetAccountApi(generics.RetrieveAPIView):
|
||||
model = Account
|
||||
serializer_class = serializers.AccountSerializer
|
||||
|
||||
def get_object(self):
|
||||
system_user_id = self.kwargs.get('pk')
|
||||
asset_id = self.kwargs.get('asset_id')
|
||||
user_id = self.kwargs.get("user_id")
|
||||
system_user = SystemUser.objects.get(id=system_user_id)
|
||||
account = system_user.get_account(user_id, asset_id)
|
||||
return account
|
||||
|
||||
|
||||
class SystemUserAssetAccountSecretApi(SystemUserAssetAccountApi):
|
||||
model = Account
|
||||
serializer_class = serializers.AccountSecretSerializer
|
||||
rbac_perms = {
|
||||
'retrieve': 'assets.view_accountsecret'
|
||||
}
|
||||
|
||||
|
||||
class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""
|
||||
Get system user auth info
|
||||
"""
|
||||
model = SystemUser
|
||||
serializer_class = serializers.AccountSerializer
|
||||
rbac_perms = {
|
||||
'retrieve': 'assets.view_systemusersecret',
|
||||
'list': 'assets.view_systemusersecret',
|
||||
'change': 'assets.change_systemuser',
|
||||
'destroy': 'assets.change_systemuser',
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
system_user_id = self.kwargs.get('pk')
|
||||
asset_id = self.kwargs.get('asset_id')
|
||||
user_id = self.kwargs.get("user_id")
|
||||
system_user = SystemUser.objects.get(id=system_user_id)
|
||||
account = system_user.get_account(user_id, asset_id)
|
||||
return account
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
instance.clear_auth()
|
||||
return Response(status=204)
|
||||
|
||||
|
||||
class SystemUserCommandFilterRuleListApi(generics.ListAPIView):
|
||||
rbac_perms = {
|
||||
'list': 'assets.view_commandfilterule'
|
||||
}
|
||||
|
||||
def get_serializer_class(self):
|
||||
from ..serializers import CommandFilterRuleSerializer
|
||||
return CommandFilterRuleSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user_id = self.request.query_params.get('user_id')
|
||||
user_group_id = self.request.query_params.get('user_group_id')
|
||||
system_user_id = self.kwargs.get('pk', None)
|
||||
system_user = get_object_or_none(SystemUser, pk=system_user_id)
|
||||
if not system_user:
|
||||
system_user_id = self.request.query_params.get('system_user_id')
|
||||
asset_id = self.request.query_params.get('asset_id')
|
||||
application_id = self.request.query_params.get('application_id')
|
||||
rules = CommandFilterRule.get_queryset(
|
||||
user_id=user_id,
|
||||
user_group_id=user_group_id,
|
||||
system_user_id=system_user_id,
|
||||
asset_id=asset_id,
|
||||
application_id=application_id
|
||||
)
|
||||
return rules
|
||||
|
|
@ -1,15 +1,12 @@
|
|||
from .base import *
|
||||
from .asset import *
|
||||
from .label import Label
|
||||
from .user import *
|
||||
from .group import *
|
||||
from .domain import *
|
||||
from .node import *
|
||||
from .cmd_filter import *
|
||||
from .authbook import *
|
||||
from .utils import *
|
||||
from .authbook import *
|
||||
from .gathered_user import *
|
||||
from .favorite_asset import *
|
||||
from .account import *
|
||||
from .backup import *
|
||||
from .user import *
|
||||
|
|
|
@ -2,7 +2,7 @@ from django.db import models
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
from .user import ProtocolMixin
|
||||
from .protocol import ProtocolMixin
|
||||
from .base import BaseUser, AbsConnectivity
|
||||
|
||||
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import F
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
from common.utils import lazyproperty, get_logger
|
||||
from .base import BaseUser, AbsConnectivity
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
__all__ = ['AuthBook']
|
||||
|
||||
|
||||
class AuthBook(BaseUser, AbsConnectivity):
|
||||
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset'))
|
||||
systemuser = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user"))
|
||||
version = models.IntegerField(default=1, verbose_name=_('Version'))
|
||||
history = HistoricalRecords()
|
||||
|
||||
auth_attrs = ['username', 'password', 'private_key', 'public_key']
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('AuthBook')
|
||||
unique_together = [('username', 'asset', 'systemuser')]
|
||||
permissions = [
|
||||
('test_authbook', _('Can test asset account connectivity')),
|
||||
('view_assetaccountsecret', _('Can view asset account secret')),
|
||||
('change_assetaccountsecret', _('Can change asset account secret')),
|
||||
('view_assethistoryaccount', _('Can view asset history account')),
|
||||
('view_assethistoryaccountsecret', _('Can view asset history account secret')),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.auth_snapshot = {}
|
||||
|
||||
def get_or_systemuser_attr(self, attr):
|
||||
val = getattr(self, attr, None)
|
||||
if val:
|
||||
return val
|
||||
if self.systemuser:
|
||||
return getattr(self.systemuser, attr, '')
|
||||
return ''
|
||||
|
||||
def load_auth(self):
|
||||
for attr in self.auth_attrs:
|
||||
value = self.get_or_systemuser_attr(attr)
|
||||
self.auth_snapshot[attr] = [getattr(self, attr), value]
|
||||
setattr(self, attr, value)
|
||||
|
||||
def unload_auth(self):
|
||||
if not self.systemuser:
|
||||
return
|
||||
|
||||
for attr, values in self.auth_snapshot.items():
|
||||
origin_value, loaded_value = values
|
||||
current_value = getattr(self, attr, '')
|
||||
if current_value == loaded_value:
|
||||
setattr(self, attr, origin_value)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.unload_auth()
|
||||
instance = super().save(*args, **kwargs)
|
||||
self.load_auth()
|
||||
return instance
|
||||
|
||||
@property
|
||||
def username_display(self):
|
||||
return self.get_or_systemuser_attr('username') or '*'
|
||||
|
||||
@lazyproperty
|
||||
def systemuser_display(self):
|
||||
if not self.systemuser:
|
||||
return ''
|
||||
return str(self.systemuser)
|
||||
|
||||
@property
|
||||
def smart_name(self):
|
||||
username = self.username_display
|
||||
|
||||
if self.asset:
|
||||
asset = str(self.asset)
|
||||
else:
|
||||
asset = '*'
|
||||
return '{}@{}'.format(username, asset)
|
||||
|
||||
def sync_to_system_user_account(self):
|
||||
if self.systemuser:
|
||||
return
|
||||
matched = AuthBook.objects.filter(
|
||||
asset=self.asset, systemuser__username=self.username
|
||||
)
|
||||
if not matched:
|
||||
return
|
||||
|
||||
for i in matched:
|
||||
i.password = self.password
|
||||
i.private_key = self.private_key
|
||||
i.public_key = self.public_key
|
||||
i.comment = 'Update triggered by account {}'.format(self.id)
|
||||
|
||||
# 不触发post_save信号
|
||||
self.__class__.objects.bulk_update(matched, fields=['password', 'private_key', 'public_key'])
|
||||
|
||||
def remove_asset_admin_user_if_need(self):
|
||||
if not self.asset or not self.systemuser:
|
||||
return
|
||||
if not self.systemuser.is_admin_user or self.asset.admin_user != self.systemuser:
|
||||
return
|
||||
self.asset.admin_user = None
|
||||
self.asset.save()
|
||||
logger.debug('Remove asset admin user: {} {}'.format(self.asset, self.systemuser))
|
||||
|
||||
def update_asset_admin_user_if_need(self):
|
||||
if not self.asset or not self.systemuser:
|
||||
return
|
||||
if not self.systemuser.is_admin_user or self.asset.admin_user == self.systemuser:
|
||||
return
|
||||
self.asset.admin_user = self.systemuser
|
||||
self.asset.save()
|
||||
logger.debug('Update asset admin user: {} {}'.format(self.asset, self.systemuser))
|
||||
|
||||
@classmethod
|
||||
def get_queryset(cls, is_history_model=False):
|
||||
model = cls.history.model if is_history_model else cls
|
||||
queryset = model.objects.all() \
|
||||
.annotate(ip=F('asset__ip')) \
|
||||
.annotate(hostname=F('asset__hostname')) \
|
||||
.annotate(platform=F('asset__platform__name')) \
|
||||
.annotate(protocols=F('asset__protocols'))
|
||||
return queryset
|
||||
|
||||
def __str__(self):
|
||||
return self.smart_name
|
||||
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
import uuid
|
||||
import re
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from users.models import User, UserGroup
|
||||
from applications.models import Application
|
||||
from ..models import SystemUser, Asset
|
||||
|
||||
from common.utils import lazyproperty, get_logger, get_object_or_none
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
__all__ = [
|
||||
'CommandFilter', 'CommandFilterRule'
|
||||
]
|
||||
|
||||
|
||||
class CommandFilter(OrgModelMixin):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=64, verbose_name=_("Name"))
|
||||
users = models.ManyToManyField(
|
||||
'users.User', related_name='cmd_filters', blank=True,
|
||||
verbose_name=_("User")
|
||||
)
|
||||
user_groups = models.ManyToManyField(
|
||||
'users.UserGroup', related_name='cmd_filters', blank=True,
|
||||
verbose_name=_("User group"),
|
||||
)
|
||||
assets = models.ManyToManyField(
|
||||
'assets.Asset', related_name='cmd_filters', blank=True,
|
||||
verbose_name=_("Asset")
|
||||
)
|
||||
system_users = models.ManyToManyField(
|
||||
'assets.SystemUser', related_name='cmd_filters', blank=True,
|
||||
verbose_name=_("System user"))
|
||||
applications = models.ManyToManyField(
|
||||
'applications.Application', related_name='cmd_filters', blank=True,
|
||||
verbose_name=_("Application")
|
||||
)
|
||||
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
|
||||
comment = models.TextField(blank=True, default='', verbose_name=_("Comment"))
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
date_updated = models.DateTimeField(auto_now=True)
|
||||
created_by = models.CharField(
|
||||
max_length=128, blank=True, default='', verbose_name=_('Created by')
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
unique_together = [('org_id', 'name')]
|
||||
verbose_name = _("Command filter")
|
||||
|
||||
|
||||
class CommandFilterRule(OrgModelMixin):
|
||||
TYPE_REGEX = 'regex'
|
||||
TYPE_COMMAND = 'command'
|
||||
TYPE_CHOICES = (
|
||||
(TYPE_REGEX, _('Regex')),
|
||||
(TYPE_COMMAND, _('Command')),
|
||||
)
|
||||
|
||||
ACTION_UNKNOWN = 10
|
||||
|
||||
class ActionChoices(models.IntegerChoices):
|
||||
deny = 0, _('Deny')
|
||||
allow = 9, _('Allow')
|
||||
confirm = 2, _('Reconfirm')
|
||||
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
filter = models.ForeignKey(
|
||||
'CommandFilter', on_delete=models.CASCADE, verbose_name=_("Filter"), related_name='rules'
|
||||
)
|
||||
type = models.CharField(max_length=16, default=TYPE_COMMAND, choices=TYPE_CHOICES, verbose_name=_("Type"))
|
||||
priority = models.IntegerField(
|
||||
default=50, verbose_name=_("Priority"), help_text=_("1-100, the lower the value will be match first"),
|
||||
validators=[MinValueValidator(1), MaxValueValidator(100)]
|
||||
)
|
||||
content = models.TextField(verbose_name=_("Content"), help_text=_("One line one command"))
|
||||
ignore_case = models.BooleanField(default=True, verbose_name=_('Ignore case'))
|
||||
action = models.IntegerField(default=ActionChoices.deny, choices=ActionChoices.choices, verbose_name=_("Action"))
|
||||
# 动作: 附加字段
|
||||
# - confirm: 命令复核人
|
||||
reviewers = models.ManyToManyField(
|
||||
'users.User', related_name='review_cmd_filter_rules', blank=True,
|
||||
verbose_name=_("Reviewers")
|
||||
)
|
||||
comment = models.CharField(max_length=64, blank=True, default='', verbose_name=_("Comment"))
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
date_updated = models.DateTimeField(auto_now=True)
|
||||
created_by = models.CharField(max_length=128, blank=True, default='', verbose_name=_('Created by'))
|
||||
|
||||
class Meta:
|
||||
ordering = ('priority', 'action')
|
||||
verbose_name = _("Command filter rule")
|
||||
|
||||
@lazyproperty
|
||||
def pattern(self):
|
||||
if self.type == 'command':
|
||||
s = self.construct_command_regex(content=self.content)
|
||||
else:
|
||||
s = r'{0}'.format(self.content)
|
||||
|
||||
return s
|
||||
|
||||
@classmethod
|
||||
def construct_command_regex(cls, content):
|
||||
regex = []
|
||||
content = content.replace('\r\n', '\n')
|
||||
for _cmd in content.split('\n'):
|
||||
cmd = re.sub(r'\s+', ' ', _cmd)
|
||||
cmd = re.escape(cmd)
|
||||
cmd = cmd.replace('\\ ', '\s+')
|
||||
|
||||
# 有空格就不能 铆钉单词了
|
||||
if ' ' in _cmd:
|
||||
regex.append(cmd)
|
||||
continue
|
||||
|
||||
# 如果是单个字符
|
||||
if cmd[-1].isalpha():
|
||||
regex.append(r'\b{0}\b'.format(cmd))
|
||||
else:
|
||||
regex.append(r'\b{0}'.format(cmd))
|
||||
s = r'{}'.format('|'.join(regex))
|
||||
return s
|
||||
|
||||
@staticmethod
|
||||
def compile_regex(regex, ignore_case):
|
||||
try:
|
||||
if ignore_case:
|
||||
pattern = re.compile(regex, re.IGNORECASE)
|
||||
else:
|
||||
pattern = re.compile(regex)
|
||||
except Exception as e:
|
||||
error = _('The generated regular expression is incorrect: {}').format(str(e))
|
||||
logger.error(error)
|
||||
return False, error, None
|
||||
return True, '', pattern
|
||||
|
||||
def match(self, data):
|
||||
succeed, error, pattern = self.compile_regex(self.pattern, self.ignore_case)
|
||||
if not succeed:
|
||||
return self.ACTION_UNKNOWN, ''
|
||||
|
||||
found = pattern.search(data)
|
||||
if not found:
|
||||
return self.ACTION_UNKNOWN, ''
|
||||
|
||||
if self.action == self.ActionChoices.allow:
|
||||
return self.ActionChoices.allow, found.group()
|
||||
else:
|
||||
return self.ActionChoices.deny, found.group()
|
||||
|
||||
def __str__(self):
|
||||
return '{} % {}'.format(self.type, self.content)
|
||||
|
||||
def create_command_confirm_ticket(self, run_command, session, cmd_filter_rule, org_id):
|
||||
from tickets.const import TicketType
|
||||
from tickets.models import ApplyCommandTicket
|
||||
data = {
|
||||
'title': _('Command confirm') + ' ({})'.format(session.user),
|
||||
'type': TicketType.command_confirm,
|
||||
'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_command': run_command[:4090],
|
||||
'apply_from_session_id': str(session.id),
|
||||
'apply_from_cmd_filter_rule_id': str(cmd_filter_rule.id),
|
||||
'apply_from_cmd_filter_id': str(cmd_filter_rule.filter.id),
|
||||
'org_id': org_id,
|
||||
}
|
||||
ticket = ApplyCommandTicket.objects.create(**data)
|
||||
assignees = self.reviewers.all()
|
||||
ticket.open_by_system(assignees)
|
||||
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):
|
||||
user_groups = []
|
||||
user = get_object_or_none(User, pk=user_id)
|
||||
if user:
|
||||
user_groups.extend(list(user.groups.all()))
|
||||
user_group = get_object_or_none(UserGroup, pk=user_group_id)
|
||||
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)
|
||||
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 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:
|
||||
cmd_filters = cmd_filters.filter(org_id=org_id)
|
||||
rule_ids = cmd_filters.values_list('rules', flat=True)
|
||||
rules = cls.objects.filter(id__in=rule_ids)
|
||||
else:
|
||||
rules = cls.objects.none()
|
||||
return rules
|
|
@ -40,23 +40,6 @@ class SystemUser(ProtocolMixin, BaseUser):
|
|||
username = '*'
|
||||
return '{0.name}({1})'.format(self, username)
|
||||
|
||||
@property
|
||||
def cmd_filter_rules(self):
|
||||
from .cmd_filter import CommandFilterRule
|
||||
rules = CommandFilterRule.objects.filter(
|
||||
filter__in=self.cmd_filters.all()
|
||||
).distinct()
|
||||
return rules
|
||||
|
||||
def is_command_can_run(self, command):
|
||||
for rule in self.cmd_filter_rules:
|
||||
action, matched_cmd = rule.match(command)
|
||||
if action == rule.ActionChoices.allow:
|
||||
return True, None
|
||||
elif action == rule.ActionChoices.deny:
|
||||
return False, matched_cmd
|
||||
return True, None
|
||||
|
||||
@classmethod
|
||||
def create_accounts_with_assets(cls, asset_ids, system_user_ids):
|
||||
pass
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from django.db.models.signals import (
|
||||
post_save, m2m_changed
|
||||
)
|
||||
from django.dispatch import receiver
|
||||
|
||||
from common.exceptions import M2MReverseNotAllowed
|
||||
from common.const.signals import POST_ADD
|
||||
from common.utils import get_logger
|
||||
from common.decorator import on_transaction_commit
|
||||
from assets.models import Asset, SystemUser, Node
|
||||
from users.models import User
|
||||
from assets.tasks import (
|
||||
push_system_user_to_assets_manual,
|
||||
push_system_user_to_assets,
|
||||
add_nodes_assets_to_system_users
|
||||
)
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=SystemUser.assets.through)
|
||||
@on_transaction_commit
|
||||
def on_system_user_assets_change(instance, action, model, pk_set, **kwargs):
|
||||
"""
|
||||
当系统用户和资产关系发生变化时,应该重新推送系统用户到新添加的资产中
|
||||
"""
|
||||
logger.debug("System user assets change signal recv: {}".format(instance))
|
||||
|
||||
if not instance:
|
||||
logger.debug('No system user found')
|
||||
return
|
||||
|
||||
if action != POST_ADD:
|
||||
return
|
||||
|
||||
if model == Asset:
|
||||
system_user_ids = [instance.id]
|
||||
asset_ids = pk_set
|
||||
else:
|
||||
system_user_ids = pk_set
|
||||
asset_ids = [instance.id]
|
||||
# todo: Auto create account if need
|
||||
SystemUser.create_accounts_with_assets(asset_ids, system_user_ids)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=SystemUser.users.through)
|
||||
@on_transaction_commit
|
||||
def on_system_user_users_change(sender, instance: SystemUser, action, model, pk_set, reverse, **kwargs):
|
||||
"""
|
||||
当系统用户和用户关系发生变化时,应该重新推送系统用户资产中
|
||||
"""
|
||||
if action != POST_ADD:
|
||||
return
|
||||
|
||||
if reverse:
|
||||
raise M2MReverseNotAllowed
|
||||
|
||||
if not instance.username_same_with_user:
|
||||
return
|
||||
|
||||
logger.debug("System user users change signal recv: {}".format(instance))
|
||||
usernames = model.objects.filter(pk__in=pk_set).values_list('username', flat=True)
|
||||
|
||||
for username in usernames:
|
||||
push_system_user_to_assets_manual.delay(instance, username)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=SystemUser.nodes.through)
|
||||
@on_transaction_commit
|
||||
def on_system_user_nodes_change(sender, instance=None, action=None, model=None, pk_set=None, **kwargs):
|
||||
"""
|
||||
当系统用户和节点关系发生变化时,应该将节点下资产关联到新的系统用户上
|
||||
"""
|
||||
if action != POST_ADD:
|
||||
return
|
||||
logger.info("System user nodes update signal recv: {}".format(instance))
|
||||
|
||||
queryset = model.objects.filter(pk__in=pk_set)
|
||||
if model == Node:
|
||||
nodes_keys = queryset.values_list('key', flat=True)
|
||||
system_users = [instance]
|
||||
else:
|
||||
nodes_keys = [instance.key]
|
||||
system_users = queryset
|
||||
add_nodes_assets_to_system_users.delay(nodes_keys, system_users)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=SystemUser.groups.through)
|
||||
def on_system_user_groups_change(instance, action, pk_set, reverse, **kwargs):
|
||||
"""
|
||||
当系统用户和用户组关系发生变化时,应该将组下用户关联到新的系统用户上
|
||||
"""
|
||||
if action != POST_ADD:
|
||||
return
|
||||
if reverse:
|
||||
raise M2MReverseNotAllowed
|
||||
logger.info("System user groups update signal recv: {}".format(instance))
|
||||
|
||||
users = User.objects.filter(groups__id__in=pk_set).distinct()
|
||||
instance.users.add(*users)
|
||||
|
||||
|
||||
@receiver(post_save, sender=SystemUser, dispatch_uid="jms")
|
||||
@on_transaction_commit
|
||||
def on_system_user_update(instance: SystemUser, created, **kwargs):
|
||||
"""
|
||||
当系统用户更新时,可能更新了密钥,用户名等,这时要自动推送系统用户到资产上,
|
||||
其实应该当 用户名,密码,密钥 sudo等更新时再推送,这里偷个懒,
|
||||
这里直接取了 instance.assets 因为nodes和系统用户发生变化时,会自动将nodes下的资产
|
||||
关联到上面
|
||||
"""
|
||||
if instance and not created:
|
||||
logger.info("System user update signal recv: {}".format(instance))
|
||||
assets = instance.assets.all().valid()
|
||||
push_system_user_to_assets.delay(instance.id, [_asset.id for _asset in assets])
|
||||
# add assets to su_from
|
||||
instance.add_related_assets_to_su_from_if_need(assets)
|
|
@ -1,307 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from itertools import groupby
|
||||
from celery import shared_task
|
||||
from common.db.utils import get_object_if_need, get_objects
|
||||
from django.utils.translation import ugettext as _, gettext_noop
|
||||
from django.db.models import Empty
|
||||
|
||||
from common.utils import encrypt_password, get_logger
|
||||
from assets.models import SystemUser, Asset
|
||||
from orgs.utils import org_aware_func, tmp_to_root_org
|
||||
from . import const
|
||||
from .utils import clean_ansible_task_hosts, group_asset_by_platform
|
||||
|
||||
|
||||
logger = get_logger(__file__)
|
||||
__all__ = [
|
||||
'push_system_user_util', 'push_system_user_to_assets',
|
||||
'push_system_user_to_assets_manual', 'push_system_user_a_asset_manual',
|
||||
'push_system_users_a_asset'
|
||||
]
|
||||
|
||||
|
||||
def _split_by_comma(raw: str):
|
||||
try:
|
||||
return [i.strip() for i in raw.split(',')]
|
||||
except AttributeError:
|
||||
return []
|
||||
|
||||
|
||||
def _dump_args(args: dict):
|
||||
return ' '.join([f'{k}={v}' for k, v in args.items() if v is not Empty])
|
||||
|
||||
|
||||
def get_push_unixlike_system_user_tasks(system_user, username=None, **kwargs):
|
||||
algorithm = kwargs.get('algorithm')
|
||||
if username is None:
|
||||
username = system_user.username
|
||||
|
||||
comment = system_user.name
|
||||
if system_user.username_same_with_user:
|
||||
from users.models import User
|
||||
user = User.objects.filter(username=username).only('name', 'username').first()
|
||||
if user:
|
||||
comment = f'{system_user.name}[{str(user)}]'
|
||||
comment = comment.replace(' ', '')
|
||||
|
||||
password = system_user.password
|
||||
public_key = system_user.public_key
|
||||
|
||||
groups = _split_by_comma(system_user.system_groups)
|
||||
|
||||
if groups:
|
||||
groups = '"%s"' % ','.join(groups)
|
||||
|
||||
add_user_args = {
|
||||
'name': username,
|
||||
'shell': system_user.shell or Empty,
|
||||
'state': 'present',
|
||||
'home': system_user.home or Empty,
|
||||
'expires': -1,
|
||||
'groups': groups or Empty,
|
||||
'comment': comment
|
||||
}
|
||||
|
||||
tasks = [
|
||||
{
|
||||
'name': 'Add user {}'.format(username),
|
||||
'action': {
|
||||
'module': 'user',
|
||||
'args': _dump_args(add_user_args),
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Add group {}'.format(username),
|
||||
'action': {
|
||||
'module': 'group',
|
||||
'args': 'name={} state=present'.format(username),
|
||||
}
|
||||
}
|
||||
]
|
||||
if not system_user.home:
|
||||
tasks.extend([
|
||||
{
|
||||
'name': 'Check home dir exists',
|
||||
'action': {
|
||||
'module': 'stat',
|
||||
'args': 'path=/home/{}'.format(username)
|
||||
},
|
||||
'register': 'home_existed'
|
||||
},
|
||||
{
|
||||
'name': "Set home dir permission",
|
||||
'action': {
|
||||
'module': 'file',
|
||||
'args': "path=/home/{0} owner={0} group={0} mode=700".format(username)
|
||||
},
|
||||
'when': 'home_existed.stat.exists == true'
|
||||
}
|
||||
])
|
||||
if password:
|
||||
tasks.append({
|
||||
'name': 'Set {} password'.format(username),
|
||||
'action': {
|
||||
'module': 'user',
|
||||
'args': 'name={} shell={} state=present password={}'.format(
|
||||
username, system_user.shell,
|
||||
encrypt_password(password, salt="K3mIlKK", algorithm=algorithm),
|
||||
),
|
||||
}
|
||||
})
|
||||
if public_key:
|
||||
tasks.append({
|
||||
'name': 'Set {} authorized key'.format(username),
|
||||
'action': {
|
||||
'module': 'authorized_key',
|
||||
'args': "user={} state=present key='{}'".format(
|
||||
username, public_key
|
||||
)
|
||||
}
|
||||
})
|
||||
if system_user.sudo:
|
||||
sudo = system_user.sudo.replace('\r\n', '\n').replace('\r', '\n')
|
||||
sudo_list = sudo.split('\n')
|
||||
sudo_tmp = []
|
||||
for s in sudo_list:
|
||||
sudo_tmp.append(s.strip(','))
|
||||
sudo = ','.join(sudo_tmp)
|
||||
tasks.append({
|
||||
'name': 'Set {} sudo setting'.format(username),
|
||||
'action': {
|
||||
'module': 'lineinfile',
|
||||
'args': "dest=/etc/sudoers state=present regexp='^{0} ALL=' "
|
||||
"line='{0} ALL=(ALL) NOPASSWD: {1}' "
|
||||
"validate='visudo -cf %s'".format(username, sudo)
|
||||
}
|
||||
})
|
||||
|
||||
return tasks
|
||||
|
||||
|
||||
def get_push_windows_system_user_tasks(system_user: SystemUser, username=None, **kwargs):
|
||||
if username is None:
|
||||
username = system_user.username
|
||||
password = system_user.password
|
||||
groups = {'Users', 'Remote Desktop Users'}
|
||||
if system_user.system_groups:
|
||||
groups.update(_split_by_comma(system_user.system_groups))
|
||||
groups = ','.join(groups)
|
||||
|
||||
tasks = []
|
||||
if not password:
|
||||
logger.error("Error: no password found")
|
||||
return tasks
|
||||
|
||||
if system_user.ad_domain:
|
||||
logger.error('System user with AD domain do not support push.')
|
||||
return tasks
|
||||
|
||||
task = {
|
||||
'name': 'Add user {}'.format(username),
|
||||
'action': {
|
||||
'module': 'win_user',
|
||||
'args': 'fullname={} '
|
||||
'name={} '
|
||||
'password={} '
|
||||
'state=present '
|
||||
'update_password=always '
|
||||
'password_expired=no '
|
||||
'password_never_expires=yes '
|
||||
'groups="{}" '
|
||||
'groups_action=add '
|
||||
''.format(username, username, password, groups),
|
||||
}
|
||||
}
|
||||
tasks.append(task)
|
||||
return tasks
|
||||
|
||||
|
||||
def get_push_system_user_tasks(system_user, platform="unixlike", username=None, algorithm=None):
|
||||
"""
|
||||
获取推送系统用户的 ansible 命令,跟资产无关
|
||||
:param system_user:
|
||||
:param platform:
|
||||
:param username: 当动态时,近推送某个
|
||||
:return:
|
||||
"""
|
||||
get_task_map = {
|
||||
"unixlike": get_push_unixlike_system_user_tasks,
|
||||
"windows": get_push_windows_system_user_tasks,
|
||||
}
|
||||
get_tasks = get_task_map.get(platform, get_push_unixlike_system_user_tasks)
|
||||
if not system_user.username_same_with_user:
|
||||
return get_tasks(system_user, algorithm=algorithm)
|
||||
tasks = []
|
||||
# 仅推送这个username
|
||||
if username is not None:
|
||||
tasks.extend(get_tasks(system_user, username, algorithm=algorithm))
|
||||
return tasks
|
||||
users = system_user.users.all().values_list('username', flat=True)
|
||||
print(_("System user is dynamic: {}").format(list(users)))
|
||||
for _username in users:
|
||||
tasks.extend(get_tasks(system_user, _username, algorithm=algorithm))
|
||||
return tasks
|
||||
|
||||
|
||||
@org_aware_func("system_user")
|
||||
def push_system_user_util(system_user, assets, task_name, username=None):
|
||||
from ops.utils import update_or_create_ansible_task
|
||||
assets = clean_ansible_task_hosts(assets, system_user=system_user)
|
||||
if not assets:
|
||||
return {}
|
||||
|
||||
# 资产按平台分类
|
||||
assets_sorted = sorted(assets, key=group_asset_by_platform)
|
||||
platform_hosts = groupby(assets_sorted, key=group_asset_by_platform)
|
||||
|
||||
if system_user.username_same_with_user:
|
||||
if username is None:
|
||||
# 动态系统用户,但是没有指定 username
|
||||
usernames = list(system_user.users.all().values_list('username', flat=True).distinct())
|
||||
else:
|
||||
usernames = [username]
|
||||
else:
|
||||
# 非动态系统用户指定 username 无效
|
||||
assert username is None, 'Only Dynamic user can assign `username`'
|
||||
usernames = [system_user.username]
|
||||
|
||||
def run_task(_tasks, _hosts):
|
||||
if not _tasks:
|
||||
return
|
||||
task, created = update_or_create_ansible_task(
|
||||
task_name=task_name, hosts=_hosts, tasks=_tasks, pattern='all',
|
||||
options=const.TASK_OPTIONS, run_as_admin=True,
|
||||
)
|
||||
task.run()
|
||||
|
||||
for platform, _assets in platform_hosts:
|
||||
_assets = list(_assets)
|
||||
if not _assets:
|
||||
continue
|
||||
print(_("Start push system user for platform: [{}]").format(platform))
|
||||
print(_("Hosts count: {}").format(len(_assets)))
|
||||
|
||||
for u in usernames:
|
||||
for a in _assets:
|
||||
system_user.load_asset_special_auth(a, u)
|
||||
algorithm = 'des' if a.platform.name == 'AIX' else 'sha512'
|
||||
tasks = get_push_system_user_tasks(
|
||||
system_user, platform, username=u,
|
||||
algorithm=algorithm
|
||||
)
|
||||
run_task(tasks, [a])
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
@tmp_to_root_org()
|
||||
def push_system_user_to_assets_manual(system_user, username=None):
|
||||
"""
|
||||
将系统用户推送到与它关联的所有资产上
|
||||
"""
|
||||
system_user = get_object_if_need(SystemUser, system_user)
|
||||
assets = system_user.get_related_assets()
|
||||
task_name = gettext_noop("Push system users to assets: ") + system_user.name
|
||||
return push_system_user_util(system_user, assets, task_name=task_name, username=username)
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
@tmp_to_root_org()
|
||||
def push_system_user_a_asset_manual(system_user, asset, username=None):
|
||||
"""
|
||||
将系统用户推送到一个资产上
|
||||
"""
|
||||
# if username is None:
|
||||
# username = system_user.username
|
||||
task_name = gettext_noop("Push system users to asset: ") + "{}({}) => {}".format(
|
||||
system_user.name, username or system_user.username, asset
|
||||
)
|
||||
return push_system_user_util(system_user, [asset], task_name=task_name, username=username)
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
@tmp_to_root_org()
|
||||
def push_system_users_a_asset(system_users, asset):
|
||||
for system_user in system_users:
|
||||
push_system_user_a_asset_manual(system_user, asset)
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
@tmp_to_root_org()
|
||||
def push_system_user_to_assets(system_user_id, asset_ids, username=None):
|
||||
"""
|
||||
推送系统用户到指定的若干资产上
|
||||
"""
|
||||
system_user = SystemUser.objects.get(id=system_user_id)
|
||||
assets = get_objects(Asset, asset_ids)
|
||||
task_name = gettext_noop("Push system users to assets: ") + system_user.name
|
||||
|
||||
return push_system_user_util(system_user, assets, task_name, username=username)
|
||||
|
||||
# @shared_task
|
||||
# @register_as_period_task(interval=3600)
|
||||
# @after_app_ready_start
|
||||
# @after_app_shutdown_clean_periodic
|
||||
# def push_system_user_period():
|
||||
# for system_user in SystemUser.objects.all():
|
||||
# push_system_user_related_nodes(system_user)
|
|
@ -1,151 +0,0 @@
|
|||
|
||||
from itertools import groupby
|
||||
from collections import defaultdict
|
||||
|
||||
from celery import shared_task
|
||||
from django.utils.translation import ugettext as _, gettext_noop
|
||||
|
||||
from assets.models import Asset
|
||||
from common.utils import get_logger
|
||||
from orgs.utils import tmp_to_org, org_aware_func
|
||||
from ..models import SystemUser, Connectivity, Account
|
||||
from . import const
|
||||
from .utils import (
|
||||
clean_ansible_task_hosts, group_asset_by_platform
|
||||
)
|
||||
|
||||
logger = get_logger(__name__)
|
||||
__all__ = [
|
||||
'test_system_user_connectivity_util', 'test_system_user_connectivity_manual',
|
||||
'test_system_user_connectivity_period', 'test_system_user_connectivity_a_asset',
|
||||
'test_system_users_connectivity_a_asset'
|
||||
]
|
||||
|
||||
|
||||
def set_assets_accounts_connectivity(system_user, assets, results_summary):
|
||||
asset_ids_ok = set()
|
||||
asset_ids_failed = set()
|
||||
|
||||
asset_hostnames_ok = results_summary.get('contacted', {}).keys()
|
||||
|
||||
for asset in assets:
|
||||
if asset.hostname in asset_hostnames_ok:
|
||||
asset_ids_ok.add(asset.id)
|
||||
else:
|
||||
asset_ids_failed.add(asset.id)
|
||||
|
||||
accounts_ok = Account.objects.filter(asset_id__in=asset_ids_ok, systemuser=system_user)
|
||||
accounts_failed = Account.objects.filter(asset_id__in=asset_ids_failed, systemuser=system_user)
|
||||
|
||||
Account.bulk_set_connectivity(accounts_ok, Connectivity.ok)
|
||||
Account.bulk_set_connectivity(accounts_failed, Connectivity.failed)
|
||||
|
||||
|
||||
@org_aware_func("system_user")
|
||||
def test_system_user_connectivity_util(system_user, assets, task_name):
|
||||
"""
|
||||
Test system cant connect his assets or not.
|
||||
:param system_user:
|
||||
:param assets:
|
||||
:param task_name:
|
||||
:return:
|
||||
"""
|
||||
from ops.utils import update_or_create_ansible_task
|
||||
|
||||
if system_user.username_same_with_user:
|
||||
logger.error(_("Dynamic system user not support test"))
|
||||
return
|
||||
|
||||
# hosts = clean_ansible_task_hosts(assets, system_user=system_user)
|
||||
# TODO: 这里不传递系统用户,因为clean_ansible_task_hosts会通过system_user来判断是否可以推送,
|
||||
# 不符合测试可连接性逻辑, 后面需要优化此逻辑
|
||||
hosts = clean_ansible_task_hosts(assets)
|
||||
if not hosts:
|
||||
return {}
|
||||
platform_hosts_map = {}
|
||||
hosts_sorted = sorted(hosts, key=group_asset_by_platform)
|
||||
platform_hosts = groupby(hosts_sorted, key=group_asset_by_platform)
|
||||
for i in platform_hosts:
|
||||
platform_hosts_map[i[0]] = list(i[1])
|
||||
|
||||
platform_tasks_map = {
|
||||
"unixlike": const.PING_UNIXLIKE_TASKS,
|
||||
"windows": const.PING_WINDOWS_TASKS
|
||||
}
|
||||
|
||||
results_summary = dict(
|
||||
contacted=defaultdict(dict), dark=defaultdict(dict), success=True
|
||||
)
|
||||
|
||||
def run_task(_tasks, _hosts, _username):
|
||||
old_name = "{}".format(system_user)
|
||||
new_name = "{}({})".format(system_user.name, _username)
|
||||
_task_name = task_name.replace(old_name, new_name)
|
||||
_task, created = update_or_create_ansible_task(
|
||||
task_name=_task_name, hosts=_hosts, tasks=_tasks,
|
||||
pattern='all', options=const.TASK_OPTIONS,
|
||||
run_as=_username, system_user=system_user
|
||||
)
|
||||
raw, summary = _task.run()
|
||||
success = summary.get('success', False)
|
||||
contacted = summary.get('contacted', {})
|
||||
dark = summary.get('dark', {})
|
||||
|
||||
results_summary['success'] &= success
|
||||
results_summary['contacted'].update(contacted)
|
||||
results_summary['dark'].update(dark)
|
||||
|
||||
for platform, _hosts in platform_hosts_map.items():
|
||||
if not _hosts:
|
||||
continue
|
||||
if platform not in ["unixlike", "windows"]:
|
||||
continue
|
||||
|
||||
tasks = platform_tasks_map[platform]
|
||||
print(_("Start test system user connectivity for platform: [{}]").format(platform))
|
||||
print(_("Hosts count: {}").format(len(_hosts)))
|
||||
# 用户名不是动态的,用户名则是一个
|
||||
logger.debug("System user not has special auth")
|
||||
run_task(tasks, _hosts, system_user.username)
|
||||
|
||||
set_assets_accounts_connectivity(system_user, hosts, results_summary)
|
||||
return results_summary
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
@org_aware_func("system_user")
|
||||
def test_system_user_connectivity_manual(system_user, asset_ids=None):
|
||||
task_name = gettext_noop("Test system user connectivity: ") + str(system_user)
|
||||
if asset_ids:
|
||||
assets = Asset.objects.filter(id__in=asset_ids)
|
||||
else:
|
||||
assets = system_user.get_related_assets()
|
||||
test_system_user_connectivity_util(system_user, assets, task_name)
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
@org_aware_func("system_user")
|
||||
def test_system_user_connectivity_a_asset(system_user, asset):
|
||||
task_name = gettext_noop("Test system user connectivity: ") + "{} => {}".format(
|
||||
system_user, asset
|
||||
)
|
||||
test_system_user_connectivity_util(system_user, [asset], task_name)
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
def test_system_users_connectivity_a_asset(system_users, asset):
|
||||
for system_user in system_users:
|
||||
test_system_user_connectivity_a_asset(system_user, asset)
|
||||
|
||||
|
||||
@shared_task(queue="ansible")
|
||||
def test_system_user_connectivity_period():
|
||||
if not const.PERIOD_TASK_ENABLED:
|
||||
logger.debug("Period task disabled, test system user connectivity pass")
|
||||
return
|
||||
queryset_map = SystemUser.objects.all_group_by_org()
|
||||
for org, system_user in queryset_map.items():
|
||||
task_name = gettext_noop("Test system user connectivity period: ") + str(system_user)
|
||||
with tmp_to_org(org):
|
||||
assets = system_user.get_related_assets()
|
||||
test_system_user_connectivity_util(system_user, assets, task_name)
|
|
@ -16,7 +16,6 @@ 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')
|
||||
router.register(r'platforms', api.AssetPlatformViewSet, 'platform')
|
||||
router.register(r'system-users', api.SystemUserViewSet, 'system-user')
|
||||
router.register(r'labels', api.LabelViewSet, 'label')
|
||||
router.register(r'nodes', api.NodeViewSet, 'node')
|
||||
router.register(r'domains', api.DomainViewSet, 'domain')
|
||||
|
@ -41,11 +40,6 @@ urlpatterns = [
|
|||
path('assets/<uuid:pk>/perm-user-groups/', api.AssetPermUserGroupListApi.as_view(), name='asset-perm-user-group-list'),
|
||||
path('assets/<uuid:pk>/perm-user-groups/<uuid:perm_user_group_id>/permissions/', api.AssetPermUserGroupPermissionsListApi.as_view(), name='asset-perm-user-group-permission-list'),
|
||||
|
||||
path('system-users/<uuid:pk>/assets/<uuid:asset_id>/users/<uuid:user_id>/account/', api.SystemUserAssetAccountApi.as_view(), name='system-user-asset-account'),
|
||||
path('system-users/<uuid:pk>/assets/<uuid:asset_id>/users/<uuid:user_id>/account-secret/', api.SystemUserAssetAccountSecretApi.as_view(), name='system-user-asset-account-secret'),
|
||||
path('system-users/<uuid:pk>/cmd-filter-rules/', api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'),
|
||||
path('cmd-filter-rules/', api.SystemUserCommandFilterRuleListApi.as_view(), name='cmd-filter-rules'),
|
||||
|
||||
path('accounts/tasks/', api.AccountTaskCreateAPI.as_view(), name='account-task-create'),
|
||||
|
||||
path('nodes/tree/', api.NodeListAsTreeApi.as_view(), name='node-tree'),
|
||||
|
@ -65,9 +59,5 @@ urlpatterns = [
|
|||
|
||||
]
|
||||
|
||||
old_version_urlpatterns = [
|
||||
re_path('(?P<resource>admin-user|system-user|domain|gateway|cmd-filter|asset-user)/.*', capi.redirect_plural_name_api)
|
||||
]
|
||||
|
||||
urlpatterns += router.urls + cmd_filter_router.urls + old_version_urlpatterns
|
||||
urlpatterns += router.urls + cmd_filter_router.urls
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from django.db.models import F, TextChoices
|
|||
from orgs.mixins.models import OrgModelMixin
|
||||
from common.db import models
|
||||
from common.utils import lazyproperty
|
||||
from assets.models import Asset, SystemUser, Node, FamilyMixin
|
||||
from assets.models import Asset, Node, FamilyMixin
|
||||
|
||||
from .base import BasePermission
|
||||
|
||||
|
|
Loading…
Reference in New Issue