角色key问题修复

pull/26/head
ibuler 2015-11-25 14:59:57 +08:00
parent a7db713b1e
commit 6fe6342ca4
8 changed files with 175 additions and 156 deletions

View File

@ -6,6 +6,7 @@ import os.path
from paramiko.rsakey import RSAKey from paramiko.rsakey import RSAKey
from jumpserver.api import mkdir from jumpserver.api import mkdir
from uuid import uuid4 from uuid import uuid4
from jumpserver.api import CRYPTOR
from jumpserver.settings import KEY_DIR from jumpserver.settings import KEY_DIR
@ -14,18 +15,7 @@ def get_rand_pass():
""" """
get a reandom password. get a reandom password.
""" """
lower = [chr(i) for i in range(97,123)] CRYPTOR.gen_rand_pass(20)
upper = [chr(i).upper() for i in range(97,123)]
digit = [str(i) for i in range(10)]
password_pool = []
password_pool.extend(lower)
password_pool.extend(upper)
password_pool.extend(digit)
pass_list = [random.choice(password_pool) for i in range(1,14)]
pass_list.insert(random.choice(range(1,14)), '@')
pass_list.insert(random.choice(range(1,14)), random.choice(digit))
password = ''.join(pass_list)
return password
def updates_dict(*args): def updates_dict(*args):
@ -38,7 +28,7 @@ def updates_dict(*args):
return result return result
def gen_keys(): def gen_keys(gen=True):
""" """
在KEY_DIR下创建一个 uuid命名的目录 在KEY_DIR下创建一个 uuid命名的目录
并且在该目录下 生产一对秘钥 并且在该目录下 生产一对秘钥
@ -47,6 +37,8 @@ def gen_keys():
key_basename = "key-" + uuid4().hex key_basename = "key-" + uuid4().hex
key_path_dir = os.path.join(KEY_DIR, 'role_key', key_basename) key_path_dir = os.path.join(KEY_DIR, 'role_key', key_basename)
mkdir(key_path_dir, mode=0755) mkdir(key_path_dir, mode=0755)
if not gen:
return key_path_dir
key = RSAKey.generate(2048) key = RSAKey.generate(2048)
private_key = os.path.join(key_path_dir, 'id_rsa') private_key = os.path.join(key_path_dir, 'id_rsa')
public_key = os.path.join(key_path_dir, 'id_rsa.pub') public_key = os.path.join(key_path_dir, 'id_rsa.pub')

View File

@ -255,36 +255,41 @@ def perm_role_add(request):
# 渲染数据 # 渲染数据
header_title, path1, path2 = "系统角色", "角色管理", "添加角色" header_title, path1, path2 = "系统角色", "角色管理", "添加角色"
if request.method == "GET": if request.method == "POST":
default_password = get_rand_pass()
return my_render('jperm/perm_role_add.html', locals(), request)
elif request.method == "POST":
# 获取参数: name, comment # 获取参数: name, comment
name = request.POST.get("role_name") name = request.POST.get("role_name", "")
comment = request.POST.get("role_comment") comment = request.POST.get("role_comment", "")
password = request.POST.get("role_password") password = request.POST.get("role_password", "")
encrypt_pass = CRYPTOR.encrypt(password) key_content = request.POST.get("role_key", "")
# 生成随机密码,生成秘钥对 try:
if get_object(PermRole, name=name):
raise ServerError('已经存在该用户 %s' % name)
key_path = gen_keys() if '' == password and '' == key_content:
role = PermRole(name=name, comment=comment, password=encrypt_pass, key_path=key_path) raise ServerError('账号和密码必填一项')
role.save() if password:
encrypt_pass = CRYPTOR.encrypt(password)
msg = u"添加角色: %s" % name else:
# 渲染 刷新数据 encrypt_pass = CRYPTOR.encrypt(CRYPTOR.gen_rand_pass(20))
header_title, path1, path2 = "系统角色", "角色管理", "查看角色" # 生成随机密码,生成秘钥对
roles_list = PermRole.objects.all() if key_content:
# TODO: 搜索和分页 key_path = gen_keys(gen=False)
keyword = request.GET.get('search', '') with open(os.path.join(key_path, 'id_rsa'), 'w') as f:
if keyword: f.write(key_content)
roles_list = roles_list.filter(Q(name=keyword)) else:
key_path = gen_keys()
roles_list, p, roles, page_range, current_page, show_first, show_end = pages(roles_list, request) logger.debug('generate role key: %s' % key_path)
return my_render('jperm/perm_role_list.html', locals(), request) role = PermRole(name=name, comment=comment, password=encrypt_pass, key_path=key_path)
role.save()
msg = u"添加角色: %s" % name
return HttpResponseRedirect('/perm/role/')
except ServerError, e:
error = e
else: else:
return HttpResponse(u"不支持该操作") return HttpResponse(u"不支持该操作")
return my_render('jperm/perm_role_add.html', locals(), request)
@require_role('admin') @require_role('admin')
def perm_role_delete(request): def perm_role_delete(request):
@ -346,36 +351,37 @@ def perm_role_edit(request):
# 渲染数据 # 渲染数据
role_id = request.GET.get("id") role_id = request.GET.get("id")
role = PermRole.objects.get(id=role_id) role = get_object(PermRole, id=role_id)
role_pass = CRYPTOR.decrypt(role.password)
if request.method == "GET":
return my_render('jperm/perm_role_edit.html', locals(), request)
if request.method == "POST": if request.method == "POST":
# 获取 POST 数据 # 获取 POST 数据
role_name = request.POST.get("role_name") role_name = request.POST.get("role_name")
role_password = request.POST.get("role_password") role_password = request.POST.get("role_password")
encrypt_role_pass = CRYPTOR.encrypt(role_password)
role_comment = request.POST.get("role_comment") role_comment = request.POST.get("role_comment")
key_content = request.POST.get("role_key", "")
try:
if not role:
raise ServerError('角色用户不能存在')
# 写入数据库 if role_password:
role.name = role_name encrypt_pass = CRYPTOR.encrypt(role_password)
role.password = encrypt_role_pass role.password = encrypt_pass
role.comment = role_comment # 生成随机密码,生成秘钥对
if key_content:
with open(os.path.join(role.key_path, 'id_rsa'), 'w') as f:
f.write(key_content)
logger.debug('Recreate role key: %s' % role.key_path)
# 写入数据库
role.name = role_name
role.comment = role_comment
role.save() role.save()
msg = u"更新系统角色: %s" % role.name msg = u"更新系统角色: %s" % role.name
return HttpResponseRedirect('/jperm/role/')
except ServerError, e:
error = e
# 渲染 刷新数据 return my_render('jperm/perm_role_edit.html', locals(), request)
header_title, path1, path2 = "系统角色", "角色管理", "查看角色"
roles_list = PermRole.objects.all()
# TODO: 搜索和分页
keyword = request.GET.get('search', '')
if keyword:
roles_list = roles_list.filter(Q(name=keyword))
roles_list, p, roles, page_range, current_page, show_first, show_end = pages(roles_list, request)
return my_render('jperm/perm_role_list.html', locals(), request)
@require_role('admin') @require_role('admin')

View File

@ -48,6 +48,9 @@ def set_log(level):
def get_asset_info(asset): def get_asset_info(asset):
"""
获取资产的相关账号端口信息
"""
default = get_object(Setting, name='default') default = get_object(Setting, name='default')
info = {'hostname': asset.hostname, 'ip': asset.ip} info = {'hostname': asset.hostname, 'ip': asset.ip}
if asset.use_default_auth: if asset.use_default_auth:
@ -68,6 +71,9 @@ def get_asset_info(asset):
def get_role(user, asset): def get_role(user, asset):
"""
获取用户在这个资产上的授权角色列表
"""
roles = [] roles = []
rules = PermRule.objects.filter(user=user, asset=asset) rules = PermRule.objects.filter(user=user, asset=asset)
for rule in rules: for rule in rules:
@ -77,20 +83,19 @@ def get_role(user, asset):
def get_role_key(user, role): def get_role_key(user, role):
""" """
由于role的key的权限是所有人可以读的 ansible要求为600所以拷贝一份到特殊目录 由于role的key的权限是所有人可以读的 ansible执行命令等要求为600所以拷贝一份到特殊目录
:param user: :param user:
:param role: :param role:
:return: self key path :return: self key path
""" """
user_role_key_dir = os.path.join(KEY_DIR, 'user') user_role_key_dir = os.path.join(KEY_DIR, 'user')
user_role_key_path = os.path.join(user_role_key_dir, '%s_%s.pem' % (user.username, role.name)) user_role_key_path = os.path.join(user_role_key_dir, '%s_%s.pem' % (user.username, role.name))
mkdir(user_role_key_dir, mode=777) mkdir(user_role_key_dir, mode=0777)
if not os.path.isfile(user_role_key_path): if not os.path.isfile(user_role_key_path):
with open(os.path.join(role.key_path, 'id_rsa')) as fk: with open(os.path.join(role.key_path, 'id_rsa')) as fk:
with open(user_role_key_path, 'w') as fu: with open(user_role_key_path, 'w') as fu:
fu.write(fk.read()) fu.write(fk.read())
logger.debug("创建新的用户角色key %s" % user_role_key_path)
print user_role_key_path, user.username
chown(user_role_key_path, user.username) chown(user_role_key_path, user.username)
os.chmod(user_role_key_path, 0600) os.chmod(user_role_key_path, 0600)
return user_role_key_path return user_role_key_path

View File

@ -4566,4 +4566,6 @@ body.skin-3 {
.form-group.required .control-label:after { .form-group.required .control-label:after {
content: " *"; content: " *";
color: red; color: red;
} }
.n-invalid {border: 1px solid #f00;}

View File

@ -26,7 +26,7 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<form method="post" id="userForm" class="form-horizontal" action=""> <form method="post" id="roleForm" class="form-horizontal" action="">
{% if error %} {% if error %}
<div class="alert alert-warning text-center">{{ error }}</div> <div class="alert alert-warning text-center">{{ error }}</div>
{% endif %} {% endif %}
@ -41,9 +41,18 @@
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<label for="role_password_label" class="col-sm-2 control-label">角色密码<span class="red-fonts">*</span></label> <label for="role_password" class="col-sm-2 control-label">角色密码</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input id="role_password" name="role_password" type="password" class="form-control" value="{{ default_password }}"> <input id="role_password" name="role_password" placeholder="Role Password" type="password" class="form-control">
<span class="help-block m-b-none">如果不添加密码,会自动生成</span>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="role_key" class="col-sm-2 control-label">角色密钥</label>
<div class="col-sm-8">
<textarea class="form-control" name="role_key" placeholder="请复制粘贴私钥" rows="10" style="font-size: 9px;"></textarea>
<span class="help-block m-b-none">如果不添加密钥,会自动生成, 密码密钥必填一项</span>
</div> </div>
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
@ -69,52 +78,34 @@
{% endblock %} {% endblock %}
{% block self_footer_js %} {% block self_footer_js %}
<script> <script>
$(document).ready(function(){ $('#roleForm').validator({
$("input.role").click(function(){ timely: 2,
if($("input.role[value=GA]").is( ":checked" )){ theme: "yellow_right_effect",
$("#admin_groups").css("display", 'none'); rules: {
check_name: [/^\w{2,20}$/, '大小写字母数字和下划线,2-20位'],
either: function(){
return $('#role_password').val() == ''
} }
else { },
$("#admin_groups").css("display", 'block'); fields: {
"role_name": {
rule: "required;check_name",
tip: "输入角色名称",
ok: "",
msg: {required: "角色名称必填"}
},
"role_key": {
rule: "required(either)",
tip: "输入密钥",
ok: "",
msg: {required: "密码和密钥必填一个!"}
} }
}); },
valid: function(form) {
$('#use_password').click(function(){ form.submit();
if ($(this).is(':checked')){
$('#admin_account_password').css('display', 'block')
} }
else { })
$('#admin_account_password').css('display', 'none')
}
});
$('#use_publicKey').click(function(){
if ($(this).is(':checked')){
$('#admin_account_publicKey').css('display', 'block')
}
else {
$('#admin_account_publicKey').css('display', 'none')
}
});
});
var config = {
'.chosen-select' : {},
'.chosen-select-deselect' : {allow_single_deselect:true},
'.chosen-select-no-single' : {disable_search_threshold:10},
'.chosen-select-no-results': {no_results_text:'Oops, nothing found!'},
'.chosen-select-width' : {width:"95%"}
};
for (var selector in config) {
$(selector).chosen(config[selector]);
}
</script> </script>
<script src="/static/js/cropper/cropper.min.js"></script>
<script src="/static/js/datapicker/bootstrap-datepicker.js"></script>
{% endblock %} {% endblock %}

View File

@ -26,7 +26,7 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<form method="post" id="userForm" class="form-horizontal" action=""> <form method="post" id="roleForm" class="form-horizontal" action="">
{% if error %} {% if error %}
<div class="alert alert-warning text-center">{{ error }}</div> <div class="alert alert-warning text-center">{{ error }}</div>
{% endif %} {% endif %}
@ -41,9 +41,18 @@
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<label for="role_password_label" class="col-sm-2 control-label">角色密码<span class="red-fonts">*</span></label> <label for="role_password" class="col-sm-2 control-label">角色密码</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input id="role_password" name="role_password" type="password" class="form-control" value="{{ role_pass }}"> <input id="role_password" name="role_password" type="password" class="form-control">
<span class="help-block m-b-none">不修改请留空</span>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="role_key" class="col-sm-2 control-label">角色密钥</label>
<div class="col-sm-8">
<textarea class="form-control" name="role_key" placeholder="请复制粘贴私钥" rows="10" style="font-size: 9px;"></textarea>
<span class="help-block m-b-none">不修改请留空</span>
</div> </div>
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
@ -69,49 +78,25 @@
{% endblock %} {% endblock %}
{% block self_footer_js %} {% block self_footer_js %}
<script> <script>
$(document).ready(function(){ $('#roleForm').validator({
$("input.role").click(function(){ timely: 2,
if($("input.role[value=GA]").is( ":checked" )){ theme: "yellow_right_effect",
$("#admin_groups").css("display", 'none'); rules: {
check_name: [/^\w{2,20}$/, '大小写字母数字和下划线,2-20位']
},
fields: {
"role_name": {
rule: "required;check_name",
tip: "输入角色名称",
ok: "",
msg: {required: "角色名称必填"}
} }
else { },
valid: function(form) {
$("#admin_groups").css("display", 'block'); form.submit();
} }
}); })
$('#use_password').click(function(){
if ($(this).is(':checked')){
$('#admin_account_password').css('display', 'block')
}
else {
$('#admin_account_password').css('display', 'none')
}
});
$('#use_publicKey').click(function(){
if ($(this).is(':checked')){
$('#admin_account_publicKey').css('display', 'block')
}
else {
$('#admin_account_publicKey').css('display', 'none')
}
});
});
var config = {
'.chosen-select' : {},
'.chosen-select-deselect' : {allow_single_deselect:true},
'.chosen-select-no-single' : {disable_search_threshold:10},
'.chosen-select-no-results': {no_results_text:'Oops, nothing found!'},
'.chosen-select-width' : {width:"95%"}
};
for (var selector in config) {
$(selector).chosen(config[selector]);
}
</script> </script>
<script src="/static/js/cropper/cropper.min.js"></script> <script src="/static/js/cropper/cropper.min.js"></script>

View File

@ -34,7 +34,6 @@
<div class=""> <div class="">
<a href="/jperm/role/perm_role_add/" class="btn btn-sm btn-primary "> 添加角色 </a> <a href="/jperm/role/perm_role_add/" class="btn btn-sm btn-primary "> 添加角色 </a>
<a href="/jperm/role/perm_role_push/" class="btn btn-sm btn-primary "> 推送角色 </a> <a href="/jperm/role/perm_role_push/" class="btn btn-sm btn-primary "> 推送角色 </a>
<a id="del_btn" class="btn btn-sm btn-danger "> 删除所选 </a>
<form id="search_form" method="get" action="" class="pull-right mail-search"> <form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control input-sm" id="search_input" name="search" placeholder="Search"> <input type="text" class="form-control input-sm" id="search_input" name="search" placeholder="Search">

View File

@ -37,7 +37,7 @@
<div class="panel-body"> <div class="panel-body">
<div class="tab-content"> <div class="tab-content">
<div id="tab-default" class="tab-pane active"> <div id="tab-default" class="tab-pane active">
<form method="post" id="userForm" class="form-horizontal" action=""> <form method="post" id="settingForm" class="form-horizontal" action="">
{% if error %} {% if error %}
<div class="alert alert-warning text-center">{{ error }}</div> <div class="alert alert-warning text-center">{{ error }}</div>
{% endif %} {% endif %}
@ -71,7 +71,7 @@
<label for="key" class="col-sm-2 control-label">默认密钥</label> <label for="key" class="col-sm-2 control-label">默认密钥</label>
<div class="col-sm-8"> <div class="col-sm-8">
<textarea class="form-control" name="key" placeholder="请复制粘贴私钥" rows="10" style="font-size: 9px;"></textarea> <textarea class="form-control" name="key" placeholder="请复制粘贴私钥" rows="10" style="font-size: 9px;"></textarea>
<span class="help-block m-b-none">如果不修改密钥,请留空</span> <span class="help-block m-b-none">如果不修改密钥,请留空, 密钥密码必填一项</span>
</div> </div>
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
@ -101,4 +101,43 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %}
{% block self_footer_js %}
<script>
$('#settingForm').validator({
timely: 2,
theme: "yellow_right_effect",
rules: {
check_name: [/^\w{2,20}$/, '大小写字母数字和下划线,2-20位'],
check_port: [/^\d{1,5}$/, '端口号不正确'],
either: function(){
return $('#password').val() == ''
}
},
fields: {
"username": {
rule: "required;check_name",
tip: "输入用户名",
ok: "",
msg: {required: "用户名称必填"}
},
"port": {
rule: "required;check_port",
tip: "输入端口号",
ok: "",
msg: {required: "端口号必填"}
},
"key": {
rule: "required(either)",
tip: "输入密钥",
ok: "",
msg: {required: "密码和密钥必填一个!"}
}
},
valid: function(form) {
form.submit();
}
})
</script>
{% endblock %} {% endblock %}