Unverified Commit 84b3e29d authored by BaiJiangJie's avatar BaiJiangJie Committed by GitHub

Merge pull request #3366 from jumpserver/bugfix

Bugfix
parents 334e3bef a33d5cc5
...@@ -7,6 +7,7 @@ from rest_framework import filters ...@@ -7,6 +7,7 @@ from rest_framework import filters
from rest_framework_bulk import BulkModelViewSet from rest_framework_bulk import BulkModelViewSet
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.http import Http404 from django.http import Http404
from django.conf import settings
from common.permissions import IsOrgAdminOrAppUser, NeedMFAVerify from common.permissions import IsOrgAdminOrAppUser, NeedMFAVerify
from common.utils import get_object_or_none, get_logger from common.utils import get_object_or_none, get_logger
...@@ -110,12 +111,22 @@ class AssetUserViewSet(CommonApiMixin, BulkModelViewSet): ...@@ -110,12 +111,22 @@ class AssetUserViewSet(CommonApiMixin, BulkModelViewSet):
class AssetUserExportViewSet(AssetUserViewSet): class AssetUserExportViewSet(AssetUserViewSet):
serializer_class = serializers.AssetUserExportSerializer serializer_class = serializers.AssetUserExportSerializer
http_method_names = ['get'] http_method_names = ['get']
permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify] permission_classes = [IsOrgAdminOrAppUser]
def get_permissions(self):
if settings.CONFIG.SECURITY_VIEW_AUTH_NEED_MFA:
self.permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify]
return super().get_permissions()
class AssetUserAuthInfoApi(generics.RetrieveAPIView): class AssetUserAuthInfoApi(generics.RetrieveAPIView):
serializer_class = serializers.AssetUserAuthInfoSerializer serializer_class = serializers.AssetUserAuthInfoSerializer
permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify] permission_classes = [IsOrgAdminOrAppUser]
def get_permissions(self):
if settings.CONFIG.SECURITY_VIEW_AUTH_NEED_MFA:
self.permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify]
return super().get_permissions()
def get_object(self): def get_object(self):
query_params = self.request.query_params query_params = self.request.query_params
......
...@@ -41,8 +41,8 @@ class AssetUserManager: ...@@ -41,8 +41,8 @@ class AssetUserManager:
instances_map = {} instances_map = {}
instances = [] instances = []
for name, backend in self.backends: for name, backend in self.backends:
if name != "db" and self._prefer != name: # if name != "db":
continue # continue
_instances = backend.filter( _instances = backend.filter(
username=username, assets=assets, latest=latest, username=username, assets=assets, latest=latest,
prefer=self._prefer, prefer_id=prefer_id, prefer=self._prefer, prefer_id=prefer_id,
......
...@@ -40,6 +40,7 @@ var prefer = null; ...@@ -40,6 +40,7 @@ var prefer = null;
var lastMFATime = "{{ request.session.MFA_VERIFY_TIME }}"; var lastMFATime = "{{ request.session.MFA_VERIFY_TIME }}";
var testDatetime = "{% trans 'Test datetime: ' %}"; var testDatetime = "{% trans 'Test datetime: ' %}";
var mfaVerifyTTL = "{{ SECURITY_MFA_VERIFY_TTL }}"; var mfaVerifyTTL = "{{ SECURITY_MFA_VERIFY_TTL }}";
var mfaNeedCheck = "{{ SECURITY_VIEW_AUTH_NEED_MFA }}" === "True";
function initAssetUserTable() { function initAssetUserTable() {
var options = { var options = {
...@@ -112,6 +113,10 @@ $(document).ready(function(){ ...@@ -112,6 +113,10 @@ $(document).ready(function(){
authAssetId = $(this).data("asset") ; authAssetId = $(this).data("asset") ;
authHostname = $(this).data("hostname"); authHostname = $(this).data("hostname");
authUsername = $(this).data('user'); authUsername = $(this).data('user');
if (!mfaNeedCheck){
$("#asset_user_auth_view").modal('show');
return
}
var now = new Date(); var now = new Date();
var nowTime = now.getTime() / 1000; var nowTime = now.getTime() / 1000;
if ( !lastMFATime || nowTime - lastMFATime > mfaVerifyTTL ) { if ( !lastMFATime || nowTime - lastMFATime > mfaVerifyTTL ) {
......
...@@ -70,43 +70,6 @@ function initTable() { ...@@ -70,43 +70,6 @@ function initTable() {
var detail_btn = '<a href="{% url "assets:admin-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:admin-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
return detail_btn.replace('{{ DEFAULT_PK }}', rowData.id); return detail_btn.replace('{{ DEFAULT_PK }}', rowData.id);
}}, }},
{#{targets: 4, createdCell: function (td, cellData) {#}
{# var innerHtml = "";#}
{# var data = cellData.reachable;#}
{# if (data !== 0) {#}
{# innerHtml = "<span class='text-navy'>" + data + "</span>";#}
{# } else {#}
{# innerHtml = "<span>" + data + "</span>";#}
{# }#}
{# $(td).html(innerHtml)#}
{#}},#}
{#{targets: 5, createdCell: function (td, cellData) {#}
{# var data = cellData.unreachable;#}
{# var innerHtml = "";#}
{# if (data !== 0) {#}
{# innerHtml = "<span class='text-danger'>" + data + "</span>";#}
{# } else {#}
{# innerHtml = "<span>" + data + "</span>";#}
{# }#}
{# $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + data + '">' + innerHtml + '</span>');#}
{#}},#}
{#{targets: 6, createdCell: function (td, cellData, rowData) {#}
{# var val = 0;#}
{# var innerHtml = "";#}
{# var total = rowData.assets_amount;#}
{# var reachable = cellData.reachable;#}
{# if (total !== 0) {#}
{# val = reachable/total * 100;#}
{# }#}
{##}
{# if (val === 100) {#}
{# innerHtml = "<span class='text-navy'>" + val + "% </span>";#}
{# } else {#}
{# var num = new Number(val);#}
{# innerHtml = "<span class='text-danger'>" + num.toFixed(1) + "% </span>";#}
{# }#}
{# $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');#}
{#}},#}
{targets: 5, createdCell: function (td, cellData, rowData) { {targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:admin-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var update_btn = '<a href="{% url "assets:admin-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
...@@ -116,7 +79,7 @@ function initTable() { ...@@ -116,7 +79,7 @@ function initTable() {
columns: [ columns: [
{data: function(){return ""}}, {data: "name"}, {data: "username" }, {data: "assets_amount", orderable: false}, {data: function(){return ""}}, {data: "name"}, {data: "username" }, {data: "assets_amount", orderable: false},
{#{data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "connectivity_amount"},#} {#{data: "connectivity_amount"}, {data: "connectivity_amount"}, {data: "connectivity_amount"},#}
{data: "comment"}, {data: "id", orderable: false} {data: "comment"}, {data: "id", orderable: false, width: "100px"}
] ]
}; };
admin_user_table = jumpserver.initServerSideDataTable(options); admin_user_table = jumpserver.initServerSideDataTable(options);
......
...@@ -177,7 +177,7 @@ function initTable() { ...@@ -177,7 +177,7 @@ function initTable() {
data: "connectivity", data: "connectivity",
orderable: false, orderable: false,
width: '60px' width: '60px'
}, {data: "id", orderable: false} }, {data: "id", orderable: false, width: "100px"}
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
......
...@@ -63,7 +63,8 @@ function initTable() { ...@@ -63,7 +63,8 @@ function initTable() {
ajax_url: '{% url "api-assets:cmd-filter-list" %}', ajax_url: '{% url "api-assets:cmd-filter-list" %}',
columns: [ columns: [
{data: "id"}, {data: "name" }, {data: "rules", orderable: false}, {data: "id"}, {data: "name" }, {data: "rules", orderable: false},
{data: "system_users", orderable: false}, {data: "comment"}, {data: "id", orderable: false} {data: "system_users", orderable: false}, {data: "comment"},
{data: "id", orderable: false, width: "100px"}
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
......
...@@ -59,7 +59,7 @@ function initTable() { ...@@ -59,7 +59,7 @@ function initTable() {
ajax_url: '{% url "api-assets:domain-list" %}', ajax_url: '{% url "api-assets:domain-list" %}',
columns: [ columns: [
{data: "id"}, {data: "name" }, {data: "asset_count", orderable: false }, {data: "id"}, {data: "name" }, {data: "asset_count", orderable: false },
{data: "gateway_count", orderable: false }, {data: "comment" }, {data: "id", orderable: false} {data: "gateway_count", orderable: false }, {data: "comment" }, {data: "id", orderable: false, width: "100px"}
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
......
...@@ -44,7 +44,8 @@ function initTable() { ...@@ -44,7 +44,8 @@ function initTable() {
ajax_url: '{% url "api-assets:label-list" %}?sort=name', ajax_url: '{% url "api-assets:label-list" %}?sort=name',
columns: [ columns: [
{data: "id"}, {data: "name" }, {data: "value" }, {data: "id"}, {data: "name" }, {data: "value" },
{data: "asset_count", orderable: false}, {data: "id", orderable: false} {data: "asset_count", orderable: false},
{data: "id", orderable: false, width: "100px"}
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
......
...@@ -3,10 +3,6 @@ ...@@ -3,10 +3,6 @@
{% block help_message %} {% block help_message %}
<div class="alert alert-info help-message"> <div class="alert alert-info help-message">
{# 系统用户是 Jumpserver跳转登录资产时使用的用户,可以理解为登录资产用户,如 web, sa, dba(`ssh web@some-host`), 而不是使用某个用户的用户名跳转登录服务器(`ssh xiaoming@some-host`);#}
{# 简单来说是 用户使用自己的用户名登录Jumpserver, Jumpserver使用系统用户登录资产。#}
{# 系统用户创建时,如果选择了自动推送 Jumpserver会使用ansible自动推送系统用户到资产中,如果资产(交换机、windows)不支持ansible, 请手动填写账号密码。#}
{# 目前还不支持Windows的自动推送#}
{% trans 'System user is Jumpserver jump login assets used by the users, can be understood as the user login assets, such as web, sa, the dba (` ssh web@some-host `), rather than using a user the username login server jump (` ssh xiaoming@some-host `); '%} {% trans 'System user is Jumpserver jump login assets used by the users, can be understood as the user login assets, such as web, sa, the dba (` ssh web@some-host `), rather than using a user the username login server jump (` ssh xiaoming@some-host `); '%}
{% trans 'In simple terms, users log into Jumpserver using their own username, and Jumpserver uses system users to log into assets. '%} {% trans 'In simple terms, users log into Jumpserver using their own username, and Jumpserver uses system users to log into assets. '%}
{% trans 'When system users are created, if you choose auto push Jumpserver to use Ansible push system users into the asset, if the asset (Switch) does not support ansible, please manually fill in the account password.' %} {% trans 'When system users are created, if you choose auto push Jumpserver to use Ansible push system users into the asset, if the asset (Switch) does not support ansible, please manually fill in the account password.' %}
...@@ -91,7 +87,7 @@ function initTable() { ...@@ -91,7 +87,7 @@ function initTable() {
columns: [ columns: [
{data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"},
{data: "login_mode"}, {data: "assets_amount", orderable: false }, {data: "login_mode"}, {data: "assets_amount", orderable: false },
{data: "comment" }, {data: "id", orderable: false } {data: "comment" }, {data: "id", orderable: false, width: "100px"}
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
......
...@@ -182,3 +182,7 @@ def encrypt_password(password, salt=None): ...@@ -182,3 +182,7 @@ def encrypt_password(password, salt=None):
def get_signer(): def get_signer():
signer = Signer(settings.SECRET_KEY) signer = Signer(settings.SECRET_KEY)
return signer return signer
def ensure_last_char_is_ascii(data):
remain = ''
...@@ -361,6 +361,7 @@ defaults = { ...@@ -361,6 +361,7 @@ defaults = {
'TERMINAL_COMMAND_STORAGE': {}, 'TERMINAL_COMMAND_STORAGE': {},
'SECURITY_MFA_AUTH': False, 'SECURITY_MFA_AUTH': False,
'SECURITY_SERVICE_ACCOUNT_REGISTRATION': True, 'SECURITY_SERVICE_ACCOUNT_REGISTRATION': True,
'SECURITY_VIEW_AUTH_NEED_MFA': True,
'SECURITY_LOGIN_LIMIT_COUNT': 7, 'SECURITY_LOGIN_LIMIT_COUNT': 7,
'SECURITY_LOGIN_LIMIT_TIME': 30, 'SECURITY_LOGIN_LIMIT_TIME': 30,
'SECURITY_MAX_IDLE_TIME': 30, 'SECURITY_MAX_IDLE_TIME': 30,
......
...@@ -18,6 +18,7 @@ def jumpserver_processor(request): ...@@ -18,6 +18,7 @@ def jumpserver_processor(request):
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2019', 'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2019',
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION, 'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
'SECURITY_MFA_VERIFY_TTL': settings.SECURITY_MFA_VERIFY_TTL, 'SECURITY_MFA_VERIFY_TTL': settings.SECURITY_MFA_VERIFY_TTL,
'SECURITY_VIEW_AUTH_NEED_MFA': settings.CONFIG.SECURITY_VIEW_AUTH_NEED_MFA,
} }
return context return context
......
...@@ -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: 2019-10-17 16:09+0800\n" "POT-Creation-Date: 2019-10-21 17:00+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"
...@@ -95,7 +95,7 @@ msgstr "运行参数" ...@@ -95,7 +95,7 @@ msgstr "运行参数"
#: terminal/templates/terminal/command_list.html:66 #: terminal/templates/terminal/command_list.html:66
#: terminal/templates/terminal/session_list.html:28 #: terminal/templates/terminal/session_list.html:28
#: terminal/templates/terminal/session_list.html:72 #: terminal/templates/terminal/session_list.html:72
#: xpack/plugins/change_auth_plan/forms.py:64 #: xpack/plugins/change_auth_plan/forms.py:73
#: xpack/plugins/change_auth_plan/models.py:412 #: xpack/plugins/change_auth_plan/models.py:412
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54
...@@ -112,7 +112,7 @@ msgstr "资产" ...@@ -112,7 +112,7 @@ msgstr "资产"
#: applications/templates/applications/remote_app_detail.html:53 #: applications/templates/applications/remote_app_detail.html:53
#: applications/templates/applications/remote_app_list.html:20 #: applications/templates/applications/remote_app_list.html:20
#: applications/templates/applications/user_remote_app_list.html:16 #: applications/templates/applications/user_remote_app_list.html:16
#: assets/forms/asset.py:21 assets/forms/domain.py:73 assets/forms/user.py:75 #: assets/forms/asset.py:21 assets/forms/domain.py:77 assets/forms/user.py:75
#: assets/forms/user.py:95 assets/models/base.py:28 assets/models/cluster.py:18 #: assets/forms/user.py:95 assets/models/base.py:28 assets/models/cluster.py:18
#: assets/models/cmd_filter.py:21 assets/models/domain.py:20 #: assets/models/cmd_filter.py:21 assets/models/domain.py:20
#: assets/models/group.py:20 assets/models/label.py:18 #: assets/models/group.py:20 assets/models/label.py:18
...@@ -151,7 +151,7 @@ msgstr "资产" ...@@ -151,7 +151,7 @@ msgstr "资产"
#: users/templates/users/user_list.html:35 #: users/templates/users/user_list.html:35
#: users/templates/users/user_profile.html:51 #: users/templates/users/user_profile.html:51
#: users/templates/users/user_pubkey_update.html:57 #: users/templates/users/user_pubkey_update.html:57
#: xpack/plugins/change_auth_plan/forms.py:47 #: xpack/plugins/change_auth_plan/forms.py:56
#: xpack/plugins/change_auth_plan/models.py:63 #: xpack/plugins/change_auth_plan/models.py:63
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12
...@@ -322,6 +322,7 @@ msgstr "远程应用" ...@@ -322,6 +322,7 @@ msgstr "远程应用"
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create_update.html:53 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_create_update.html:53
#: xpack/plugins/gathered_user/templates/gathered_user/task_create_update.html:44 #: xpack/plugins/gathered_user/templates/gathered_user/task_create_update.html:44
#: xpack/plugins/interface/templates/interface/interface.html:72 #: xpack/plugins/interface/templates/interface/interface.html:72
#: xpack/plugins/orgs/templates/orgs/org_create_update.html:33
#: xpack/plugins/vault/templates/vault/vault_create.html:45 #: xpack/plugins/vault/templates/vault/vault_create.html:45
msgid "Reset" msgid "Reset"
msgstr "重置" msgstr "重置"
...@@ -639,7 +640,7 @@ msgstr "网域" ...@@ -639,7 +640,7 @@ msgstr "网域"
#: perms/templates/perms/asset_permission_list.html:53 #: perms/templates/perms/asset_permission_list.html:53
#: perms/templates/perms/asset_permission_list.html:74 #: perms/templates/perms/asset_permission_list.html:74
#: perms/templates/perms/asset_permission_list.html:124 #: perms/templates/perms/asset_permission_list.html:124
#: xpack/plugins/change_auth_plan/forms.py:65 #: xpack/plugins/change_auth_plan/forms.py:74
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:55 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:55
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:15 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:15
#: xpack/plugins/cloud/models.py:157 #: xpack/plugins/cloud/models.py:157
...@@ -668,7 +669,7 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域, ...@@ -668,7 +669,7 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,
#: assets/forms/asset.py:132 assets/forms/asset.py:136 #: assets/forms/asset.py:132 assets/forms/asset.py:136
#: assets/forms/domain.py:17 assets/forms/label.py:15 #: assets/forms/domain.py:17 assets/forms/label.py:15
#: perms/templates/perms/asset_permission_asset.html:78 #: perms/templates/perms/asset_permission_asset.html:78
#: xpack/plugins/change_auth_plan/forms.py:55 #: xpack/plugins/change_auth_plan/forms.py:64
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:74 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:74
msgid "Select assets" msgid "Select assets"
msgstr "选择资产" msgstr "选择资产"
...@@ -677,15 +678,15 @@ msgstr "选择资产" ...@@ -677,15 +678,15 @@ msgstr "选择资产"
msgid "Content should not be contain: {}" msgid "Content should not be contain: {}"
msgstr "内容不能包含: {}" msgstr "内容不能包含: {}"
#: assets/forms/domain.py:51 #: assets/forms/domain.py:55
msgid "Password should not contain special characters" msgid "Password should not contain special characters"
msgstr "不能包含特殊字符" msgstr "不能包含特殊字符"
#: assets/forms/domain.py:70 #: assets/forms/domain.py:74
msgid "SSH gateway support proxy SSH,RDP,VNC" msgid "SSH gateway support proxy SSH,RDP,VNC"
msgstr "SSH网关,支持代理SSH,RDP和VNC" msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: assets/forms/domain.py:74 assets/forms/user.py:76 assets/forms/user.py:96 #: assets/forms/domain.py:78 assets/forms/user.py:76 assets/forms/user.py:96
#: assets/models/base.py:29 assets/models/gathered_user.py:16 #: assets/models/base.py:29 assets/models/gathered_user.py:16
#: assets/templates/assets/_asset_user_auth_update_modal.html:15 #: assets/templates/assets/_asset_user_auth_update_modal.html:15
#: assets/templates/assets/_asset_user_auth_view_modal.html:21 #: assets/templates/assets/_asset_user_auth_view_modal.html:21
...@@ -706,7 +707,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" ...@@ -706,7 +707,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: users/templates/users/user_detail.html:67 #: users/templates/users/user_detail.html:67
#: users/templates/users/user_list.html:36 #: users/templates/users/user_list.html:36
#: users/templates/users/user_profile.html:47 #: users/templates/users/user_profile.html:47
#: xpack/plugins/change_auth_plan/forms.py:49 #: xpack/plugins/change_auth_plan/forms.py:58
#: xpack/plugins/change_auth_plan/models.py:65 #: xpack/plugins/change_auth_plan/models.py:65
#: xpack/plugins/change_auth_plan/models.py:408 #: xpack/plugins/change_auth_plan/models.py:408
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65
...@@ -1451,7 +1452,7 @@ msgid "Update asset user auth" ...@@ -1451,7 +1452,7 @@ msgid "Update asset user auth"
msgstr "更新资产用户认证信息" msgstr "更新资产用户认证信息"
#: assets/templates/assets/_asset_user_auth_update_modal.html:23 #: assets/templates/assets/_asset_user_auth_update_modal.html:23
#: xpack/plugins/change_auth_plan/forms.py:51 #: xpack/plugins/change_auth_plan/forms.py:60
msgid "Please input password" msgid "Please input password"
msgstr "请输入密码" msgstr "请输入密码"
...@@ -1637,7 +1638,7 @@ msgstr "替换资产的管理员" ...@@ -1637,7 +1638,7 @@ msgstr "替换资产的管理员"
#: assets/templates/assets/admin_user_detail.html:91 #: assets/templates/assets/admin_user_detail.html:91
#: perms/templates/perms/asset_permission_asset.html:103 #: perms/templates/perms/asset_permission_asset.html:103
#: xpack/plugins/change_auth_plan/forms.py:59 #: xpack/plugins/change_auth_plan/forms.py:68
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:99 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:99
#: xpack/plugins/gathered_user/forms.py:36 #: xpack/plugins/gathered_user/forms.py:36
msgid "Select nodes" msgid "Select nodes"
...@@ -1877,7 +1878,6 @@ msgstr "删除选择资产" ...@@ -1877,7 +1878,6 @@ msgstr "删除选择资产"
#: users/templates/users/user_group_list.html:118 #: users/templates/users/user_group_list.html:118
#: users/templates/users/user_list.html:254 #: users/templates/users/user_list.html:254
#: xpack/plugins/interface/templates/interface/interface.html:101 #: xpack/plugins/interface/templates/interface/interface.html:101
#: xpack/plugins/orgs/templates/orgs/org_create_update.html:33
msgid "Cancel" msgid "Cancel"
msgstr "取消" msgstr "取消"
...@@ -3394,33 +3394,33 @@ msgstr "远程应用授权用户列表" ...@@ -3394,33 +3394,33 @@ msgstr "远程应用授权用户列表"
msgid "RemoteApp permission RemoteApp list" msgid "RemoteApp permission RemoteApp list"
msgstr "远程应用授权远程应用列表" msgstr "远程应用授权远程应用列表"
#: settings/api.py:27 #: settings/api.py:28
msgid "Test mail sent to {}, please check" msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查" msgstr "邮件已经发送{}, 请检查"
#: settings/api.py:55 #: settings/api.py:67
msgid "Test ldap success" msgid "Test ldap success"
msgstr "连接LDAP成功" msgstr "连接LDAP成功"
#: settings/api.py:92 #: settings/api.py:104
msgid "Match {} s users" msgid "Match {} s users"
msgstr "匹配 {} 个用户" msgstr "匹配 {} 个用户"
#: settings/api.py:151 #: settings/api.py:163
msgid "succeed: {} failed: {} total: {}" msgid "succeed: {} failed: {} total: {}"
msgstr "成功:{} 失败:{} 总数:{}" msgstr "成功:{} 失败:{} 总数:{}"
#: settings/api.py:173 settings/api.py:209 #: settings/api.py:185 settings/api.py:221
msgid "" msgid ""
"Error: Account invalid (Please make sure the information such as Access key " "Error: Account invalid (Please make sure the information such as Access key "
"or Secret key is correct)" "or Secret key is correct)"
msgstr "错误:账户无效 (请确保 Access key 或 Secret key 等信息正确)" msgstr "错误:账户无效 (请确保 Access key 或 Secret key 等信息正确)"
#: settings/api.py:179 settings/api.py:215 #: settings/api.py:191 settings/api.py:227
msgid "Create succeed" msgid "Create succeed"
msgstr "创建成功" msgstr "创建成功"
#: settings/api.py:197 settings/api.py:235 #: settings/api.py:209 settings/api.py:247
#: settings/templates/settings/terminal_setting.html:154 #: settings/templates/settings/terminal_setting.html:154
msgid "Delete succeed" msgid "Delete succeed"
msgstr "删除成功" msgstr "删除成功"
...@@ -4536,7 +4536,7 @@ msgid "" ...@@ -4536,7 +4536,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/user.py:176 #: users/api/user.py:173
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置" msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
...@@ -4874,7 +4874,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry" ...@@ -4874,7 +4874,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry"
msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry" msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry"
#: users/templates/users/reset_password.html:46 #: users/templates/users/reset_password.html:46
#: users/templates/users/user_detail.html:379 users/utils.py:84 #: users/templates/users/user_detail.html:379 users/utils.py:83
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
...@@ -5190,61 +5190,57 @@ msgid "" ...@@ -5190,61 +5190,57 @@ msgid ""
"corresponding private key." "corresponding private key."
msgstr "新的公钥已设置成功,请下载对应的私钥" msgstr "新的公钥已设置成功,请下载对应的私钥"
# msgid "Update user"
# msgstr "更新用户"
#: users/utils.py:24 #: users/utils.py:24
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
" <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/" " <div>\n"
"bootstrap/3.2.0/css/bootstrap.min.css\">\n" " <p>Your account has been created successfully</p>\n"
" <p style=\"text-indent:2em;\">\n" " <div>\n"
" <span>\n" " Username: %(username)s\n"
" Username: %(username)s.\n" " <br/>\n"
" </span>\n" " Password: <a href=\"%(rest_password_url)s?token="
" <span>\n" "%(rest_password_token)s\">\n"
" <a href=\"%(rest_password_url)s?token=%(rest_password_token)s" " click here to set your password</a> \n"
"\">click here to set your password</a>\n" " (This link is valid for 1 hour. After it expires, <a href="
" </span> \n" "\"%(forget_password_url)s?email=%(email)s\">request new one</a>)\n"
" <span>\n" " </div>\n"
" This link is valid for 1 hour. After it expires, <a href=" " <div>\n"
"\"%(forget_password_url)s?email=%(email)s\">request new one</a>\n" " <p>---</p>\n"
" </span> \n"
" <span>\n"
" <a href=\"%(login_url)s\">Login direct</a>\n" " <a href=\"%(login_url)s\">Login direct</a>\n"
" </span>\n" " </div>\n"
" </p>\n" " </div>\n"
" " " "
msgstr "" msgstr ""
"\n" "\n"
" <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/" " <div>\n"
"bootstrap/3.2.0/css/bootstrap.min.css\">\n" " <p>您的账户已创建成功</p>\n"
" <p style=\"text-indent:2em;\">\n" " <div>\n"
" <span>\n" " 用户名: %(username)s\n"
" 用户名: %(username)s.\n" " <br/>\n"
" </span>\n" " 密码: <a href=\"%(rest_password_url)s?token="
" <span>\n" "%(rest_password_token)s\">请点击这里设置密码</a> (这个链接有效期1小时, 超过时"
" <a href=\"%(rest_password_url)s?token=%(rest_password_token)s\">" "间您可以 <a href=\"%(forget_password_url)s?email=%(email)s\">重新申请</a>)\n"
"请点击这里设置密码</a>\n" " </div>\n"
" </span> \n" " <div>\n"
" <span>\n" " <p>---</p>\n"
" 这个链接有效期1小时, 超过时间您可以 <a href=" " <a href=\"%(login_url)s\">直接登录</a>\n"
"\"%(forget_password_url)s?email=%(email)s\">重新申请</a>\n" " </div>\n"
" </span> \n" " </div>\n"
" <span>\n"
" <a href=\"%(login_url)s\">---登录页面</a>\n"
" </span>\n"
" </p>\n"
" " " "
#: users/utils.py:59 #: users/utils.py:58
msgid "Create account successfully" msgid "Create account successfully"
msgstr "创建账户成功" msgstr "创建账户成功"
#: users/utils.py:63 #: users/utils.py:62
#, python-format #, python-format
msgid "Hello %(name)s" msgid "Hello %(name)s"
msgstr "您好 %(name)s" msgstr "您好 %(name)s"
#: users/utils.py:86 #: users/utils.py:85
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5288,11 +5284,11 @@ msgstr "" ...@@ -5288,11 +5284,11 @@ msgstr ""
" <br>\n" " <br>\n"
" " " "
#: users/utils.py:117 #: users/utils.py:116
msgid "Security notice" msgid "Security notice"
msgstr "安全通知" msgstr "安全通知"
#: users/utils.py:119 #: users/utils.py:118
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5341,11 +5337,11 @@ msgstr "" ...@@ -5341,11 +5337,11 @@ msgstr ""
" <br>\n" " <br>\n"
" " " "
#: users/utils.py:155 #: users/utils.py:154
msgid "Expiration notice" msgid "Expiration notice"
msgstr "过期通知" msgstr "过期通知"
#: users/utils.py:157 #: users/utils.py:156
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5367,11 +5363,11 @@ msgstr "" ...@@ -5367,11 +5363,11 @@ msgstr ""
" <br>\n" " <br>\n"
" " " "
#: users/utils.py:176 #: users/utils.py:175
msgid "SSH Key Reset" msgid "SSH Key Reset"
msgstr "重置ssh密钥" msgstr "重置ssh密钥"
#: users/utils.py:178 #: users/utils.py:177
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5485,7 +5481,7 @@ msgstr "MFA 解绑成功,返回登录页面" ...@@ -5485,7 +5481,7 @@ msgstr "MFA 解绑成功,返回登录页面"
msgid "Password length" msgid "Password length"
msgstr "密码长度" msgstr "密码长度"
#: xpack/plugins/change_auth_plan/forms.py:66 #: xpack/plugins/change_auth_plan/forms.py:75
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:60 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:60
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:81 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:81
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:17 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:17
...@@ -5499,7 +5495,7 @@ msgstr "密码长度" ...@@ -5499,7 +5495,7 @@ msgstr "密码长度"
msgid "Periodic perform" msgid "Periodic perform"
msgstr "定时执行" msgstr "定时执行"
#: xpack/plugins/change_auth_plan/forms.py:70 #: xpack/plugins/change_auth_plan/forms.py:79
msgid "" msgid ""
"Tips: The username of the user on the asset to be modified. if the user " "Tips: The username of the user on the asset to be modified. if the user "
"exists, change the password; If the user does not exist, create the user." "exists, change the password; If the user does not exist, create the user."
...@@ -5507,12 +5503,12 @@ msgstr "" ...@@ -5507,12 +5503,12 @@ msgstr ""
"提示:用户名为将要修改的资产上的用户的用户名。如果用户存在,则修改密码;如果" "提示:用户名为将要修改的资产上的用户的用户名。如果用户存在,则修改密码;如果"
"用户不存在,则创建用户。" "用户不存在,则创建用户。"
#: xpack/plugins/change_auth_plan/forms.py:74 xpack/plugins/cloud/forms.py:90 #: xpack/plugins/change_auth_plan/forms.py:83 xpack/plugins/cloud/forms.py:90
#: xpack/plugins/gathered_user/forms.py:44 #: xpack/plugins/gathered_user/forms.py:44
msgid "Tips: (Units: hour)" msgid "Tips: (Units: hour)"
msgstr "提示:(单位: 时)" msgstr "提示:(单位: 时)"
#: xpack/plugins/change_auth_plan/forms.py:75 xpack/plugins/cloud/forms.py:91 #: xpack/plugins/change_auth_plan/forms.py:84 xpack/plugins/cloud/forms.py:91
#: xpack/plugins/gathered_user/forms.py:45 #: xpack/plugins/gathered_user/forms.py:45
msgid "" msgid ""
"eg: Every Sunday 03:05 run <5 3 * * 0> <br> Tips: Using 5 digits linux " "eg: Every Sunday 03:05 run <5 3 * * 0> <br> Tips: Using 5 digits linux "
...@@ -6307,45 +6303,6 @@ msgstr "创建" ...@@ -6307,45 +6303,6 @@ msgstr "创建"
#~ msgid "Update user groups" #~ msgid "Update user groups"
#~ msgstr "更新用户组" #~ msgstr "更新用户组"
# msgid "Update user"
# msgstr "更新用户"
#~ msgid ""
#~ "\n"
#~ " <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/"
#~ "bootstrap/3.2.0/css/bootstrap.min.css\">\n"
#~ " <p style=\"text-indent:2em;\">\n"
#~ " <span>\n"
#~ " <a href=\"%(rest_password_url)s?token="
#~ "%(rest_password_token)s\">click here to set your password</a>\n"
#~ " </span> \n"
#~ " <span>\n"
#~ " This link is valid for 1 hour. After it expires, <a href="
#~ "\"%(forget_password_url)s?email=%(email)s\">request new one</a>\n"
#~ " </span> \n"
#~ " <span>\n"
#~ " <a href=\"%(login_url)s\">Login direct</a>\n"
#~ " </span>\n"
#~ " </p>\n"
#~ " "
#~ msgstr ""
#~ "\n"
#~ " <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/"
#~ "bootstrap/3.2.0/css/bootstrap.min.css\">\n"
#~ " <p style=\"text-indent:2em;\">\n"
#~ " <span>\n"
#~ " <a href=\"%(rest_password_url)s?token="
#~ "%(rest_password_token)s\">请点击这里设置密码</a>\n"
#~ " </span> \n"
#~ " <span>\n"
#~ " 这个链接有效期1小时, 超过时间您可以, <a href="
#~ "\"%(forget_password_url)s?email=%(email)s\">重新申请</a>\n"
#~ " </span> \n"
#~ " <span>\n"
#~ " <a href=\"%(login_url)s\">Login direct</a>\n"
#~ " </span>\n"
#~ " </p>\n"
#~ " "
#~ msgid "Template" #~ msgid "Template"
#~ msgstr "模板" #~ msgstr "模板"
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
<title>{% trans 'Task log' %}</title> <title>{% trans 'Task log' %}</title>
<script src="{% static 'js/jquery-3.1.1.min.js' %}"></script> <script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
<script src="{% static 'js/plugins/xterm/xterm.js' %}"></script> <script src="{% static 'js/plugins/xterm/xterm.js' %}"></script>
<script src="{% static 'js/plugins/xterm/addons/fit/fit.js' %}"></script>
<link rel="stylesheet" href="{% static 'js/plugins/xterm/xterm.css' %}" /> <link rel="stylesheet" href="{% static 'js/plugins/xterm/xterm.css' %}" />
<style> <style>
body { body {
...@@ -40,7 +41,7 @@ ...@@ -40,7 +41,7 @@
disableStdin: true disableStdin: true
}); });
term.open(document.getElementById('term')); term.open(document.getElementById('term'));
term.resize(120, 30); window.fit.fit(term);
ws = new WebSocket(wsURL); ws = new WebSocket(wsURL);
ws.onmessage = function(e) { ws.onmessage = function(e) {
...@@ -61,5 +62,7 @@ ...@@ -61,5 +62,7 @@
term.write("Connect websocket server error") term.write("Connect websocket server error")
} }
} }
}).on('resize', window, function () {
window.fit.fit(term);
}); });
</script> </script>
...@@ -80,9 +80,7 @@ ...@@ -80,9 +80,7 @@
<select class="select2 form-control" <select class="select2 form-control"
id="system-users-select"> id="system-users-select">
{% for s in system_users %} {% for s in system_users %}
{% if s.protocol == 'ssh' and s.login_mode == 'auto' %} <option value="{{ s.id }}" {% if s.protocol != 'ssh' or s.login_mode != 'auto' %}disabled{% endif %}>{{ s }}</option>
<option value="{{ s.id }}">{{ s }}</option>
{% endif %}
{% endfor %} {% endfor %}
</select> </select>
<button type="button" <button type="button"
...@@ -104,41 +102,6 @@ ...@@ -104,41 +102,6 @@
var url = null; var url = null;
var treeUrl = "{% url 'api-perms:my-nodes-with-assets-as-tree' %}?cache_policy=1"; var treeUrl = "{% url 'api-perms:my-nodes-with-assets-as-tree' %}?cache_policy=1";
function proposeGeometry(term) {
if (!term.element.parentElement) {
return null;
}
var parentElementStyle = window.getComputedStyle(term.element.parentElement);
var parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
var parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));
var elementStyle = window.getComputedStyle(term.element);
var elementPadding = {
top: parseInt(elementStyle.getPropertyValue('padding-top')),
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
right: parseInt(elementStyle.getPropertyValue('padding-right')),
left: parseInt(elementStyle.getPropertyValue('padding-left'))
};
var elementPaddingVer = elementPadding.top + elementPadding.bottom;
var elementPaddingHor = elementPadding.right + elementPadding.left;
var availableHeight = parentElementHeight - elementPaddingVer;
var availableWidth = parentElementWidth - elementPaddingHor - term._core.viewport.scrollBarWidth;
var geometry = {
cols: Math.floor(availableWidth / term._core.renderer.dimensions.actualCellWidth),
rows: Math.floor(availableHeight / term._core.renderer.dimensions.actualCellHeight)
};
return geometry;
}
function fit(term) {
var geometry = proposeGeometry(term);
if (geometry) {
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
term._core.renderer.clear();
term.resize(geometry.cols, geometry.rows);
}
}
}
function initTree() { function initTree() {
$('#assetTree').html("{% trans 'Loading' %}" + '..'); $('#assetTree').html("{% trans 'Loading' %}" + '..');
if (systemUserId) { if (systemUserId) {
...@@ -159,12 +122,6 @@ ...@@ -159,12 +122,6 @@
enable: true enable: true
} }
}, },
async: {
enable: true,
url: url,
autoParam: ["id=key", "name=n", "level=lv"],
type: 'get'
},
edit: { edit: {
enable: true, enable: true,
showRemoveBtn: false, showRemoveBtn: false,
...@@ -248,13 +205,15 @@ ...@@ -248,13 +205,15 @@
lineHeight: 1, lineHeight: 1,
rightClickSelectsWord: true, rightClickSelectsWord: true,
disableStdin: true, disableStdin: true,
cursorBlink: false,
theme: { theme: {
background: '#1f1b1b' background: '#1f1b1b'
} }
}); });
term.open(document.getElementById('term')); term.open(document.getElementById('term'));
var msg = "{% trans 'Select the left asset, select the running system user, execute command in batch' %}" + "\r\n"; var msg = "{% trans 'Select the left asset, select the running system user, execute command in batch' %}" + "\r\n";
fit(term); window.fit.fit(term);
{#fit(term);#}
term.write(msg); term.write(msg);
var scheme = document.location.protocol === "https:" ? "wss" : "ws"; var scheme = document.location.protocol === "https:" ? "wss" : "ws";
......
...@@ -70,7 +70,7 @@ class CommandExecutionStartView(PermissionsMixin, TemplateView): ...@@ -70,7 +70,7 @@ class CommandExecutionStartView(PermissionsMixin, TemplateView):
user = self.request.user user = self.request.user
with tmp_to_root_org(): with tmp_to_root_org():
util = AssetPermissionUtilV2(user) util = AssetPermissionUtilV2(user)
system_users = [s for s in util.get_system_users() if s.protocol == 'ssh'] system_users = util.get_system_users()
return system_users return system_users
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
......
...@@ -3,11 +3,13 @@ import os ...@@ -3,11 +3,13 @@ import os
import threading import threading
import json import json
from celery.result import AsyncResult from common.utils import get_logger
from .celery.utils import get_celery_task_log_path from .celery.utils import get_celery_task_log_path
from channels.generic.websocket import JsonWebsocketConsumer from channels.generic.websocket import JsonWebsocketConsumer
logger = get_logger(__name__)
class CeleryLogWebsocket(JsonWebsocketConsumer): class CeleryLogWebsocket(JsonWebsocketConsumer):
disconnected = False disconnected = False
...@@ -22,6 +24,7 @@ class CeleryLogWebsocket(JsonWebsocketConsumer): ...@@ -22,6 +24,7 @@ class CeleryLogWebsocket(JsonWebsocketConsumer):
self.handle_task(task_id) self.handle_task(task_id)
def handle_task(self, task_id): def handle_task(self, task_id):
logger.info("Task id: {}".format(task_id))
log_path = get_celery_task_log_path(task_id) log_path = get_celery_task_log_path(task_id)
def func(): def func():
...@@ -34,19 +37,24 @@ class CeleryLogWebsocket(JsonWebsocketConsumer): ...@@ -34,19 +37,24 @@ class CeleryLogWebsocket(JsonWebsocketConsumer):
continue continue
self.send_json({'message': '\r\n'}) self.send_json({'message': '\r\n'})
try: try:
task_log_f = open(log_path) logger.debug('Task log path: {}'.format(log_path))
task_log_f = open(log_path, 'rb')
break break
except OSError: except OSError:
return return
if not task_log_f:
return
while not self.disconnected: while not self.disconnected:
data = task_log_f.readline() data = task_log_f.readline()
if data: if data:
data = data.replace('\n', '\r\n') data = data.replace(b'\n', b'\r\n')
self.send_json({'message': data, 'task': task_id}) self.send_json({'message': data.decode(errors='ignore'), 'task': task_id})
if data.startswith('Task') and data.find('succeeded'): if data.startswith(b'Task') and data.find(b'succeeded'):
break break
time.sleep(0.2) time.sleep(0.1)
task_log_f.close() task_log_f.close()
thread = threading.Thread(target=func) thread = threading.Thread(target=func)
thread.start() thread.start()
......
...@@ -190,7 +190,7 @@ function initTable() { ...@@ -190,7 +190,7 @@ function initTable() {
{data: "id"}, {data: "name"}, {data: "users", orderable: false}, {data: "id"}, {data: "name"}, {data: "users", orderable: false},
{data: "user_groups", orderable: false}, {data: "assets", orderable: false}, {data: "user_groups", orderable: false}, {data: "assets", orderable: false},
{data: "nodes", orderable: false}, {data: "system_users", orderable: false}, {data: "nodes", orderable: false}, {data: "system_users", orderable: false},
{data: "is_valid", orderable: false}, {data: "id", orderable: false} {data: "is_valid", orderable: false}, {data: "id", orderable: false, width: "100px"}
], ],
select: {}, select: {},
op_html: $('#actions').html() op_html: $('#actions').html()
......
...@@ -62,10 +62,10 @@ asset_permission_urlpatterns = [ ...@@ -62,10 +62,10 @@ asset_permission_urlpatterns = [
path('user-groups/<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGroupGrantedAssetSystemUsersApi.as_view(), name='user-group-asset-system-users'), path('user-groups/<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGroupGrantedAssetSystemUsersApi.as_view(), name='user-group-asset-system-users'),
# 用户和资产授权变更 # 用户和资产授权变更
path('asset-permissions/<uuid:pk>/user/remove/', api.AssetPermissionRemoveUserApi.as_view(), name='asset-permission-remove-user'), path('asset-permissions/<uuid:pk>/users/remove/', api.AssetPermissionRemoveUserApi.as_view(), name='asset-permission-remove-user'),
path('asset-permissions/<uuid:pk>/user/add/', api.AssetPermissionAddUserApi.as_view(), name='asset-permission-add-user'), path('asset-permissions/<uuid:pk>/users/add/', api.AssetPermissionAddUserApi.as_view(), name='asset-permission-add-user'),
path('asset-permissions/<uuid:pk>/asset/remove/', api.AssetPermissionRemoveAssetApi.as_view(), name='asset-permission-remove-asset'), path('asset-permissions/<uuid:pk>/assets/remove/', api.AssetPermissionRemoveAssetApi.as_view(), name='asset-permission-remove-asset'),
path('asset-permissions/<uuid:pk>/asset/add/', api.AssetPermissionAddAssetApi.as_view(), name='asset-permission-add-asset'), path('asset-permissions/<uuid:pk>/assets/add/', api.AssetPermissionAddAssetApi.as_view(), name='asset-permission-add-asset'),
# 授权规则中授权的资产 # 授权规则中授权的资产
path('asset-permissions/<uuid:pk>/assets/', api.AssetPermissionAssetsApi.as_view(), name='asset-permission-assets'), path('asset-permissions/<uuid:pk>/assets/', api.AssetPermissionAssetsApi.as_view(), name='asset-permission-assets'),
...@@ -75,7 +75,7 @@ asset_permission_urlpatterns = [ ...@@ -75,7 +75,7 @@ asset_permission_urlpatterns = [
path('asset-permissions/user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'), path('asset-permissions/user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'),
# 刷新缓存 # 刷新缓存
path('asset-permissions/user/cache/refresh/', api.RefreshAssetPermissionCacheApi.as_view(), name='refresh-asset-permission-cache'), path('asset-permissions/cache/refresh/', api.RefreshAssetPermissionCacheApi.as_view(), name='refresh-asset-permission-cache'),
] ]
...@@ -99,10 +99,10 @@ remote_app_permission_urlpatterns = [ ...@@ -99,10 +99,10 @@ remote_app_permission_urlpatterns = [
path('remote-app-permissions/user/validate/', api.ValidateUserRemoteAppPermissionApi.as_view(), name='validate-user-remote-app-permission'), path('remote-app-permissions/user/validate/', api.ValidateUserRemoteAppPermissionApi.as_view(), name='validate-user-remote-app-permission'),
# 用户和RemoteApp变更 # 用户和RemoteApp变更
path('remote-app-permissions/<uuid:pk>/user/add/', api.RemoteAppPermissionAddUserApi.as_view(), name='remote-app-permission-add-user'), path('remote-app-permissions/<uuid:pk>/users/add/', api.RemoteAppPermissionAddUserApi.as_view(), name='remote-app-permission-add-user'),
path('remote-app-permissions/<uuid:pk>/user/remove/', api.RemoteAppPermissionRemoveUserApi.as_view(), name='remote-app-permission-remove-user'), path('remote-app-permissions/<uuid:pk>/users/remove/', api.RemoteAppPermissionRemoveUserApi.as_view(), name='remote-app-permission-remove-user'),
path('remote-app-permissions/<uuid:pk>/remote-app/remove/', api.RemoteAppPermissionRemoveRemoteAppApi.as_view(), name='remote-app-permission-remove-remote-app'), path('remote-app-permissions/<uuid:pk>/remote-apps/remove/', api.RemoteAppPermissionRemoveRemoteAppApi.as_view(), name='remote-app-permission-remove-remote-app'),
path('remote-app-permissions/<uuid:pk>/remote-app/add/', api.RemoteAppPermissionAddRemoteAppApi.as_view(), name='remote-app-permission-add-remote-app'), path('remote-app-permissions/<uuid:pk>/remote-apps/add/', api.RemoteAppPermissionAddRemoteAppApi.as_view(), name='remote-app-permission-add-remote-app'),
] ]
old_version_urlpatterns = [ old_version_urlpatterns = [
......
...@@ -234,6 +234,9 @@ class AssetPermissionUtilV2(AssetPermissionUtilCacheMixin): ...@@ -234,6 +234,9 @@ class AssetPermissionUtilV2(AssetPermissionUtilCacheMixin):
if user_tree.contains(key): if user_tree.contains(key):
nodes_single_assets.pop(key) nodes_single_assets.pop(key)
if not nodes_single_assets:
return
# 如果要设置到ungroup中 # 如果要设置到ungroup中
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE: if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
node_key = Node.ungrouped_key node_key = Node.ungrouped_key
...@@ -336,8 +339,8 @@ class AssetPermissionUtilV2(AssetPermissionUtilCacheMixin): ...@@ -336,8 +339,8 @@ class AssetPermissionUtilV2(AssetPermissionUtilCacheMixin):
self.add_direct_nodes_to_user_tree(user_tree) self.add_direct_nodes_to_user_tree(user_tree)
self.add_single_assets_node_to_user_tree(user_tree) self.add_single_assets_node_to_user_tree(user_tree)
self.parse_user_tree_to_full_tree(user_tree) self.parse_user_tree_to_full_tree(user_tree)
self.add_empty_node_if_need(user_tree)
self.add_favorite_node_if_need(user_tree) self.add_favorite_node_if_need(user_tree)
self.add_empty_node_if_need(user_tree)
self.set_user_tree_to_cache_if_need(user_tree) self.set_user_tree_to_cache_if_need(user_tree)
self.set_user_tree_to_local(user_tree) self.set_user_tree_to_local(user_tree)
return user_tree return user_tree
...@@ -487,6 +490,7 @@ class ParserNode: ...@@ -487,6 +490,7 @@ class ParserNode:
'ip': asset.ip, 'ip': asset.ip,
'protocols': asset.protocols_as_list, 'protocols': asset.protocols_as_list,
'platform': asset.platform, 'platform': asset.platform,
"org_name": asset.org_name,
}, },
} }
} }
......
...@@ -5,6 +5,7 @@ import os ...@@ -5,6 +5,7 @@ import os
import json import json
import jms_storage import jms_storage
from smtplib import SMTPSenderRefused
from rest_framework import generics from rest_framework import generics
from rest_framework.views import Response, APIView from rest_framework.views import Response, APIView
from django.conf import settings from django.conf import settings
...@@ -41,9 +42,20 @@ class MailTestingAPI(APIView): ...@@ -41,9 +42,20 @@ class MailTestingAPI(APIView):
email_from = email_from or email_host_user email_from = email_from or email_host_user
email_recipient = email_recipient or email_from email_recipient = email_recipient or email_from
send_mail(subject, message, email_from, [email_recipient]) send_mail(subject, message, email_from, [email_recipient])
except SMTPSenderRefused as e:
resp = e.smtp_error
if isinstance(resp, bytes):
for coding in ('gbk', 'utf8'):
try:
resp = resp.decode(coding)
except UnicodeDecodeError:
continue
else:
break
return Response({"error": str(resp)}, status=401)
except Exception as e: except Exception as e:
print(e)
return Response({"error": str(e)}, status=401) return Response({"error": str(e)}, status=401)
return Response({"msg": self.success_message.format(email_recipient)}) return Response({"msg": self.success_message.format(email_recipient)})
else: else:
return Response({"error": str(serializer.errors)}, status=401) return Response({"error": str(serializer.errors)}, status=401)
......
...@@ -201,7 +201,7 @@ function formSubmit(props) { ...@@ -201,7 +201,7 @@ function formSubmit(props) {
var errors = jqXHR.responseJSON; var errors = jqXHR.responseJSON;
var noneFieldErrorRef = props.form.children('.alert-danger'); var noneFieldErrorRef = props.form.children('.alert-danger');
if (noneFieldErrorRef.length !== 1) { if (noneFieldErrorRef.length !== 1) {
props.form.prepend('<div class="alert alert-danger" style="display: none"></div>'); props.form.prepend('<div class="alert alert-danger has-error" style="display: none"></div>');
noneFieldErrorRef = props.form.children('.alert-danger'); noneFieldErrorRef = props.form.children('.alert-danger');
} }
var noneFieldErrorMsg = ""; var noneFieldErrorMsg = "";
...@@ -247,6 +247,7 @@ function formSubmit(props) { ...@@ -247,6 +247,7 @@ function formSubmit(props) {
noneFieldErrorRef.css('display', 'block'); noneFieldErrorRef.css('display', 'block');
noneFieldErrorRef.html(noneFieldErrorMsg); noneFieldErrorRef.html(noneFieldErrorMsg);
} }
$('.has-error').get(0).scrollIntoView();
} }
}) })
...@@ -453,6 +454,7 @@ jumpserver.initDataTable = function (options) { ...@@ -453,6 +454,7 @@ jumpserver.initDataTable = function (options) {
{ {
targets: 0, targets: 0,
orderable: false, orderable: false,
width: "20px",
createdCell: function (td, cellData) { createdCell: function (td, cellData) {
$(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData)); $(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData));
} }
...@@ -550,6 +552,7 @@ jumpserver.initServerSideDataTable = function (options) { ...@@ -550,6 +552,7 @@ jumpserver.initServerSideDataTable = function (options) {
{ {
targets: 0, targets: 0,
orderable: false, orderable: false,
width: "20px",
createdCell: function (td, cellData) { createdCell: function (td, cellData) {
$(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData)); $(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData));
} }
......
...@@ -82,7 +82,7 @@ function initTable() { ...@@ -82,7 +82,7 @@ function initTable() {
], ],
ajax_url: '{% url "api-users:user-group-list" %}?display=1', ajax_url: '{% url "api-users:user-group-list" %}?display=1',
columns: [{data: function(){return ""}}, {data: "name" }, {data: "users", orderable: false}, columns: [{data: function(){return ""}}, {data: "name" }, {data: "users", orderable: false},
{data: "comment"}, {data: "id", orderable: false }], {data: "comment"}, {data: "id", orderable: false, width:"100px"}],
order: [], order: [],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
......
...@@ -125,7 +125,7 @@ function initTable() { ...@@ -125,7 +125,7 @@ function initTable() {
{data: "groups_display", orderable: false}, {data: "groups_display", orderable: false},
{data: "source"}, {data: "source"},
{data: "is_valid", orderable: false}, {data: "is_valid", orderable: false},
{data: "id", orderable: false} {data: "id", orderable: false, width: "100px"}
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
}; };
......
...@@ -22,21 +22,20 @@ logger = logging.getLogger('jumpserver') ...@@ -22,21 +22,20 @@ logger = logging.getLogger('jumpserver')
def construct_user_created_email_body(user): def construct_user_created_email_body(user):
default_body = _(""" default_body = _("""
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <div>
<p style="text-indent:2em;"> <p>Your account has been created successfully</p>
<span> <div>
Username: %(username)s. Username: %(username)s
</span> <br/>
<span> Password: <a href="%(rest_password_url)s?token=%(rest_password_token)s">
<a href="%(rest_password_url)s?token=%(rest_password_token)s">click here to set your password</a> click here to set your password</a>
</span> (This link is valid for 1 hour. After it expires, <a href="%(forget_password_url)s?email=%(email)s">request new one</a>)
<span> </div>
This link is valid for 1 hour. After it expires, <a href="%(forget_password_url)s?email=%(email)s">request new one</a> <div>
</span> <p>---</p>
<span>
<a href="%(login_url)s">Login direct</a> <a href="%(login_url)s">Login direct</a>
</span> </div>
</p> </div>
""") % { """) % {
'username': user.username, 'username': user.username,
'rest_password_url': reverse('users:reset-password', external=True), 'rest_password_url': reverse('users:reset-password', external=True),
......
...@@ -65,6 +65,7 @@ logging.basicConfig( ...@@ -65,6 +65,7 @@ logging.basicConfig(
EXIT_EVENT = threading.Event() EXIT_EVENT = threading.Event()
LOCK = threading.Lock() LOCK = threading.Lock()
files_preserve = [] files_preserve = []
STOP_TIMEOUT = 10
logger = logging.getLogger() logger = logging.getLogger()
...@@ -120,7 +121,7 @@ def check_pid(pid): ...@@ -120,7 +121,7 @@ def check_pid(pid):
def get_pid_file_path(s): def get_pid_file_path(s):
return os.path.join('/tmp', '{}.pid'.format(s)) return os.path.join(TMP_DIR, '{}.pid'.format(s))
def get_log_file_path(s): def get_log_file_path(s):
...@@ -433,9 +434,19 @@ def stop_service(srv, sig=15): ...@@ -433,9 +434,19 @@ def stop_service(srv, sig=15):
if not is_running(s): if not is_running(s):
show_service_status(s) show_service_status(s)
continue continue
logging.info("Stop service: {}".format(s)) print("Stop service: {}".format(s), end='')
pid = get_pid(s) pid = get_pid(s)
os.kill(pid, sig) os.kill(pid, sig)
for i in range(STOP_TIMEOUT):
if i == STOP_TIMEOUT - 1:
print("\033[31m Error\033[0m")
if not is_running(s):
print("\033[32m Ok\033[0m")
break
else:
time.sleep(1)
continue
with LOCK: with LOCK:
processes.pop(s, None) processes.pop(s, None)
...@@ -472,9 +483,9 @@ def show_service_status(s): ...@@ -472,9 +483,9 @@ def show_service_status(s):
for ns in services_set: for ns in services_set:
if is_running(ns): if is_running(ns):
pid = get_pid(ns) pid = get_pid(ns)
logging.info("{} is running: {}".format(ns, pid)) print("{} is running: {}".format(ns, pid))
else: else:
logging.info("{} is stopped".format(ns)) print("{} is stopped".format(ns))
if __name__ == '__main__': if __name__ == '__main__':
...@@ -499,6 +510,7 @@ if __name__ == '__main__': ...@@ -499,6 +510,7 @@ if __name__ == '__main__':
) )
parser.add_argument('-d', '--daemon', nargs="?", const=1) parser.add_argument('-d', '--daemon', nargs="?", const=1)
parser.add_argument('-w', '--worker', type=int, nargs="?", const=4) parser.add_argument('-w', '--worker', type=int, nargs="?", const=4)
parser.add_argument('-f', '--force', nargs="?", const=1)
args = parser.parse_args() args = parser.parse_args()
if args.daemon: if args.daemon:
DAEMON = True DAEMON = True
...@@ -513,6 +525,9 @@ if __name__ == '__main__': ...@@ -513,6 +525,9 @@ if __name__ == '__main__':
start_services_and_watch(srv) start_services_and_watch(srv)
os._exit(0) os._exit(0)
elif action == "stop": elif action == "stop":
if args.force:
stop_service_force(srv)
else:
stop_service(srv) stop_service(srv)
elif action == "restart": elif action == "restart":
DAEMON = True DAEMON = True
......
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