mirror of https://github.com/jumpserver/jumpserver
Add form validate
parent
072da114db
commit
a75e1db970
|
@ -1,8 +1,9 @@
|
|||
# coding:utf-8
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser, Tag
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from common.utils import validate_ssh_private_key, ssh_pubkey_gen
|
||||
|
||||
|
||||
# class AssetForm(forms.ModelForm):
|
||||
|
@ -141,7 +142,6 @@ class AdminUserForm(forms.ModelForm):
|
|||
widget=forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
||||
)
|
||||
auto_generate_key = forms.BooleanField(required=True, initial=True)
|
||||
# Form field name can not start with `_`, so redefine it,
|
||||
password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True,
|
||||
help_text=_('If also set private key, use that first'), required=False)
|
||||
|
@ -166,21 +166,36 @@ class AdminUserForm(forms.ModelForm):
|
|||
# Because we define custom field, so we need rewrite :method: `save`
|
||||
admin_user = super(AdminUserForm, self).save(commit=commit)
|
||||
password = self.cleaned_data['password']
|
||||
private_key_file = self.cleaned_data['private_key_file']
|
||||
private_key = self.cleaned_data['private_key_file']
|
||||
public_key = ssh_pubkey_gen(private_key)
|
||||
|
||||
if password:
|
||||
admin_user.password = password
|
||||
print(password)
|
||||
# Todo: Validate private key file, and generate public key
|
||||
# Todo: Auto generate private key and public key
|
||||
if private_key_file:
|
||||
admin_user.private_key = private_key_file.read()
|
||||
if private_key:
|
||||
admin_user.private_key = private_key
|
||||
admin_user.public_key = public_key
|
||||
admin_user.save()
|
||||
return self.instance
|
||||
return admin_user
|
||||
|
||||
def clean_private_key_file(self):
|
||||
private_key_file = self.cleaned_data['private_key_file']
|
||||
if private_key_file:
|
||||
private_key = private_key_file.read()
|
||||
if not validate_ssh_private_key(private_key):
|
||||
raise forms.ValidationError(_('Invalid private key'))
|
||||
return private_key
|
||||
return private_key_file
|
||||
|
||||
def clean(self):
|
||||
password = self.cleaned_data['password']
|
||||
private_key_file = self.cleaned_data.get('private_key_file', '')
|
||||
|
||||
if not (password or private_key_file):
|
||||
raise forms.ValidationError(_('Password and private key file must be input one'))
|
||||
|
||||
class Meta:
|
||||
model = AdminUser
|
||||
fields = ['name', 'username', 'auto_generate_key', 'password', 'private_key_file', 'as_default', 'comment']
|
||||
fields = ['name', 'username', 'password', 'private_key_file', 'comment']
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
||||
|
|
|
@ -6,8 +6,9 @@ from django.db import models
|
|||
from django.core import serializers
|
||||
import logging
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from common.utils import signer
|
||||
from common.utils import signer, validate_ssh_private_key
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -91,13 +92,21 @@ class AssetExtend(models.Model):
|
|||
unique_together = ('key', 'value')
|
||||
|
||||
|
||||
def private_key_validator(value):
|
||||
if not validate_ssh_private_key(value):
|
||||
raise ValidationError(
|
||||
_('%(value)s is not an even number'),
|
||||
params={'value': value},
|
||||
)
|
||||
|
||||
|
||||
class AdminUser(models.Model):
|
||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
||||
_password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
|
||||
_private_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH private key'))
|
||||
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
|
||||
_private_key = models.CharField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'),
|
||||
validators=[private_key_validator,])
|
||||
_public_key = models.CharField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
|
||||
as_default = models.BooleanField(default=False, verbose_name=_('As default'))
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
date_created = models.DateTimeField(auto_now_add=True, null=True)
|
||||
created_by = models.CharField(max_length=32, null=True, verbose_name=_('Created by'))
|
||||
|
|
|
@ -31,20 +31,8 @@
|
|||
{% csrf_token %}
|
||||
{{ form.name|bootstrap_horizontal }}
|
||||
{{ form.username|bootstrap_horizontal }}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.auto_generate_key.id_for_label }}" class="col-sm-2 control-label">{% trans 'Auto generate key' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.auto_generate_key}}
|
||||
</div>
|
||||
</div>
|
||||
{{ form.password|bootstrap_horizontal }}
|
||||
{{ form.private_key_file|bootstrap_horizontal }}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.as_default.id_for_label }}" class="col-sm-2 control-label">{% trans 'As default' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.as_default}}
|
||||
</div>
|
||||
</div>
|
||||
{{ form.assets|bootstrap_horizontal }}
|
||||
{{ form.comment|bootstrap_horizontal }}
|
||||
|
||||
|
|
|
@ -1,22 +1,10 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n static %}
|
||||
{% block custom_head_css_js %}
|
||||
{{ block.super }}
|
||||
<style>
|
||||
div.dataTables_wrapper div.dataTables_filter,
|
||||
.dataTables_length {
|
||||
float: right !important;
|
||||
}
|
||||
|
||||
div.dataTables_wrapper div.dataTables_filter {
|
||||
margin-left: 15px;
|
||||
}
|
||||
</style>
|
||||
{% block table_search %}
|
||||
{% endblock %}
|
||||
{% block table_search %}{% endblock %}
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5">
|
||||
<a href="{% url "assets:idc-create" %}" class="btn btn-sm btn-primary"> {% trans "Create IDC" %} </a>
|
||||
<a href="{% url "assets:admin-user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create admin user" %} </a>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover " id="admin_user_list_table" >
|
||||
<thead>
|
||||
|
@ -29,7 +17,7 @@
|
|||
<th class="text-center">{% trans 'Asset num' %}</th>
|
||||
<th class="text-center">{% trans 'Lost connection' %}</th>
|
||||
<th class="text-center">{% trans 'Comment' %}</th>
|
||||
<th class="text-center"></th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -59,9 +47,10 @@ $(document).ready(function(){
|
|||
{# }#}
|
||||
{# }},#}
|
||||
{targets: 6, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "assets:admin-user-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
|
||||
var script_btn = '<a href="{% url "assets:admin-user-update" pk=99991937 %}" class="btn btn-xs btn-primary">{% trans "Script" %}</a>'.replace('99991937', cellData);
|
||||
var update_btn = '<a href="{% url "assets:admin-user-update" pk=99991937 %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
|
||||
$(td).html(update_btn + del_btn)
|
||||
$(td).html(script_btn + update_btn + del_btn)
|
||||
}}],
|
||||
ajax_url: '{% url "assets:api-admin-user-list" %}',
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" }, {data: function () {return 'lost'} },
|
||||
|
|
|
@ -483,6 +483,9 @@ class AdminUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie
|
|||
))
|
||||
return success_message
|
||||
|
||||
def form_invalid(self, form):
|
||||
return super(AdminUserCreateView, self).form_invalid(form)
|
||||
|
||||
|
||||
class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = AdminUser
|
||||
|
|
|
@ -3,11 +3,14 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
from six import string_types
|
||||
import os
|
||||
from itertools import chain
|
||||
import string
|
||||
import logging
|
||||
import datetime
|
||||
import paramiko
|
||||
|
||||
import paramiko
|
||||
from itsdangerous import TimedJSONWebSignatureSerializer, JSONWebSignatureSerializer, \
|
||||
BadSignature, SignatureExpired
|
||||
from django.shortcuts import reverse as dj_reverse
|
||||
|
@ -15,6 +18,11 @@ from django.conf import settings
|
|||
from django.core import signing
|
||||
from django.utils import timezone
|
||||
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
|
||||
SECRET_KEY = settings.SECRET_KEY
|
||||
|
||||
|
||||
|
@ -162,4 +170,70 @@ def timesince(dt, since='', default="just now"):
|
|||
return default
|
||||
|
||||
|
||||
def ssh_key_string_to_obj(text):
|
||||
key_f = StringIO.StringIO(text)
|
||||
key = None
|
||||
try:
|
||||
key = paramiko.RSAKey.from_private_key(key_f)
|
||||
except paramiko.SSHException:
|
||||
pass
|
||||
|
||||
try:
|
||||
key = paramiko.DSSKey.from_private_key(key_f)
|
||||
except paramiko.SSHException:
|
||||
pass
|
||||
return key
|
||||
|
||||
|
||||
def ssh_pubkey_gen(private_key=None, username='jumpserver', hostname='localhost'):
|
||||
if isinstance(private_key, string_types):
|
||||
private_key = ssh_key_string_to_obj(private_key)
|
||||
|
||||
if not isinstance(private_key, (paramiko.RSAKey, paramiko.DSSKey)):
|
||||
raise IOError('Invalid private key')
|
||||
|
||||
public_key = "%(key_type)s %(key_content)s %(username)s@%(hostname)s" % {
|
||||
'key_type': private_key.get_name(),
|
||||
'key_content': private_key.get_base64(),
|
||||
'username': username,
|
||||
'hostname': hostname,
|
||||
}
|
||||
return public_key
|
||||
|
||||
|
||||
def ssh_key_gen(length=2048, type='rsa', password=None, username='jumpserver', hostname=None):
|
||||
"""Generate user ssh private and public key
|
||||
|
||||
Use paramiko RSAKey generate it.
|
||||
:return private key str and public key str
|
||||
"""
|
||||
|
||||
if hostname is None:
|
||||
hostname = os.uname()[1]
|
||||
|
||||
f = StringIO.StringIO()
|
||||
|
||||
try:
|
||||
if type == 'rsa':
|
||||
private_key_obj = paramiko.RSAKey.generate(length)
|
||||
elif type == 'dsa':
|
||||
private_key_obj = paramiko.DSSKey.generate(length)
|
||||
else:
|
||||
raise IOError('SSH private key must be `rsa` or `dsa`')
|
||||
private_key_obj.write_private_key(f, password=password)
|
||||
private_key = f.getvalue()
|
||||
public_key = ssh_pubkey_gen(private_key_obj, username=username, hostname=hostname)
|
||||
return private_key, public_key
|
||||
except IOError:
|
||||
raise IOError('These is error when generate ssh key.')
|
||||
|
||||
|
||||
def validate_ssh_private_key(text):
|
||||
key = ssh_key_string_to_obj(text)
|
||||
if key is None:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
signer = Signer()
|
|
@ -34,36 +34,7 @@ class AdminUserRequiredMixin(UserPassesTestMixin):
|
|||
return self.request.user.is_staff
|
||||
|
||||
|
||||
def ssh_key_gen(length=2048, password=None, username='root', hostname=None):
|
||||
"""Generate user ssh private and public key
|
||||
|
||||
Use paramiko RSAKey generate it.
|
||||
|
||||
"""
|
||||
|
||||
if hostname is None:
|
||||
hostname = os.uname()[1]
|
||||
|
||||
f = StringIO.StringIO()
|
||||
|
||||
try:
|
||||
logger.debug(_('Begin to generate ssh private key ...'))
|
||||
private_key_obj = RSAKey.generate(length)
|
||||
private_key_obj.write_private_key(f, password=password)
|
||||
private_key = f.getvalue()
|
||||
|
||||
public_key = "%(key_type)s %(key_content)s %(username)s@%(hostname)s" % {
|
||||
'key_type': private_key_obj.get_name(),
|
||||
'key_content': private_key_obj.get_base64(),
|
||||
'username': username,
|
||||
'hostname': hostname,
|
||||
}
|
||||
|
||||
logger.debug(_('Finish to generate ssh private key ...'))
|
||||
return private_key, public_key
|
||||
|
||||
except IOError:
|
||||
raise IOError(_('These is error when generate ssh key.'))
|
||||
|
||||
|
||||
def user_add_success_next(user):
|
||||
|
|
|
@ -11,3 +11,4 @@ django-simple-captcha==0.5.2
|
|||
django-formtools==1.0
|
||||
sshpubkeys==2.2.0
|
||||
djangorestframework-bulk==0.2.1
|
||||
paramiko==2.0.2
|
||||
|
|
Loading…
Reference in New Issue