Commit 2ecfecb0 authored by ibuler's avatar ibuler

[Update] Merge with dev

parents 2abb9efe e41add61
...@@ -19,25 +19,25 @@ Jumpserver采纳分布式架构,支持多机房跨区域部署,中心节点 ...@@ -19,25 +19,25 @@ Jumpserver采纳分布式架构,支持多机房跨区域部署,中心节点
---- ----
### 功能 ### 功能
![Jumpserver功能](https://jumpserver-release.oss-cn-hangzhou.aliyuncs.com/Jumpserver13.jpg "Jumpserver功能") ![Jumpserver功能](https://jumpserver-release.oss-cn-hangzhou.aliyuncs.com/Jumpserver13.jpg "Jumpserver功能")
### 开始使用 ### 开始使用
快速开始文档 [Docker安装](http://docs.jumpserver.org/zh/latest/quickstart.html) 快速开始文档 [Docker安装](http://docs.jumpserver.org/zh/docs/dockerinstall.html)
一步一步安装文档 [详细部署](http://docs.jumpserver.org/zh/latest/step_by_step.html) 一步一步安装文档 [详细部署](http://docs.jumpserver.org/zh/docs/step_by_step.html)
也可以查看我们完整文档包括了使用和开发 [文档](http://docs.jumpserver.org) 也可以查看我们完整文档包括了使用和开发 [文档](http://docs.jumpserver.org)
### Demo 和 截图 ### Demo 和 截图
我们提供了DEMO和截图可以让你快速了解Jumpserver 我们提供了DEMO和截图可以让你快速了解Jumpserver
[DEMO](http://demo.jumpserver.org) [DEMO](http://demo.jumpserver.org)
[截图](http://docs.jumpserver.org/zh/docs/snapshot.html) [截图](http://docs.jumpserver.org/zh/docs/snapshot.html)
### SDK ### SDK
我们还编写了一些SDK,供你其它系统快速和Jumpserver APi交互, 我们还编写了一些SDK,供你其它系统快速和Jumpserver APi交互,
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
__version__ = "1.3.2" __version__ = "1.3.3"
...@@ -142,7 +142,7 @@ class Asset(OrgModelMixin): ...@@ -142,7 +142,7 @@ class Asset(OrgModelMixin):
return False, warning return False, warning
def is_unixlike(self): def is_unixlike(self):
if self.platform not in ("Windows",): if self.platform not in ("Windows", "Windows2016"):
return True return True
else: else:
return False return False
......
...@@ -53,7 +53,7 @@ class SystemUserAuthSerializer(AuthSerializer): ...@@ -53,7 +53,7 @@ class SystemUserAuthSerializer(AuthSerializer):
model = SystemUser model = SystemUser
fields = [ fields = [
"id", "name", "username", "protocol", "id", "name", "username", "protocol",
"password", "private_key", "login_mode", "password", "private_key",
] ]
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
{% bootstrap_field form.domain layout="horizontal" %} {% bootstrap_field form.domain layout="horizontal" %}
{% block auth %} {% block auth %}
<h3>{% trans 'Auth' %}</h3> <h3 id="auth_title">{% trans 'Auth' %}</h3>
<div class="auth-fields"> <div class="auth-fields">
{% bootstrap_field form.username layout="horizontal" %} {% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.password layout="horizontal" %} {% bootstrap_field form.password layout="horizontal" %}
...@@ -72,14 +72,23 @@ ...@@ -72,14 +72,23 @@
var protocol_id = '#' + '{{ form.protocol.id_for_label }}'; var protocol_id = '#' + '{{ form.protocol.id_for_label }}';
var private_key_id = '#' + '{{ form.private_key_file.id_for_label }}'; var private_key_id = '#' + '{{ form.private_key_file.id_for_label }}';
var port = '#' + '{{ form.port.id_for_label }}'; var port = '#' + '{{ form.port.id_for_label }}';
var username = '#' + '{{ form.username.id_for_label }}';
var password = '#' + '{{ form.password.id_for_label }}';
var auth_title = '#auth_title';
function protocolChange() { function protocolChange() {
if ($(protocol_id + " option:selected").text() === 'rdp') { if ($(protocol_id + " option:selected").text() === 'rdp') {
{#$(port).val(3389);#} {#$(port).val(3389);#}
$(private_key_id).closest('.form-group').addClass('hidden') $(private_key_id).closest('.form-group').addClass('hidden');
$(username).closest('.form-group').addClass('hidden');
$(password).closest('.form-group').addClass('hidden');
$(auth_title).addClass('hidden');
} else { } else {
{#$(port).val(22);#} {#$(port).val(22);#}
$(private_key_id).closest('.form-group').removeClass('hidden') $(private_key_id).closest('.form-group').removeClass('hidden');
$(username).closest('.form-group').removeClass('hidden');
$(password).closest('.form-group').removeClass('hidden');
$(auth_title).removeClass('hidden');
} }
} }
......
...@@ -152,15 +152,14 @@ ...@@ -152,15 +152,14 @@
</span> </span>
</td> </td>
</tr> </tr>
{# <tr>#}
<tr> {# <td width="50%">{% trans 'Clear auth' %}:</td>#}
<td width="50%">{% trans 'Clear auth' %}:</td> {# <td>#}
<td> {# <span style="float: right">#}
<span style="float: right"> {# <button type="button" class="btn btn-primary btn-xs btn-clear-auth" style="width: 54px">{% trans 'Clear' %}</button>#}
<button type="button" class="btn btn-primary btn-xs btn-clear-auth" style="width: 54px">{% trans 'Clear' %}</button> {# </span>#}
</span> {# </td>#}
</td> {# </tr>#}
</tr>
{# <tr>#} {# <tr>#}
{# <td width="50%">{% trans 'Change auth period' %}:</td>#} {# <td width="50%">{% trans 'Change auth period' %}:</td>#}
......
...@@ -50,4 +50,3 @@ urlpatterns = [ ...@@ -50,4 +50,3 @@ urlpatterns = [
url(r'^domain/(?P<pk>[0-9a-zA-Z\-]{36})/gateway/create/$', views.DomainGatewayCreateView.as_view(), name='domain-gateway-create'), url(r'^domain/(?P<pk>[0-9a-zA-Z\-]{36})/gateway/create/$', views.DomainGatewayCreateView.as_view(), name='domain-gateway-create'),
url(r'^domain/gateway/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.DomainGatewayUpdateView.as_view(), name='domain-gateway-update'), url(r'^domain/gateway/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.DomainGatewayUpdateView.as_view(), name='domain-gateway-update'),
] ]
...@@ -92,7 +92,7 @@ class DatetimeSearchMixin: ...@@ -92,7 +92,7 @@ class DatetimeSearchMixin:
date_format = '%Y-%m-%d' date_format = '%Y-%m-%d'
date_from = date_to = None date_from = date_to = None
def get(self, request, *args, **kwargs): def get_date_range(self):
date_from_s = self.request.GET.get('date_from') date_from_s = self.request.GET.get('date_from')
date_to_s = self.request.GET.get('date_to') date_to_s = self.request.GET.get('date_to')
...@@ -112,6 +112,9 @@ class DatetimeSearchMixin: ...@@ -112,6 +112,9 @@ class DatetimeSearchMixin:
) )
else: else:
self.date_to = timezone.now() self.date_to = timezone.now()
def get(self, request, *args, **kwargs):
self.get_date_range()
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
......
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-07-06 13:11+0800\n" "POT-Creation-Date: 2018-07-19 18:29+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
...@@ -32,7 +32,7 @@ msgstr "" ...@@ -32,7 +32,7 @@ msgstr ""
#: assets/forms/asset.py:24 assets/models/asset.py:89 assets/models/user.py:112 #: assets/forms/asset.py:24 assets/models/asset.py:89 assets/models/user.py:112
#: assets/templates/assets/asset_detail.html:183 #: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/asset_detail.html:191 #: assets/templates/assets/asset_detail.html:191
#: assets/templates/assets/system_user_detail.html:179 perms/models.py:33 #: assets/templates/assets/system_user_detail.html:178 perms/models.py:33
msgid "Nodes" msgid "Nodes"
msgstr "节点管理" msgstr "节点管理"
...@@ -101,7 +101,7 @@ msgstr "端口" ...@@ -101,7 +101,7 @@ msgstr "端口"
#: assets/forms/domain.py:14 assets/forms/label.py:13 #: assets/forms/domain.py:14 assets/forms/label.py:13
#: assets/models/asset.py:237 assets/templates/assets/admin_user_list.html:25 #: assets/models/asset.py:237 assets/templates/assets/admin_user_list.html:25
#: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:15 #: assets/templates/assets/domain_list.html:23
#: assets/templates/assets/label_list.html:16 #: assets/templates/assets/label_list.html:16
#: assets/templates/assets/system_user_list.html:30 audits/models.py:11 #: assets/templates/assets/system_user_list.html:30 audits/models.py:11
#: audits/templates/audits/ftp_log_list.html:41 #: audits/templates/audits/ftp_log_list.html:41
...@@ -125,7 +125,7 @@ msgstr "资产" ...@@ -125,7 +125,7 @@ msgstr "资产"
#: assets/templates/assets/admin_user_list.html:23 #: assets/templates/assets/admin_user_list.html:23
#: assets/templates/assets/domain_detail.html:56 #: assets/templates/assets/domain_detail.html:56
#: assets/templates/assets/domain_gateway_list.html:56 #: assets/templates/assets/domain_gateway_list.html:56
#: assets/templates/assets/domain_list.html:14 #: assets/templates/assets/domain_list.html:22
#: assets/templates/assets/label_list.html:14 #: assets/templates/assets/label_list.html:14
#: assets/templates/assets/system_user_detail.html:58 #: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_list.html:26 common/models.py:26 #: assets/templates/assets/system_user_list.html:26 common/models.py:26
...@@ -356,7 +356,7 @@ msgstr "创建日期" ...@@ -356,7 +356,7 @@ msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:125 #: assets/templates/assets/asset_detail.html:125
#: assets/templates/assets/domain_detail.html:76 #: assets/templates/assets/domain_detail.html:76
#: assets/templates/assets/domain_gateway_list.html:61 #: assets/templates/assets/domain_gateway_list.html:61
#: assets/templates/assets/domain_list.html:17 #: assets/templates/assets/domain_list.html:25
#: assets/templates/assets/system_user_detail.html:104 #: assets/templates/assets/system_user_detail.html:104
#: assets/templates/assets/system_user_list.html:34 common/models.py:30 #: assets/templates/assets/system_user_list.html:34 common/models.py:30
#: ops/models/adhoc.py:42 perms/models.py:40 perms/models.py:83 #: ops/models/adhoc.py:42 perms/models.py:40 perms/models.py:83
...@@ -445,7 +445,7 @@ msgstr "默认资产组" ...@@ -445,7 +445,7 @@ msgstr "默认资产组"
#: terminal/templates/terminal/session_list.html:71 users/forms.py:282 #: terminal/templates/terminal/session_list.html:71 users/forms.py:282
#: users/models/user.py:31 users/models/user.py:333 #: users/models/user.py:31 users/models/user.py:333
#: users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:13 users/views/user.py:361 #: users/templates/users/user_group_list.html:13 users/views/user.py:367
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
...@@ -685,6 +685,7 @@ msgstr "重置" ...@@ -685,6 +685,7 @@ msgstr "重置"
#: common/templates/common/security_setting.html:71 #: common/templates/common/security_setting.html:71
#: common/templates/common/terminal_setting.html:108 #: common/templates/common/terminal_setting.html:108
#: perms/templates/perms/asset_permission_create_update.html:70 #: perms/templates/perms/asset_permission_create_update.html:70
#: terminal/templates/terminal/command_list.html:103
#: terminal/templates/terminal/session_list.html:126 #: terminal/templates/terminal/session_list.html:126
#: terminal/templates/terminal/terminal_update.html:48 #: terminal/templates/terminal/terminal_update.html:48
#: users/templates/users/_user.html:47 #: users/templates/users/_user.html:47
...@@ -756,7 +757,7 @@ msgstr "测试" ...@@ -756,7 +757,7 @@ msgstr "测试"
#: assets/templates/assets/domain_detail.html:24 #: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103 #: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:85 #: assets/templates/assets/domain_gateway_list.html:85
#: assets/templates/assets/domain_list.html:42 #: assets/templates/assets/domain_list.html:50
#: assets/templates/assets/label_list.html:38 #: assets/templates/assets/label_list.html:38
#: assets/templates/assets/system_user_detail.html:26 #: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:89 #: assets/templates/assets/system_user_list.html:89
...@@ -780,7 +781,7 @@ msgstr "更新" ...@@ -780,7 +781,7 @@ msgstr "更新"
#: assets/templates/assets/domain_detail.html:28 #: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104 #: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:86 #: assets/templates/assets/domain_gateway_list.html:86
#: assets/templates/assets/domain_list.html:43 #: assets/templates/assets/domain_list.html:51
#: assets/templates/assets/label_list.html:39 #: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:30 #: assets/templates/assets/system_user_detail.html:30
#: assets/templates/assets/system_user_list.html:90 #: assets/templates/assets/system_user_list.html:90
...@@ -808,12 +809,13 @@ msgstr "选择节点" ...@@ -808,12 +809,13 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200 #: assets/templates/assets/asset_detail.html:200
#: assets/templates/assets/asset_list.html:638 #: assets/templates/assets/asset_list.html:638
#: assets/templates/assets/system_user_detail.html:196 #: assets/templates/assets/system_user_detail.html:195
#: assets/templates/assets/system_user_list.html:139 templates/_modal.html:22 #: assets/templates/assets/system_user_list.html:139 templates/_modal.html:22
#: terminal/templates/terminal/session_detail.html:108 #: terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:366 #: users/templates/users/user_detail.html:374
#: users/templates/users/user_detail.html:391 #: users/templates/users/user_detail.html:399
#: users/templates/users/user_detail.html:414 #: users/templates/users/user_detail.html:422
#: users/templates/users/user_detail.html:466
#: users/templates/users/user_group_create_update.html:32 #: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:86 #: users/templates/users/user_group_list.html:86
#: users/templates/users/user_list.html:200 #: users/templates/users/user_list.html:200
...@@ -841,7 +843,7 @@ msgstr "比例" ...@@ -841,7 +843,7 @@ msgstr "比例"
#: assets/templates/assets/admin_user_list.html:30 #: assets/templates/assets/admin_user_list.html:30
#: assets/templates/assets/asset_list.html:91 #: assets/templates/assets/asset_list.html:91
#: assets/templates/assets/domain_gateway_list.html:62 #: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_list.html:18 #: assets/templates/assets/domain_list.html:26
#: assets/templates/assets/label_list.html:17 #: assets/templates/assets/label_list.html:17
#: assets/templates/assets/system_user_list.html:35 #: assets/templates/assets/system_user_list.html:35
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64 #: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
...@@ -905,8 +907,8 @@ msgid "Refresh" ...@@ -905,8 +907,8 @@ msgid "Refresh"
msgstr "刷新" msgstr "刷新"
#: assets/templates/assets/asset_detail.html:300 #: assets/templates/assets/asset_detail.html:300
#: users/templates/users/user_detail.html:286 #: users/templates/users/user_detail.html:294
#: users/templates/users/user_detail.html:313 #: users/templates/users/user_detail.html:321
msgid "Update successfully!" msgid "Update successfully!"
msgstr "更新成功" msgstr "更新成功"
...@@ -1002,8 +1004,9 @@ msgstr "存在资产,不能删除" ...@@ -1002,8 +1004,9 @@ msgstr "存在资产,不能删除"
#: assets/templates/assets/asset_list.html:633 #: assets/templates/assets/asset_list.html:633
#: assets/templates/assets/system_user_list.html:134 #: assets/templates/assets/system_user_list.html:134
#: users/templates/users/user_detail.html:361 #: users/templates/users/user_detail.html:369
#: users/templates/users/user_detail.html:386 #: users/templates/users/user_detail.html:394
#: users/templates/users/user_detail.html:461
#: users/templates/users/user_group_list.html:81 #: users/templates/users/user_group_list.html:81
#: users/templates/users/user_list.html:195 #: users/templates/users/user_list.html:195
msgid "Are you sure?" msgid "Are you sure?"
...@@ -1043,7 +1046,7 @@ msgstr "您确定删除吗?" ...@@ -1043,7 +1046,7 @@ msgstr "您确定删除吗?"
#: assets/templates/assets/domain_detail.html:21 #: assets/templates/assets/domain_detail.html:21
#: assets/templates/assets/domain_detail.html:64 #: assets/templates/assets/domain_detail.html:64
#: assets/templates/assets/domain_gateway_list.html:21 #: assets/templates/assets/domain_gateway_list.html:21
#: assets/templates/assets/domain_list.html:16 #: assets/templates/assets/domain_list.html:24
msgid "Gateway" msgid "Gateway"
msgstr "网关" msgstr "网关"
...@@ -1063,7 +1066,7 @@ msgstr "创建网关" ...@@ -1063,7 +1066,7 @@ msgstr "创建网关"
msgid "Test connection" msgid "Test connection"
msgstr "测试连接" msgstr "测试连接"
#: assets/templates/assets/domain_list.html:6 assets/views/domain.py:46 #: assets/templates/assets/domain_list.html:14 assets/views/domain.py:46
msgid "Create domain" msgid "Create domain"
msgstr "创建网域" msgstr "创建网域"
...@@ -1106,20 +1109,15 @@ msgstr "家目录" ...@@ -1106,20 +1109,15 @@ msgstr "家目录"
msgid "Uid" msgid "Uid"
msgstr "Uid" msgstr "Uid"
#: assets/templates/assets/system_user_detail.html:157 #: assets/templates/assets/system_user_detail.html:186
#: assets/templates/assets/system_user_detail.html:343
msgid "Clear auth"
msgstr "清除认证信息"
#: assets/templates/assets/system_user_detail.html:160
msgid "Clear"
msgstr "清除"
#: assets/templates/assets/system_user_detail.html:187
msgid "Add to node" msgid "Add to node"
msgstr "添加到节点" msgstr "添加到节点"
#: assets/templates/assets/system_user_detail.html:343 #: assets/templates/assets/system_user_detail.html:353
msgid "Clear auth"
msgstr "清除认证信息"
#: assets/templates/assets/system_user_detail.html:353
msgid "success" msgid "success"
msgstr "成功" msgstr "成功"
...@@ -1238,6 +1236,7 @@ msgstr "文件名" ...@@ -1238,6 +1236,7 @@ msgstr "文件名"
#: audits/models.py:15 audits/templates/audits/ftp_log_list.html:77 #: audits/models.py:15 audits/templates/audits/ftp_log_list.html:77
#: ops/templates/ops/task_list.html:39 users/models/authentication.py:66 #: ops/templates/ops/task_list.html:39 users/models/authentication.py:66
#: users/templates/users/user_detail.html:443
msgid "Success" msgid "Success"
msgstr "成功" msgstr "成功"
...@@ -1854,7 +1853,7 @@ msgstr "选择用户" ...@@ -1854,7 +1853,7 @@ msgstr "选择用户"
#: perms/templates/perms/asset_permission_list.html:136 templates/_nav.html:14 #: perms/templates/perms/asset_permission_list.html:136 templates/_nav.html:14
#: users/models/group.py:23 users/models/user.py:55 #: users/models/group.py:23 users/models/user.py:55
#: users/templates/users/_select_user_modal.html:16 #: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:192 #: users/templates/users/user_detail.html:200
#: users/templates/users/user_list.html:26 #: users/templates/users/user_list.html:26
msgid "User group" msgid "User group"
msgstr "用户组" msgstr "用户组"
...@@ -1907,7 +1906,7 @@ msgid "Add node to this permission" ...@@ -1907,7 +1906,7 @@ msgid "Add node to this permission"
msgstr "添加节点" msgstr "添加节点"
#: perms/templates/perms/asset_permission_asset.html:125 #: perms/templates/perms/asset_permission_asset.html:125
#: users/templates/users/user_detail.html:209 #: users/templates/users/user_detail.html:217
msgid "Join" msgid "Join"
msgstr "加入" msgstr "加入"
...@@ -2004,7 +2003,7 @@ msgstr "文档" ...@@ -2004,7 +2003,7 @@ msgstr "文档"
#: users/templates/users/user_profile.html:17 #: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37 #: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57 #: users/templates/users/user_profile_update.html:57
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:343 #: users/templates/users/user_pubkey_update.html:37 users/views/user.py:349
msgid "Profile" msgid "Profile"
msgstr "个人信息" msgstr "个人信息"
...@@ -2061,13 +2060,13 @@ msgstr "关闭" ...@@ -2061,13 +2060,13 @@ msgstr "关闭"
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44 #: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44
#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95 #: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95
#: users/views/login.py:330 users/views/login.py:388 users/views/user.py:65 #: users/views/login.py:332 users/views/login.py:390 users/views/user.py:67
#: users/views/user.py:80 users/views/user.py:102 users/views/user.py:175 #: users/views/user.py:82 users/views/user.py:104 users/views/user.py:180
#: users/views/user.py:330 users/views/user.py:380 users/views/user.py:415 #: users/views/user.py:336 users/views/user.py:386 users/views/user.py:421
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: templates/_nav.html:13 users/views/user.py:66 #: templates/_nav.html:13 users/views/user.py:68
msgid "User list" msgid "User list"
msgstr "用户列表" msgstr "用户列表"
...@@ -2095,7 +2094,7 @@ msgstr "命令记录" ...@@ -2095,7 +2094,7 @@ msgstr "命令记录"
msgid "Web terminal" msgid "Web terminal"
msgstr "Web终端" msgstr "Web终端"
#: templates/_nav.html:51 terminal/views/command.py:47 #: templates/_nav.html:51 terminal/views/command.py:49
#: terminal/views/session.py:75 terminal/views/session.py:93 #: terminal/views/session.py:75 terminal/views/session.py:93
#: terminal/views/session.py:115 terminal/views/terminal.py:31 #: terminal/views/session.py:115 terminal/views/terminal.py:31
#: terminal/views/terminal.py:46 terminal/views/terminal.py:58 #: terminal/views/terminal.py:46 terminal/views/terminal.py:58
...@@ -2204,13 +2203,17 @@ msgstr "参数" ...@@ -2204,13 +2203,17 @@ msgstr "参数"
msgid "Goto" msgid "Goto"
msgstr "转到" msgstr "转到"
#: terminal/templates/terminal/command_list.html:99
msgid "Export command"
msgstr "导出命令"
#: terminal/templates/terminal/session_detail.html:17 #: terminal/templates/terminal/session_detail.html:17
#: terminal/views/session.py:116 #: terminal/views/session.py:116
msgid "Session detail" msgid "Session detail"
msgstr "会话详情" msgstr "会话详情"
#: terminal/templates/terminal/session_detail.html:28 #: terminal/templates/terminal/session_detail.html:28
#: terminal/views/command.py:48 #: terminal/views/command.py:50
msgid "Command list" msgid "Command list"
msgstr "命令记录列表" msgstr "命令记录列表"
...@@ -2326,7 +2329,7 @@ msgid "" ...@@ -2326,7 +2329,7 @@ msgid ""
"You should use your ssh client tools connect terminal: {} <br /> <br />{}" "You should use your ssh client tools connect terminal: {} <br /> <br />{}"
msgstr "你可以使用ssh客户端工具连接终端" msgstr "你可以使用ssh客户端工具连接终端"
#: users/api.py:208 users/templates/users/login.html:50 #: users/api.py:226 users/templates/users/login.html:50
msgid "Log in frequently and try again later" msgid "Log in frequently and try again later"
msgstr "登录频繁, 稍后重试" msgstr "登录频繁, 稍后重试"
...@@ -2405,7 +2408,7 @@ msgstr "" ...@@ -2405,7 +2408,7 @@ msgstr ""
msgid "Paste user id_rsa.pub here." msgid "Paste user id_rsa.pub here."
msgstr "复制用户公钥到这里" msgstr "复制用户公钥到这里"
#: users/forms.py:73 users/templates/users/user_detail.html:200 #: users/forms.py:73 users/templates/users/user_detail.html:208
msgid "Join user groups" msgid "Join user groups"
msgstr "添加到用户组" msgstr "添加到用户组"
...@@ -2701,7 +2704,7 @@ msgid "Can't provide security? Please contact the administrator!" ...@@ -2701,7 +2704,7 @@ msgid "Can't provide security? Please contact the administrator!"
msgstr "如果不能提供MFA验证码,请联系管理员!" msgstr "如果不能提供MFA验证码,请联系管理员!"
#: users/templates/users/reset_password.html:46 #: users/templates/users/reset_password.html:46
#: users/templates/users/user_detail.html:352 users/utils.py:80 #: users/templates/users/user_detail.html:360 users/utils.py:80
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
...@@ -2727,7 +2730,7 @@ msgid "Setting" ...@@ -2727,7 +2730,7 @@ msgid "Setting"
msgstr "设置" msgstr "设置"
#: users/templates/users/user_create.html:4 #: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:16 users/views/user.py:80 #: users/templates/users/user_list.html:16 users/views/user.py:82
msgid "Create user" msgid "Create user"
msgstr "创建用户" msgstr "创建用户"
...@@ -2736,7 +2739,7 @@ msgid "Reset link will be generated and sent to the user. " ...@@ -2736,7 +2739,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户" msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19 #: users/templates/users/user_detail.html:19
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:176 #: users/templates/users/user_granted_asset.html:18 users/views/user.py:181
msgid "User detail" msgid "User detail"
msgstr "用户详情" msgstr "用户详情"
...@@ -2773,44 +2776,57 @@ msgstr "发送" ...@@ -2773,44 +2776,57 @@ msgstr "发送"
msgid "Send reset ssh key mail" msgid "Send reset ssh key mail"
msgstr "发送重置密钥邮件" msgstr "发送重置密钥邮件"
#: users/templates/users/user_detail.html:295 #: users/templates/users/user_detail.html:186
#: users/templates/users/user_detail.html:446
msgid "Unblock user"
msgstr "解除登录限制"
#: users/templates/users/user_detail.html:189
msgid "Unblock"
msgstr "解除"
#: users/templates/users/user_detail.html:303
msgid "Goto profile page enable MFA" msgid "Goto profile page enable MFA"
msgstr "请去个人信息页面启用自己的MFA" msgstr "请去个人信息页面启用自己的MFA"
#: users/templates/users/user_detail.html:351 #: users/templates/users/user_detail.html:359
msgid "An e-mail has been sent to the user`s mailbox." msgid "An e-mail has been sent to the user`s mailbox."
msgstr "已发送邮件到用户邮箱" msgstr "已发送邮件到用户邮箱"
#: users/templates/users/user_detail.html:362 #: users/templates/users/user_detail.html:370
msgid "This will reset the user password and send a reset mail" msgid "This will reset the user password and send a reset mail"
msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱" msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱"
#: users/templates/users/user_detail.html:376 #: users/templates/users/user_detail.html:384
msgid "" msgid ""
"The reset-ssh-public-key E-mail has been sent successfully. Please inform " "The reset-ssh-public-key E-mail has been sent successfully. Please inform "
"the user to update his new ssh public key." "the user to update his new ssh public key."
msgstr "重设密钥邮件将会发送到用户邮箱" msgstr "重设密钥邮件将会发送到用户邮箱"
#: users/templates/users/user_detail.html:377 #: users/templates/users/user_detail.html:385
msgid "Reset SSH public key" msgid "Reset SSH public key"
msgstr "重置SSH密钥" msgstr "重置SSH密钥"
#: users/templates/users/user_detail.html:387 #: users/templates/users/user_detail.html:395
msgid "This will reset the user public key and send a reset mail" msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱" msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
#: users/templates/users/user_detail.html:404 #: users/templates/users/user_detail.html:412
#: users/templates/users/user_profile.html:211 #: users/templates/users/user_profile.html:211
msgid "Successfully updated the SSH public key." msgid "Successfully updated the SSH public key."
msgstr "更新ssh密钥成功" msgstr "更新ssh密钥成功"
#: users/templates/users/user_detail.html:405 #: users/templates/users/user_detail.html:413
#: users/templates/users/user_detail.html:409 #: users/templates/users/user_detail.html:417
#: users/templates/users/user_profile.html:212 #: users/templates/users/user_profile.html:212
#: users/templates/users/user_profile.html:217 #: users/templates/users/user_profile.html:217
msgid "User SSH public key update" msgid "User SSH public key update"
msgstr "ssh密钥" msgstr "ssh密钥"
#: users/templates/users/user_detail.html:462
msgid "After unlocking the user, the user can log in normally."
msgstr "解除用户登录限制后,此用户即可正常登录"
#: users/templates/users/user_group_create_update.html:31 #: users/templates/users/user_group_create_update.html:31
msgid "Cancel" msgid "Cancel"
msgstr "取消" msgstr "取消"
...@@ -2867,8 +2883,8 @@ msgstr "用户删除失败" ...@@ -2867,8 +2883,8 @@ msgstr "用户删除失败"
msgid "Administrator Settings force MFA login" msgid "Administrator Settings force MFA login"
msgstr "管理员设置强制使用MFA登录" msgstr "管理员设置强制使用MFA登录"
#: users/templates/users/user_profile.html:116 users/views/user.py:205 #: users/templates/users/user_profile.html:116 users/views/user.py:211
#: users/views/user.py:259 #: users/views/user.py:265
msgid "User groups" msgid "User groups"
msgstr "用户组" msgstr "用户组"
...@@ -2914,7 +2930,7 @@ msgid "" ...@@ -2914,7 +2930,7 @@ msgid ""
"corresponding private key." "corresponding private key."
msgstr "新的公钥已设置成功,请下载对应的私钥" msgstr "新的公钥已设置成功,请下载对应的私钥"
#: users/templates/users/user_update.html:4 users/views/user.py:103 #: users/templates/users/user_update.html:4 users/views/user.py:105
msgid "Update user" msgid "Update user"
msgstr "更新用户" msgstr "更新用户"
...@@ -3068,106 +3084,112 @@ msgstr "更新用户组" ...@@ -3068,106 +3084,112 @@ msgstr "更新用户组"
msgid "User group granted asset" msgid "User group granted asset"
msgstr "用户组授权资产" msgstr "用户组授权资产"
#: users/views/login.py:75 #: users/views/login.py:76
msgid "Please enable cookies and try again." msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie" msgstr "设置你的浏览器支持cookie"
#: users/views/login.py:178 users/views/user.py:500 users/views/user.py:525 #: users/views/login.py:180 users/views/user.py:506 users/views/user.py:531
msgid "MFA code invalid" msgid "MFA code invalid"
msgstr "MFA码认证失败" msgstr "MFA码认证失败"
#: users/views/login.py:207 #: users/views/login.py:209
msgid "Logout success" msgid "Logout success"
msgstr "退出登录成功" msgstr "退出登录成功"
#: users/views/login.py:208 #: users/views/login.py:210
msgid "Logout success, return login page" msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面" msgstr "退出登录成功,返回到登录页面"
#: users/views/login.py:224 #: users/views/login.py:226
msgid "Email address invalid, please input again" msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入" msgstr "邮箱地址错误,重新输入"
#: users/views/login.py:237 #: users/views/login.py:239
msgid "Send reset password message" msgid "Send reset password message"
msgstr "发送重置密码邮件" msgstr "发送重置密码邮件"
#: users/views/login.py:238 #: users/views/login.py:240
msgid "Send reset password mail success, login your mail box and follow it " msgid "Send reset password mail success, login your mail box and follow it "
msgstr "" msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" "发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views/login.py:251 #: users/views/login.py:253
msgid "Reset password success" msgid "Reset password success"
msgstr "重置密码成功" msgstr "重置密码成功"
#: users/views/login.py:252 #: users/views/login.py:254
msgid "Reset password success, return to login page" msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面" msgstr "重置密码成功,返回到登录页面"
#: users/views/login.py:273 users/views/login.py:286 #: users/views/login.py:275 users/views/login.py:288
msgid "Token invalid or expired" msgid "Token invalid or expired"
msgstr "Token错误或失效" msgstr "Token错误或失效"
#: users/views/login.py:282 #: users/views/login.py:284
msgid "Password not same" msgid "Password not same"
msgstr "密码不一致" msgstr "密码不一致"
#: users/views/login.py:292 users/views/user.py:118 users/views/user.py:398 #: users/views/login.py:294 users/views/user.py:120 users/views/user.py:404
msgid "* Your password does not meet the requirements" msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求" msgstr "* 您的密码不符合要求"
#: users/views/login.py:330 #: users/views/login.py:332
msgid "First login" msgid "First login"
msgstr "首次登陆" msgstr "首次登陆"
#: users/views/login.py:389 #: users/views/login.py:391
msgid "Login log list" msgid "Login log list"
msgstr "登录日志" msgstr "登录日志"
#: users/views/user.py:129 #: users/views/user.py:131
msgid "Bulk update user success" msgid "Bulk update user success"
msgstr "批量更新用户成功" msgstr "批量更新用户成功"
#: users/views/user.py:234 #: users/views/user.py:240
msgid "Invalid file." msgid "Invalid file."
msgstr "文件不合法" msgstr "文件不合法"
#: users/views/user.py:331 #: users/views/user.py:337
msgid "User granted assets" msgid "User granted assets"
msgstr "用户授权资产" msgstr "用户授权资产"
#: users/views/user.py:362 #: users/views/user.py:368
msgid "Profile setting" msgid "Profile setting"
msgstr "个人信息设置" msgstr "个人信息设置"
#: users/views/user.py:381 #: users/views/user.py:387
msgid "Password update" msgid "Password update"
msgstr "密码更新" msgstr "密码更新"
#: users/views/user.py:416 #: users/views/user.py:422
msgid "Public key update" msgid "Public key update"
msgstr "密钥更新" msgstr "密钥更新"
#: users/views/user.py:457 #: users/views/user.py:463
msgid "Password invalid" msgid "Password invalid"
msgstr "用户名或密码无效" msgstr "用户名或密码无效"
#: users/views/user.py:551 #: users/views/user.py:557
msgid "MFA enable success" msgid "MFA enable success"
msgstr "MFA 绑定成功" msgstr "MFA 绑定成功"
#: users/views/user.py:552 #: users/views/user.py:558
msgid "MFA enable success, return login page" msgid "MFA enable success, return login page"
msgstr "MFA 绑定成功,返回到登录页面" msgstr "MFA 绑定成功,返回到登录页面"
#: users/views/user.py:554 #: users/views/user.py:560
msgid "MFA disable success" msgid "MFA disable success"
msgstr "MFA 解绑成功" msgstr "MFA 解绑成功"
#: users/views/user.py:555 #: users/views/user.py:561
msgid "MFA disable success, return login page" msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面" msgstr "MFA 解绑成功,返回登录页面"
#~ msgid "Unblock user successfully. "
#~ msgstr "解除登录限制成功"
#~ msgid "Clear"
#~ msgstr "清除"
#~ msgid "MFA setting" #~ msgid "MFA setting"
#~ msgstr "MFA 设置" #~ msgstr "MFA 设置"
...@@ -341,6 +341,7 @@ AUTH_LDAP_GROUP_SEARCH = LDAPSearch( ...@@ -341,6 +341,7 @@ AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
AUTH_LDAP_CONNECTION_OPTIONS = { AUTH_LDAP_CONNECTION_OPTIONS = {
ldap.OPT_TIMEOUT: 5 ldap.OPT_TIMEOUT: 5
} }
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 1
AUTH_LDAP_ALWAYS_UPDATE_USER = True AUTH_LDAP_ALWAYS_UPDATE_USER = True
AUTH_LDAP_BACKEND = 'django_auth_ldap.backend.LDAPBackend' AUTH_LDAP_BACKEND = 'django_auth_ldap.backend.LDAPBackend'
......
...@@ -10,6 +10,7 @@ from users.models import User ...@@ -10,6 +10,7 @@ from users.models import User
from assets.models import Asset from assets.models import Asset
from terminal.models import Session from terminal.models import Session
from common.permissions import AdminUserRequiredMixin from common.permissions import AdminUserRequiredMixin
from orgs.utils import current_org
class IndexView(AdminUserRequiredMixin, TemplateView): class IndexView(AdminUserRequiredMixin, TemplateView):
...@@ -27,7 +28,7 @@ class IndexView(AdminUserRequiredMixin, TemplateView): ...@@ -27,7 +28,7 @@ class IndexView(AdminUserRequiredMixin, TemplateView):
@staticmethod @staticmethod
def get_user_count(): def get_user_count():
return User.objects.filter(role__in=('Admin', 'User')).count() return current_org.get_org_users().count()
@staticmethod @staticmethod
def get_asset_count(): def get_asset_count():
...@@ -49,7 +50,6 @@ class IndexView(AdminUserRequiredMixin, TemplateView): ...@@ -49,7 +50,6 @@ class IndexView(AdminUserRequiredMixin, TemplateView):
def get_week_login_asset_count(self): def get_week_login_asset_count(self):
return self.session_week.count() return self.session_week.count()
# return self.session_week.values('asset').distinct().count()
def get_month_day_metrics(self): def get_month_day_metrics(self):
month_str = [d.strftime('%m-%d') for d in self.session_month_dates] or ['0'] month_str = [d.strftime('%m-%d') for d in self.session_month_dates] or ['0']
......
...@@ -55,9 +55,11 @@ class Organization(models.Model): ...@@ -55,9 +55,11 @@ class Organization(models.Model):
def get_org_users(self): def get_org_users(self):
from users.models import User from users.models import User
if self.is_default(): if self.is_default():
return User.objects.filter(orgs__isnull=True) users = User.objects.filter(orgs__isnull=True)
else: else:
return self.users.all() users = self.users.all()
users = users.exclude(role=User.ROLE_APP)
return users
def get_org_admins(self): def get_org_admins(self):
if self.is_real(): if self.is_real():
......
...@@ -5,6 +5,7 @@ from django.shortcuts import get_object_or_404 ...@@ -5,6 +5,7 @@ from django.shortcuts import get_object_or_404
from rest_framework.views import APIView, Response from rest_framework.views import APIView, Response
from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.pagination import LimitOffsetPagination
from common.utils import set_or_append_attr_bulk, get_object_or_none from common.utils import set_or_append_attr_bulk, get_object_or_none
from common.permissions import IsValidUser, IsOrgAdmin, IsOrgAdminOrAppUser from common.permissions import IsValidUser, IsOrgAdmin, IsOrgAdminOrAppUser
...@@ -72,10 +73,7 @@ class UserGrantedAssetsApi(ListAPIView): ...@@ -72,10 +73,7 @@ class UserGrantedAssetsApi(ListAPIView):
util = AssetPermissionUtil(user) util = AssetPermissionUtil(user)
for k, v in util.get_assets().items(): for k, v in util.get_assets().items():
if k.is_unixlike(): system_users_granted = [s for s in v if s.protocol == k.protocol]
system_users_granted = [s for s in v if s.protocol in ['ssh', 'telnet']]
else:
system_users_granted = [s for s in v if s.protocol in ['rdp', 'telnet']]
k.system_users_granted = system_users_granted k.system_users_granted = system_users_granted
queryset.append(k) queryset.append(k)
return queryset return queryset
...@@ -123,10 +121,7 @@ class UserGrantedNodesWithAssetsApi(ListAPIView): ...@@ -123,10 +121,7 @@ class UserGrantedNodesWithAssetsApi(ListAPIView):
for node, _assets in nodes.items(): for node, _assets in nodes.items():
assets = _assets.keys() assets = _assets.keys()
for k, v in _assets.items(): for k, v in _assets.items():
if k.is_unixlike(): system_users_granted = [s for s in v if s.protocol == k.protocol]
system_users_granted = [s for s in v if s.protocol in ['ssh', 'telnet']]
else:
system_users_granted = [s for s in v if s.protocol in ['rdp', 'telnet']]
k.system_users_granted = system_users_granted k.system_users_granted = system_users_granted
node.assets_granted = assets node.assets_granted = assets
queryset.append(node) queryset.append(node)
......
...@@ -6,13 +6,11 @@ from .. import views ...@@ -6,13 +6,11 @@ from .. import views
app_name = 'perms' app_name = 'perms'
urlpatterns = [ urlpatterns = [
url(r'^asset-permission$', views.AssetPermissionListView.as_view(), name='asset-permission-list'), url(r'^asset-permission/$', views.AssetPermissionListView.as_view(), name='asset-permission-list'),
url(r'^asset-permission/create$', views.AssetPermissionCreateView.as_view(), name='asset-permission-create'), url(r'^asset-permission/create/$', views.AssetPermissionCreateView.as_view(), name='asset-permission-create'),
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/update$', views.AssetPermissionUpdateView.as_view(), name='asset-permission-update'), url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.AssetPermissionUpdateView.as_view(), name='asset-permission-update'),
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'), url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'),
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/delete$', views.AssetPermissionDeleteView.as_view(), name='asset-permission-delete'), url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/delete/$', views.AssetPermissionDeleteView.as_view(), name='asset-permission-delete'),
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'), url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user/$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'),
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'), url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset/$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'),
] ]
<div class="footer fixed"> <div class="footer fixed">
<div class="pull-right"> <div class="pull-right">
Version <strong>1.3.2-{% include '_build.html' %}</strong> GPLv2. Version <strong>1.3.3-{% include '_build.html' %}</strong> GPLv2.
<!--<img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg">--> <!--<img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg">-->
</div> </div>
<div> <div>
......
...@@ -4,6 +4,7 @@ from collections import OrderedDict ...@@ -4,6 +4,7 @@ from collections import OrderedDict
import logging import logging
import os import os
import uuid import uuid
import copy
from django.core.cache import cache from django.core.cache import cache
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
...@@ -310,6 +311,7 @@ class SessionReplayViewSet(viewsets.ViewSet): ...@@ -310,6 +311,7 @@ class SessionReplayViewSet(viewsets.ViewSet):
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
session_id = kwargs.get('pk') session_id = kwargs.get('pk')
self.session = get_object_or_404(Session, id=session_id) self.session = get_object_or_404(Session, id=session_id)
# 新版本和老版本的文件后缀不同 # 新版本和老版本的文件后缀不同
session_path = self.get_session_path() # 存在外部存储上的路径 session_path = self.get_session_path() # 存在外部存储上的路径
local_path = self.get_local_path() local_path = self.get_local_path()
......
...@@ -92,27 +92,52 @@ ...@@ -92,27 +92,52 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<div id="actions" class="">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="export">{% trans 'Export command' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script> <script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script> <script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$('.footable').footable(); $('.footable').footable();
$('.select2').select2({ $('.select2').select2({
dropdownAutoWidth : true, dropdownAutoWidth : true,
width: 'auto' width: 'auto'
}); });
$('#date .input-daterange').datepicker({ $('#date .input-daterange').datepicker({
format: "yyyy-mm-dd", format: "yyyy-mm-dd",
todayBtn: "linked", todayBtn: "linked",
keyboardNavigation: false, keyboardNavigation: false,
forceParse: false, forceParse: false,
calendarWeeks: true, calendarWeeks: true,
autoclose: true autoclose: true
});
}); });
})
.on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var param_action = '&action=' + action;
var local_params = window.location.search;
if(!local_params){
param_action = '?action=' + action;
}
var params = local_params + param_action;
var pathname = window.location.pathname + 'export/';
var url = pathname + params;
window.open(url);
});
</script> </script>
{% endblock %} {% endblock %}
......
{% load common_tags %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Command Report</title>
<style>
*{
margin: 0;
padding: 0;
}
.background {
background-color: #535659;
padding-top: 50px;
padding-bottom: 50px;
}
.paper {
margin-left: 23%;
margin-right: 24%;
border: solid;
padding: 50px;
background-color: #fff;
}
h2 {
font-style: italic;
text-align: center;
}
.info {
width: 200px;
margin-left: 450px;
font-style: italic;
text-align: left;
padding-top: 20px;
padding-bottom: 20px;
}
.command {
margin-left: 10px;
}
.command-desc {
font-size: 12px;
}
.command-desc span {
float: right;
}
.command-input {
{#font-style: italic;#}
font-size: 15px;
margin-top: 10px;
margin-bottom: 10px;
}
.command-input span {
font-size: 13px;
}
.hr-line-dashed {
border-top: 1px dashed #000;
color: #000;
background-color: #fff;
height: 1px;
margin: 20px 0;
}
pre {
font-size: 12px;
}
</style>
</head>
<body>
<div class="background">
<div class="paper">
<h2>Command Report</h2>
<div class="info">
<p>total: {{ total_count }}</p>
<p>date: {{ now | ts_to_date }}</p>
</div>
<div class="hr-line-dashed"></div>
<div>
{% for command in queryset %}
<div class="command">
<p class="command-desc">
[{{ command.user}} {{ command.system_user }}@{{ command.asset }} {{ command.timestamp | ts_to_date }}]
<span>{{ forloop.counter }}</span>
</p>
<p class="command-input"><span>$ </span>{{ command.input }}</p>
<pre>{{ command.output }}</pre>
</div>
<div class="hr-line-dashed"></div>
{% endfor %}
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
...@@ -24,5 +24,6 @@ urlpatterns = [ ...@@ -24,5 +24,6 @@ urlpatterns = [
# Command view # Command view
url(r'^command/$', views.CommandListView.as_view(), name='command-list'), url(r'^command/$', views.CommandListView.as_view(), name='command-list'),
url(r'^command/export/$', views.CommandExportView.as_view(), name='command-export')
] ]
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.views.generic import ListView from django.views.generic import ListView, View
from django.conf import settings from django.conf import settings
from django.utils import timezone
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.http import HttpResponse
from django.template import loader
import time
from common.mixins import DatetimeSearchMixin from common.mixins import DatetimeSearchMixin
from common.permissions import AdminUserRequiredMixin from common.permissions import AdminUserRequiredMixin
...@@ -12,7 +14,7 @@ from ..models import Command ...@@ -12,7 +14,7 @@ from ..models import Command
from .. import utils from .. import utils
from ..backends import get_multi_command_storage from ..backends import get_multi_command_storage
__all__ = ['CommandListView'] __all__ = ['CommandListView', 'CommandExportView']
common_storage = get_multi_command_storage() common_storage = get_multi_command_storage()
...@@ -61,7 +63,43 @@ class CommandListView(DatetimeSearchMixin, AdminUserRequiredMixin, ListView): ...@@ -61,7 +63,43 @@ class CommandListView(DatetimeSearchMixin, AdminUserRequiredMixin, ListView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class CommandExportView(DatetimeSearchMixin, AdminUserRequiredMixin, View):
model = Command
command = user = asset = system_user = action = ''
date_from = date_to = None
def get(self, request, *args, **kwargs):
queryset = self.get_queryset()
template = 'terminal/command_report.html'
context = {
'queryset': queryset,
'total_count': len(queryset),
'now': time.time(),
}
content = loader.render_to_string(template, context, request)
content_type = 'application/octet-stream'
response = HttpResponse(content, content_type)
filename = 'command-report-{}.html'.format(int(time.time()))
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
return response
def get_queryset(self):
self.get_date_range()
self.action = self.request.GET.get('action', '')
self.command = self.request.GET.get('command', '')
self.user = self.request.GET.get("user", '')
self.asset = self.request.GET.get('asset', '')
self.system_user = self.request.GET.get('system_user', '')
filter_kwargs = dict()
filter_kwargs['date_from'] = self.date_from
filter_kwargs['date_to'] = self.date_to
if self.user:
filter_kwargs['user'] = self.user
if self.asset:
filter_kwargs['asset'] = self.asset
if self.system_user:
filter_kwargs['system_user'] = self.system_user
if self.command:
filter_kwargs['input'] = self.command
queryset = common_storage.filter(**filter_kwargs)
return queryset
...@@ -101,7 +101,23 @@ class UserUpdatePKApi(generics.UpdateAPIView): ...@@ -101,7 +101,23 @@ class UserUpdatePKApi(generics.UpdateAPIView):
user.save() user.save()
class UserGroupViewSet(BulkModelViewSet): class UserUnblockPKApi(generics.UpdateAPIView):
queryset = User.objects.all()
permission_classes = (IsSuperUser,)
serializer_class = UserSerializer
key_prefix_limit = "_LOGIN_LIMIT_{}_{}"
key_prefix_block = "_LOGIN_BLOCK_{}"
def perform_update(self, serializer):
user = self.get_object()
username = user.username if user else ''
key_limit = self.key_prefix_limit.format(username, '*')
key_block = self.key_prefix_block.format(username)
cache.delete_pattern(key_limit)
cache.delete(key_block)
class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
queryset = UserGroup.objects.all() queryset = UserGroup.objects.all()
serializer_class = UserGroupSerializer serializer_class = UserGroupSerializer
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
...@@ -203,13 +219,15 @@ class UserAuthApi(APIView): ...@@ -203,13 +219,15 @@ class UserAuthApi(APIView):
permission_classes = (AllowAny,) permission_classes = (AllowAny,)
serializer_class = UserSerializer serializer_class = UserSerializer
key_prefix_limit = "_LOGIN_LIMIT_{}_{}" key_prefix_limit = "_LOGIN_LIMIT_{}_{}"
key_prefix_block = "_LOGIN_BLOCK_{}"
def post(self, request): def post(self, request):
# limit login # limit login
username = request.data.get('username') username = request.data.get('username')
ip = request.data.get('remote_addr', None) ip = request.data.get('remote_addr', None)
ip = ip if ip else get_login_ip(request) ip = ip if ip else get_login_ip(request)
key_limit = self.key_prefix_limit.format(ip, username) key_limit = self.key_prefix_limit.format(username, ip)
key_block = self.key_prefix_block.format(username)
if is_block_login(key_limit): if is_block_login(key_limit):
msg = _("Log in frequently and try again later") msg = _("Log in frequently and try again later")
return Response({'msg': msg}, status=401) return Response({'msg': msg}, status=401)
...@@ -224,7 +242,7 @@ class UserAuthApi(APIView): ...@@ -224,7 +242,7 @@ class UserAuthApi(APIView):
} }
self.write_login_log(request, data) self.write_login_log(request, data)
set_user_login_failed_count_to_cache(key_limit) set_user_login_failed_count_to_cache(key_limit, key_block)
return Response({'msg': msg}, status=401) return Response({'msg': msg}, status=401)
if not user.otp_enabled: if not user.otp_enabled:
......
...@@ -182,6 +182,14 @@ ...@@ -182,6 +182,14 @@
</span> </span>
</td> </td>
</tr> </tr>
<tr style="{% if not unblock %}display:none{% endif %}">
<td>{% trans 'Unblock user' %}</td>
<td>
<span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" id="btn-unblock-user" style="width: 54px">{% trans 'Unblock' %}</button>
</span>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
...@@ -275,7 +283,7 @@ $(document).ready(function() { ...@@ -275,7 +283,7 @@ $(document).ready(function() {
.on('select2:unselect', function(evt) { .on('select2:unselect', function(evt) {
var data = evt.params.data; var data = evt.params.data;
delete jumpserver.nodes_selected[data.id]; delete jumpserver.nodes_selected[data.id];
}) });
}) })
.on('click', '#is_active', function() { .on('click', '#is_active', function() {
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}"; var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
...@@ -293,7 +301,7 @@ $(document).ready(function() { ...@@ -293,7 +301,7 @@ $(document).ready(function() {
.on('click', '#force_enable_otp', function() { .on('click', '#force_enable_otp', function() {
{% if request.user == user_object %} {% if request.user == user_object %}
toastr.error("{% trans 'Goto profile page enable MFA' %}"); toastr.error("{% trans 'Goto profile page enable MFA' %}");
return return;
{% endif %} {% endif %}
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}"; var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
...@@ -426,6 +434,40 @@ $(document).ready(function() { ...@@ -426,6 +434,40 @@ $(document).ready(function() {
var the_url = '{% url "api-users:user-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid); var the_url = '{% url "api-users:user-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
var redirect_url = "{% url 'users:user-list' %}"; var redirect_url = "{% url 'users:user-list' %}";
objectDelete($this, name, the_url, redirect_url); objectDelete($this, name, the_url, redirect_url);
}).on('click', '#btn-unblock-user', function () {
function doReset() {
{#var the_url = '{% url "api-users:user-reset-password" pk=user_object.id %}';#}
var the_url = '{% url "api-users:user-unblock" pk=user_object.id %}';
var body = {};
var success = function() {
var msg = "{% trans "Success" %}";
{#swal("{% trans 'Unblock user' %}", msg, "success");#}
swal({
title: "{% trans 'Unblock user' %}",
text: msg,
type: "success"
}, function() {
location.reload()
}
);
};
APIUpdateAttr({
url: the_url,
body: JSON.stringify(body),
success: success
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans "After unlocking the user, the user can log in normally."%}",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doReset();
});
}) })
</script> </script>
{% endblock %} {% endblock %}
...@@ -59,7 +59,7 @@ function initTable() { ...@@ -59,7 +59,7 @@ function initTable() {
ele: $('#user_list_table'), ele: $('#user_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "users:user-detail" pk=DEFAULT_PK %}">' + escape(cellData) + '</a>'; var detail_btn = '<a href="{% url "users:user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace("{{ DEFAULT_PK }}", rowData.id)); $(td).html(detail_btn.replace("{{ DEFAULT_PK }}", rowData.id));
}}, }},
{targets: 4, createdCell: function (td, cellData) { {targets: 4, createdCell: function (td, cellData) {
......
...@@ -29,6 +29,8 @@ urlpatterns = [ ...@@ -29,6 +29,8 @@ urlpatterns = [
api.UserResetPKApi.as_view(), name='user-public-key-reset'), api.UserResetPKApi.as_view(), name='user-public-key-reset'),
url(r'^users/(?P<pk>[0-9a-zA-Z\-]{36})/pubkey/update/$', url(r'^users/(?P<pk>[0-9a-zA-Z\-]{36})/pubkey/update/$',
api.UserUpdatePKApi.as_view(), name='user-public-key-update'), api.UserUpdatePKApi.as_view(), name='user-public-key-update'),
url(r'^users/(?P<pk>[0-9a-zA-Z\-]{36})/unblock/$',
api.UserUnblockPKApi.as_view(), name='user-unblock'),
url(r'^users/(?P<pk>[0-9a-zA-Z\-]{36})/groups/$', url(r'^users/(?P<pk>[0-9a-zA-Z\-]{36})/groups/$',
api.UserUpdateGroupApi.as_view(), name='user-update-group'), api.UserUpdateGroupApi.as_view(), name='user-update-group'),
url(r'^groups/(?P<pk>[0-9a-zA-Z\-]{36})/users/$', url(r'^groups/(?P<pk>[0-9a-zA-Z\-]{36})/users/$',
......
...@@ -8,13 +8,13 @@ app_name = 'users' ...@@ -8,13 +8,13 @@ app_name = 'users'
urlpatterns = [ urlpatterns = [
# Login view # Login view
url(r'^login$', views.UserLoginView.as_view(), name='login'), url(r'^login/$', views.UserLoginView.as_view(), name='login'),
url(r'^logout$', views.UserLogoutView.as_view(), name='logout'), url(r'^logout/$', views.UserLogoutView.as_view(), name='logout'),
url(r'^login/otp$', views.UserLoginOtpView.as_view(), name='login-otp'), url(r'^login/otp/$', views.UserLoginOtpView.as_view(), name='login-otp'),
url(r'^password/forgot$', views.UserForgotPasswordView.as_view(), name='forgot-password'), url(r'^password/forgot/$', views.UserForgotPasswordView.as_view(), name='forgot-password'),
url(r'^password/forgot/sendmail-success$', views.UserForgotPasswordSendmailSuccessView.as_view(), name='forgot-password-sendmail-success'), url(r'^password/forgot/sendmail-success/$', views.UserForgotPasswordSendmailSuccessView.as_view(), name='forgot-password-sendmail-success'),
url(r'^password/reset$', views.UserResetPasswordView.as_view(), name='reset-password'), url(r'^password/reset/$', views.UserResetPasswordView.as_view(), name='reset-password'),
url(r'^password/reset/success$', views.UserResetPasswordSuccessView.as_view(), name='reset-password-success'), url(r'^password/reset/success/$', views.UserResetPasswordSuccessView.as_view(), name='reset-password-success'),
# Profile # Profile
url(r'^profile/$', views.UserProfileView.as_view(), name='user-profile'), url(r'^profile/$', views.UserProfileView.as_view(), name='user-profile'),
...@@ -29,23 +29,23 @@ urlpatterns = [ ...@@ -29,23 +29,23 @@ urlpatterns = [
url(r'^profile/otp/settings-success/$', views.UserOtpSettingsSuccessView.as_view(), name='user-otp-settings-success'), url(r'^profile/otp/settings-success/$', views.UserOtpSettingsSuccessView.as_view(), name='user-otp-settings-success'),
# User view # User view
url(r'^user$', views.UserListView.as_view(), name='user-list'), url(r'^user/$', views.UserListView.as_view(), name='user-list'),
url(r'^user/export/', views.UserExportView.as_view(), name='user-export'), url(r'^user/export/$', views.UserExportView.as_view(), name='user-export'),
url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'), url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'),
url(r'^user/import/$', views.UserBulkImportView.as_view(), name='user-import'), url(r'^user/import/$', views.UserBulkImportView.as_view(), name='user-import'),
url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'), url(r'^user/create/$', views.UserCreateView.as_view(), name='user-create'),
url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})/update$', views.UserUpdateView.as_view(), name='user-update'), url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.UserUpdateView.as_view(), name='user-update'),
url(r'^user/update$', views.UserBulkUpdateView.as_view(), name='user-bulk-update'), url(r'^user/update/$', views.UserBulkUpdateView.as_view(), name='user-bulk-update'),
url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})$', views.UserDetailView.as_view(), name='user-detail'), url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})/assets', views.UserGrantedAssetView.as_view(), name='user-granted-asset'), url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', views.UserGrantedAssetView.as_view(), name='user-granted-asset'),
url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})/login-history', views.UserDetailView.as_view(), name='user-login-history'), url(r'^user/(?P<pk>[0-9a-zA-Z\-]{36})/login-history/$', views.UserDetailView.as_view(), name='user-login-history'),
# User group view # User group view
url(r'^user-group$', views.UserGroupListView.as_view(), name='user-group-list'), url(r'^user-group/$', views.UserGroupListView.as_view(), name='user-group-list'),
url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]{36})$', views.UserGroupDetailView.as_view(), name='user-group-detail'), url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]{36})/$', views.UserGroupDetailView.as_view(), name='user-group-detail'),
url(r'^user-group/create$', views.UserGroupCreateView.as_view(), name='user-group-create'), url(r'^user-group/create/$', views.UserGroupCreateView.as_view(), name='user-group-create'),
url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]{36})/update$', views.UserGroupUpdateView.as_view(), name='user-group-update'), url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]{36})/update/$', views.UserGroupUpdateView.as_view(), name='user-group-update'),
url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets', views.UserGroupGrantedAssetView.as_view(), name='user-group-granted-asset'), url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', views.UserGroupGrantedAssetView.as_view(), name='user-group-granted-asset'),
# Login log # Login log
url(r'^login-log/$', views.LoginLogListView.as_view(), name='login-log-list'), url(r'^login-log/$', views.LoginLogListView.as_view(), name='login-log-list'),
......
...@@ -212,10 +212,10 @@ def write_login_log(*args, **kwargs): ...@@ -212,10 +212,10 @@ def write_login_log(*args, **kwargs):
def get_ip_city(ip, timeout=10): def get_ip_city(ip, timeout=10):
# Taobao ip api: http://ip.taobao.com//service/getIpInfo.php?ip=8.8.8.8 # Taobao ip api: http://ip.taobao.com/service/getIpInfo.php?ip=8.8.8.8
# Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=json # Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=json
url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip url = 'http://ip.taobao.com/service/getIpInfo.php?ip=%s' % ip
try: try:
r = requests.get(url, timeout=timeout) r = requests.get(url, timeout=timeout)
except: except:
...@@ -224,8 +224,8 @@ def get_ip_city(ip, timeout=10): ...@@ -224,8 +224,8 @@ def get_ip_city(ip, timeout=10):
if r and r.status_code == 200: if r and r.status_code == 200:
try: try:
data = r.json() data = r.json()
if not isinstance(data, int) and data['ret'] == 1: if not isinstance(data, int) and data['code'] == 0:
city = data['country'] + ' ' + data['city'] city = data['data']['country'] + ' ' + data['data']['city']
except ValueError: except ValueError:
pass pass
return city return city
...@@ -333,7 +333,7 @@ def check_password_rules(password): ...@@ -333,7 +333,7 @@ def check_password_rules(password):
return bool(match_obj) return bool(match_obj)
def set_user_login_failed_count_to_cache(key_limit): def set_user_login_failed_count_to_cache(key_limit, key_block):
count = cache.get(key_limit) count = cache.get(key_limit)
count = count + 1 if count else 1 count = count + 1 if count else 1
...@@ -343,6 +343,15 @@ def set_user_login_failed_count_to_cache(key_limit): ...@@ -343,6 +343,15 @@ def set_user_login_failed_count_to_cache(key_limit):
limit_time = setting_limit_time.cleaned_value if setting_limit_time \ limit_time = setting_limit_time.cleaned_value if setting_limit_time \
else settings.DEFAULT_LOGIN_LIMIT_TIME else settings.DEFAULT_LOGIN_LIMIT_TIME
setting_limit_count = Setting.objects.filter(
name='SECURITY_LOGIN_LIMIT_COUNT'
).first()
limit_count = setting_limit_count.cleaned_value if setting_limit_count \
else settings.DEFAULT_LOGIN_LIMIT_COUNT
if count >= limit_count:
cache.set(key_block, 1, int(limit_time)*60)
cache.set(key_limit, count, int(limit_time)*60) cache.set(key_limit, count, int(limit_time)*60)
...@@ -357,3 +366,9 @@ def is_block_login(key_limit): ...@@ -357,3 +366,9 @@ def is_block_login(key_limit):
if count and count >= limit_count: if count and count >= limit_count:
return True return True
def is_need_unblock(key_block):
if not cache.get(key_block):
return False
return True
...@@ -52,6 +52,7 @@ class UserLoginView(FormView): ...@@ -52,6 +52,7 @@ class UserLoginView(FormView):
redirect_field_name = 'next' redirect_field_name = 'next'
key_prefix_captcha = "_LOGIN_INVALID_{}" key_prefix_captcha = "_LOGIN_INVALID_{}"
key_prefix_limit = "_LOGIN_LIMIT_{}_{}" key_prefix_limit = "_LOGIN_LIMIT_{}_{}"
key_prefix_block = "_LOGIN_BLOCK_{}"
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if request.user.is_staff: if request.user.is_staff:
...@@ -65,7 +66,7 @@ class UserLoginView(FormView): ...@@ -65,7 +66,7 @@ class UserLoginView(FormView):
# limit login authentication # limit login authentication
ip = get_login_ip(request) ip = get_login_ip(request)
username = self.request.POST.get('username') username = self.request.POST.get('username')
key_limit = self.key_prefix_limit.format(ip, username) key_limit = self.key_prefix_limit.format(username, ip)
if is_block_login(key_limit): if is_block_login(key_limit):
return self.render_to_response(self.get_context_data(block_login=True)) return self.render_to_response(self.get_context_data(block_login=True))
...@@ -91,8 +92,9 @@ class UserLoginView(FormView): ...@@ -91,8 +92,9 @@ class UserLoginView(FormView):
# limit user login failed count # limit user login failed count
ip = get_login_ip(self.request) ip = get_login_ip(self.request)
key_limit = self.key_prefix_limit.format(ip, username) key_limit = self.key_prefix_limit.format(username, ip)
set_user_login_failed_count_to_cache(key_limit) key_block = self.key_prefix_block.format(username)
set_user_login_failed_count_to_cache(key_limit, key_block)
# show captcha # show captcha
cache.set(self.key_prefix_captcha.format(ip), 1, 3600) cache.set(self.key_prefix_captcha.format(ip), 1, 3600)
......
...@@ -37,7 +37,9 @@ from common.models import Setting ...@@ -37,7 +37,9 @@ from common.models import Setting
from common.permissions import AdminUserRequiredMixin from common.permissions import AdminUserRequiredMixin
from .. import forms from .. import forms
from ..models import User, UserGroup from ..models import User, UserGroup
from ..utils import generate_otp_uri, check_otp_code, get_user_or_tmp_user, get_password_check_rules, check_password_rules from ..utils import generate_otp_uri, check_otp_code, \
get_user_or_tmp_user, get_password_check_rules, check_password_rules, \
is_need_unblock
from ..signals import post_user_create from ..signals import post_user_create
from ..tasks import write_login_log_async from ..tasks import write_login_log_async
...@@ -169,13 +171,17 @@ class UserDetailView(AdminUserRequiredMixin, DetailView): ...@@ -169,13 +171,17 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
model = User model = User
template_name = 'users/user_detail.html' template_name = 'users/user_detail.html'
context_object_name = "user_object" context_object_name = "user_object"
key_prefix_block = "_LOGIN_BLOCK_{}"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
user = self.get_object()
key_block = self.key_prefix_block.format(user.username)
groups = UserGroup.objects.exclude(id__in=self.object.groups.all()) groups = UserGroup.objects.exclude(id__in=self.object.groups.all())
context = { context = {
'app': _('Users'), 'app': _('Users'),
'action': _('User detail'), 'action': _('User detail'),
'groups': groups 'groups': groups,
'unblock': is_need_unblock(key_block),
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
......
...@@ -228,7 +228,7 @@ Luna 已改为纯前端,需要 Nginx 来运行访问 ...@@ -228,7 +228,7 @@ Luna 已改为纯前端,需要 Nginx 来运行访问
-p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \ -p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \
-e JUMPSERVER_KEY_DIR=/config/guacamole/key \ -e JUMPSERVER_KEY_DIR=/config/guacamole/key \
-e JUMPSERVER_SERVER=http://<填写本机的IP地址>:8080 \ -e JUMPSERVER_SERVER=http://<填写本机的IP地址>:8080 \
registry.jumpserver.org/public/guacamole:1.0.0 registry.jumpserver.org/public/guacamole:latest
这里所需要注意的是 guacamole 暴露出来的端口是 8081,若与主机上其他端口冲突请自定义一下。 这里所需要注意的是 guacamole 暴露出来的端口是 8081,若与主机上其他端口冲突请自定义一下。
......
...@@ -122,8 +122,8 @@ def start_gunicorn(): ...@@ -122,8 +122,8 @@ def start_gunicorn():
cmd = [ cmd = [
'gunicorn', 'jumpserver.wsgi', 'gunicorn', 'jumpserver.wsgi',
'-b', bind, '-b', bind,
'-w', str(WORKERS),
'-k', 'eventlet', '-k', 'eventlet',
'-w', str(WORKERS),
'--access-logformat', log_format, '--access-logformat', log_format,
'-p', pid_file, '-p', pid_file,
] ]
......
...@@ -48,7 +48,7 @@ MarkupSafe==1.0 ...@@ -48,7 +48,7 @@ MarkupSafe==1.0
mysqlclient==1.3.12 mysqlclient==1.3.12
olefile==0.44 olefile==0.44
openapi-codec==1.3.2 openapi-codec==1.3.2
paramiko==2.4.0 paramiko==2.4.1
passlib==1.7.1 passlib==1.7.1
Pillow==4.3.0 Pillow==4.3.0
pyasn1==0.4.2 pyasn1==0.4.2
......
...@@ -5,4 +5,4 @@ python3 ../apps/manage.py makemigrations ...@@ -5,4 +5,4 @@ python3 ../apps/manage.py makemigrations
python3 ../apps/manage.py migrate python3 ../apps/manage.py migrate
python3 ../apps/manage.py makemigrations -merge python3 ../apps/manage.py makemigrations --merge
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment