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

[Update] 修复系统用户管理用户提及重置密码的bug (#2899)

* [Update] 修复系统用户管理用户提及重置密码的bug

* [Update]  去掉forms

* [Update] 修改翻译

* [Update] 去掉debug信息
parent 4c342467
...@@ -65,17 +65,7 @@ class PasswordAndKeyAuthForm(forms.ModelForm): ...@@ -65,17 +65,7 @@ class PasswordAndKeyAuthForm(forms.ModelForm):
class AdminUserForm(PasswordAndKeyAuthForm): class AdminUserForm(PasswordAndKeyAuthForm):
def save(self, commit=True): def save(self, commit=True):
# Because we define custom field, so we need rewrite :method: `save` raise forms.ValidationError("Use api to save")
admin_user = super().save(commit=commit)
password = self.cleaned_data.get('password', '') or None
private_key, public_key = super().gen_keys()
admin_user.set_auth(password=password, public_key=public_key, private_key=private_key)
return admin_user
def clean(self):
super().clean()
if not self.instance:
super().validate_password_key()
class Meta: class Meta:
model = AdminUser model = AdminUser
...@@ -91,51 +81,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): ...@@ -91,51 +81,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm):
auto_generate_key = forms.BooleanField(initial=True, required=False) auto_generate_key = forms.BooleanField(initial=True, required=False)
def save(self, commit=True): def save(self, commit=True):
# Because we define custom field, so we need rewrite :method: `save` raise forms.ValidationError("Use api to save")
system_user = super().save()
password = self.cleaned_data.get('password', '') or None
login_mode = self.cleaned_data.get('login_mode', '') or None
protocol = self.cleaned_data.get('protocol') or None
auto_generate_key = self.cleaned_data.get('auto_generate_key', False)
private_key, public_key = super().gen_keys()
if login_mode == SystemUser.LOGIN_MANUAL or \
protocol in [SystemUser.PROTOCOL_TELNET,
SystemUser.PROTOCOL_VNC]:
system_user.auto_push = 0
system_user.save()
auto_generate_key = False
if auto_generate_key:
logger.info('Auto generate key and set system user auth')
if protocol == SystemUser.PROTOCOL_SSH:
system_user.auto_gen_auth()
elif protocol == SystemUser.PROTOCOL_RDP:
system_user.auto_gen_auth_password()
else:
system_user.set_auth(password=password, private_key=private_key,
public_key=public_key)
return system_user
def clean(self):
super().clean()
auto_generate = self.cleaned_data.get('auto_generate_key')
if not self.instance and not auto_generate:
super().validate_password_key()
def clean_username(self):
username = self.data.get('username')
login_mode = self.data.get('login_mode')
protocol = self.data.get('protocol')
if username:
return username
if login_mode == SystemUser.LOGIN_AUTO and \
protocol != SystemUser.PROTOCOL_VNC:
msg = _('* Automatic login mode must fill in the username.')
raise forms.ValidationError(msg)
return username
class Meta: class Meta:
model = SystemUser model = SystemUser
......
...@@ -197,6 +197,17 @@ class AssetUser(OrgModelMixin): ...@@ -197,6 +197,17 @@ class AssetUser(OrgModelMixin):
self.public_key = '' self.public_key = ''
self.save() self.save()
@staticmethod
def gen_password():
return str(uuid.uuid4())
@staticmethod
def gen_key(username):
private_key, public_key = ssh_key_gen(
username=username
)
return private_key, public_key
def auto_gen_auth(self): def auto_gen_auth(self):
password = str(uuid.uuid4()) password = str(uuid.uuid4())
private_key, public_key = ssh_key_gen( private_key, public_key = ssh_key_gen(
......
...@@ -8,10 +8,10 @@ from common.serializers import AdaptedBulkListSerializer ...@@ -8,10 +8,10 @@ from common.serializers import AdaptedBulkListSerializer
from ..models import Node, AdminUser from ..models import Node, AdminUser
from orgs.mixins import BulkOrgResourceModelSerializer from orgs.mixins import BulkOrgResourceModelSerializer
from .base import AuthSerializer from .base import AuthSerializer, AuthSerializerMixin
class AdminUserSerializer(BulkOrgResourceModelSerializer): class AdminUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
""" """
管理用户 管理用户
""" """
......
...@@ -4,12 +4,11 @@ ...@@ -4,12 +4,11 @@
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from rest_framework import serializers from rest_framework import serializers
from common.utils import validate_ssh_private_key
from common.serializers import AdaptedBulkListSerializer from common.serializers import AdaptedBulkListSerializer
from orgs.mixins import BulkOrgResourceModelSerializer from orgs.mixins import BulkOrgResourceModelSerializer
from ..models import AuthBook, Asset from ..models import AuthBook, Asset
from ..backends import AssetUserManager from ..backends import AssetUserManager
from .base import ConnectivitySerializer from .base import ConnectivitySerializer, AuthSerializerMixin
__all__ = [ __all__ = [
...@@ -24,7 +23,7 @@ class BasicAssetSerializer(serializers.ModelSerializer): ...@@ -24,7 +23,7 @@ class BasicAssetSerializer(serializers.ModelSerializer):
fields = ['hostname', 'ip'] fields = ['hostname', 'ip']
class AssetUserSerializer(BulkOrgResourceModelSerializer): class AssetUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
hostname = serializers.CharField(read_only=True, label=_("Hostname")) hostname = serializers.CharField(read_only=True, label=_("Hostname"))
ip = serializers.CharField(read_only=True, label=_("IP")) ip = serializers.CharField(read_only=True, label=_("IP"))
connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity")) connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity"))
...@@ -50,13 +49,6 @@ class AssetUserSerializer(BulkOrgResourceModelSerializer): ...@@ -50,13 +49,6 @@ class AssetUserSerializer(BulkOrgResourceModelSerializer):
'public_key': {'write_only': True}, 'public_key': {'write_only': True},
} }
def validate_private_key(self, key):
password = self.initial_data.get("password")
valid = validate_ssh_private_key(key, password)
if not valid:
raise serializers.ValidationError(_("private key invalid"))
return key
def create(self, validated_data): def create(self, validated_data):
if not validated_data.get("name") and validated_data.get("username"): if not validated_data.get("name") and validated_data.get("username"):
validated_data["name"] = validated_data["username"] validated_data["name"] = validated_data["username"]
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
from rest_framework import serializers from rest_framework import serializers
from common.utils import ssh_pubkey_gen from common.utils import ssh_pubkey_gen, validate_ssh_private_key
class AuthSerializer(serializers.ModelSerializer): class AuthSerializer(serializers.ModelSerializer):
...@@ -29,3 +29,37 @@ class AuthSerializer(serializers.ModelSerializer): ...@@ -29,3 +29,37 @@ class AuthSerializer(serializers.ModelSerializer):
class ConnectivitySerializer(serializers.Serializer): class ConnectivitySerializer(serializers.Serializer):
status = serializers.IntegerField() status = serializers.IntegerField()
datetime = serializers.DateTimeField() datetime = serializers.DateTimeField()
class AuthSerializerMixin:
def validate_password(self, password):
return password
def validate_private_key(self, private_key):
if not private_key:
return
password = self.initial_data.get("password")
valid = validate_ssh_private_key(private_key, password)
if not valid:
raise serializers.ValidationError(_("private key invalid"))
return private_key
def validate_public_key(self, public_key):
return public_key
@staticmethod
def clean_auth_fields(validated_data):
for field in ('password', 'private_key', 'public_key'):
value = validated_data.get(field)
if not value:
validated_data.pop(field, None)
# print(validated_data)
# raise serializers.ValidationError(">>>>>>")
def create(self, validated_data):
self.clean_auth_fields(validated_data)
return super().create(validated_data)
def update(self, instance, validated_data):
self.clean_auth_fields(validated_data)
return super().update(instance, validated_data)
...@@ -5,13 +5,14 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -5,13 +5,14 @@ from django.utils.translation import ugettext_lazy as _
from common.serializers import AdaptedBulkListSerializer from common.serializers import AdaptedBulkListSerializer
from orgs.mixins import BulkOrgResourceModelSerializer from orgs.mixins import BulkOrgResourceModelSerializer
from ..models import SystemUser from ..models import SystemUser
from .base import AuthSerializer from .base import AuthSerializer, AuthSerializerMixin
class SystemUserSerializer(BulkOrgResourceModelSerializer): class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
""" """
系统用户 系统用户
""" """
auto_generate_key = serializers.BooleanField(initial=True, required=False, write_only=True)
class Meta: class Meta:
model = SystemUser model = SystemUser
...@@ -20,7 +21,7 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer): ...@@ -20,7 +21,7 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer):
'id', 'name', 'username', 'password', 'public_key', 'private_key', 'id', 'name', 'username', 'password', 'public_key', 'private_key',
'login_mode', 'login_mode_display', 'priority', 'protocol', 'login_mode', 'login_mode_display', 'priority', 'protocol',
'auto_push', 'cmd_filters', 'sudo', 'shell', 'comment', 'nodes', 'auto_push', 'cmd_filters', 'sudo', 'shell', 'comment', 'nodes',
'assets_amount', 'connectivity_amount' 'assets_amount', 'connectivity_amount', 'auto_generate_key'
] ]
extra_kwargs = { extra_kwargs = {
'password': {"write_only": True}, 'password': {"write_only": True},
...@@ -32,6 +33,63 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer): ...@@ -32,6 +33,63 @@ class SystemUserSerializer(BulkOrgResourceModelSerializer):
'created_by': {'read_only': True}, 'created_by': {'read_only': True},
} }
def validate_auto_push(self, value):
login_mode = self.initial_data.get("login_mode")
protocol = self.initial_data.get("protocol")
if login_mode == SystemUser.LOGIN_MANUAL or \
protocol in [SystemUser.PROTOCOL_TELNET,
SystemUser.PROTOCOL_VNC]:
value = False
return value
def validate_auto_generate_key(self, value):
login_mode = self.initial_data.get("login_mode")
protocol = self.initial_data.get("protocol")
if self.context["request"].method.lower() != "post":
value = False
elif self.instance:
value = False
elif login_mode == SystemUser.LOGIN_MANUAL:
value = False
elif protocol in [SystemUser.PROTOCOL_TELNET, SystemUser.PROTOCOL_VNC]:
value = False
return value
def validate_username(self, username):
if username:
return username
login_mode = self.validated_data.get("login_mode")
protocol = self.validated_data.get("protocol")
if login_mode == SystemUser.LOGIN_AUTO and \
protocol != SystemUser.PROTOCOL_VNC:
msg = _('* Automatic login mode must fill in the username.')
raise serializers.ValidationError(msg)
return username
def validate_password(self, password):
super().validate_password(password)
auto_gen_key = self.initial_data.get("auto_generate_key", False)
private_key = self.initial_data.get("private_key")
if not self.instance and not auto_gen_key and not password and not private_key:
raise serializers.ValidationError(_("Password or private key required"))
return password
def validate(self, attrs):
username = attrs.get("username", "manual")
protocol = attrs.get("protocol")
auto_gen_key = attrs.get("auto_generate_key", False)
if auto_gen_key:
password = SystemUser.gen_password()
attrs["password"] = password
if protocol == SystemUser.PROTOCOL_SSH:
private_key, public_key = SystemUser.gen_key(username)
attrs["private_key"] = private_key
attrs["public_key"] = public_key
attrs.pop("auto_generate_key", None)
return attrs
@classmethod @classmethod
def setup_eager_loading(cls, queryset): def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """ """ Perform necessary eager loading of data. """
...@@ -52,7 +110,6 @@ class SystemUserAuthSerializer(AuthSerializer): ...@@ -52,7 +110,6 @@ class SystemUserAuthSerializer(AuthSerializer):
] ]
class SystemUserSimpleSerializer(serializers.ModelSerializer): class SystemUserSimpleSerializer(serializers.ModelSerializer):
""" """
系统用户最基本信息的数据结构 系统用户最基本信息的数据结构
......
...@@ -218,6 +218,31 @@ $(document).ready(function () { ...@@ -218,6 +218,31 @@ $(document).ready(function () {
}) })
.on('change', protocol_id, function(){ .on('change', protocol_id, function(){
fieldDisplay(); fieldDisplay();
}).on("submit", "form", function (evt) {
evt.preventDefault();
{% block formUrl %}
var the_url = '{% url 'api-assets:system-user-list' %}';
var redirect_to = '{% url "assets:system-user-list" %}';
var method = "POST";
{% endblock %}
var form = $("form");
var data = form.serializeObject();
objectAttrsIsBool(data, ["auto_generate_key", "auto_push"]);
data["private_key"] = $("#id_private_key_file").data('file');
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
}).on('change', '#id_private_key_file', function () {
readFile($(this)).on("onload", function (evt, data) {
$(this).attr("data-file", data)
})
}) })
</script> </script>
......
...@@ -54,9 +54,38 @@ ...@@ -54,9 +54,38 @@
</div> </div>
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2(); $('.select2').select2();
})
.on("submit", "form", function (evt) {
evt.preventDefault();
var the_url = '{% url 'api-assets:admin-user-list' %}';
var redirect_to = '{% url "assets:admin-user-list" %}';
var method = "POST";
{% if type == "update" %}
the_url = '{% url 'api-assets:admin-user-detail' pk=object.id %}';
redirect_to = '{% url "assets:admin-user-list" %}';
method = "PUT";
{% endif %}
var form = $("form");
var data = form.serializeObject();
data["private_key"] = $("#id_private_key_file").data('file');
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
})
.on('change', '#id_private_key_file', function () {
readFile($(this)).on("onload", function (evt, data) {
$(this).attr("data-file", data)
}) })
</script> })
</script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -14,3 +14,9 @@ ...@@ -14,3 +14,9 @@
</div> </div>
{% endblock %} {% endblock %}
{% block formUrl %}
var the_url = '{% url 'api-assets:system-user-detail' pk=object.pk %}';
var redirect_to = '{% url "assets:system-user-list" %}';
var method = "PUT";
{% endblock %}
...@@ -47,7 +47,8 @@ class AdminUserCreateView(PermissionsMixin, ...@@ -47,7 +47,8 @@ class AdminUserCreateView(PermissionsMixin,
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Assets'), 'app': _('Assets'),
'action': _('Create admin user') 'action': _('Create admin user'),
"type": "create"
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
...@@ -65,6 +66,7 @@ class AdminUserUpdateView(PermissionsMixin, SuccessMessageMixin, UpdateView): ...@@ -65,6 +66,7 @@ class AdminUserUpdateView(PermissionsMixin, SuccessMessageMixin, UpdateView):
context = { context = {
'app': _('Assets'), 'app': _('Assets'),
'action': _('Update admin user'), 'action': _('Update admin user'),
"type": "update"
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
......
This diff is collapsed.
...@@ -1157,3 +1157,21 @@ function timeOffset(a, b) { ...@@ -1157,3 +1157,21 @@ function timeOffset(a, b) {
} }
return "" return ""
} }
function readFile(ref) {
var files = ref.prop('files');
var hasFile = files && files.length > 0;
if (hasFile) {
var reader = new FileReader();//新建一个FileReader
console.log(typeof files[0]);
reader.readAsText(files[0], "UTF-8");//读取文件
reader.onload = function(evt){ //读取完文件之后会回来这里
ref.trigger("onload", evt.target.result);
};
} else {
ref.trigger("onload", null);
}
return ref
}
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