Unverified Commit fdf2807d authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #1419 from jumpserver/feature_login_mode

[Update] 添加功能,系统用户选择登录模式(自动/手动登录)
parents 73f9f546 2e6d238c
...@@ -93,14 +93,20 @@ class SystemUserForm(PasswordAndKeyAuthForm): ...@@ -93,14 +93,20 @@ class SystemUserForm(PasswordAndKeyAuthForm):
# Because we define custom field, so we need rewrite :method: `save` # Because we define custom field, so we need rewrite :method: `save`
system_user = super().save() system_user = super().save()
password = self.cleaned_data.get('password', '') or None password = self.cleaned_data.get('password', '') or None
login_mode = self.cleaned_data.get('login_mode', '') or None
auto_generate_key = self.cleaned_data.get('auto_generate_key', False) auto_generate_key = self.cleaned_data.get('auto_generate_key', False)
private_key, public_key = super().gen_keys() private_key, public_key = super().gen_keys()
if login_mode == SystemUser.MANUAL_LOGIN:
system_user.auto_push = 0
system_user.save()
if auto_generate_key: if auto_generate_key:
logger.info('Auto generate key and set system user auth') logger.info('Auto generate key and set system user auth')
system_user.auto_gen_auth() system_user.auto_gen_auth()
else: else:
system_user.set_auth(password=password, private_key=private_key, public_key=public_key) system_user.set_auth(password=password, private_key=private_key, public_key=public_key)
return system_user return system_user
def clean(self): def clean(self):
...@@ -109,12 +115,24 @@ class SystemUserForm(PasswordAndKeyAuthForm): ...@@ -109,12 +115,24 @@ class SystemUserForm(PasswordAndKeyAuthForm):
if not self.instance and not auto_generate: if not self.instance and not auto_generate:
super().validate_password_key() super().validate_password_key()
def is_valid(self):
validated = super().is_valid()
username = self.cleaned_data.get('username')
login_mode = self.cleaned_data.get('login_mode')
if login_mode == SystemUser.AUTO_LOGIN and not username:
self.add_error(
"username", _('* Automatic login mode,'
' must fill in the username.')
)
return False
return validated
class Meta: class Meta:
model = SystemUser model = SystemUser
fields = [ fields = [
'name', 'username', 'protocol', 'auto_generate_key', 'name', 'username', 'protocol', 'auto_generate_key',
'password', 'private_key_file', 'auto_push', 'sudo', 'password', 'private_key_file', 'auto_push', 'sudo',
'comment', 'shell', 'priority', 'comment', 'shell', 'priority', 'login_mode',
] ]
widgets = { widgets = {
'name': forms.TextInput(attrs={'placeholder': _('Name')}), 'name': forms.TextInput(attrs={'placeholder': _('Name')}),
...@@ -124,5 +142,8 @@ class SystemUserForm(PasswordAndKeyAuthForm): ...@@ -124,5 +142,8 @@ class SystemUserForm(PasswordAndKeyAuthForm):
'name': '* required', 'name': '* required',
'username': '* required', 'username': '* required',
'auto_push': _('Auto push system user to asset'), 'auto_push': _('Auto push system user to asset'),
'priority': _('High level will be using login asset as default, if user was granted more than 2 system user'), 'priority': _('High level will be using login asset as default, '
} 'if user was granted more than 2 system user'),
\ No newline at end of file 'login_mode': _('If you choose manual login mode, you do not '
'need to fill in the username and password.')
}
...@@ -19,7 +19,7 @@ signer = get_signer() ...@@ -19,7 +19,7 @@ signer = get_signer()
class AssetUser(models.Model): class AssetUser(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
username = models.CharField(max_length=32, verbose_name=_('Username'), validators=[alphanumeric]) username = models.CharField(max_length=32, blank=True, verbose_name=_('Username'), validators=[alphanumeric])
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password')) _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ]) _private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key')) _public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
......
...@@ -100,6 +100,13 @@ class SystemUser(AssetUser): ...@@ -100,6 +100,13 @@ class SystemUser(AssetUser):
(RDP_PROTOCOL, 'rdp'), (RDP_PROTOCOL, 'rdp'),
) )
AUTO_LOGIN = 'auto'
MANUAL_LOGIN = 'manual'
LOGIN_MODE_CHOICES = (
(AUTO_LOGIN, _('Automatic login')),
(MANUAL_LOGIN, _('Manually login'))
)
nodes = models.ManyToManyField('assets.Node', blank=True, verbose_name=_("Nodes")) nodes = models.ManyToManyField('assets.Node', blank=True, verbose_name=_("Nodes"))
assets = models.ManyToManyField('assets.Asset', blank=True, verbose_name=_("Assets")) assets = models.ManyToManyField('assets.Asset', blank=True, verbose_name=_("Assets"))
priority = models.IntegerField(default=10, verbose_name=_("Priority")) priority = models.IntegerField(default=10, verbose_name=_("Priority"))
...@@ -107,6 +114,7 @@ class SystemUser(AssetUser): ...@@ -107,6 +114,7 @@ class SystemUser(AssetUser):
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push')) auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo')) sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell')) shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
login_mode = models.CharField(choices=LOGIN_MODE_CHOICES, default=AUTO_LOGIN, max_length=10, verbose_name=_('Login mode'))
def __str__(self): def __str__(self):
return '{0.name}({0.username})'.format(self) return '{0.name}({0.username})'.format(self)
......
...@@ -18,6 +18,13 @@ class SystemUserSerializer(serializers.ModelSerializer): ...@@ -18,6 +18,13 @@ class SystemUserSerializer(serializers.ModelSerializer):
model = SystemUser model = SystemUser
exclude = ('_password', '_private_key', '_public_key') exclude = ('_password', '_private_key', '_public_key')
def get_field_names(self, declared_fields, info):
fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info)
fields.extend([
'get_login_mode_display',
])
return fields
@staticmethod @staticmethod
def get_unreachable_assets(obj): def get_unreachable_assets(obj):
return obj.unreachable_assets return obj.unreachable_assets
...@@ -56,7 +63,10 @@ class AssetSystemUserSerializer(serializers.ModelSerializer): ...@@ -56,7 +63,10 @@ class AssetSystemUserSerializer(serializers.ModelSerializer):
""" """
class Meta: class Meta:
model = SystemUser model = SystemUser
fields = ('id', 'name', 'username', 'priority', 'protocol', 'comment',) fields = (
'id', 'name', 'username', 'priority',
'protocol', 'comment', 'login_mode'
)
class SystemUserSimpleSerializer(serializers.ModelSerializer): class SystemUserSimpleSerializer(serializers.ModelSerializer):
......
...@@ -36,12 +36,13 @@ ...@@ -36,12 +36,13 @@
{% endif %} {% endif %}
<h3>{% trans 'Basic' %}</h3> <h3>{% trans 'Basic' %}</h3>
{% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.login_mode layout="horizontal" %}
{% bootstrap_field form.username layout="horizontal" %} {% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.priority layout="horizontal" %} {% bootstrap_field form.priority layout="horizontal" %}
{% bootstrap_field form.protocol layout="horizontal" %} {% bootstrap_field form.protocol layout="horizontal" %}
<h3 id="auth_title_id">{% trans 'Auth' %}</h3>
{% block auth %} {% block auth %}
<h3>{% trans 'Auth' %}</h3>
<div class="auto-generate"> <div class="auto-generate">
<div class="form-group"> <div class="form-group">
<label for="{{ form.auto_generate_key.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto generate key' %}</label> <label for="{{ form.auto_generate_key.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto generate key' %}</label>
...@@ -80,15 +81,22 @@ ...@@ -80,15 +81,22 @@
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}';
var protocol_id = '#' + '{{ form.protocol.id_for_label }}'; var protocol_id = '#' + '{{ form.protocol.id_for_label }}';
var login_mode_id = '#' + '{{ form.login_mode.id_for_label }}';
var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}';
var password_id = '#' + '{{ form.password.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 auto_push_id = '#' + '{{ form.auto_push.id_for_label }}'; var auto_push_id = '#' + '{{ form.auto_push.id_for_label }}';
var sudo_id = '#' + '{{ form.sudo.id_for_label }}'; var sudo_id = '#' + '{{ form.sudo.id_for_label }}';
var shell_id = '#' + '{{ form.shell.id_for_label }}'; var shell_id = '#' + '{{ form.shell.id_for_label }}';
var need_change_field = [ var need_change_field = [
auto_generate_key, private_key_id, auto_push_id, sudo_id, shell_id auto_generate_key, private_key_id, auto_push_id, sudo_id, shell_id
]; ];
var need_change_field_login_mode = [
auto_generate_key, private_key_id, auto_push_id, password_id
];
function protocolChange() { function protocolChange() {
if ($(protocol_id + " option:selected").text() === 'rdp') { if ($(protocol_id + " option:selected").text() === 'rdp') {
...@@ -97,6 +105,11 @@ function protocolChange() { ...@@ -97,6 +105,11 @@ function protocolChange() {
$(value).closest('.form-group').addClass('hidden') $(value).closest('.form-group').addClass('hidden')
}); });
} else { } else {
if($(login_mode_id).val() === 'manual'){
$(sudo_id).closest('.form-group').removeClass('hidden');
$(shell_id).closest('.form-group').removeClass('hidden');
return
}
authFieldsDisplay(); authFieldsDisplay();
$.each(need_change_field, function (index, value) { $.each(need_change_field, function (index, value) {
$(value).closest('.form-group').removeClass('hidden') $(value).closest('.form-group').removeClass('hidden')
...@@ -111,18 +124,35 @@ function authFieldsDisplay() { ...@@ -111,18 +124,35 @@ function authFieldsDisplay() {
$('.auth-fields').removeClass('hidden'); $('.auth-fields').removeClass('hidden');
} }
} }
function loginModeChange(){
if ($(login_mode_id).val() === 'manual'){
$('#auth_title_id').addClass('hidden');
$.each(need_change_field_login_mode, function(index, value){
$(value).closest('.form-group').addClass('hidden')
})
}
else if($(login_mode_id).val() === 'auto'){
$('#auth_title_id').removeClass('hidden');
protocolChange();
$(password_id).closest('.form-group').removeClass('hidden')
}
}
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2(); $('.select2').select2();
authFieldsDisplay(); authFieldsDisplay();
protocolChange(); protocolChange();
loginModeChange();
}) })
.on('change', protocol_id, function(){ .on('change', protocol_id, function(){
protocolChange(); protocolChange();
}) })
.on('change', auto_generate_key, function(){ .on('change', auto_generate_key, function(){
authFieldsDisplay(); authFieldsDisplay();
}); })
.on('change', login_mode_id, function(){
loginModeChange();
})
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -62,6 +62,10 @@ ...@@ -62,6 +62,10 @@
<td>{% trans 'Username' %}:</td> <td>{% trans 'Username' %}:</td>
<td><b>{{ system_user.username }}</b></td> <td><b>{{ system_user.username }}</b></td>
</tr> </tr>
<tr>
<td>{% trans 'Login mode' %}:</td>
<td><b>{{ system_user.get_login_mode_display }}</b></td>
</tr>
<tr> <tr>
<td>{% trans 'Protocol' %}:</td> <td>{% trans 'Protocol' %}:</td>
<td><b id="id_protocol_type">{{ system_user.protocol }}</b></td> <td><b id="id_protocol_type">{{ system_user.protocol }}</b></td>
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
<th class="text-center">{% trans 'Name' %}</th> <th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Username' %}</th> <th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Protocol' %}</th> <th class="text-center">{% trans 'Protocol' %}</th>
<th class="text-center">{% trans 'Login mode' %}</th>
<th class="text-center">{% trans 'Asset' %}</th> <th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'Reachable' %}</th> <th class="text-center">{% trans 'Reachable' %}</th>
<th class="text-center">{% trans 'Unreachable' %}</th> <th class="text-center">{% trans 'Unreachable' %}</th>
...@@ -48,7 +49,7 @@ function initTable() { ...@@ -48,7 +49,7 @@ function initTable() {
var detail_btn = '<a href="{% url "assets:system-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:system-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: 5, createdCell: function (td, cellData) { {targets: 6, createdCell: function (td, cellData) {
var innerHtml = ""; var innerHtml = "";
if (cellData !== 0) { if (cellData !== 0) {
innerHtml = "<span class='text-navy'>" + cellData + "</span>"; innerHtml = "<span class='text-navy'>" + cellData + "</span>";
...@@ -57,7 +58,7 @@ function initTable() { ...@@ -57,7 +58,7 @@ function initTable() {
} }
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData +'">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData +'">' + innerHtml + '</span>');
}}, }},
{targets: 6, createdCell: function (td, cellData) { {targets: 7, createdCell: function (td, cellData) {
var innerHtml = ""; var innerHtml = "";
if (cellData !== 0) { if (cellData !== 0) {
innerHtml = "<span class='text-danger'>" + cellData + "</span>"; innerHtml = "<span class='text-danger'>" + cellData + "</span>";
...@@ -66,7 +67,7 @@ function initTable() { ...@@ -66,7 +67,7 @@ function initTable() {
} }
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}}, }},
{targets: 7, createdCell: function (td, cellData, rowData) { {targets: 8, createdCell: function (td, cellData, rowData) {
var val = 0; var val = 0;
var innerHtml = ""; var innerHtml = "";
var total = rowData.assets_amount; var total = rowData.assets_amount;
...@@ -84,14 +85,14 @@ function initTable() { ...@@ -84,14 +85,14 @@ function initTable() {
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}}, }},
{targets: 9, createdCell: function (td, cellData, rowData) { {targets: 10, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:system-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:system-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);
$(td).html(update_btn + del_btn) $(td).html(update_btn + del_btn)
}}], }}],
ajax_url: '{% url "api-assets:system-user-list" %}', ajax_url: '{% url "api-assets:system-user-list" %}',
columns: [ columns: [
{data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "assets_amount" }, {data: "id" }, {data: "name" }, {data: "username" }, {data: "protocol"}, {data: "get_login_mode_display"}, {data: "assets_amount" },
{data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" } {data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" }
], ],
op_html: $('#actions').html() op_html: $('#actions').html()
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
{% load bootstrap3 %} {% load bootstrap3 %}
{% block auth %} {% block auth %}
<h3>{% trans 'Auth' %}</h3>
{% bootstrap_field form.password layout="horizontal" %} {% bootstrap_field form.password layout="horizontal" %}
{% bootstrap_field form.private_key_file layout="horizontal" %} {% bootstrap_field form.private_key_file layout="horizontal" %}
<div class="form-group"> <div class="form-group">
......
This diff is collapsed.
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