mirror of https://github.com/jumpserver/jumpserver
no change...
commit
e0aaba2cf5
|
@ -285,10 +285,10 @@ class Tasks(Command):
|
|||
"""
|
||||
push the ssh authorized key to target.
|
||||
"""
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}"' % (user, key_path)
|
||||
module_args = 'user="%s" key="{{ lookup("file", "%s") }}" state=present' % (user, key_path)
|
||||
self.__run(module_args, "authorized_key")
|
||||
|
||||
return {"status": "failed","msg": self.msg} if self.msg else {"status": "ok"}
|
||||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def push_multi_key(self, **user_info):
|
||||
"""
|
||||
|
@ -319,13 +319,17 @@ class Tasks(Command):
|
|||
|
||||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
def add_user(self, username, password):
|
||||
def add_user(self, username, password=''):
|
||||
"""
|
||||
add a host user.
|
||||
"""
|
||||
encrypt_pass = sha512_crypt.encrypt(password)
|
||||
module_args = 'name=%s shell=/bin/bash password=%s' % (username, encrypt_pass)
|
||||
self.__run(module_args, "user", become=True)
|
||||
|
||||
if password:
|
||||
encrypt_pass = sha512_crypt.encrypt(password)
|
||||
module_args = 'name=%s shell=/bin/bash password=%s' % (username, encrypt_pass)
|
||||
else:
|
||||
module_args = 'name=%s shell=/bin/bash' % username
|
||||
self.__run(module_args, "user")
|
||||
|
||||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok"}
|
||||
|
||||
|
@ -440,8 +444,21 @@ class Tasks(Command):
|
|||
:return:
|
||||
"""
|
||||
module_args1 = file_path
|
||||
result = self.__run(module_args1, "script")
|
||||
print result
|
||||
ret1 = self.__run(module_args1, "script")
|
||||
module_args2 = 'visudo -c | grep "parsed OK" &> /dev/null && echo "ok" || echo "failed"'
|
||||
ret2 = self.__run(module_args2, "shell")
|
||||
ret2_status = [host_value.get("stdout") for host_value in ret2["result"]["contacted"].values()]
|
||||
|
||||
result = {}
|
||||
if not ret1["msg"]:
|
||||
result["step1"] = "ok"
|
||||
else:
|
||||
result["msg"] = ret1["msg"]
|
||||
|
||||
if not ret2["msg"] and "failed" not in ret2_status:
|
||||
result["step2"] = "ok"
|
||||
else:
|
||||
result["msg"] = ret1["msg"]
|
||||
|
||||
return result
|
||||
|
||||
|
|
|
@ -13,16 +13,9 @@ class PermLog(models.Model):
|
|||
is_finish = models.BooleanField(default=False)
|
||||
|
||||
|
||||
class SysUser(models.Model):
|
||||
username = models.CharField(max_length=100)
|
||||
password = models.CharField(max_length=100)
|
||||
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||
|
||||
|
||||
class PermSudo(models.Model):
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
date_added = models.DateTimeField(auto_now=True)
|
||||
runas = models.CharField(max_length=200, default='root')
|
||||
commands = models.TextField()
|
||||
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||
|
||||
|
@ -57,10 +50,11 @@ class PermRule(models.Model):
|
|||
|
||||
|
||||
class PermPush(models.Model):
|
||||
date_added = models.DateTimeField(auto_now=True)
|
||||
asset = models.ManyToManyField(Asset, related_name='perm_push')
|
||||
asset_group = models.ManyToManyField(AssetGroup, related_name='perm_push')
|
||||
role = models.ManyToManyField(PermRole, related_name='perm_push')
|
||||
asset = models.ForeignKey(Asset, related_name='perm_push')
|
||||
role = models.ForeignKey(PermRole, related_name='perm_push')
|
||||
is_public_key = models.BooleanField(default=False)
|
||||
is_password = models.BooleanField(default=False)
|
||||
success = models.BooleanField(default=False)
|
||||
result = models.TextField()
|
||||
date_added = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ import uuid
|
|||
import re
|
||||
|
||||
from jumpserver.models import Setting
|
||||
from jperm.models import PermRole
|
||||
from jperm.models import PermRule
|
||||
from jperm.models import PermRole, PermPush, PermRule
|
||||
|
||||
|
||||
def get_group_user_perm(ob):
|
||||
|
@ -268,37 +267,19 @@ def get_role_info(role_id, type="all"):
|
|||
|
||||
def get_role_push_host(role):
|
||||
"""
|
||||
get the role push host
|
||||
:return: the asset object
|
||||
asset_pushed: {'success': push.success, 'key': push.is_public_key, 'password': push.is_password,
|
||||
'result': push.result}
|
||||
asset_no_push: set(asset1, asset2)
|
||||
"""
|
||||
# 计算该role 所有push记录 总共推送的主机
|
||||
assets = []
|
||||
asset_groups = []
|
||||
for push in role.perm_push.all():
|
||||
assets.extend(push.asset.all())
|
||||
asset_groups.extend(push.asset_group.all())
|
||||
group_assets = []
|
||||
for asset_group in asset_groups:
|
||||
group_assets.extend(asset_group.asset_set.all())
|
||||
cacl_assets = set(assets) | set(group_assets)
|
||||
|
||||
# 计算所有主机 在push记录里面的 使用密码和使用秘钥状况
|
||||
result = []
|
||||
for asset in cacl_assets:
|
||||
all_push = asset.perm_push.all()
|
||||
if True in [push.is_password for push in all_push if role in push.role.all()]:
|
||||
is_password = u"是"
|
||||
else:
|
||||
is_password = u"否"
|
||||
if True in [push.is_public_key for push in all_push if role in push.role.all()]:
|
||||
is_public_key = u"是"
|
||||
else:
|
||||
is_public_key = u"否"
|
||||
result.append({"ip": asset.ip,
|
||||
"group": ','.join([group.name for group in asset.group.all()]),
|
||||
"password": is_password,
|
||||
"pubkey": is_public_key})
|
||||
return result
|
||||
pushs = PermPush.objects.filter(role=role)
|
||||
asset_all = Asset.objects.all()
|
||||
asset_pushed = {}
|
||||
for push in pushs:
|
||||
asset_pushed[push.asset] = {'success': push.success, 'key': push.is_public_key, 'password': push.is_password,
|
||||
'result': push.result}
|
||||
asset_no_push = set(asset_all) - set(asset_pushed.keys())
|
||||
return asset_pushed, asset_no_push
|
||||
|
||||
if __name__ == "__main__":
|
||||
print get_role_info(1)
|
||||
|
|
|
@ -12,7 +12,7 @@ urlpatterns = patterns('jperm.views',
|
|||
(r'^role/perm_role_delete/$', perm_role_delete),
|
||||
(r'^role/perm_role_detail/$', perm_role_detail),
|
||||
(r'^role/perm_role_edit/$', perm_role_edit),
|
||||
(r'^role/perm_role_push/$', perm_role_push),
|
||||
(r'^role/push/$', perm_role_push),
|
||||
(r'^sudo/$', perm_sudo_list),
|
||||
(r'^sudo/perm_sudo_add/$', perm_sudo_add),
|
||||
(r'^sudo/perm_sudo_delete/$', perm_sudo_delete),
|
||||
|
|
116
jperm/views.py
116
jperm/views.py
|
@ -94,8 +94,8 @@ def perm_rule_add(request):
|
|||
# 获取需要授权的主机列表
|
||||
assets_obj = [Asset.objects.get(id=asset_id) for asset_id in assets_select]
|
||||
asset_groups_obj = [AssetGroup.objects.get(id=group_id) for group_id in asset_groups_select]
|
||||
# group_assets_obj = [asset for asset in [group.asset_set.all() for group in asset_groups_obj]]
|
||||
# calc_assets = set(group_assets_obj) | set(assets_obj)
|
||||
group_assets_obj = [asset for asset in [group.asset_set.all() for group in asset_groups_obj]]
|
||||
calc_assets = set(group_assets_obj) | set(assets_obj)
|
||||
|
||||
# 获取需要授权的用户列表
|
||||
users_obj = [User.objects.get(id=user_id) for user_id in users_select]
|
||||
|
@ -105,6 +105,13 @@ def perm_rule_add(request):
|
|||
|
||||
# 获取授予的角色列表
|
||||
roles_obj = [PermRole.objects.get(id=role_id) for role_id in roles_select]
|
||||
need_push_asset = set()
|
||||
for role in roles_obj:
|
||||
asset_no_push = get_role_push_host(role=role)[1]
|
||||
need_push_asset.update(set(calc_assets) - set(asset_no_push))
|
||||
if need_push_asset:
|
||||
raise ServerError(u'没有推送角色 %s 的主机 %s'
|
||||
% (role.name, ','.join([asset.hostname for asset in need_push_asset])))
|
||||
|
||||
# 仅授权成功的,写回数据库(授权规则,用户,用户组,资产,资产组,用户角色)
|
||||
rule = PermRule(name=rule_name, comment=rule_comment)
|
||||
|
@ -117,7 +124,6 @@ def perm_rule_add(request):
|
|||
rule.save()
|
||||
|
||||
msg = u"添加授权规则:%s" % rule.name
|
||||
# 渲染数据
|
||||
return HttpResponseRedirect('/jperm/rule/')
|
||||
except ServerError, e:
|
||||
error = e
|
||||
|
@ -251,6 +257,8 @@ def perm_role_add(request):
|
|||
try:
|
||||
if get_object(PermRole, name=name):
|
||||
raise ServerError('已经存在该用户 %s' % name)
|
||||
default = get_object(Setting, name='default')
|
||||
|
||||
if password:
|
||||
encrypt_pass = CRYPTOR.encrypt(password)
|
||||
else:
|
||||
|
@ -319,7 +327,7 @@ def perm_role_detail(request):
|
|||
asset_groups = role_info.get("asset_groups")
|
||||
users = role_info.get("users")
|
||||
user_groups = role_info.get("user_groups")
|
||||
push_info = get_role_push_host(PermRole.objects.get(id=role_id))
|
||||
pushed_asset, need_push_asset = get_role_push_host(get_object(PermRole, id=role_id))
|
||||
|
||||
return my_render('jperm/perm_role_detail.html', locals(), request)
|
||||
|
||||
|
@ -386,15 +394,13 @@ def perm_role_push(request):
|
|||
"""
|
||||
# 渲染数据
|
||||
header_title, path1, path2 = "系统角色", "角色管理", "角色推送"
|
||||
|
||||
roles = PermRole.objects.all()
|
||||
role_id = request.GET.get('id')
|
||||
role = get_object(PermRole, id=role_id)
|
||||
assets = Asset.objects.all()
|
||||
asset_groups = AssetGroup.objects.all()
|
||||
|
||||
if request.method == "POST":
|
||||
# 获取推荐角色的名称列表
|
||||
role_ids = request.POST.getlist("roles")
|
||||
|
||||
# 计算出需要推送的资产列表
|
||||
asset_ids = request.POST.getlist("assets")
|
||||
asset_group_ids = request.POST.getlist("asset_groups")
|
||||
|
@ -422,17 +428,11 @@ def perm_role_push(request):
|
|||
# "password": password})
|
||||
push_resource = gen_resource(calc_assets)
|
||||
|
||||
# 获取角色的推送方式,以及推送需要的信息
|
||||
roles_obj = [PermRole.objects.get(id=role_id) for role_id in role_ids]
|
||||
role_pass = {}
|
||||
role_key = {}
|
||||
for role in roles_obj:
|
||||
role_pass[role.name] = role.password
|
||||
role_key[role.name] = os.path.join(role.key_path, 'id_rsa.pub')
|
||||
logger.debug('推送role res: %s' % push_resource)
|
||||
|
||||
# 调用Ansible API 进行推送
|
||||
password_push = request.POST.get("use_password")
|
||||
key_push = request.POST.get("use_publicKey")
|
||||
password_push = True if request.POST.get("use_password") else False
|
||||
key_push = True if request.POST.get("use_publicKey") else False
|
||||
task = Tasks(push_resource)
|
||||
ret = {}
|
||||
ret_failed = {}
|
||||
|
@ -440,48 +440,59 @@ def perm_role_push(request):
|
|||
# 因为要先建立用户,所以password 是必选项,而push key是在 password也完成的情况下的 可选项
|
||||
# 1. 以password 方式推送角色
|
||||
if password_push:
|
||||
ret["password_push"] = task.add_multi_user(**role_pass)
|
||||
ret["password_push"] = task.add_user(role.name, CRYPTOR.decrypt(role.password))
|
||||
if ret["password_push"].get("status") != "success":
|
||||
ret_failed["step1"] == "failed"
|
||||
ret_failed = ret["password_push"].get('msg')
|
||||
|
||||
# 2. 以秘钥 方式推送角色
|
||||
if key_push:
|
||||
ret["password_push"] = task.add_multi_user(**role_pass)
|
||||
if ret["password_push"].get("status") != "success":
|
||||
ret_failed["step2-1"] = "failed"
|
||||
ret["key_push"] = task.push_multi_key(**role_key)
|
||||
if ret["key_push"].get("status") != "success":
|
||||
ret_failed["step2-2"] = "failed"
|
||||
ret["password_push"] = task.add_user(role.name)
|
||||
if ret["password_push"].get("status") != "ok":
|
||||
ret_failed = ret["password_push"].get('msg')
|
||||
ret["key_push"] = task.push_key(role.name, os.path.join(role.key_path, 'id_rsa.pub'))
|
||||
if ret["key_push"].get("status") != "ok":
|
||||
ret_failed = ret["key_push"].get('msg')
|
||||
|
||||
# 3. 推送sudo配置文件
|
||||
role_chosen_aliase = {} # {'dev': [sudo1, sudo2], 'sa': [sudo2, sudo3]}
|
||||
sudo_alias = set() # set(sudo1, sudo2, sudo3)
|
||||
for role in roles_obj:
|
||||
sudos = set([sudo for sudo in role.sudo.all()])
|
||||
sudo_alias.update(sudos)
|
||||
role_chosen_aliase[role.name] = sudos
|
||||
add_sudo_script = get_add_sudo_script(role_chosen_aliase, sudo_alias)
|
||||
ret_sudo = task.push_sudo_file(add_sudo_script)
|
||||
if password_push or key_push:
|
||||
role_chosen_aliase = {} # {'dev': 'NETWORKING, SHUTDOWN'}
|
||||
sudo_alias = set([sudo for sudo in role.sudo.all()]) # set(sudo1, sudo2, sudo3)
|
||||
role_chosen_aliase[role.name] = ','.join(sudo.name for sudo in sudo_alias)
|
||||
add_sudo_script = get_add_sudo_script(role_chosen_aliase, sudo_alias)
|
||||
ret['sudo'] = task.push_sudo_file(add_sudo_script)
|
||||
|
||||
print add_sudo_script
|
||||
# os.remove(add_sudo_script)
|
||||
if ret['sudo'].get('msg'):
|
||||
ret_failed = ret['sudo'].get('msg')
|
||||
os.remove(add_sudo_script)
|
||||
|
||||
print ret
|
||||
logger.debug('推送role结果: %s' % ret)
|
||||
logger.debug('推送role错误: %s' % ret_failed)
|
||||
|
||||
# 结果汇总统计
|
||||
if ret_failed:
|
||||
# 推送失败
|
||||
error = u"推送失败, 原因: %s 失败" % ','.join(ret_failed.keys())
|
||||
success_asset = []
|
||||
failed_asset = []
|
||||
# 推送成功 回写push表
|
||||
for asset in calc_assets:
|
||||
push_check = PermPush.objects.filter(role=role, asset=asset)
|
||||
if push_check:
|
||||
func = push_check.update
|
||||
else:
|
||||
def func(**kwargs):
|
||||
PermPush(**kwargs).save()
|
||||
|
||||
if ret_failed.get(asset.hostname):
|
||||
failed_asset.append(asset)
|
||||
func(is_password=password_push, is_public_key=key_push, role=role, asset=asset, success=False,
|
||||
result=ret_failed.get(asset.hostname))
|
||||
else:
|
||||
success_asset.append(asset)
|
||||
func(is_password=password_push, is_public_key=key_push, role=role, asset=asset, success=True)
|
||||
|
||||
if not failed_asset:
|
||||
msg = u'角色 %s 推送成功[ %s ]' % (role.name, ','.join([asset.hostname for asset in success_asset]))
|
||||
else:
|
||||
# 推送成功 回写push表
|
||||
msg = u"推送系统角色: %s" % ','.join(role_chosen_aliase.keys())
|
||||
push = PermPush(is_public_key=bool(key_push), is_password=bool(password_push))
|
||||
push.save()
|
||||
push.asset_group = asset_groups_obj
|
||||
push.asset = calc_assets
|
||||
push.role = roles_obj
|
||||
push.save()
|
||||
|
||||
error = u'角色 %s 推送失败 [ %s ], 推送成功 [ %s ]' % (role.name,
|
||||
','.join([asset.hostname for asset in failed_asset]),
|
||||
','.join([asset.hostname for asset in success_asset]))
|
||||
return my_render('jperm/perm_role_push.html', locals(), request)
|
||||
|
||||
|
||||
|
@ -521,14 +532,13 @@ def perm_sudo_add(request):
|
|||
if request.method == "POST":
|
||||
# 获取参数: name, comment
|
||||
name = request.POST.get("sudo_name").strip()
|
||||
runas = request.POST.get('sudo_runas', 'root').strip()
|
||||
comment = request.POST.get("sudo_comment").strip()
|
||||
commands = request.POST.get("sudo_commands").strip()
|
||||
|
||||
if get_object(PermSudo, name=name):
|
||||
error = 'Sudo别名 %s已经存在' % name
|
||||
else:
|
||||
sudo = PermSudo(name=name.strip(), runas=runas, comment=comment, commands=commands.strip())
|
||||
sudo = PermSudo(name=name.strip(), comment=comment, commands=commands.strip())
|
||||
sudo.save()
|
||||
msg = u"添加Sudo命令别名: %s" % name
|
||||
# 渲染数据
|
||||
|
@ -552,11 +562,9 @@ def perm_sudo_edit(request):
|
|||
if request.method == "POST":
|
||||
name = request.POST.get("sudo_name")
|
||||
commands = request.POST.get("sudo_commands")
|
||||
runas = request.POST.get('sudo_runas', 'root')
|
||||
comment = request.POST.get("sudo_comment")
|
||||
sudo.name = name.strip()
|
||||
sudo.commands = commands.strip()
|
||||
sudo.runas = runas.strip()
|
||||
sudo.comment = comment
|
||||
sudo.save()
|
||||
|
||||
|
@ -583,5 +591,3 @@ def perm_sudo_delete(request):
|
|||
return HttpResponse(u"不支持该操作")
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ log = debug
|
|||
host = 127.0.0.1
|
||||
port = 3306
|
||||
user = jumpserver
|
||||
password = mysql1234
|
||||
password = mysql234
|
||||
database = jumpserver
|
||||
|
||||
[websocket]
|
||||
|
|
|
@ -5,7 +5,7 @@ import ast
|
|||
import time
|
||||
|
||||
from django import template
|
||||
# from jperm.models import CmdGroup
|
||||
from jperm.models import PermPush
|
||||
from jumpserver.api import *
|
||||
from jasset.models import AssetAlias
|
||||
|
||||
|
@ -259,3 +259,16 @@ def role_contain_which_sudos(role):
|
|||
sudo_names = [sudo.name for sudo in role.sudo.all()]
|
||||
return ','.join(sudo_names)
|
||||
|
||||
|
||||
@register.filter(name='get_push_info')
|
||||
def get_push_info(push_id, arg):
|
||||
push = get_object(PermPush, id=push_id)
|
||||
if push and arg:
|
||||
if arg == 'asset':
|
||||
return [asset.hostname for asset in push.asset.all()]
|
||||
if arg == 'asset_group':
|
||||
return [asset_group.name for asset_group in push.asset_group.all()]
|
||||
if arg == 'role':
|
||||
return [role.name for role in push.role.all()]
|
||||
else:
|
||||
return []
|
||||
|
|
|
@ -146,7 +146,7 @@ def user_add(request):
|
|||
error = ''
|
||||
msg = ''
|
||||
header_title, path1, path2 = '添加用户', '用户管理', '添加用户'
|
||||
user_role = {'SU': u'超级管理员', 'GA': u'组管理员', 'CU': u'普通用户'}
|
||||
user_role = {'SU': u'超级管理员', 'CU': u'普通用户'}
|
||||
group_all = UserGroup.objects.all()
|
||||
|
||||
if request.method == 'POST':
|
||||
|
@ -349,7 +349,7 @@ def user_edit(request):
|
|||
if not user_id:
|
||||
return HttpResponseRedirect('/')
|
||||
|
||||
user_role = {'SU': u'超级管理员', 'GA': u'组管理员', 'CU': u'普通用户'}
|
||||
user_role = {'SU': u'超级管理员', 'CU': u'普通用户'}
|
||||
user = get_object(User, id=user_id)
|
||||
group_all = UserGroup.objects.all()
|
||||
if user:
|
||||
|
|
|
@ -104,50 +104,48 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5>权限申请</h5>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user"></ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-envelope-o"></i> 权限申请记录 </h3>
|
||||
<small><i class="fa fa-map-marker"></i> 最近十条权限申请记录信息.</small>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div class="feed-activity-list">
|
||||
{% if perm_apply_10 %}
|
||||
{% for perm in perm_apply_10 %}
|
||||
<div class="feed-element">
|
||||
<div>
|
||||
{% ifequal perm.status 0 %}
|
||||
<small class="pull-right text-navy">{{ perm.date_add|naturaltime }}</small>
|
||||
{% else %}
|
||||
<small class="pull-right">{{ perm.date_add|naturaltime }}</small>
|
||||
{% endifequal %}
|
||||
<strong>{{ perm.applyer }}</strong>
|
||||
{# <div>申请 {{ perm.bisgroup|ast_to_list }} 主机组权限</div>#}
|
||||
{# <div>申请 {{ perm.asset|ast_to_list }} 主机权限</div>#}
|
||||
<small class="text-muted">{{ perm.date_add }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="text-center">(暂无)</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# <div class="ibox float-e-margins">#}
|
||||
{# <div class="ibox-title">#}
|
||||
{# <h5>权限申请</h5>#}
|
||||
{# <div class="ibox-tools">#}
|
||||
{# <a class="collapse-link">#}
|
||||
{# <i class="fa fa-chevron-up"></i>#}
|
||||
{# </a>#}
|
||||
{# <a class="dropdown-toggle" data-toggle="dropdown" href="#">#}
|
||||
{# <i class="fa fa-wrench"></i>#}
|
||||
{# </a>#}
|
||||
{# <ul class="dropdown-menu dropdown-user"></ul>#}
|
||||
{# <a class="close-link">#}
|
||||
{# <i class="fa fa-times"></i>#}
|
||||
{# </a>#}
|
||||
{# </div>#}
|
||||
{# </div>#}
|
||||
{# <div class="ibox-content ibox-heading">#}
|
||||
{# <h3><i class="fa fa-envelope-o"></i> 权限申请记录 </h3>#}
|
||||
{# <small><i class="fa fa-map-marker"></i> 最近十条权限申请记录信息.</small>#}
|
||||
{# </div>#}
|
||||
{# <div class="ibox-content">#}
|
||||
{# <div class="feed-activity-list">#}
|
||||
{# {% if perm_apply_10 %}#}
|
||||
{# {% for perm in perm_apply_10 %}#}
|
||||
{# <div class="feed-element">#}
|
||||
{# <div>#}
|
||||
{# {% ifequal perm.status 0 %}#}
|
||||
{# <small class="pull-right text-navy">{{ perm.date_add|naturaltime }}</small>#}
|
||||
{# {% else %}#}
|
||||
{# <small class="pull-right">{{ perm.date_add|naturaltime }}</small>#}
|
||||
{# {% endifequal %}#}
|
||||
{# <strong>{{ perm.applyer }}</strong>#}
|
||||
{# <small class="text-muted">{{ perm.date_add }}</small>#}
|
||||
{# </div>#}
|
||||
{# </div>#}
|
||||
{# {% endfor %}#}
|
||||
{# {% else %}#}
|
||||
{# <p class="text-center">(暂无)</p>#}
|
||||
{# {% endif %}#}
|
||||
{# </div>#}
|
||||
{# </div>#}
|
||||
{# </div>#}
|
||||
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
|
@ -306,7 +304,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# </div>#}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
{{ af.ip|bootstrap_horizontal }}
|
||||
<p class="col-sm-offset-2">Tips: 如果IP地址不填写, IP默认会设置与主机名一致</p>
|
||||
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">管理账号<span class="red-fonts"> *</span></label>
|
||||
|
@ -60,7 +59,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="col-sm-offset-2">Tips: 管理用户为root或用户拥有NOPASSWD:ALL sudo权限的用户</p>
|
||||
<div class="form-group" id="admin_account" style="display: none">
|
||||
<div class="hr-line-dashed"></div>
|
||||
<label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts">*</span> </label>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% include 'nav_cat_bar.html' %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权规则</b></span>
|
||||
|
@ -52,7 +52,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权用户/用户组</b></span>
|
||||
|
@ -98,7 +98,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>授权主机/主机组</b></span>
|
||||
|
@ -146,7 +146,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>推送主机</b></span>
|
||||
|
@ -175,18 +175,64 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">主机</th>
|
||||
<th class="text-center">主机组</th>
|
||||
<th class="text-center">使用密码</th>
|
||||
<th class="text-center">使用秘钥</th>
|
||||
<th class="text-center">密钥</th>
|
||||
<th class="text-center">密码</th>
|
||||
<th class="text-center">结果</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for host in push_info %}
|
||||
{% for asset, info in pushed_asset.items %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ host.ip }} </td>
|
||||
<td class="text-center"> {{ host.group }} </td>
|
||||
<td class="text-center"> {{ host.password }} </td>
|
||||
<td class="text-center"> {{ host.pubkey }} </td>
|
||||
<td class="text-center"> {{ asset.hostname }} </td>
|
||||
<td class="text-center"> {{ info.key | yesno:"是,否,未知" }} </td>
|
||||
<td class="text-center"> {{ info.password | yesno:"是,否,未知" }} </td>
|
||||
{% if info.success %}
|
||||
<td class="text-center" style="color: #1ab394;" >{{ info.success | yesno:"成功,失败,未知" }} </td>
|
||||
{% else %}
|
||||
<td class="text-center" style="color: #ec4758;cursor: help" title="{{ info.result }}" >{{ info.success | yesno:"成功,失败,未知" }} </td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>未推送主机</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="text-left">
|
||||
<table class="table table-striped" id="ugedit" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">主机</th>
|
||||
<th class="text-center">IP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in need_push_asset %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"> {{ asset.hostname }} </td>
|
||||
<td class="text-center"> {{ asset.ip }} </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
@ -29,11 +29,10 @@
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ibox-content">
|
||||
<div class="">
|
||||
<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-danger "> 推送角色 </a>
|
||||
{# <a href="/jperm/role/perm_role_push/" class="btn btn-sm btn-danger "> 推送角色 </a>#}
|
||||
<form id="search_form" method="get" action="" class="pull-right mail-search">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" id="search_input" name="search" placeholder="Search">
|
||||
|
@ -45,14 +44,13 @@
|
|||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<table class="table table-striped table-bordered table-hover " id="editable" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">名称 </th>
|
||||
<th class="text-center">备注</th>
|
||||
<th class="text-center">创建时间</th>
|
||||
<th class="text-center">sudo别名</th>
|
||||
<th class="text-center">创建时间</th>
|
||||
<th class="text-center">备注</th>
|
||||
<th class="text-center">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -60,12 +58,13 @@
|
|||
{% for role in roles %}
|
||||
<tr class="gradeX" id={{ role.id }}>
|
||||
<td class="text-center"> {{ role.name }} </td>
|
||||
<td class="text-center"> {{ role.comment }} </td>
|
||||
<td class="text-center"> {{ role.date_added | date:"Y-m-d H:i:s"}} </td>
|
||||
<td class="text-center"> {{ role | role_contain_which_sudos }} </td>
|
||||
<td class="text-center"> {{ role.date_added | date:"Y-m-d H:i:s"}} </td>
|
||||
<td class="text-center"> {{ role.comment }} </td>
|
||||
<td class="text-center">
|
||||
<a href="/jperm/role/perm_role_detail/?id={{ role.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||
<a href="/jperm/role/perm_role_edit/?id={{ role.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
<a href="/jperm/role/push/?id={{ role.id }}" class="btn btn-xs btn-warning">推送</a>
|
||||
<button onclick="remove_role({{ role.id }})" class="btn btn-xs btn-danger">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -33,12 +33,19 @@
|
|||
{% if msg %}
|
||||
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="role" class="col-sm-2 control-label">角色</label>
|
||||
<div class="col-sm-8">
|
||||
<input name="id" type="text" class="form-control" disabled value="{{ role.name }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="asset" class="col-sm-2 control-label">资产</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="assets" id="assets" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset in assets %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
<option value="{{ asset.id }}" {% if asset in pushed_assets %}selected{% endif %}>{{ asset.hostname }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -49,23 +56,13 @@
|
|||
<div class="col-sm-8">
|
||||
<select name="asset_groups" data-placeholder="请选择资产组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset_group in asset_groups %}
|
||||
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<select name="roles" data-placeholder="请选择角色" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for role in roles %}
|
||||
<option value="{{ role.id }}">{{ role.name }}</option>
|
||||
<option value="{{ asset_group.id }}"{% if asset_group in pushed_asset_groups %}selected{% endif %}>{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用密钥</label>
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
<div class="col-sm-8">
|
||||
<select name="asset" id="asset" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset in assets %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}</option>
|
||||
<option value="{{ asset.id }}">{{ asset.hostname }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span class="help-block m-b-none">资产和资产组必选一个</span>
|
||||
|
@ -136,25 +136,21 @@ $('#ruleForm').validator({
|
|||
"rulename": {
|
||||
rule: "required;check_name",
|
||||
tip: "输入规则名称",
|
||||
ok: "",
|
||||
msg: {required: "规则名称必填"}
|
||||
},
|
||||
"usergroup": {
|
||||
rule: "required(check_user)",
|
||||
tip: "请选择用户组",
|
||||
ok: "",
|
||||
msg: {required: "用户和用户组必选一个!"}
|
||||
},
|
||||
"assetgroup": {
|
||||
rule: "required(check_asset)",
|
||||
tip: "输入资产组",
|
||||
ok: "",
|
||||
msg: {required: "资产和资产组必选一个!"}
|
||||
},
|
||||
"role": {
|
||||
rule: "required",
|
||||
tip: "请选择角色",
|
||||
ok: "",
|
||||
msg: {required: "必须选择角色"}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -35,13 +35,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="sudo_runas" class="col-sm-2 control-label">RunAs<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="sudo_runas" name="sudo_runas" placeholder="Sudo RunAs User" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="sudo_commands" class="col-sm-2 control-label">系统命令<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
|
|
|
@ -40,13 +40,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="sudo_runas" class="col-sm-2 control-label">RunAs<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="sudo_runas" name="sudo_runas" placeholder="Sudo RunAs User" type="text" class="form-control" value="{{ sudo.runas }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="sudo_commands_label" class="col-sm-2 control-label">系统命令<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
<div class="ibox-content">
|
||||
<div class="">
|
||||
<a href="/jperm/sudo/perm_sudo_add/" 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">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" id="search_input" name="search" placeholder="Search">
|
||||
|
|
|
@ -22,14 +22,12 @@ add_cmd_alias() {
|
|||
|
||||
# Add Command Aliases to role
|
||||
add_role_chosen() {
|
||||
{% for role, sudos in role_chosen_aliase.items %}
|
||||
{% for sudo in sudos %}
|
||||
if $(grep '^{{ role }}.*{{ sudo.name }}' ${sudo_file} &> /dev/null); then
|
||||
sed -i 's@^{{ role }}.*{{ sudo.name }}@{{ role }} ALL = NOPASSWD: {{ sudo.name }}@g' ${sudo_file}
|
||||
{% for role, alias in role_chosen_aliase.items %}
|
||||
if $(grep '^{{ role }}.*' ${sudo_file} &> /dev/null); then
|
||||
sed -i 's@^{{ role }}.*@{{ role }} ALL = NOPASSWD: {{ alias }}@g' ${sudo_file}
|
||||
else
|
||||
echo "{{ role }} ALL = NOPASSWD: {{ sudo.name }}" >> ${sudo_file}
|
||||
echo "{{ role }} ALL = NOPASSWD: {{ alias }}" >> ${sudo_file}
|
||||
fi
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,11 +55,12 @@
|
|||
{% for group in user_groups.object_list %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center">
|
||||
<input class="shiftCheckbox"
|
||||
type="checkbox" name="selected" value="{{ group.id }}">
|
||||
<input class="shiftCheckbox" type="checkbox" name="selected" value="{{ group.id }}">
|
||||
</td>
|
||||
<td class="text-center"> {{ group.name }} </td>
|
||||
<td class="text-center"><a href="/juser/user_list/?gid={{ group.id }}"> {{ group.id | members_count }}</a> </td>
|
||||
<td class="text-center">
|
||||
<a href="/juser/user_list/?gid={{ group.id }}"> {{ group.id | members_count }}</a>
|
||||
</td>
|
||||
<td class="text-center"> {{ group.comment }} </td>
|
||||
<td class="text-center">
|
||||
<a href="../group_edit/?id={{ group.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
{% ifequal session_role_id 2 %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
|
||||
<label for="role" class="col-sm-2 control-label">权限<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
{% for r, role_name in user_role.items %}
|
||||
<div class="col-sm-3">
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<li id="jperm">
|
||||
<a href="#"><i class="fa fa-edit"></i> <span class="nav-label">授权管理</span><span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li class="rule ">
|
||||
<li class="rule perm_rule_add">
|
||||
<a href="/jperm/rule/">授权规则</a>
|
||||
</li>
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<input name="setting" value="default" style="display: none">
|
||||
<div class="col-sm-8">
|
||||
<input id="username" name="username" placeholder="Username" type="text" value="{{ setting_default.field1 }}" class="form-control">
|
||||
<span class="help-block m-b-none">该用户为root或用户NOPASS:ALL sudo权限的用户</span>
|
||||
<span class="help-block m-b-none"> 管理用户为root或用户拥有NOPASSWD:ALL sudo权限的用户</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
@ -128,13 +128,13 @@
|
|||
tip: "输入端口号",
|
||||
ok: "",
|
||||
msg: {required: "端口号必填"}
|
||||
},
|
||||
"key": {
|
||||
rule: "required(either)",
|
||||
tip: "输入密钥",
|
||||
ok: "",
|
||||
msg: {required: "密码和密钥必填一个!"}
|
||||
}
|
||||
{# "key": {#}
|
||||
{# rule: "required(either)",#}
|
||||
{# tip: "输入密钥",#}
|
||||
{# ok: "",#}
|
||||
{# msg: {required: "密码和密钥必填一个!"}#}
|
||||
{# }#}
|
||||
},
|
||||
valid: function(form) {
|
||||
form.submit();
|
||||
|
|
Loading…
Reference in New Issue