Merge pull request #2266 from jumpserver/dev

Dev
pull/2328/head
老广 2018-12-25 14:32:47 +08:00 committed by GitHub
commit 0798e3c466
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 106 additions and 33 deletions

View File

@ -28,6 +28,15 @@ class DomainForm(forms.ModelForm):
initial['assets'] = kwargs['instance'].assets.all() initial['assets'] = kwargs['instance'].assets.all()
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# 前端渲染优化, 防止过多资产
assets_field = self.fields.get('assets')
if not self.data:
instance = kwargs.get('instance')
if instance:
assets_field.queryset = instance.assets.all()
else:
assets_field.queryset = Asset.objects.none()
def save(self, commit=True): def save(self, commit=True):
instance = super().save(commit=commit) instance = super().save(commit=commit)
assets = self.cleaned_data['assets'] assets = self.cleaned_data['assets']

View File

@ -26,6 +26,15 @@ class LabelForm(forms.ModelForm):
initial['assets'] = kwargs['instance'].assets.all() initial['assets'] = kwargs['instance'].assets.all()
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# 前端渲染优化, 防止过多资产
assets_field = self.fields.get('assets')
if not self.data:
instance = kwargs.get('instance')
if instance:
assets_field.queryset = instance.assets.all()
else:
assets_field.queryset = Asset.objects.none()
def save(self, commit=True): def save(self, commit=True):
label = super().save(commit=commit) label = super().save(commit=commit)
assets = self.cleaned_data['assets'] assets = self.cleaned_data['assets']

View File

@ -1,16 +1,16 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
import json import json
import re import re
import time
import os import os
from celery import shared_task from celery import shared_task
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.cache import cache
from common.utils import capacity_convert, \ from common.utils import capacity_convert, \
sum_capacity, encrypt_password, get_logger sum_capacity, encrypt_password, get_logger
from ops.celery.utils import register_as_period_task, after_app_shutdown_clean, \ from ops.celery.utils import register_as_period_task, after_app_shutdown_clean
after_app_ready_start
from orgs.utils import set_to_root_org
from .models import SystemUser, AdminUser, Asset from .models import SystemUser, AdminUser, Asset
from . import const from . import const
@ -211,6 +211,12 @@ def test_admin_user_connectivity_period():
""" """
A period task that update the ansible task period A period task that update the ansible task period
""" """
key = '_JMS_TEST_ADMIN_USER_CONNECTIVITY_PERIOD'
prev_execute_time = cache.get(key)
if prev_execute_time:
logger.debug("Test admin user connectivity, less than 40 minutes, skip")
return
cache.set(key, 1, 60*40)
admin_users = AdminUser.objects.all() admin_users = AdminUser.objects.all()
for admin_user in admin_users: for admin_user in admin_users:
task_name = _("Test admin user connectivity period: {}").format(admin_user.name) task_name = _("Test admin user connectivity period: {}").format(admin_user.name)

View File

@ -24,7 +24,6 @@
{% block custom_foot_js %} {% block custom_foot_js %}
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function () { $(document).ready(function () {
console.log($.fn.select2.defaults);
$('.select2').select2().off("select2:open"); $('.select2').select2().off("select2:open");
}).on('click', '.select2-selection__rendered', function (e) { }).on('click', '.select2-selection__rendered', function (e) {
e.preventDefault(); e.preventDefault();
@ -33,6 +32,18 @@ $(document).ready(function () {
}) })
.on('click', '#btn_asset_modal_confirm', function () { .on('click', '#btn_asset_modal_confirm', function () {
var assets = asset_table2.selected; var assets = asset_table2.selected;
var options = [];
$('#id_assets option').each(function (i, v) {
options.push(v.value)
});
asset_table2.selected_rows.forEach(function (i) {
var name = i.hostname + '(' + i.ip + ')';
var option = new Option(name, i.id, false, true);
if (options.indexOf(i.id) === -1) {
$('#id_assets').append(option).trigger('change');
}
});
$('.select2').val(assets).trigger('change'); $('.select2').val(assets).trigger('change');
$("#asset_list_modal").modal('hide'); $("#asset_list_modal").modal('hide');

View File

@ -36,6 +36,18 @@ $(document).ready(function () {
}) })
.on('click', '#btn_asset_modal_confirm', function () { .on('click', '#btn_asset_modal_confirm', function () {
var assets = asset_table2.selected; var assets = asset_table2.selected;
var options = [];
$('#id_assets option').each(function (i, v) {
options.push(v.value)
});
asset_table2.selected_rows.forEach(function (i) {
var name = i.hostname + '(' + i.ip + ')';
var option = new Option(name, i.id, false, true);
if (options.indexOf(i.id) === -1) {
$('#id_assets').append(option).trigger('change');
}
});
$('#id_assets').val(assets).trigger('change'); $('#id_assets').val(assets).trigger('change');
$("#asset_list_modal").modal('hide'); $("#asset_list_modal").modal('hide');
}) })

View File

@ -139,22 +139,23 @@ class TerminalSettingForm(BaseForm):
(50, 50), (50, 50),
) )
TERMINAL_PASSWORD_AUTH = forms.BooleanField( TERMINAL_PASSWORD_AUTH = forms.BooleanField(
initial=True, required=False, label=_("Password auth") required=False, label=_("Password auth")
) )
TERMINAL_PUBLIC_KEY_AUTH = forms.BooleanField( TERMINAL_PUBLIC_KEY_AUTH = forms.BooleanField(
initial=True, required=False, label=_("Public key auth") required=False, label=_("Public key auth")
) )
TERMINAL_HEARTBEAT_INTERVAL = forms.IntegerField( TERMINAL_HEARTBEAT_INTERVAL = forms.IntegerField(
initial=5, label=_("Heartbeat interval"), help_text=_("Units: seconds") min_value=5, label=_("Heartbeat interval"),
help_text=_("Units: seconds")
) )
TERMINAL_ASSET_LIST_SORT_BY = forms.ChoiceField( TERMINAL_ASSET_LIST_SORT_BY = forms.ChoiceField(
choices=SORT_BY_CHOICES, initial='hostname', label=_("List sort by") choices=SORT_BY_CHOICES, label=_("List sort by")
) )
TERMINAL_ASSET_LIST_PAGE_SIZE = forms.ChoiceField( TERMINAL_ASSET_LIST_PAGE_SIZE = forms.ChoiceField(
choices=PAGE_SIZE_CHOICES, initial='auto', label=_("List page size"), choices=PAGE_SIZE_CHOICES, label=_("List page size"),
) )
TERMINAL_SESSION_KEEP_DURATION = forms.IntegerField( TERMINAL_SESSION_KEEP_DURATION = forms.IntegerField(
label=_("Session keep duration"), min_value=1, label=_("Session keep duration"),
help_text=_("Units: days, Session, record, command will be delete " help_text=_("Units: days, Session, record, command will be delete "
"if more than duration, only in database") "if more than duration, only in database")
) )
@ -167,8 +168,7 @@ class TerminalCommandStorage(BaseForm):
class SecuritySettingForm(BaseForm): class SecuritySettingForm(BaseForm):
# MFA global setting # MFA global setting
SECURITY_MFA_AUTH = forms.BooleanField( SECURITY_MFA_AUTH = forms.BooleanField(
initial=False, required=False, required=False, label=_("MFA Secondary certification"),
label=_("MFA Secondary certification"),
help_text=_( help_text=_(
'After opening, the user login must use MFA secondary ' 'After opening, the user login must use MFA secondary '
'authentication (valid for all users, including administrators)' 'authentication (valid for all users, including administrators)'
@ -176,13 +176,11 @@ class SecuritySettingForm(BaseForm):
) )
# limit login count # limit login count
SECURITY_LOGIN_LIMIT_COUNT = forms.IntegerField( SECURITY_LOGIN_LIMIT_COUNT = forms.IntegerField(
initial=7, min_value=3, min_value=3, label=_("Limit the number of login failures")
label=_("Limit the number of login failures")
) )
# limit login time # limit login time
SECURITY_LOGIN_LIMIT_TIME = forms.IntegerField( SECURITY_LOGIN_LIMIT_TIME = forms.IntegerField(
initial=30, min_value=5, min_value=5, label=_("No logon interval"),
label=_("No logon interval"),
help_text=_( help_text=_(
"Tip: (unit/minute) if the user has failed to log in for a limited " "Tip: (unit/minute) if the user has failed to log in for a limited "
"number of times, no login is allowed during this time interval." "number of times, no login is allowed during this time interval."
@ -190,8 +188,7 @@ class SecuritySettingForm(BaseForm):
) )
# ssh max idle time # ssh max idle time
SECURITY_MAX_IDLE_TIME = forms.IntegerField( SECURITY_MAX_IDLE_TIME = forms.IntegerField(
initial=30, required=False, required=False, label=_("Connection max idle time"),
label=_("Connection max idle time"),
help_text=_( help_text=_(
'If idle time more than it, disconnect connection(only ssh now) ' 'If idle time more than it, disconnect connection(only ssh now) '
'Unit: minute' 'Unit: minute'
@ -199,8 +196,8 @@ class SecuritySettingForm(BaseForm):
) )
# password expiration time # password expiration time
SECURITY_PASSWORD_EXPIRATION_TIME = forms.IntegerField( SECURITY_PASSWORD_EXPIRATION_TIME = forms.IntegerField(
initial=9999, label=_("Password expiration time"), label=_("Password expiration time"),
min_value=1, min_value=1, max_value=99999,
help_text=_( help_text=_(
"Tip: (unit: day) " "Tip: (unit: day) "
"If the user does not update the password during the time, " "If the user does not update the password during the time, "
@ -211,35 +208,30 @@ class SecuritySettingForm(BaseForm):
) )
# min length # min length
SECURITY_PASSWORD_MIN_LENGTH = forms.IntegerField( SECURITY_PASSWORD_MIN_LENGTH = forms.IntegerField(
initial=6, label=_("Password minimum length"), min_value=6, label=_("Password minimum length"),
min_value=6
) )
# upper case # upper case
SECURITY_PASSWORD_UPPER_CASE = forms.BooleanField( SECURITY_PASSWORD_UPPER_CASE = forms.BooleanField(
initial=False, required=False, required=False, label=_("Must contain capital letters"),
label=_("Must contain capital letters"),
help_text=_( help_text=_(
'After opening, the user password changes ' 'After opening, the user password changes '
'and resets must contain uppercase letters') 'and resets must contain uppercase letters')
) )
# lower case # lower case
SECURITY_PASSWORD_LOWER_CASE = forms.BooleanField( SECURITY_PASSWORD_LOWER_CASE = forms.BooleanField(
initial=False, required=False, required=False, label=_("Must contain lowercase letters"),
label=_("Must contain lowercase letters"),
help_text=_('After opening, the user password changes ' help_text=_('After opening, the user password changes '
'and resets must contain lowercase letters') 'and resets must contain lowercase letters')
) )
# number # number
SECURITY_PASSWORD_NUMBER = forms.BooleanField( SECURITY_PASSWORD_NUMBER = forms.BooleanField(
initial=False, required=False, required=False, label=_("Must contain numeric characters"),
label=_("Must contain numeric characters"),
help_text=_('After opening, the user password changes ' help_text=_('After opening, the user password changes '
'and resets must contain numeric characters') 'and resets must contain numeric characters')
) )
# special char # special char
SECURITY_PASSWORD_SPECIAL_CHAR = forms.BooleanField( SECURITY_PASSWORD_SPECIAL_CHAR = forms.BooleanField(
initial=False, required=False, required=False, label=_("Must contain special characters"),
label=_("Must contain special characters"),
help_text=_('After opening, the user password changes ' help_text=_('After opening, the user password changes '
'and resets must contain special characters') 'and resets must contain special characters')
) )

View File

@ -320,6 +320,16 @@ defaults = {
'TERMINAL_ASSET_LIST_SORT_BY': 'hostname', 'TERMINAL_ASSET_LIST_SORT_BY': 'hostname',
'TERMINAL_ASSET_LIST_PAGE_SIZE': 'auto', 'TERMINAL_ASSET_LIST_PAGE_SIZE': 'auto',
'TERMINAL_SESSION_KEEP_DURATION': 9999, 'TERMINAL_SESSION_KEEP_DURATION': 9999,
'SECURITY_MFA_AUTH': False,
'SECURITY_LOGIN_LIMIT_COUNT': 7,
'SECURITY_LOGIN_LIMIT_TIME': 30,
'SECURITY_MAX_IDLE_TIME': 30,
'SECURITY_PASSWORD_EXPIRATION_TIME': 9999,
'SECURITY_PASSWORD_MIN_LENGTH': 6,
'SECURITY_PASSWORD_UPPER_CASE': False,
'SECURITY_PASSWORD_LOWER_CASE': False,
'SECURITY_PASSWORD_NUMBER': False,
'SECURITY_PASSWORD_SPECIAL_CHAR': False,
} }

View File

@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _
from orgs.mixins import OrgModelForm from orgs.mixins import OrgModelForm
from orgs.utils import current_org from orgs.utils import current_org
from .models import AssetPermission from .models import AssetPermission
from assets.models import Asset
class AssetPermissionForm(OrgModelForm): class AssetPermissionForm(OrgModelForm):
@ -15,6 +16,15 @@ class AssetPermissionForm(OrgModelForm):
users_field = self.fields.get('users') users_field = self.fields.get('users')
if hasattr(users_field, 'queryset'): if hasattr(users_field, 'queryset'):
users_field.queryset = current_org.get_org_users() users_field.queryset = current_org.get_org_users()
assets_field = self.fields.get('assets')
# 前端渲染优化, 防止过多资产
if not self.data:
instance = kwargs.get('instance')
if instance:
assets_field.queryset = instance.assets.all()
else:
assets_field.queryset = Asset.objects.none()
class Meta: class Meta:
model = AssetPermission model = AssetPermission

View File

@ -120,8 +120,20 @@ $(document).ready(function () {
.on('click', '#btn_asset_modal_confirm', function () { .on('click', '#btn_asset_modal_confirm', function () {
var assets = asset_table2.selected; var assets = asset_table2.selected;
$('#id_assets').val(assets).trigger('change'); var options = [];
$('#id_assets option').each(function (i, v) {
options.push(v.value)
});
asset_table2.selected_rows.forEach(function (i) {
var name = i.hostname + '(' + i.ip + ')';
var option = new Option(name, i.id, false, true);
if (options.indexOf(i.id) === -1) {
$('#id_assets').append(option).trigger('change');
}
});
$('#id_assets').val(assets).trigger('change');
$("#asset_list_modal").modal('hide'); $("#asset_list_modal").modal('hide');
}); });
</script> </script>

View File

@ -528,6 +528,7 @@ jumpserver.initServerSideDataTable = function (options) {
lengthMenu: [[10, 15, 25, 50], [10, 15, 25, 50]] lengthMenu: [[10, 15, 25, 50], [10, 15, 25, 50]]
}); });
table.selected = []; table.selected = [];
table.selected_rows = [];
table.on('select', function(e, dt, type, indexes) { table.on('select', function(e, dt, type, indexes) {
var $node = table[ type ]( indexes ).nodes().to$(); var $node = table[ type ]( indexes ).nodes().to$();
$node.find('input.ipt_check').prop('checked', true); $node.find('input.ipt_check').prop('checked', true);
@ -535,6 +536,7 @@ jumpserver.initServerSideDataTable = function (options) {
if (type === 'row') { if (type === 'row') {
var rows = table.rows(indexes).data(); var rows = table.rows(indexes).data();
$.each(rows, function (id, row) { $.each(rows, function (id, row) {
table.selected_rows.push(row);
if (row.id && $.inArray(row.id, table.selected) === -1){ if (row.id && $.inArray(row.id, table.selected) === -1){
table.selected.push(row.id) table.selected.push(row.id)
} }

View File

@ -86,7 +86,7 @@ class TerminalTokenApi(APIView):
if not terminal.user or not terminal.user.access_key: if not terminal.user or not terminal.user.access_key:
return Response("No access key generate", status=401) return Response("No access key generate", status=401)
access_key = terminal.user.access_key.first() access_key = terminal.user.access_key()
data = OrderedDict() data = OrderedDict()
data['access_key'] = {'id': access_key.id, 'secret': access_key.secret} data['access_key'] = {'id': access_key.id, 'secret': access_key.secret}
return Response(data, status=200) return Response(data, status=200)

View File

@ -47,7 +47,7 @@ class UserViewSet(IDInFilterMixin, BulkModelViewSet):
return super().get_permissions() return super().get_permissions()
def allow_bulk_destroy(self, qs, filtered): def allow_bulk_destroy(self, qs, filtered):
return qs.count() == filtered.count() return qs.count() != filtered.count()
class UserChangePasswordApi(generics.RetrieveUpdateAPIView): class UserChangePasswordApi(generics.RetrieveUpdateAPIView):