Compare commits

...

16 Commits
v3.7.2 ... v2.8

Author SHA1 Message Date
Bai
e5e75e75af fix: 修改ACL提示支持的协议为: ssh、telnet 2021-04-23 16:35:06 +08:00
xinwen
00ae4d2577 fix: key=0 修改到 key=1 时 parent_key 没有更新 2021-04-15 01:33:18 -05:00
xinwen
3b95487221 fix: 添加 0069_change_node_key0_to_key1 迁移脚本 2021-04-13 21:35:21 -05:00
xinwen
eba7a7288a fix: 修复 test cookie 问题,删掉key=0迁移脚本 2021-04-09 03:13:56 -05:00
xinwen
bd11018cef fix: 管理用户输入带密码的秘钥报错 2021-04-06 19:45:40 +08:00
xinwen
8a2b0a7845 fix: 修正 key 为 0 的节点 2021-04-06 18:27:18 +08:00
xinwen
b3dbdd5389 fix: revert 一些代码 2021-03-30 10:44:48 +08:00
xinwen
a4643fe4b4 fix: Default 组织下出现 app user 2021-03-30 10:23:13 +08:00
xinwen
dce9b50ac0 feat: 增加 es 忽略 https 证书验证 2021-03-30 10:23:13 +08:00
xinwen
e2b7c902a5 perf: delete_test_cookie 2021-03-30 10:23:13 +08:00
ibuler
4055306cf8 perf: 修改表结构迁移,增加rdp terminal 2021-03-24 10:24:09 +08:00
xinwen
9e1c5bb64d fix: 授权树节点排序 2021-03-24 10:13:45 +08:00
ibuler
32df722e9d perf: 合并 2021-03-23 18:46:30 +08:00
ibuler
22f6f5c34c perf: session add rdp terminal login from 2021-03-23 18:31:42 +08:00
ibuler
6fb819ca53 perf: 优化登录ip限制提示 2021-03-23 18:31:24 +08:00
老广
043c4a7a0b Merge pull request #5813 from jumpserver/master
v2.8.1
2021-03-19 20:05:29 +08:00
12 changed files with 132 additions and 37 deletions

View File

@@ -40,7 +40,7 @@ class LoginAssetACLSystemUsersSerializer(serializers.Serializer):
protocol_group = serializers.ListField(
default=['*'], child=serializers.CharField(max_length=16), label=_('Protocol'),
help_text=const.common_help_text + _('Protocol options: {}').format(
', '.join(SystemUser.ASSET_CATEGORY_PROTOCOLS)
', '.join([SystemUser.PROTOCOL_SSH, SystemUser.PROTOCOL_TELNET])
)
)

View File

@@ -0,0 +1,61 @@
from django.db import migrations
from django.db.transaction import atomic
default_id = '00000000-0000-0000-0000-000000000002'
def change_key0_to_key1(apps, schema_editor):
from orgs.utils import set_current_org
# https://stackoverflow.com/questions/28777338/django-migrations-runpython-not-able-to-call-model-methods
Organization = apps.get_model('orgs', 'Organization')
Node = apps.get_model('assets', 'Node')
print()
org = Organization.objects.get(id=default_id)
set_current_org(org)
exists_0 = Node.objects.filter(key__startswith='0').exists()
if not exists_0:
print(f'--> Not exist key=0 nodes, do nothing.')
return
key_1_count = Node.objects.filter(key__startswith='1').count()
if key_1_count > 1:
print(f'--> Node key=1 have children, can`t just delete it. Please contact JumpServer team')
return
root_node = Node.objects.filter(key='1').first()
if root_node and root_node.assets.exists():
print(f'--> Node key=1 has assets, do nothing.')
return
with atomic():
if root_node:
print(f'--> Delete node key=1')
root_node.delete()
nodes_0 = Node.objects.filter(key__startswith='0')
for n in nodes_0:
old_key = n.key
key_list = n.key.split(':')
key_list[0] = '1'
new_key = ':'.join(key_list)
new_parent_key = ':'.join(key_list[:-1])
n.key = new_key
n.parent_key = new_parent_key
n.save()
print('--> Modify key ( {} > {} )'.format(old_key, new_key))
class Migration(migrations.Migration):
dependencies = [
('orgs', '0010_auto_20210219_1241'),
('assets', '0068_auto_20210312_1455'),
]
operations = [
migrations.RunPython(change_key0_to_key1)
]

View File

@@ -113,7 +113,7 @@ class AuthMixin:
if self.public_key:
public_key = self.public_key
elif self.private_key:
public_key = ssh_pubkey_gen(self.private_key, self.password)
public_key = ssh_pubkey_gen(private_key=self.private_key, password=self.password)
else:
return ''

View File

@@ -31,7 +31,7 @@ reason_choices = {
reason_user_invalid: _('Disabled or expired'),
reason_user_inactive: _("This account is inactive."),
reason_backend_not_match: _("Auth backend not match"),
reason_acl_not_allow: _("ACL is not allowed")
reason_acl_not_allow: _("Login IP is not allowed")
}
old_reason_choices = {
'0': '-',

View File

@@ -55,6 +55,9 @@ class UserLoginView(mixins.AuthMixin, FormView):
def form_valid(self, form):
if not self.request.session.test_cookie_worked():
return HttpResponse(_("Please enable cookies and try again."))
# https://docs.djangoproject.com/en/3.1/topics/http/sessions/#setting-test-cookies
self.request.session.delete_test_cookie()
try:
self.check_user_auth(decrypt_passwd=True)
except errors.AuthFailedError as e:
@@ -66,6 +69,7 @@ class UserLoginView(mixins.AuthMixin, FormView):
new_form = form_cls(data=form.data)
new_form._errors = form.errors
context = self.get_context_data(form=new_form)
self.request.session.set_test_cookie()
return self.render_to_response(context)
except (errors.PasswdTooSimple, errors.PasswordRequireResetError) as e:
return redirect(e.url)

Binary file not shown.

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-03-19 14:34+0800\n"
"POT-Creation-Date: 2021-03-22 14:42+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@@ -428,7 +428,7 @@ msgstr "激活"
#: assets/models/asset.py:196 assets/models/cluster.py:19
#: assets/models/user.py:66 templates/_nav.html:44
#: xpack/plugins/cloud/models.py:92 xpack/plugins/cloud/serializers.py:138
#: xpack/plugins/cloud/models.py:92 xpack/plugins/cloud/serializers.py:137
msgid "Admin user"
msgstr "管理用户"
@@ -693,7 +693,7 @@ msgstr "ssh私钥"
#: users/templates/users/user_asset_permission.html:41
#: users/templates/users/user_asset_permission.html:73
#: users/templates/users/user_asset_permission.html:158
#: xpack/plugins/cloud/models.py:89 xpack/plugins/cloud/serializers.py:139
#: xpack/plugins/cloud/models.py:89 xpack/plugins/cloud/serializers.py:138
msgid "Node"
msgstr "节点"
@@ -1140,7 +1140,7 @@ msgstr "启用"
msgid "-"
msgstr ""
#: audits/models.py:96 xpack/plugins/cloud/const.py:24
#: audits/models.py:96 xpack/plugins/cloud/const.py:23
msgid "Failed"
msgstr "失败"
@@ -1331,8 +1331,8 @@ msgid "Auth backend not match"
msgstr "没有匹配到认证后端"
#: authentication/errors.py:34
msgid "ACL is not allowed"
msgstr "ACL 不被允许"
msgid "Login IP is not allowed"
msgstr "登录 IP 不被允许"
#: authentication/errors.py:44
msgid "No session found, check your cookie"
@@ -2249,7 +2249,7 @@ msgstr "全局启用 MFA 认证"
#: settings/serializers/settings.py:133
msgid "All user enable MFA"
msgstr "强制每个启用多因子认证"
msgstr "强制所有用户启用多因子认证"
#: settings/serializers/settings.py:136
msgid "Batch command execution"
@@ -3784,7 +3784,7 @@ msgstr "安全令牌验证"
#: users/templates/users/_base_otp.html:14 users/templates/users/_user.html:13
#: users/templates/users/user_profile_update.html:55
#: xpack/plugins/cloud/models.py:78 xpack/plugins/cloud/serializers.py:137
#: xpack/plugins/cloud/models.py:78 xpack/plugins/cloud/serializers.py:136
msgid "Account"
msgstr "账户"
@@ -4774,46 +4774,42 @@ msgid "Azure (China)"
msgstr "Azure (中国)"
#: xpack/plugins/cloud/const.py:12
msgid "Azure (International)"
msgstr "Azure (国际)"
#: xpack/plugins/cloud/const.py:13
msgid "Huawei Cloud"
msgstr "华为云"
#: xpack/plugins/cloud/const.py:14
#: xpack/plugins/cloud/const.py:13
msgid "Tencent Cloud"
msgstr "腾讯云"
#: xpack/plugins/cloud/const.py:15
#: xpack/plugins/cloud/const.py:14
msgid "VMware"
msgstr ""
#: xpack/plugins/cloud/const.py:19
#: xpack/plugins/cloud/const.py:18
msgid "Instance name"
msgstr "实例名称"
#: xpack/plugins/cloud/const.py:20
#: xpack/plugins/cloud/const.py:19
msgid "Instance name and Partial IP"
msgstr "实例名称和部分IP"
#: xpack/plugins/cloud/const.py:25
#: xpack/plugins/cloud/const.py:24
msgid "Succeed"
msgstr "成功"
#: xpack/plugins/cloud/const.py:29
#: xpack/plugins/cloud/const.py:28
msgid "Unsync"
msgstr "未同步"
#: xpack/plugins/cloud/const.py:30
#: xpack/plugins/cloud/const.py:29
msgid "New Sync"
msgstr "新同步"
#: xpack/plugins/cloud/const.py:31
#: xpack/plugins/cloud/const.py:30
msgid "Synced"
msgstr "已同步"
#: xpack/plugins/cloud/const.py:32
#: xpack/plugins/cloud/const.py:31
msgid "Released"
msgstr "已释放"
@@ -4829,7 +4825,7 @@ msgstr "云服务商"
msgid "Cloud account"
msgstr "云账号"
#: xpack/plugins/cloud/models.py:81 xpack/plugins/cloud/serializers.py:118
#: xpack/plugins/cloud/models.py:81 xpack/plugins/cloud/serializers.py:117
msgid "Regions"
msgstr "地域"
@@ -4837,7 +4833,7 @@ msgstr "地域"
msgid "Hostname strategy"
msgstr "主机名策略"
#: xpack/plugins/cloud/models.py:95 xpack/plugins/cloud/serializers.py:141
#: xpack/plugins/cloud/models.py:95 xpack/plugins/cloud/serializers.py:140
msgid "Always update"
msgstr "总是更新"
@@ -5029,15 +5025,15 @@ msgstr ""
msgid "Subscription ID"
msgstr ""
#: xpack/plugins/cloud/serializers.py:116
#: xpack/plugins/cloud/serializers.py:115
msgid "History count"
msgstr "执行次数"
#: xpack/plugins/cloud/serializers.py:117
#: xpack/plugins/cloud/serializers.py:116
msgid "Instance count"
msgstr "实例个数"
#: xpack/plugins/cloud/serializers.py:140
#: xpack/plugins/cloud/serializers.py:139
#: xpack/plugins/gathered_user/serializers.py:20
msgid "Periodic display"
msgstr "定时执行"
@@ -5130,6 +5126,9 @@ msgstr "旗舰版"
msgid "Community edition"
msgstr "社区版"
#~ msgid "Azure (International)"
#~ msgstr "Azure (国际)"
#~ msgid "Root organization only allow view and delete"
#~ msgstr "全局组织仅支持 查看和删除"

View File

@@ -90,6 +90,11 @@ class OrgMemberRelationBulkViewSet(JMSBulkRelationModelViewSet):
filterset_class = OrgMemberRelationFilterSet
search_fields = ('user__name', 'user__username', 'org__name')
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.exclude(user__role=User.ROLE.APP)
return queryset
def perform_bulk_destroy(self, queryset):
objs = list(queryset.all().prefetch_related('user', 'org'))
queryset.delete()

View File

@@ -488,11 +488,12 @@ class UserGrantedAssetsQueryUtils(UserGrantedUtilsBase):
if granted_status == NodeFrom.granted:
assets = Asset.objects.order_by().filter(nodes__id=node.id)
return assets
elif granted_status == NodeFrom.asset:
return self._get_indirect_granted_node_assets(node.id)
assets = self._get_indirect_granted_node_assets(node.id)
else:
return Asset.objects.none()
assets = Asset.objects.none()
assets = assets.order_by('hostname')
return assets
def _get_indirect_granted_node_assets(self, id) -> AssetQuerySet:
assets = Asset.objects.order_by().filter(nodes__id=id).distinct() & self.get_direct_granted_assets()
@@ -538,6 +539,10 @@ class UserGrantedAssetsQueryUtils(UserGrantedUtilsBase):
class UserGrantedNodesQueryUtils(UserGrantedUtilsBase):
def sort(self, nodes):
nodes = sorted(nodes, key=lambda x: x.value)
return nodes
def get_node_children(self, key):
if not key:
return self.get_top_level_nodes()
@@ -545,11 +550,13 @@ class UserGrantedNodesQueryUtils(UserGrantedUtilsBase):
node = PermNode.objects.get(key=key)
granted_status = node.get_granted_status(self.user)
if granted_status == NodeFrom.granted:
return PermNode.objects.filter(parent_key=key)
nodes = PermNode.objects.filter(parent_key=key)
elif granted_status in (NodeFrom.asset, NodeFrom.child):
return self.get_indirect_granted_node_children(key)
nodes = self.get_indirect_granted_node_children(key)
else:
return PermNode.objects.none()
nodes = PermNode.objects.none()
nodes = self.sort(nodes)
return nodes
def get_indirect_granted_node_children(self, key):
"""
@@ -571,7 +578,8 @@ class UserGrantedNodesQueryUtils(UserGrantedUtilsBase):
def get_top_level_nodes(self):
nodes = self.get_special_nodes()
nodes.extend(self.get_indirect_granted_node_children(''))
real_nodes = self.get_indirect_granted_node_children('')
nodes.extend(self.sort(real_nodes))
return nodes
def get_ungrouped_node(self):

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.1 on 2021-03-24 02:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('terminal', '0032_auto_20210302_1853'),
]
operations = [
migrations.AlterField(
model_name='session',
name='login_from',
field=models.CharField(choices=[('ST', 'SSH Terminal'), ('RT', 'RDP Terminal'), ('WT', 'Web Terminal')], default='ST', max_length=2, verbose_name='Login from'),
),
]

View File

@@ -20,6 +20,7 @@ from .terminal import Terminal
class Session(OrgModelMixin):
class LOGIN_FROM(ChoiceSet):
ST = 'ST', 'SSH Terminal'
RT = 'RT', 'RDP Terminal'
WT = 'WT', 'Web Terminal'
class PROTOCOL(ChoiceSet):

View File

@@ -182,7 +182,6 @@ class CommandStorageTypeESSerializer(serializers.Serializer):
)
DOC_TYPE = ReadableHiddenField(default='command', label=_('Doc type'), allow_null=True)
# mapping