mirror of https://github.com/jumpserver/jumpserver
parent
bbe2678df3
commit
07c60ca75d
|
@ -8,6 +8,7 @@ from orgs.mixins.api import OrgBulkModelViewSet
|
|||
from orgs.mixins import generics
|
||||
from common.mixins.api import SuggestionMixin
|
||||
from orgs.utils import tmp_to_root_org
|
||||
from rest_framework.decorators import action
|
||||
from ..models import SystemUser, Asset
|
||||
from .. import serializers
|
||||
from ..serializers import SystemUserWithAuthInfoSerializer, SystemUserTempAuthSerializer
|
||||
|
@ -45,6 +46,32 @@ class SystemUserViewSet(SuggestionMixin, OrgBulkModelViewSet):
|
|||
ordering = ('name', )
|
||||
permission_classes = (IsOrgAdminOrAppUser,)
|
||||
|
||||
@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 SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.1.13 on 2021-11-04 05:47
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0079_auto_20211102_1922'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='systemuser',
|
||||
name='su_enabled',
|
||||
field=models.BooleanField(default=False, verbose_name='Switch user'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='systemuser',
|
||||
name='su_from',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='su_to', to='assets.systemuser', verbose_name='Switch from'),
|
||||
),
|
||||
]
|
|
@ -208,6 +208,9 @@ class SystemUser(ProtocolMixin, AuthMixin, BaseUser):
|
|||
home = models.CharField(max_length=4096, default='', verbose_name=_('Home'), blank=True)
|
||||
system_groups = models.CharField(default='', max_length=4096, verbose_name=_('System groups'), blank=True)
|
||||
ad_domain = models.CharField(default='', max_length=256)
|
||||
# linux su 命令 (switch user)
|
||||
su_enabled = models.BooleanField(default=False, verbose_name=_('Switch user'))
|
||||
su_from = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='su_to', null=True, verbose_name=_("Switch from"))
|
||||
|
||||
def __str__(self):
|
||||
username = self.username
|
||||
|
@ -267,6 +270,21 @@ class SystemUser(ProtocolMixin, AuthMixin, BaseUser):
|
|||
assets = Asset.objects.filter(id__in=asset_ids)
|
||||
return assets
|
||||
|
||||
def add_related_assets(self, assets_or_ids):
|
||||
self.assets.add(*tuple(assets_or_ids))
|
||||
self.add_related_assets_to_su_from_if_need(assets_or_ids)
|
||||
|
||||
def add_related_assets_to_su_from_if_need(self, assets_or_ids):
|
||||
if self.protocol not in [self.Protocol.ssh.value]:
|
||||
return
|
||||
if not self.su_enabled:
|
||||
return
|
||||
if not self.su_from:
|
||||
return
|
||||
if self.su_from.protocol != self.protocol:
|
||||
return
|
||||
self.su_from.assets.add(*tuple(assets_or_ids))
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
unique_together = [('name', 'org_id')]
|
||||
|
|
|
@ -40,6 +40,7 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
'login_mode', 'login_mode_display', 'priority',
|
||||
'sudo', 'shell', 'sftp_root', 'home', 'system_groups', 'ad_domain',
|
||||
'username_same_with_user', 'auto_push', 'auto_generate_key',
|
||||
'su_enabled', 'su_from',
|
||||
'date_created', 'date_updated', 'comment', 'created_by',
|
||||
]
|
||||
fields_m2m = ['cmd_filters', 'assets_amount', 'applications_amount', 'nodes']
|
||||
|
@ -57,7 +58,8 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
'login_mode_display': {'label': _('Login mode display')},
|
||||
'created_by': {'read_only': True},
|
||||
'ad_domain': {'required': False, 'allow_blank': True, 'label': _('Ad domain')},
|
||||
'is_asset_protocol': {'label': _('Is asset protocol')}
|
||||
'is_asset_protocol': {'label': _('Is asset protocol')},
|
||||
'su_from': {'help_text': _('Only ssh and automatic login system users are supported')}
|
||||
}
|
||||
|
||||
def validate_auto_push(self, value):
|
||||
|
@ -146,6 +148,29 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
raise serializers.ValidationError(_("Password or private key required"))
|
||||
return password
|
||||
|
||||
def validate_su_from(self, su_from: SystemUser):
|
||||
# self: su enabled
|
||||
su_enabled = self.get_initial_value('su_enabled', default=False)
|
||||
if not su_enabled:
|
||||
return
|
||||
if not su_from:
|
||||
error = _('This field is required.')
|
||||
raise serializers.ValidationError(error)
|
||||
# self: protocol ssh
|
||||
protocol = self.get_initial_value('protocol', default=SystemUser.Protocol.ssh.value)
|
||||
if protocol not in [SystemUser.Protocol.ssh.value]:
|
||||
error = _('Only ssh protocol system users are allowed')
|
||||
raise serializers.ValidationError(error)
|
||||
# su_from: protocol same
|
||||
if su_from.protocol != protocol:
|
||||
error = _('The protocol must be consistent with the current user: {}').format(protocol)
|
||||
raise serializers.ValidationError(error)
|
||||
# su_from: login model auto
|
||||
if su_from.login_mode != su_from.LOGIN_AUTO:
|
||||
error = _('Only system users with automatic login are allowed')
|
||||
raise serializers.ValidationError(error)
|
||||
return su_from
|
||||
|
||||
def _validate_admin_user(self, attrs):
|
||||
if self.instance:
|
||||
tp = self.instance.type
|
||||
|
|
|
@ -140,3 +140,5 @@ def on_system_user_update(instance: SystemUser, created, **kwargs):
|
|||
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)
|
||||
|
|
|
@ -298,9 +298,12 @@ class CommonSerializerMixin(DynamicFieldsMixin, DefaultValueFieldsMixin):
|
|||
|
||||
def get_initial_value(self, attr, default=None):
|
||||
value = self.initial_data.get(attr)
|
||||
if not value and self.instance:
|
||||
if value is not None:
|
||||
return value
|
||||
if self.instance:
|
||||
value = getattr(self.instance, attr, default)
|
||||
return value
|
||||
return value
|
||||
return default
|
||||
|
||||
|
||||
class CommonBulkSerializerMixin(BulkSerializerMixin, CommonSerializerMixin):
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bdad14124356449843ef2e77801fd1add5147862488baa2f24f5f14f1ad8f125
|
||||
size 90869
|
||||
oid sha256:ed378b8e141b884f9b6d82135b37446c02d6621b46f282461e733d610b36030d
|
||||
size 91465
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-03 11:14+0800\n"
|
||||
"POT-Creation-Date: 2021-11-05 11:41+0800\n"
|
||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
|
@ -129,7 +129,7 @@ msgstr "系统用户"
|
|||
#: acls/models/login_asset_acl.py:22
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:37
|
||||
#: assets/models/asset.py:357 assets/models/authbook.py:18
|
||||
#: assets/models/gathered_user.py:14 assets/serializers/system_user.py:233
|
||||
#: assets/models/gathered_user.py:14 assets/serializers/system_user.py:258
|
||||
#: audits/models.py:38 perms/models/asset_permission.py:99
|
||||
#: templates/index.html:82 terminal/backends/command/models.py:19
|
||||
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:40
|
||||
|
@ -262,7 +262,7 @@ msgid "Custom"
|
|||
msgstr "自定义"
|
||||
|
||||
#: applications/models/account.py:11 assets/models/authbook.py:19
|
||||
#: assets/models/user.py:273 audits/models.py:39
|
||||
#: assets/models/user.py:291 audits/models.py:39
|
||||
#: perms/models/application_permission.py:32
|
||||
#: perms/models/asset_permission.py:101 templates/_nav.html:45
|
||||
#: terminal/backends/command/models.py:20
|
||||
|
@ -379,6 +379,7 @@ msgid "Application path"
|
|||
msgstr "应用路径"
|
||||
|
||||
#: applications/serializers/attrs/application_category/remote_app.py:45
|
||||
#: assets/serializers/system_user.py:157
|
||||
#: xpack/plugins/change_auth_plan/serializers/asset.py:65
|
||||
#: xpack/plugins/change_auth_plan/serializers/asset.py:68
|
||||
#: xpack/plugins/change_auth_plan/serializers/asset.py:71
|
||||
|
@ -476,7 +477,7 @@ msgid "Is active"
|
|||
msgstr "激活"
|
||||
|
||||
#: assets/models/asset.py:193 assets/models/cluster.py:19
|
||||
#: assets/models/user.py:187 assets/models/user.py:322 templates/_nav.html:44
|
||||
#: assets/models/user.py:187 assets/models/user.py:340 templates/_nav.html:44
|
||||
msgid "Admin user"
|
||||
msgstr "特权用户"
|
||||
|
||||
|
@ -763,7 +764,7 @@ msgstr "全称"
|
|||
msgid "Parent key"
|
||||
msgstr "ssh私钥"
|
||||
|
||||
#: assets/models/node.py:559 assets/serializers/system_user.py:232
|
||||
#: assets/models/node.py:559 assets/serializers/system_user.py:257
|
||||
#: users/templates/users/user_asset_permission.html:41
|
||||
#: users/templates/users/user_asset_permission.html:73
|
||||
#: users/templates/users/user_asset_permission.html:158
|
||||
|
@ -835,6 +836,14 @@ msgstr "家目录"
|
|||
msgid "System groups"
|
||||
msgstr "用户组"
|
||||
|
||||
#: assets/models/user.py:212
|
||||
msgid "Switch user"
|
||||
msgstr "切换用户"
|
||||
|
||||
#: assets/models/user.py:213
|
||||
msgid "Switch from"
|
||||
msgstr "切换自"
|
||||
|
||||
#: assets/models/utils.py:35
|
||||
#, python-format
|
||||
msgid "%(value)s is not an even number"
|
||||
|
@ -864,7 +873,7 @@ msgstr "节点名称"
|
|||
msgid "Hardware info"
|
||||
msgstr "硬件信息"
|
||||
|
||||
#: assets/serializers/asset.py:104 assets/serializers/system_user.py:251
|
||||
#: assets/serializers/asset.py:104 assets/serializers/system_user.py:276
|
||||
#: orgs/mixins/serializers.py:26
|
||||
msgid "Org name"
|
||||
msgstr "组织名称"
|
||||
|
@ -878,7 +887,7 @@ msgid "private key invalid"
|
|||
msgstr "密钥不合法"
|
||||
|
||||
#: assets/serializers/domain.py:13 assets/serializers/label.py:12
|
||||
#: assets/serializers/system_user.py:56
|
||||
#: assets/serializers/system_user.py:57
|
||||
#: perms/serializers/asset/permission.py:72
|
||||
msgid "Assets amount"
|
||||
msgstr "资产数量"
|
||||
|
@ -912,48 +921,64 @@ msgstr "密钥指纹"
|
|||
msgid "Apps amount"
|
||||
msgstr "应用数量"
|
||||
|
||||
#: assets/serializers/system_user.py:55
|
||||
#: assets/serializers/system_user.py:56
|
||||
#: perms/serializers/asset/permission.py:73
|
||||
msgid "Nodes amount"
|
||||
msgstr "节点数量"
|
||||
|
||||
#: assets/serializers/system_user.py:57 assets/serializers/system_user.py:234
|
||||
#: assets/serializers/system_user.py:58 assets/serializers/system_user.py:259
|
||||
msgid "Login mode display"
|
||||
msgstr "认证方式名称"
|
||||
|
||||
#: assets/serializers/system_user.py:59
|
||||
#: assets/serializers/system_user.py:60
|
||||
msgid "Ad domain"
|
||||
msgstr "Ad 网域"
|
||||
|
||||
#: assets/serializers/system_user.py:60
|
||||
#: assets/serializers/system_user.py:61
|
||||
msgid "Is asset protocol"
|
||||
msgstr "资产协议"
|
||||
|
||||
#: assets/serializers/system_user.py:100
|
||||
#: assets/serializers/system_user.py:62
|
||||
msgid "Only ssh and automatic login system users are supported"
|
||||
msgstr "仅支持ssh协议和自动登录的系统用户"
|
||||
|
||||
#: assets/serializers/system_user.py:102
|
||||
msgid "Username same with user with protocol {} only allow 1"
|
||||
msgstr "用户名和用户相同的一种协议只允许存在一个"
|
||||
|
||||
#: assets/serializers/system_user.py:110 common/validators.py:14
|
||||
#: assets/serializers/system_user.py:112 common/validators.py:14
|
||||
msgid "Special char not allowed"
|
||||
msgstr "不能包含特殊字符"
|
||||
|
||||
#: assets/serializers/system_user.py:119
|
||||
#: assets/serializers/system_user.py:121
|
||||
msgid "* Automatic login mode must fill in the username."
|
||||
msgstr "自动登录模式,必须填写用户名"
|
||||
|
||||
#: assets/serializers/system_user.py:134
|
||||
#: assets/serializers/system_user.py:136
|
||||
msgid "Path should starts with /"
|
||||
msgstr "路径应该以 / 开头"
|
||||
|
||||
#: assets/serializers/system_user.py:146
|
||||
#: assets/serializers/system_user.py:148
|
||||
msgid "Password or private key required"
|
||||
msgstr "密码或密钥密码需要一个"
|
||||
|
||||
#: assets/serializers/system_user.py:250
|
||||
#: assets/serializers/system_user.py:162
|
||||
msgid "Only ssh protocol system users are allowed"
|
||||
msgstr "仅允许ssh协议的系统用户"
|
||||
|
||||
#: assets/serializers/system_user.py:166
|
||||
msgid "The protocol must be consistent with the current user: {}"
|
||||
msgstr "协议必须和当前用户保持一致: {}"
|
||||
|
||||
#: assets/serializers/system_user.py:170
|
||||
msgid "Only system users with automatic login are allowed"
|
||||
msgstr "仅允许自动登录的系统用户"
|
||||
|
||||
#: assets/serializers/system_user.py:275
|
||||
msgid "System user name"
|
||||
msgstr "系统用户名称"
|
||||
|
||||
#: assets/serializers/system_user.py:260
|
||||
#: assets/serializers/system_user.py:285
|
||||
msgid "Asset hostname"
|
||||
msgstr "资产主机名"
|
||||
|
||||
|
@ -3149,7 +3174,8 @@ msgstr "邮件的内容"
|
|||
msgid ""
|
||||
"Tips: When creating a user, send the content of the email, support "
|
||||
"{username} {name} {email} label"
|
||||
msgstr "提示: 创建用户时,发送设置密码邮件的内容, 支持 {username} {name} {email} 标签"
|
||||
msgstr ""
|
||||
"提示: 创建用户时,发送设置密码邮件的内容, 支持 {username} {name} {email} 标签"
|
||||
|
||||
#: settings/serializers/email.py:64
|
||||
msgid "Tips: Email signature (eg:jumpserver)"
|
||||
|
@ -5404,8 +5430,8 @@ msgstr "* 新密码不能是最近 {} 次的密码"
|
|||
msgid "Reset password success, return to login page"
|
||||
msgstr "重置密码成功,返回到登录页面"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/api/app.py:113
|
||||
#: xpack/plugins/change_auth_plan/api/asset.py:100
|
||||
#: xpack/plugins/change_auth_plan/api/app.py:114
|
||||
#: xpack/plugins/change_auth_plan/api/asset.py:101
|
||||
msgid "The parameter 'action' must be [{}]"
|
||||
msgstr "参数 'action' 必须是 [{}]"
|
||||
|
||||
|
@ -5536,15 +5562,15 @@ msgstr "* 请输入正确的密码长度"
|
|||
msgid "* Password length range 6-30 bits"
|
||||
msgstr "* 密码长度范围 6-30 位"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:248
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:249
|
||||
msgid "Invalid/incorrect password"
|
||||
msgstr "无效/错误 密码"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:250
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:251
|
||||
msgid "Failed to connect to the host"
|
||||
msgstr "连接主机失败"
|
||||
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:252
|
||||
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:253
|
||||
msgid "Data could not be sent to remote"
|
||||
msgstr "无法将数据发送到远程"
|
||||
|
||||
|
@ -5902,7 +5928,7 @@ msgstr "执行次数"
|
|||
msgid "Instance count"
|
||||
msgstr "实例个数"
|
||||
|
||||
#: xpack/plugins/cloud/utils.py:65
|
||||
#: xpack/plugins/cloud/utils.py:68
|
||||
msgid "Account unavailable"
|
||||
msgstr "账户无效"
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ def set_remote_app_asset_system_users_if_need(instance: ApplicationPermission, s
|
|||
|
||||
system_users = system_users or instance.system_users.all()
|
||||
for system_user in system_users:
|
||||
system_user.assets.add(*asset_ids)
|
||||
system_user.add_related_assets(asset_ids)
|
||||
|
||||
if system_user.username_same_with_user:
|
||||
users = users or instance.users.all()
|
||||
|
|
|
@ -70,7 +70,8 @@ def on_permission_assets_changed(instance, action, reverse, pk_set, model, **kwa
|
|||
# TODO 待优化
|
||||
system_users = instance.system_users.all()
|
||||
for system_user in system_users:
|
||||
system_user.assets.add(*tuple(assets))
|
||||
system_user: SystemUser
|
||||
system_user.add_related_assets(assets)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=AssetPermission.system_users.through)
|
||||
|
@ -88,7 +89,7 @@ def on_asset_permission_system_users_changed(instance, action, reverse, **kwargs
|
|||
|
||||
for system_user in system_users:
|
||||
system_user.nodes.add(*tuple(nodes))
|
||||
system_user.assets.add(*tuple(assets))
|
||||
system_user.add_related_assets(assets)
|
||||
|
||||
# 动态系统用户,需要关联用户和用户组了
|
||||
if system_user.username_same_with_user:
|
||||
|
|
Loading…
Reference in New Issue