Commit 759760e7 authored by ibuler's avatar ibuler

[Update] 服务器可以生成用户密钥

parent 6f29cf5d
This diff is collapsed.
......@@ -26,6 +26,11 @@ class UserCreateUpdateForm(forms.ModelForm):
max_length=128, strip=False, required=False,
)
role = forms.ChoiceField(choices=role_choices, required=True, initial=User.ROLE_USER, label=_("Role"))
public_key = forms.CharField(
label=_('ssh public key'), max_length=5000,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
help_text=_('Paste user id_rsa.pub here.')
)
class Meta:
model = User
......@@ -47,12 +52,26 @@ class UserCreateUpdateForm(forms.ModelForm):
),
}
def clean_public_key(self):
public_key = self.cleaned_data['public_key']
if self.instance.public_key and public_key == self.instance.public_key:
msg = _('Public key should not be the same as your old one.')
raise forms.ValidationError(msg)
if not validate_ssh_public_key(public_key):
raise forms.ValidationError(_('Not a valid ssh public key'))
return public_key
def save(self, commit=True):
password = self.cleaned_data.get('password')
public_key = self.cleaned_data.get('public_key')
user = super().save(commit=commit)
if password:
user.set_password(password)
user.save()
if public_key:
user.public_key = public_key
user.save()
return user
......@@ -70,6 +89,9 @@ class UserProfileForm(forms.ModelForm):
}
UserProfileForm.verbose_name = _("Profile")
class UserPasswordForm(forms.Form):
old_password = forms.CharField(
max_length=128, widget=forms.PasswordInput,
......@@ -113,7 +135,7 @@ class UserPasswordForm(forms.Form):
class UserPublicKeyForm(forms.Form):
public_key = forms.CharField(
label=_('ssh public key'), max_length=5000,
label=_('ssh public key'), max_length=5000, required=False,
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
help_text=_('Paste your id_rsa.pub here.')
)
......@@ -131,17 +153,21 @@ class UserPublicKeyForm(forms.Form):
msg = _('Public key should not be the same as your old one.')
raise forms.ValidationError(msg)
if not validate_ssh_public_key(public_key):
if public_key and not validate_ssh_public_key(public_key):
raise forms.ValidationError(_('Not a valid ssh public key'))
return public_key
def save(self):
public_key = self.cleaned_data['public_key']
self.instance.public_key = public_key
self.instance.save()
if public_key:
self.instance.public_key = public_key
self.instance.save()
return self.instance
UserPublicKeyForm.verbose_name = _("Public key")
class UserBulkUpdateForm(forms.ModelForm):
users = forms.ModelMultipleChoiceField(
required=True,
......
......@@ -115,7 +115,7 @@ class User(AbstractUser):
import sshpubkeys
try:
return sshpubkeys.SSHKey(self.public_key)
except TabError:
except (TabError, TypeError):
pass
return PubKey()
......
......@@ -45,10 +45,8 @@
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{% bootstrap_form form %}
{# {{ form|bootstrap }}#}
{% endfor %}
{% else %}
{# {{ wizard.form|bootstrap }}#}
{% bootstrap_form wizard.form %}
{% endif %}
</form>
......@@ -56,8 +54,10 @@
<div class="actions clearfix">
<ul>
{% if wizard.steps.prev %}
<li><a class="fl_goto" data-goto="{{ wizard.steps.first }}">{% trans "First step" %}</a></li>
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.prev }}">{% trans "Prev step" %}</a></li>
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.prev }}">{% trans "Previous" %}</a></li>
{% endif %}
{% if wizard.steps.next %}
<li><a class="fl_goto" name="wizard_goto_step" data-goto="{{ wizard.steps.next }}">{% trans "Next" %}</a></li>
{% endif %}
<li><a id="fl_submit">{% trans "Submit" %}</a></li>
</ul>
......
......@@ -22,7 +22,7 @@
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0;">
<div class="col-sm-8" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-primary"><b>{{ user.name }}</b></span>
......@@ -120,7 +120,7 @@
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick modify' %}
......@@ -129,18 +129,26 @@
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td>{% trans 'Reset password' %}:</td>
<td>{% trans 'Update password' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-password-update' %}">{% trans 'Reset' %}</a>
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-password-update' %}">{% trans 'Update' %}</a>
</span>
</td>
</tr>
<tr>
<td>{% trans 'Reset SSH public key' %}:</td>
<td>{% trans 'Update SSH public key' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-pubkey-update' %}">{% trans 'Reset' %}</a>
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-pubkey-update' %}">{% trans 'Update' %}</a>
</span>
</td>
</tr>
<tr>
<td>{% trans 'Reset public key and download' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs btn-reset-pubkey" style="width: 54px">{% trans 'Reset' %}</a>
</span>
</td>
</tr>
......@@ -180,8 +188,11 @@ $(document).on('click', '#btn_update_pk', function() {
$('#txt_pk').focus();
}
);
}
};
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
}).on('click', '.btn-reset-pubkey', function () {
var the_url = '{% url "users:user-pubkey-generate" %}';
window.open(the_url, "_blank")
})
</script>
{% endblock %}
......@@ -64,6 +64,12 @@
<div class="hr-line-dashed"></div>
<h3>{% trans 'Update public key' %}</h3>
{% bootstrap_field form.public_key layout="horizontal" %}
<div class="form-group">
<label class="control-label col-sm-2 col-lg-2" style="padding-top: 0">{% trans 'Or reset by server' %}</label>
<div class=" col-sm-9 col-lg-9 ">
<a href="{% url 'users:user-pubkey-generate' %}">{% trans 'Reset' %}</a>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
......
......@@ -5,4 +5,5 @@
{% block password %}
<h3>{% trans 'Auth' %}</h3>
{% bootstrap_field form.password layout="horizontal" %}
{% bootstrap_field form.public_key layout="horizontal" %}
{% endblock %}
......@@ -20,6 +20,7 @@ urlpatterns = [
url(r'^profile/update/$', views.UserProfileUpdateView.as_view(), name='user-profile-update'),
url(r'^profile/password/update/$', views.UserPasswordUpdateView.as_view(), name='user-password-update'),
url(r'^profile/pubkey/update/$', views.UserPublicKeyUpdateView.as_view(), name='user-pubkey-update'),
url(r'^profile/pubkey/generate/$', views.UserPublicKeyGenerateView.as_view(), name='user-pubkey-generate'),
# User view
url(r'^user$', views.UserListView.as_view(), name='user-list'),
......
......@@ -31,7 +31,7 @@ from django.contrib.auth import logout as auth_logout
from common.const import create_success_msg, update_success_msg
from common.mixins import JSONResponseMixin
from common.utils import get_logger, get_object_or_none, is_uuid
from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen
from .. import forms
from ..models import User, UserGroup
from ..utils import AdminUserRequiredMixin
......@@ -45,6 +45,7 @@ __all__ = [
'UserExportView', 'UserBulkImportView', 'UserProfileView',
'UserProfileUpdateView', 'UserPasswordUpdateView',
'UserPublicKeyUpdateView', 'UserBulkUpdateView',
'UserPublicKeyGenerateView',
]
logger = get_logger(__name__)
......@@ -375,3 +376,15 @@ class UserPublicKeyUpdateView(LoginRequiredMixin, UpdateView):
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class UserPublicKeyGenerateView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
private, public = ssh_key_gen(username=request.user.username, hostname='jumpserver')
request.user.public_key = public
request.user.save()
response = HttpResponse(private, content_type='text/plain')
filename = "{0}-jumpserver.pem".format(request.user.username)
response['Content-Disposition'] = 'attachment; filename={}'.format(filename)
return response
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