mirror of https://github.com/jumpserver/jumpserver
Merge branch 'dev' into cmdb
commit
b8cb6f4246
|
@ -37,6 +37,7 @@ nosetests.xml
|
|||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
*.log
|
||||
logs/*
|
||||
keys/*
|
||||
jumpserver.conf
|
||||
|
|
247
connect.py
247
connect.py
|
@ -19,10 +19,11 @@ import struct, fcntl, signal, socket, select
|
|||
os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
|
||||
if django.get_version() != '1.6':
|
||||
django.setup()
|
||||
from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object
|
||||
from jumpserver.api import logger, mkdir, Log, TtyLog
|
||||
from jumpserver.api import ServerError, User, Asset, AssetGroup, get_object, mkdir, get_asset_info, get_role
|
||||
from jumpserver.api import logger, Log, TtyLog, get_role_key
|
||||
from jperm.perm_api import gen_resource, get_group_asset_perm, get_group_user_perm
|
||||
from jumpserver.settings import LOG_DIR
|
||||
|
||||
from jperm.ansible_api import Command
|
||||
|
||||
login_user = get_object(User, username=getpass.getuser())
|
||||
VIM_FLAG = False
|
||||
|
@ -68,23 +69,20 @@ def check_vim_status(command, ssh):
|
|||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Tty(object):
|
||||
"""
|
||||
A virtual tty class
|
||||
一个虚拟终端类,实现连接ssh和记录日志,基类
|
||||
"""
|
||||
def __init__(self, username, asset_name):
|
||||
self.username = username
|
||||
self.asset_name = asset_name
|
||||
def __init__(self, user, asset, role):
|
||||
self.username = user.username
|
||||
self.asset_name = asset.hostname
|
||||
self.ip = None
|
||||
self.port = 22
|
||||
self.channel = None
|
||||
#self.asset = get_object(Asset, name=asset_name)
|
||||
#self.user = get_object(User, username=username)
|
||||
self.role = None
|
||||
self.asset = asset
|
||||
self.user = user
|
||||
self.role = role
|
||||
self.ssh = None
|
||||
self.connect_info = None
|
||||
self.login_type = 'ssh'
|
||||
|
@ -252,6 +250,7 @@ class Tty(object):
|
|||
log_file_path = os.path.join(today_connect_log_dir, '%s_%s_%s' % (self.username, self.asset_name, time_start))
|
||||
|
||||
try:
|
||||
mkdir(os.path.dirname(today_connect_log_dir), mode=0777)
|
||||
mkdir(today_connect_log_dir, mode=0777)
|
||||
except OSError:
|
||||
logger.debug('创建目录 %s 失败,请修改%s目录权限' % (today_connect_log_dir, tty_log_dir))
|
||||
|
@ -289,7 +288,10 @@ class Tty(object):
|
|||
# 2. get 映射用户
|
||||
# 3. get 映射用户的账号,密码或者key
|
||||
# self.connect_info = {'user': '', 'asset': '', 'ip': '', 'port': 0, 'role_name': '', 'role_pass': '', 'role_key': ''}
|
||||
self.connect_info = {'user': 'a', 'asset': 'b', 'ip': '127.0.0.1', 'port': 22, 'role_name': 'root', 'role_pass': '', 'role_key': '/root/.ssh/id_rsa.bak'}
|
||||
asset_info = get_asset_info(self.asset)
|
||||
self.connect_info = {'user': self.user, 'asset': self.asset, 'ip': asset_info.get('ip'),
|
||||
'port': int(asset_info.get('port')), 'role_name': self.role.name,
|
||||
'role_pass': self.role.password, 'role_key': self.role.key_path}
|
||||
return self.connect_info
|
||||
|
||||
def get_connection(self):
|
||||
|
@ -303,18 +305,24 @@ class Tty(object):
|
|||
ssh.load_system_host_keys()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
try:
|
||||
if connect_info.get('role_pass'):
|
||||
ssh.connect(connect_info.get('ip'),
|
||||
port=connect_info.get('port'),
|
||||
username=connect_info.get('role_name'),
|
||||
password=connect_info.get('role_pass'),
|
||||
look_for_keys=False)
|
||||
else:
|
||||
ssh.connect(connect_info.get('ip'),
|
||||
port=connect_info.get('port'),
|
||||
username=connect_info.get('role_name'),
|
||||
key_filename=connect_info.get('role_key'),
|
||||
look_for_keys=False)
|
||||
role_key = get_role_key(self.user, self.role)
|
||||
if role_key and os.path.isfile(role_key):
|
||||
try:
|
||||
ssh.connect(connect_info.get('ip'),
|
||||
port=connect_info.get('port'),
|
||||
username=connect_info.get('role_name'),
|
||||
key_filename=role_key,
|
||||
look_for_keys=False)
|
||||
self.ssh = ssh
|
||||
return ssh
|
||||
except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException:
|
||||
pass
|
||||
|
||||
ssh.connect(connect_info.get('ip'),
|
||||
port=connect_info.get('port'),
|
||||
username=connect_info.get('role_name'),
|
||||
password=connect_info.get('role_pass'),
|
||||
look_for_keys=False)
|
||||
|
||||
except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException:
|
||||
raise ServerError('认证失败 Authentication Error.')
|
||||
|
@ -452,7 +460,7 @@ class SshTty(Tty):
|
|||
#print 'ok'+tmp+'ok'
|
||||
# SSH_TTY = re.search(r'(?<=/dev/).*', tmp).group().strip()
|
||||
# SSH_TTY = ''
|
||||
channel.send('clear\n')
|
||||
# channel.send('clear\n')
|
||||
# Make ssh interactive tunnel
|
||||
self.posix_shell()
|
||||
|
||||
|
@ -460,28 +468,123 @@ class SshTty(Tty):
|
|||
channel.close()
|
||||
ssh.close()
|
||||
|
||||
def execute(self, cmd):
|
||||
"""
|
||||
execute cmd on the asset
|
||||
执行命令
|
||||
"""
|
||||
pass
|
||||
|
||||
class Nav(object):
|
||||
def __init__(self, user):
|
||||
self.user = user
|
||||
self.search_result = {}
|
||||
self.user_perm = {}
|
||||
|
||||
def print_prompt():
|
||||
"""
|
||||
Print prompt
|
||||
打印提示导航
|
||||
"""
|
||||
msg = """\033[1;32m### Welcome Use JumpServer To Login. ### \033[0m
|
||||
1) Type \033[32mIP or Part IP, Host Alias or Comments \033[0m To Login.
|
||||
2) Type \033[32mP/p\033[0m To Print The Servers You Available.
|
||||
3) Type \033[32mG/g\033[0m To Print The Server Groups You Available.
|
||||
4) Type \033[32mG/g(1-N)\033[0m To Print The Server Group Hosts You Available.
|
||||
5) Type \033[32mE/e\033[0m To Execute Command On Several Servers.
|
||||
6) Type \033[32mQ/q\033[0m To Quit.
|
||||
"""
|
||||
print textwrap.dedent(msg)
|
||||
@staticmethod
|
||||
def print_nav():
|
||||
"""
|
||||
Print prompt
|
||||
打印提示导航
|
||||
"""
|
||||
msg = """\n\033[1;32m### Welcome To Use JumpServer, A Open Source System . ### \033[0m
|
||||
1) Type \033[32mID\033[0m To Login.
|
||||
2) Type \033[32m/\033[0m + \033[32mIP, Host Name, Host Alias or Comments \033[0mTo Search.
|
||||
3) Type \033[32mP/p\033[0m To Print The Servers You Available.
|
||||
4) Type \033[32mG/g\033[0m To Print The Server Groups You Available.
|
||||
5) Type \033[32mG/g\033[0m\033[0m + \033[32mGroup ID\033[0m To Print The Server Group You Available.
|
||||
6) Type \033[32mE/e\033[0m To Execute Command On Several Servers.
|
||||
7) Type \033[32mQ/q\033[0m To Quit.
|
||||
"""
|
||||
|
||||
msg = """\n\033[1;32m### 欢迎使用Jumpserver开源跳板机 ### \033[0m
|
||||
1) 输入 \033[32mID\033[0m 直接登录.
|
||||
2) 输入 \033[32m/\033[0m + \033[32mIP, 主机名, 主机别名 or 备注 \033[0m搜索.
|
||||
3) 输入 \033[32mP/p\033[0m 显示您有权限的主机.
|
||||
4) 输入 \033[32mG/g\033[0m 显示您有权限的主机组.
|
||||
5) 输入 \033[32mG/g\033[0m\033[0m + \033[32m组ID\033[0m 显示该组下主机.
|
||||
6) 输入 \033[32mE/e\033[0m 批量执行命令.
|
||||
7) 输入 \033[32mQ/q\033[0m 退出.
|
||||
"""
|
||||
print textwrap.dedent(msg)
|
||||
|
||||
def search(self, str_r=''):
|
||||
gid_pattern = re.compile(r'^g\d+$')
|
||||
if not self.user_perm:
|
||||
self.user_perm = get_group_user_perm(self.user)
|
||||
user_asset_all = self.user_perm.get('asset').keys()
|
||||
user_asset_search = []
|
||||
if str_r:
|
||||
if gid_pattern.match(str_r):
|
||||
user_asset_search = list(Asset.objects.all())
|
||||
else:
|
||||
for asset in user_asset_all:
|
||||
if str_r in asset.ip or str_r in str(asset.comment):
|
||||
user_asset_search.append(asset)
|
||||
else:
|
||||
user_asset_search = user_asset_all
|
||||
|
||||
self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search))
|
||||
print '\033[32m[%-3s] %-15s %-15s %-5s %-10s %s \033[0m' % ('ID', 'AssetName', 'IP', 'Port', 'Role', 'Comment')
|
||||
for index, asset in self.search_result.items():
|
||||
asset_info = get_asset_info(asset)
|
||||
role = [str(role.name) for role in self.user_perm.get('asset').get(asset).get('role')]
|
||||
if asset.comment:
|
||||
print '[%-3s] %-15s %-15s %-5s %-10s %s' % (index, asset.hostname, asset.ip, asset_info.get('port'),
|
||||
role, asset.comment)
|
||||
else:
|
||||
print '[%-3s] %-15s %-15s %-5s %-10s' % (index, asset.hostname, asset.ip, asset_info.get('port'), role)
|
||||
print
|
||||
|
||||
@staticmethod
|
||||
def print_asset_group():
|
||||
user_asset_group_all = AssetGroup.objects.all()
|
||||
|
||||
print '\033[32m[%-3s] %-15s %s \033[0m' % ('ID', 'GroupName', 'Comment')
|
||||
for asset_group in user_asset_group_all:
|
||||
if asset_group.comment:
|
||||
print '[%-3s] %-15s %s' % (asset_group.id, asset_group.name, asset_group.comment)
|
||||
else:
|
||||
print '[%-3s] %-15s' % (asset_group.id, asset_group.name)
|
||||
print
|
||||
|
||||
def exec_cmd(self):
|
||||
self.search()
|
||||
while True:
|
||||
print "请输入主机名、IP或ansile支持的pattern, q退出"
|
||||
try:
|
||||
pattern = raw_input("\033[1;32mPattern>:\033[0m ").strip()
|
||||
if pattern == 'q':
|
||||
break
|
||||
else:
|
||||
if not self.user_perm:
|
||||
self.user_perm = get_group_user_perm(self.user)
|
||||
res = gen_resource(self.user, perm=self.user_perm)
|
||||
cmd = Command(res)
|
||||
logger.debug(res)
|
||||
for inv in cmd.inventory.get_hosts(pattern=pattern):
|
||||
print inv.name
|
||||
confirm_host = raw_input("\033[1;32mIs that [y/n]>:\033[0m ").strip()
|
||||
if confirm_host == 'y':
|
||||
while True:
|
||||
print "请输入执行的命令, 按q退出"
|
||||
command = raw_input("\033[1;32mCmds>:\033[0m ").strip()
|
||||
if command == 'q':
|
||||
break
|
||||
result = cmd.run(module_name='shell', command=command, pattern=pattern)
|
||||
for k, v in result.items():
|
||||
if k == 'ok':
|
||||
for host, output in v.items():
|
||||
color_print("%s => %s" % (host, 'Ok'), 'green')
|
||||
print output
|
||||
print
|
||||
else:
|
||||
for host, output in v.items():
|
||||
color_print("%s => %s" % (host, k), 'red')
|
||||
color_print(output, 'red')
|
||||
print
|
||||
print "=" * 20
|
||||
print
|
||||
else:
|
||||
continue
|
||||
|
||||
except EOFError:
|
||||
print
|
||||
break
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -492,38 +595,60 @@ def main():
|
|||
if not login_user: # 判断用户是否存在
|
||||
color_print(u'没有该用户,或许你是以root运行的 No that user.', exits=True)
|
||||
|
||||
print_prompt()
|
||||
gid_pattern = re.compile(r'^g\d+$')
|
||||
nav = Nav(login_user)
|
||||
nav.print_nav()
|
||||
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
option = raw_input("\033[1;32mOpt or IP>:\033[0m ")
|
||||
option = raw_input("\033[1;32mOpt or ID>:\033[0m ").strip()
|
||||
except EOFError:
|
||||
print_prompt()
|
||||
nav.print_nav()
|
||||
continue
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
if option in ['P', 'p']:
|
||||
login_user.get_asset_info(printable=True)
|
||||
if option in ['P', 'p', '\n', '']:
|
||||
nav.search()
|
||||
continue
|
||||
if option.startswith('/') or gid_pattern.match(option):
|
||||
nav.search(option.lstrip('/'))
|
||||
elif option in ['G', 'g']:
|
||||
login_user.get_asset_group_info(printable=True)
|
||||
continue
|
||||
elif gid_pattern.match(option):
|
||||
gid = option[1:].strip()
|
||||
asset_group = get_object(AssetGroup, id=gid)
|
||||
if asset_group and asset_group.is_permed(user=login_user):
|
||||
asset_group.get_asset_info(printable=True)
|
||||
nav.print_asset_group()
|
||||
continue
|
||||
elif option in ['E', 'e']:
|
||||
# exec_cmd_servers(login_name)
|
||||
pass
|
||||
nav.exec_cmd()
|
||||
continue
|
||||
elif option in ['Q', 'q', 'exit']:
|
||||
sys.exit()
|
||||
else:
|
||||
try:
|
||||
verify_connect(login_user, option)
|
||||
asset = nav.search_result[int(option)]
|
||||
roles = get_role(login_user, asset)
|
||||
if len(roles) > 1:
|
||||
role_check = dict(zip(range(len(roles)), roles))
|
||||
print role_check
|
||||
for index, role in role_check.items():
|
||||
print "[%s] %s" % (index, role.name)
|
||||
print "输入角色ID, q退出"
|
||||
try:
|
||||
role_index = raw_input("\033[1;32mID>:\033[0m ").strip()
|
||||
if role_index == 'q':
|
||||
continue
|
||||
else:
|
||||
role = role_check[int(role_index)]
|
||||
except IndexError:
|
||||
color_print('请输入正确ID', 'red')
|
||||
continue
|
||||
elif len(roles) == 1:
|
||||
role = roles[0]
|
||||
else:
|
||||
color_print('没有映射用户', 'red')
|
||||
continue
|
||||
ssh_tty = SshTty(login_user, asset, role)
|
||||
ssh_tty.connect()
|
||||
except (KeyError, ValueError):
|
||||
color_print('请输入正确ID', 'red')
|
||||
except ServerError, e:
|
||||
color_print(e, 'red')
|
||||
except IndexError:
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
sphinx-me==0.3
|
||||
django==1.6
|
||||
python-ldap==2.4.19
|
||||
pycrypto==2.6.1
|
||||
paramiko==1.15.2
|
||||
ecdsa==0.13
|
||||
|
@ -9,4 +8,9 @@ django-uuidfield==0.5.0
|
|||
psutil==2.2.1
|
||||
xlsxwriter==0.7.7
|
||||
xlrd==0.9.4
|
||||
django-bootstrap-form
|
||||
django-bootstrap-form
|
||||
tornado
|
||||
ansible
|
||||
pyinotify
|
||||
passlib
|
||||
argparse
|
|
@ -145,7 +145,7 @@ def asset_add(request):
|
|||
asset_save = af_post.save(commit=False)
|
||||
if not use_default_auth:
|
||||
password = request.POST.get('password', '')
|
||||
password_encode = CRYPTOR.encrypt(password)
|
||||
password_encode = password
|
||||
asset_save.password = password_encode
|
||||
if not ip:
|
||||
asset_save.ip = hostname
|
||||
|
|
|
@ -15,11 +15,11 @@ from utils import get_rand_pass
|
|||
|
||||
|
||||
import os.path
|
||||
|
||||
API_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
ANSIBLE_DIR = os.path.join(API_DIR, 'playbooks')
|
||||
|
||||
|
||||
|
||||
class AnsibleError(StandardError):
|
||||
"""
|
||||
the base AnsibleError which contains error(required),
|
||||
|
@ -61,7 +61,7 @@ class MyInventory(object):
|
|||
[{"hostname": "10.10.10.10", "port": "22", "username": "test", "password": "mypass"}, ...]
|
||||
"""
|
||||
self.resource = resource
|
||||
self.inventory = Inventory()
|
||||
self.inventory = Inventory(host_list=[])
|
||||
self.gen_inventory()
|
||||
|
||||
def add_group(self, hosts, groupname, groupvars=None):
|
||||
|
@ -79,14 +79,17 @@ class MyInventory(object):
|
|||
for host in hosts:
|
||||
# set connection variables
|
||||
hostname = host.get("hostname")
|
||||
hostip = host.get('ip', hostname)
|
||||
hostport = host.get("port")
|
||||
username = host.get("username")
|
||||
password = host.get("password")
|
||||
ssh_key = host.get("ssh_key")
|
||||
my_host = Host(name=hostname, port=hostport)
|
||||
my_host.set_variable('ansible_ssh_host', hostname)
|
||||
my_host.set_variable('ansible_ssh_host', hostip)
|
||||
my_host.set_variable('ansible_ssh_port', hostport)
|
||||
my_host.set_variable('ansible_ssh_user', username)
|
||||
my_host.set_variable('ansible_ssh_pass', password)
|
||||
my_host.set_variable('ansible_ssh_private_key_file', ssh_key)
|
||||
# set other variables
|
||||
for key, value in host.iteritems():
|
||||
if key not in ["hostname", "port", "username", "password"]:
|
||||
|
@ -101,47 +104,78 @@ class MyInventory(object):
|
|||
add hosts to inventory.
|
||||
"""
|
||||
if isinstance(self.resource, list):
|
||||
self.add_group(self.resource, 'my_group')
|
||||
self.add_group(self.resource, 'default_group')
|
||||
elif isinstance(self.resource, dict):
|
||||
for groupname, hosts_and_vars in self.resource.iteritems():
|
||||
self.add_group(hosts_and_vars.get("hosts"), groupname, hosts_and_vars.get("vars"))
|
||||
|
||||
|
||||
class MyRunner(MyInventory):
|
||||
"""
|
||||
This is a General object for parallel execute modules.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyRunner, self).__init__(*args, **kwargs)
|
||||
self.results = {}
|
||||
|
||||
def run(self, module_name, module_args='', timeout=10, forks=10, pattern='',
|
||||
sudo=False, sudo_user='root', sudo_pass=''):
|
||||
"""
|
||||
run module from andible ad-hoc.
|
||||
module_name: ansible module_name
|
||||
module_args: ansible module args
|
||||
"""
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=module_args,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
pattern=pattern,
|
||||
forks=forks,
|
||||
become=sudo,
|
||||
become_method='sudo',
|
||||
become_user=sudo_user,
|
||||
become_pass=sudo_pass
|
||||
)
|
||||
self.results = hoc.run()
|
||||
return self.results
|
||||
|
||||
|
||||
class Command(MyInventory):
|
||||
"""
|
||||
this is a command object for parallel execute command.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Command, self).__init__(*args, **kwargs)
|
||||
self.results = ''
|
||||
self.results = {}
|
||||
|
||||
def run(self, command, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
def run(self, command, module_name="command", timeout=10, forks=10, pattern='*'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
'uname -a'
|
||||
"""
|
||||
data = {}
|
||||
|
||||
if module_name not in ["raw", "command", "shell"]:
|
||||
raise CommandValueError("module_name",
|
||||
"module_name must be of the 'raw, command, shell'")
|
||||
raise CommandValueError("module_name",
|
||||
"module_name must be of the 'raw, command, shell'")
|
||||
hoc = Runner(module_name=module_name,
|
||||
module_args=command,
|
||||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
pattern=pattern,
|
||||
forks=forks,
|
||||
)
|
||||
self.results = hoc.run()
|
||||
|
||||
if self.stdout:
|
||||
return {"ok": self.stdout}
|
||||
else:
|
||||
msg = []
|
||||
if self.stderr:
|
||||
msg.append(self.stderr)
|
||||
if self.dark:
|
||||
msg.append(self.dark)
|
||||
return {"failed": msg}
|
||||
data['ok'] = self.stdout
|
||||
if self.stderr:
|
||||
data['err'] = self.stderr
|
||||
if self.dark:
|
||||
data['dark'] = self.dark
|
||||
|
||||
return data
|
||||
|
||||
@property
|
||||
def raw_results(self):
|
||||
|
@ -172,7 +206,7 @@ class Command(MyInventory):
|
|||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = value.get("stdout")
|
||||
result[key] = value.get("stdout")
|
||||
return result
|
||||
|
||||
@property
|
||||
|
@ -183,7 +217,8 @@ class Command(MyInventory):
|
|||
result = {}
|
||||
all = self.results.get("contacted")
|
||||
for key, value in all.iteritems():
|
||||
result[key] = {
|
||||
if value.get("stderr") or value.get("warnings"):
|
||||
result[key] = {
|
||||
"stderr": value.get("stderr"),
|
||||
"warnings": value.get("warnings"),}
|
||||
return result
|
||||
|
@ -203,7 +238,7 @@ class Tasks(Command):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super(Tasks, self).__init__(*args, **kwargs)
|
||||
|
||||
def __run(self, module_args, module_name="command", timeout=5, forks=10, group='my_group'):
|
||||
def __run(self, module_args, module_name="command", timeout=5, forks=10, group='default_group', pattern='*'):
|
||||
"""
|
||||
run command from andible ad-hoc.
|
||||
command : 必须是一个需要执行的命令字符串, 比如
|
||||
|
@ -214,7 +249,8 @@ class Tasks(Command):
|
|||
timeout=timeout,
|
||||
inventory=self.inventory,
|
||||
subset=group,
|
||||
forks=forks
|
||||
pattern=pattern,
|
||||
forks=forks,
|
||||
)
|
||||
|
||||
self.results = hoc.run()
|
||||
|
@ -368,7 +404,7 @@ class Tasks(Command):
|
|||
|
||||
result[key] = {
|
||||
"all_ip": setup.get("ansible_all_ipv4_addresses"),
|
||||
"hostname" : setup.get("ansible_hostname" ),
|
||||
"hostname" : setup.get("ansible_hostname"),
|
||||
"default_ip": setup.get("ansible_default_ipv4").get("address"),
|
||||
"default_mac": setup.get("ansible_default_ipv4").get("macaddress"),
|
||||
"product_name": setup.get("ansible_product_name"),
|
||||
|
@ -385,8 +421,6 @@ class Tasks(Command):
|
|||
return {"status": "failed", "msg": self.msg} if self.msg else {"status": "ok", "result": result}
|
||||
|
||||
|
||||
|
||||
|
||||
class CustomAggregateStats(callbacks.AggregateStats):
|
||||
"""
|
||||
Holds stats about per-host activity during playbook runs.
|
||||
|
@ -405,7 +439,6 @@ class CustomAggregateStats(callbacks.AggregateStats):
|
|||
|
||||
self.results.append(runner_results)
|
||||
|
||||
|
||||
def summarize(self, host):
|
||||
"""
|
||||
Return information about a particular host
|
||||
|
@ -425,7 +458,6 @@ class MyPlaybook(MyInventory):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super(MyPlaybook, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def run(self, playbook_relational_path, extra_vars=None):
|
||||
"""
|
||||
run ansible playbook,
|
||||
|
@ -464,7 +496,6 @@ class App(MyPlaybook):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
# resource = {
|
||||
# "group1": {
|
||||
|
@ -472,8 +503,10 @@ if __name__ == "__main__":
|
|||
# "vars" : {"var1": "value1", "var2": "value2"},
|
||||
# },
|
||||
# }
|
||||
# command = Command(resource)
|
||||
# print command.run("who", group="group1")
|
||||
|
||||
resource = [{"hostname": "127.0.0.1", "port": "22", "username": "yumaojun", "password": "yusky0902"}]
|
||||
command = Command(resource)
|
||||
print command.run("who")
|
||||
|
||||
# resource = [{"hostname": "192.168.10.148", "port": "22", "username": "root", "password": "xxx"}]
|
||||
# task = Tasks(resource)
|
||||
|
|
|
@ -5,20 +5,6 @@ from jasset.models import Asset, AssetGroup
|
|||
from juser.models import User, UserGroup
|
||||
|
||||
|
||||
class PermLog(models.Model):
|
||||
datetime = models.DateTimeField(auto_now_add=True)
|
||||
action = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||
results = models.CharField(max_length=1000, null=True, blank=True, default='')
|
||||
is_success = models.BooleanField(default=False)
|
||||
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 PermRole(models.Model):
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
comment = models.CharField(max_length=100, null=True, blank=True, default='')
|
||||
|
@ -32,14 +18,13 @@ class PermRole(models.Model):
|
|||
|
||||
class PermRule(models.Model):
|
||||
date_added = models.DateTimeField(auto_now=True)
|
||||
name = models.CharField(max_length=100)
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
comment = models.CharField(max_length=100)
|
||||
asset = models.ManyToManyField(Asset, related_name='perm_rule')
|
||||
asset_group = models.ManyToManyField(AssetGroup, related_name='perm_rule')
|
||||
user = models.ManyToManyField(User, related_name='perm_rule')
|
||||
user_group = models.ManyToManyField(UserGroup, related_name='perm_rule')
|
||||
role = models.ManyToManyField(PermRole, related_name='perm_rule')
|
||||
ssh_type = models.BooleanField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
return self.name
|
||||
|
|
|
@ -1,15 +1,179 @@
|
|||
# coding: utf-8
|
||||
|
||||
|
||||
from django.db.models.query import QuerySet
|
||||
from jumpserver.api import *
|
||||
import uuid
|
||||
import re
|
||||
from jumpserver.tasks import playbook_run
|
||||
|
||||
from jumpserver.models import Setting
|
||||
from jperm.models import PermLog
|
||||
|
||||
from jperm.models import PermRole
|
||||
from jperm.models import PermRule
|
||||
|
||||
|
||||
def get_group_user_perm(ob):
|
||||
"""
|
||||
ob为用户或用户组
|
||||
获取用户、用户组授权的资产、资产组
|
||||
return:
|
||||
{’asset_group': {
|
||||
asset_group1: {'asset': [], 'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
asset_group2: {'asset: [], 'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
}
|
||||
'asset':{
|
||||
asset1: {'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
asset2: {'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
}
|
||||
]},
|
||||
'rule':[rule1, rule2,]
|
||||
}
|
||||
"""
|
||||
perm = {}
|
||||
if isinstance(ob, User):
|
||||
rule_all = PermRule.objects.filter(user=ob)
|
||||
elif isinstance(ob, UserGroup):
|
||||
rule_all = PermRule.objects.filter(user_group=ob)
|
||||
else:
|
||||
rule_all = []
|
||||
|
||||
perm['rule'] = rule_all
|
||||
perm_asset_group = perm['asset_group'] = {}
|
||||
perm_asset = perm['asset'] = {}
|
||||
for rule in rule_all:
|
||||
asset_groups = rule.asset_group.all()
|
||||
assets = rule.asset.all()
|
||||
|
||||
# 获取一个规则用户授权的资产
|
||||
for asset in assets:
|
||||
if perm_asset.get(asset):
|
||||
perm_asset[asset].get('role', set()).update(set(rule.role.all()))
|
||||
perm_asset[asset].get('rule', set()).add(rule)
|
||||
else:
|
||||
perm_asset[asset] = {'role': set(rule.role.all()), 'rule': set([rule])}
|
||||
|
||||
# 获取一个规则用户授权的资产组
|
||||
for asset_group in asset_groups:
|
||||
asset_group_assets = asset_group.asset_set.all()
|
||||
if perm_asset_group.get(asset_group):
|
||||
perm_asset_group[asset_group].get('role', set()).update(set(rule.role.all()))
|
||||
perm_asset_group[asset_group].get('rule', set()).add(rule)
|
||||
else:
|
||||
perm_asset_group[asset_group] = {'role': set(rule.role.all()), 'rule': set([rule]),
|
||||
'asset': asset_group_assets}
|
||||
|
||||
# 将资产组中的资产添加到资产授权中
|
||||
for asset in asset_group_assets:
|
||||
if perm_asset.get(asset):
|
||||
perm_asset[asset].get('role', set()).update(perm_asset_group[asset_group].get('role', set()))
|
||||
perm_asset[asset].get('rule', set()).update(perm_asset_group[asset_group].get('rule', set()))
|
||||
else:
|
||||
perm_asset[asset] = {'role': perm_asset_group[asset_group].get('role', set()),
|
||||
'rule': perm_asset_group[asset_group].get('rule', set())}
|
||||
return perm
|
||||
|
||||
|
||||
def get_group_asset_perm(ob):
|
||||
"""
|
||||
ob为资产或资产组
|
||||
获取资产,资产组授权的用户,用户组
|
||||
return:
|
||||
{’user_group': {
|
||||
user_group1: {'user': [], 'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
user_group2: {'user: [], 'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
}
|
||||
'user':{
|
||||
user1: {'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
user2: {'role': [role1, role2], 'rule': [rule1, rule2]},
|
||||
}
|
||||
]},
|
||||
'rule':[rule1, rule2,]
|
||||
}
|
||||
"""
|
||||
perm = {}
|
||||
if isinstance(ob, Asset):
|
||||
rule_all = PermRule.objects.filter(asset=ob)
|
||||
elif isinstance(ob, AssetGroup):
|
||||
rule_all = PermRule.objects.filter(asset_group=ob)
|
||||
else:
|
||||
rule_all = []
|
||||
|
||||
perm['rule'] = rule_all
|
||||
perm_user_group = perm['user_group'] = {}
|
||||
perm_user = perm['user'] = {}
|
||||
for rule in rule_all:
|
||||
user_groups = rule.user_group.all()
|
||||
users = rule.user.all()
|
||||
|
||||
# 获取一个规则资产的用户
|
||||
for user in users:
|
||||
if perm_user.get(user):
|
||||
perm_user[user].get('role', set()).update(set(rule.role.all()))
|
||||
perm_user[user].get('rule', set()).add(rule)
|
||||
else:
|
||||
perm_user[user] = {'role': set(rule.role.all()), 'rule': set([rule])}
|
||||
|
||||
# 获取一个规则资产授权的用户组
|
||||
for user_group in user_groups:
|
||||
user_group_users = user_group.user_set.all()
|
||||
if perm_user_group.get(user_group):
|
||||
perm_user_group[user_group].get('role', set()).update(set(rule.role.all()))
|
||||
perm_user_group[user_group].get('rule', set()).add(rule)
|
||||
else:
|
||||
perm_user_group[user_group] = {'role': set(rule.role.all()), 'rule': set([rule]),
|
||||
'user': user_group_users}
|
||||
|
||||
# 将用户组中的资产添加到用户授权中
|
||||
for user in user_group_users:
|
||||
if perm_user.get(user):
|
||||
perm_user[user].get('role', set()).update(perm_user_group[user_group].get('role', set()))
|
||||
perm_user[user].get('rule', set()).update(perm_user_group[user_group].get('rule', set()))
|
||||
else:
|
||||
perm_user[user] = {'role': perm_user_group[user_group].get('role', set()),
|
||||
'rule': perm_user_group[user_group].get('rule', set())}
|
||||
return perm
|
||||
|
||||
|
||||
def gen_resource(ob, ex='', perm=None):
|
||||
"""
|
||||
ob为用户或资产列表或资产queryset, 如果同时输入用户和资产,则获取用户在这些资产上的信息
|
||||
生成MyInventory需要的 resource文件
|
||||
"""
|
||||
res = []
|
||||
if isinstance(ob, User) and isinstance(ex, (list, QuerySet)):
|
||||
if not perm:
|
||||
perm = get_group_user_perm(ob)
|
||||
for asset, asset_info in perm.get('asset').items():
|
||||
if asset not in ex:
|
||||
continue
|
||||
asset_info = get_asset_info(asset)
|
||||
info = {'hostname': asset.hostname, 'ip': asset.ip, 'port': asset_info.get('port', 22)}
|
||||
try:
|
||||
role = sorted(list(perm.get('asset').get(asset).get('role')))[0]
|
||||
except IndexError:
|
||||
continue
|
||||
info['username'] = role.name
|
||||
info['password'] = role.password
|
||||
info['ssh_key'] = get_role_key(ob, role)
|
||||
res.append(info)
|
||||
elif isinstance(ob, User):
|
||||
if not perm:
|
||||
perm = get_group_user_perm(ob)
|
||||
|
||||
for asset, asset_info in perm.get('asset').items():
|
||||
asset_info = get_asset_info(asset)
|
||||
info = {'hostname': asset.hostname, 'ip': asset.ip, 'port': asset_info.get('port', 22)}
|
||||
try:
|
||||
role = sorted(list(perm.get('asset').get(asset).get('role')))[0]
|
||||
except IndexError:
|
||||
continue
|
||||
info['username'] = role.name
|
||||
info['password'] = role.password
|
||||
info['ssh_key'] = get_role_key(ob, role)
|
||||
res.append(info)
|
||||
elif isinstance(ob, (list, QuerySet)):
|
||||
for asset in ob:
|
||||
info = get_asset_info(asset)
|
||||
res.append(info)
|
||||
return res
|
||||
|
||||
|
||||
def get_object_list(model, id_list):
|
||||
|
@ -22,267 +186,6 @@ def get_object_list(model, id_list):
|
|||
return object_list
|
||||
|
||||
|
||||
def get_rand_file_path(base_dir=os.path.join(BASE_DIR, 'tmp')):
|
||||
"""获取随机文件路径"""
|
||||
filename = uuid.uuid1().hex
|
||||
return os.path.join(base_dir, filename)
|
||||
|
||||
|
||||
def get_inventory(host_group):
|
||||
"""生成资产表库存清单"""
|
||||
path = get_rand_file_path()
|
||||
f = open(path, 'w')
|
||||
for group, host_list in host_group.items():
|
||||
f.write('[%s]\n' % group)
|
||||
for ip in host_list:
|
||||
asset = get_object(Asset, ip=ip)
|
||||
if asset.use_default:
|
||||
f.write('%s\n' % ip)
|
||||
else:
|
||||
f.write('%s ansible_ssh_port=%s ansible_ssh_user=%s ansible_ssh_pass=%s\n' %
|
||||
(ip, asset.port, asset.username, CRYPTOR.decrypt(asset.password)))
|
||||
f.close()
|
||||
return path
|
||||
|
||||
|
||||
def get_playbook(template, var):
|
||||
"""根据playbook模板,生成playbook"""
|
||||
str_playbook = open(template).read()
|
||||
for k, v in var.items():
|
||||
str_playbook = re.sub(r'%s' % k, v, str_playbook) # 正则来替换传入的字符
|
||||
path = get_rand_file_path()
|
||||
f = open(path, 'w')
|
||||
f.write(str_playbook)
|
||||
return path
|
||||
|
||||
|
||||
def perm_user_api(perm_info):
|
||||
"""
|
||||
用户授权api,通过调用ansible API完成用户新建等,传入参数必须如下,列表中可以是对象,也可以是用户名和ip
|
||||
perm_info = {'del': {'users': [],
|
||||
'assets': [],
|
||||
},
|
||||
'new': {'users': [],
|
||||
'assets': []}}
|
||||
"""
|
||||
log = PermLog(action=perm_info.get('action', ''))
|
||||
try:
|
||||
new_users = perm_info.get('new', {}).get('users', [])
|
||||
new_assets = perm_info.get('new', {}).get('assets', [])
|
||||
del_users = perm_info.get('del', {}).get('users', [])
|
||||
del_assets = perm_info.get('del', {}).get('assets', [])
|
||||
print new_users, new_assets
|
||||
except IndexError:
|
||||
raise ServerError("Error: function perm_user_api传入参数错误")
|
||||
|
||||
try:
|
||||
new_ip = [asset.ip for asset in new_assets if isinstance(asset, Asset)]
|
||||
del_ip = [asset.ip for asset in del_assets if isinstance(asset, Asset)]
|
||||
new_username = [user.username for user in new_users]
|
||||
del_username = [user.username for user in del_users]
|
||||
except IndexError:
|
||||
raise ServerError("Error: function perm_user_api传入参数类型错误")
|
||||
|
||||
host_group = {'new': new_ip, 'del': del_ip}
|
||||
inventory = get_inventory(host_group)
|
||||
|
||||
the_new_users = ','.join(new_username)
|
||||
the_del_users = ','.join(del_username)
|
||||
|
||||
playbook = get_playbook(os.path.join(BASE_DIR, 'playbook', 'user_perm.yaml'),
|
||||
{'the_new_group': 'new', 'the_del_group': 'del',
|
||||
'the_new_users': the_new_users, 'the_del_users': the_del_users,
|
||||
'KEY_DIR': os.path.join(SSH_KEY_DIR, 'sysuser')})
|
||||
|
||||
print playbook, inventory
|
||||
|
||||
settings = get_object(Setting, name='default')
|
||||
results = playbook_run(inventory, playbook, settings)
|
||||
if not results.get('failures', 1) and not results.get('unreachable', ''):
|
||||
is_success = True
|
||||
else:
|
||||
is_success = False
|
||||
|
||||
log.results = results
|
||||
log.is_finish = True
|
||||
log.is_success = is_success
|
||||
log.save()
|
||||
return results
|
||||
|
||||
|
||||
def user_group_permed(user_group):
|
||||
assets = user_group.asset.all()
|
||||
asset_groups = user_group.asset_group.all()
|
||||
|
||||
for asset_group in asset_groups:
|
||||
assets.extend(asset_group.asset.all())
|
||||
|
||||
return {'assets': assets, 'asset_groups': asset_groups}
|
||||
|
||||
|
||||
def user_permed(user):
|
||||
asset_groups = []
|
||||
assets = []
|
||||
user_groups = user.group.all()
|
||||
asset_groups.extend(user.asset_group.all())
|
||||
assets.extend(user.asset.all())
|
||||
|
||||
for user_group in user_groups:
|
||||
asset_groups.extend(user_group_permed(user_group).get('assets', []))
|
||||
assets.extend((user_group_permed(user_group).get('asset_groups', [])))
|
||||
|
||||
return {'assets': assets, 'asset_groups': asset_groups}
|
||||
|
||||
|
||||
def _public_perm_api(info):
|
||||
"""
|
||||
公用的用户,用户组,主机,主机组编辑修改新建调用的api,用来完成授权
|
||||
info like that:
|
||||
{
|
||||
'type': 'new_user',
|
||||
'user': 'a',
|
||||
'group': ['A', 'B']
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'edit_user',
|
||||
'user': 'a',
|
||||
'group': {'new': ['A'], 'del': []}
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'del_user',
|
||||
'user': ['a', 'b']
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'edit_user_group',
|
||||
'group': 'A',
|
||||
'user': {'del': ['a', 'b'], 'new': ['c', 'd']}
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'del_user_group',
|
||||
'group': ['A']
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'new_asset',
|
||||
'asset': 'a',
|
||||
'group': ['A', 'B']
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'edit_asset',
|
||||
'asset': 'a',
|
||||
'group': {
|
||||
'del': ['A', ['B'],
|
||||
'new': ['C', ['D']]
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'del_asset',
|
||||
'asset': ['a', 'b']
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'edit_asset_group',
|
||||
'group': 'A',
|
||||
'asset': {'new': ['a', 'b'], 'del': ['c', 'd']}
|
||||
}
|
||||
|
||||
{
|
||||
'type': 'del_asset_group',
|
||||
'group': ['A', 'B']
|
||||
}
|
||||
"""
|
||||
|
||||
if info.get('type') == 'new_user':
|
||||
new_assets = []
|
||||
user = info.get('user')
|
||||
user_groups = info.get('group')
|
||||
for user_group in user_groups:
|
||||
new_assets.extend(user_group_permed(user_group).get('assets', []))
|
||||
|
||||
perm_info = {
|
||||
'action': 'new user: ' + user.name,
|
||||
'new': {'users': [user], 'assets': new_assets}
|
||||
}
|
||||
elif info.get('type') == 'edit_user':
|
||||
new_assets = []
|
||||
del_assets = []
|
||||
user = info.get('user')
|
||||
new_group = info.get('group').get('new')
|
||||
del_group = info.get('group').get('del')
|
||||
|
||||
for user_group in new_group:
|
||||
new_assets.extend(user_group_permed(user_group).get('assets', []))
|
||||
|
||||
for user_group in del_group:
|
||||
del_assets.extend((user_group_permed(user_group).get('assets', [])))
|
||||
|
||||
perm_info = {
|
||||
'action': 'edit user: ' + user.name,
|
||||
'del': {'users': [user], 'assets': del_assets},
|
||||
'new': {'users': [user], 'assets': new_assets}
|
||||
}
|
||||
|
||||
elif info.get('type') == 'del_user':
|
||||
user = info.get('user')
|
||||
del_assets = user_permed(user).get('assets', [])
|
||||
perm_info = {
|
||||
'action': 'del user: ' + user.name, 'del': {'users': [user], 'assets': del_assets},
|
||||
}
|
||||
|
||||
elif info.get('type') == 'edit_user_group':
|
||||
user_group = info.get('group')
|
||||
new_users = info.get('user').get('new')
|
||||
del_users = info.get('user').get('del')
|
||||
assets = user_group_permed(user_group).get('assets', [])
|
||||
|
||||
perm_info = {
|
||||
'action': 'edit user group: ' + user_group.name,
|
||||
'new': {'users': new_users, 'assets': assets},
|
||||
'del': {'users': del_users, 'assets': assets}
|
||||
}
|
||||
|
||||
elif info.get('type') == 'del_user_group':
|
||||
user_group = info.get('group', [])
|
||||
del_users = user_group.user_set.all()
|
||||
assets = user_group_permed(user_group).get('assets', [])
|
||||
|
||||
perm_info = {
|
||||
'action': "del user group: " + user_group.name, 'del': {'users': del_users, 'assets': assets}
|
||||
}
|
||||
else:
|
||||
return
|
||||
|
||||
try:
|
||||
results = perm_user_api(perm_info) # 通过API授权或回收
|
||||
except ServerError, e:
|
||||
return e
|
||||
else:
|
||||
return results
|
||||
|
||||
|
||||
def push_user(user, asset_groups_id):
|
||||
assets = []
|
||||
if not user:
|
||||
return {'error': '没有该用户'}
|
||||
for group_id in asset_groups_id:
|
||||
asset_group = get_object(AssetGroup, id=group_id)
|
||||
if asset_group:
|
||||
assets.extend(asset_group.asset_set.all())
|
||||
perm_info = {
|
||||
'action': 'Push user:' + user.username,
|
||||
'new': {'users': [user], 'assets': assets}
|
||||
}
|
||||
|
||||
results = perm_user_api(perm_info)
|
||||
return results
|
||||
|
||||
|
||||
def get_role_info(role_id, type="all"):
|
||||
"""
|
||||
获取role对应的一些信息
|
||||
|
|
|
@ -13,11 +13,4 @@ urlpatterns = patterns('jperm.views',
|
|||
(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'^log/$', log),
|
||||
(r'^sys_user_add/$', sys_user_add),
|
||||
(r'^perm_user_list/$', sys_user_list),
|
||||
(r'^sys_user_del/$', sys_user_del),
|
||||
(r'^sys_user_edit/$', sys_user_edit),
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ import random
|
|||
import os.path
|
||||
|
||||
from paramiko.rsakey import RSAKey
|
||||
from os import chmod, mkdir
|
||||
from jumpserver.api import mkdir
|
||||
from uuid import uuid4
|
||||
|
||||
from jumpserver.settings import KEY_DIR
|
||||
|
@ -45,13 +45,13 @@ def gen_keys():
|
|||
:return: 返回目录名(uuid)
|
||||
"""
|
||||
key_basename = "key-" + uuid4().hex
|
||||
key_path_dir = os.path.join(KEY_DIR, key_basename)
|
||||
mkdir(key_path_dir, 0700)
|
||||
|
||||
key_path_dir = os.path.join(KEY_DIR, 'role_key', key_basename)
|
||||
mkdir(key_path_dir, 0755)
|
||||
key = RSAKey.generate(2048)
|
||||
private_key = os.path.join(key_path_dir, 'id_rsa')
|
||||
public_key = os.path.join(key_path_dir, 'id_rsa.pub')
|
||||
key.write_private_key_file(private_key)
|
||||
os.chmod(private_key, 0644)
|
||||
|
||||
with open(public_key, 'w') as content_file:
|
||||
for data in [key.get_name(),
|
||||
|
@ -62,8 +62,6 @@ def gen_keys():
|
|||
return key_path_dir
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print gen_keys()
|
||||
|
||||
|
|
282
jperm/views.py
282
jperm/views.py
|
@ -1,22 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from django.db.models import Q
|
||||
from jperm.perm_api import *
|
||||
from jperm.models import PermLog as Log
|
||||
from jperm.models import SysUser
|
||||
from juser.user_api import gen_ssh_key
|
||||
|
||||
|
||||
from juser.models import User, UserGroup
|
||||
from jasset.models import Asset, AssetGroup
|
||||
from jperm.models import PermRole, PermRule
|
||||
from jumpserver.models import Setting
|
||||
|
||||
from jperm.utils import updates_dict, gen_keys, get_rand_pass
|
||||
from jperm.ansible_api import Tasks
|
||||
from jperm.perm_api import get_role_info
|
||||
|
||||
from jumpserver.api import my_render, get_object
|
||||
from jumpserver.api import my_render, get_object, CRYPTOR
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -62,7 +60,7 @@ def perm_rule_detail(request):
|
|||
assets = asset_obj
|
||||
|
||||
return my_render('jperm/perm_rule_detail.html', locals(), request)
|
||||
|
||||
|
||||
|
||||
def perm_rule_add(request):
|
||||
"""
|
||||
|
@ -89,7 +87,8 @@ def perm_rule_add(request):
|
|||
asset_groups_select = request.POST.getlist('assetgroup', [])
|
||||
roles_select = request.POST.getlist('role', [])
|
||||
rule_name = request.POST.get('rulename')
|
||||
rule_comment = request.POST.get('comment')
|
||||
rule_comment = request.POST.get('rule_comment')
|
||||
rule_ssh_key = request.POST.get("use_publicKey")
|
||||
|
||||
# 获取需要授权的主机列表
|
||||
assets_obj = [Asset.objects.get(ip=asset) for asset in assets_select]
|
||||
|
@ -115,7 +114,19 @@ def perm_rule_add(request):
|
|||
rule.asset_group = asset_groups_obj
|
||||
rule.role = roles_obj
|
||||
rule.save()
|
||||
return HttpResponse(u"添加授权规则:%s" % rule.name)
|
||||
|
||||
msg = u"添加授权规则:%s" % rule.name
|
||||
# 渲染数据
|
||||
header_title, path1, path2 = "授权规则", "规则管理", "查看规则"
|
||||
rules_list = PermRule.objects.all()
|
||||
|
||||
# TODO: 搜索和分页
|
||||
keyword = request.GET.get('search', '')
|
||||
if keyword:
|
||||
rules_list = rules_list.filter(Q(name=keyword))
|
||||
rules_list, p, rules, page_range, current_page, show_first, show_end = pages(rules_list, request)
|
||||
|
||||
return my_render('jperm/perm_rule_list.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -131,17 +142,69 @@ def perm_rule_edit(request):
|
|||
rule = PermRule.objects.get(id=rule_id)
|
||||
|
||||
if request.method == 'GET' and rule_id:
|
||||
# 渲染数据, 获取所有的rule对象
|
||||
users = rule.user.all()
|
||||
user_groups = rule.user_group.all()
|
||||
assets = rule.asset.all()
|
||||
asset_groups = rule.asset_group.all()
|
||||
roles = rule.role.all()
|
||||
# 渲染数据, 获取所选的rule对象
|
||||
rule_comment = rule.comment
|
||||
users_select = rule.user.all()
|
||||
user_groups_select = rule.user_group.all()
|
||||
assets_select = rule.asset.all()
|
||||
asset_groups_select = rule.asset_group.all()
|
||||
roles_select = rule.role.all()
|
||||
|
||||
users = User.objects.all()
|
||||
user_groups = UserGroup.objects.all()
|
||||
assets = Asset.objects.all()
|
||||
asset_groups = AssetGroup.objects.all()
|
||||
roles = PermRole.objects.all()
|
||||
|
||||
return my_render('jperm/perm_rule_edit.html', locals(), request)
|
||||
|
||||
elif request.method == 'POST' and rule_id:
|
||||
return HttpResponse("uncompleted")
|
||||
# 获取用户选择的 用户,用户组,资产,资产组,用户角色
|
||||
rule_name = request.POST.get('rule_name')
|
||||
rule_comment = request.POST.get("rule_comment")
|
||||
users_select = request.POST.getlist('user', [])
|
||||
user_groups_select = request.POST.getlist('usergroup', [])
|
||||
assets_select = request.POST.getlist('asset', [])
|
||||
asset_groups_select = request.POST.getlist('assetgroup', [])
|
||||
roles_select = request.POST.getlist('role', [])
|
||||
|
||||
# 获取需要授权的主机列表
|
||||
assets_obj = [Asset.objects.get(ip=asset) for asset in assets_select]
|
||||
asset_groups_obj = [AssetGroup.objects.get(name=group) for group 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)
|
||||
|
||||
# 获取需要授权的用户列表
|
||||
users_obj = [User.objects.get(name=user) for user in users_select]
|
||||
user_groups_obj = [UserGroup.objects.get(name=group) for group in user_groups_select]
|
||||
group_users_obj = [user for user in [group.user_set.all() for group in user_groups_obj]]
|
||||
calc_users = set(group_users_obj) | set(users_obj)
|
||||
|
||||
# 获取授予的角色列表
|
||||
roles_obj = [PermRole.objects.get(name=role) for role in roles_select]
|
||||
|
||||
# 仅授权成功的,写回数据库(授权规则,用户,用户组,资产,资产组,用户角色)
|
||||
rule.user = users_obj
|
||||
rule.usergroup = user_groups_obj
|
||||
rule.asset = assets_obj
|
||||
rule.asset_group = asset_groups_obj
|
||||
rule.role = roles_obj
|
||||
rule.name = rule_name
|
||||
rule.comment = rule.comment
|
||||
rule.save()
|
||||
|
||||
msg = u"更新授权规则:%s" % rule.name
|
||||
# 渲染数据
|
||||
header_title, path1, path2 = "授权规则", "规则管理", "查看规则"
|
||||
rules_list = PermRule.objects.all()
|
||||
|
||||
# TODO: 搜索和分页
|
||||
keyword = request.GET.get('search', '')
|
||||
if keyword:
|
||||
rules_list = rules_list.filter(Q(name=keyword))
|
||||
rules_list, p, rules, page_range, current_page, show_first, show_end = pages(rules_list, request)
|
||||
|
||||
return my_render('jperm/perm_rule_list.html', locals(), request)
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
|
@ -201,12 +264,24 @@ def perm_role_add(request):
|
|||
name = request.POST.get("role_name")
|
||||
comment = request.POST.get("role_comment")
|
||||
password = request.POST.get("role_password")
|
||||
encrypt_pass = CRYPTOR.encrypt(password)
|
||||
# 生成随机密码,生成秘钥对
|
||||
|
||||
key_path = gen_keys()
|
||||
role = PermRole(name=name, comment=comment, password=password, key_path=key_path)
|
||||
role = PermRole(name=name, comment=comment, password=encrypt_pass, key_path=key_path)
|
||||
role.save()
|
||||
return HttpResponse(u"添加角色: %s" % name)
|
||||
|
||||
msg = u"添加角色: %s" % name
|
||||
# 渲染 刷新数据
|
||||
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)
|
||||
else:
|
||||
return HttpResponse(u"不支持该操作")
|
||||
|
||||
|
@ -252,8 +327,12 @@ def perm_role_detail(request):
|
|||
role_info = get_role_info(role_id)
|
||||
|
||||
# 渲染数据
|
||||
for key, value in role_info.iteritems():
|
||||
key = value
|
||||
rules = role_info.get("rules")
|
||||
assets = role_info.get("assets")
|
||||
asset_groups = role_info.get("asset_groups")
|
||||
users = role_info.get("users")
|
||||
user_groups = role_info.get("user_groups")
|
||||
|
||||
return my_render('jperm/perm_role_detail.html', locals(), request)
|
||||
|
||||
|
||||
|
@ -265,15 +344,38 @@ def perm_role_edit(request):
|
|||
# 渲染数据
|
||||
header_title, path1, path2 = "系统角色", "角色管理", "角色编辑"
|
||||
|
||||
# 渲染数据
|
||||
role_id = request.GET.get("id")
|
||||
role = PermRole.objects.get(id=role_id)
|
||||
role_pass = CRYPTOR.decrypt(role.password)
|
||||
if request.method == "GET":
|
||||
role_id = request.GET.get("id")
|
||||
# 渲染数据
|
||||
role = PermRole.objects.get(id=role_id)
|
||||
|
||||
return my_render('jperm/perm_role_edit.html', locals(), request)
|
||||
|
||||
if request.method == "POST":
|
||||
return HttpResponse(u"未实现")
|
||||
# 获取 POST 数据
|
||||
role_name = request.POST.get("role_name")
|
||||
role_password = request.POST.get("role_password")
|
||||
encrypt_role_pass = CRYPTOR.encrypt(role_password)
|
||||
role_comment = request.POST.get("role_comment")
|
||||
|
||||
# 写入数据库
|
||||
role.name = role_name
|
||||
role.password = encrypt_role_pass
|
||||
role.comment = role_comment
|
||||
|
||||
role.save()
|
||||
msg = u"更新系统角色: %s" % role.name
|
||||
|
||||
# 渲染 刷新数据
|
||||
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')
|
||||
|
@ -307,10 +409,20 @@ def perm_role_push(request):
|
|||
calc_assets = set(assets_obj) | set(group_assets_obj)
|
||||
|
||||
# 生成Inventory
|
||||
push_resource = [{"hostname": asset.ip,
|
||||
"port": asset.port,
|
||||
"username": asset.username,
|
||||
"password": asset.password} for asset in calc_assets]
|
||||
push_resource = []
|
||||
for asset in calc_assets:
|
||||
if asset.use_default_auth:
|
||||
username = Setting.default_user
|
||||
password = Setting.default_password
|
||||
port = Setting.default_port
|
||||
else:
|
||||
username = asset.username
|
||||
password = asset.password
|
||||
port = asset.port
|
||||
push_resource.append({"hostname": asset.ip,
|
||||
"port": port,
|
||||
"username": username,
|
||||
"password": password})
|
||||
|
||||
# 获取角色的推送方式,以及推送需要的信息
|
||||
roles_obj = [PermRole.objects.get(name=role_name) for role_name in role_names]
|
||||
|
@ -326,10 +438,13 @@ def perm_role_push(request):
|
|||
task = Tasks(push_resource)
|
||||
ret = {}
|
||||
ret_failed = []
|
||||
if password_push:
|
||||
ret["password_push"] = task.add_multi_user(**role_pass)
|
||||
if ret["password_push"].get("status") != "success":
|
||||
ret_failed.append(1)
|
||||
|
||||
# 因为要先建立用户,所以password 是必选项,
|
||||
# 而push key是在 password也完成的情况下的 可选项
|
||||
ret["password_push"] = task.add_multi_user(**role_pass)
|
||||
if ret["password_push"].get("status") != "success":
|
||||
ret_failed.append(1)
|
||||
|
||||
if key_push:
|
||||
ret["key_push"] = task.push_multi_key(**role_key)
|
||||
if ret["key_push"].get("status") != "success":
|
||||
|
@ -341,108 +456,3 @@ def perm_role_push(request):
|
|||
else:
|
||||
return HttpResponse(u"推送系统角色: %s" % ','.join(role_names))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def perm_group_list(request):
|
||||
header_title, path1, path2 = '用户组授权', '授权管理', '用户组授权'
|
||||
keyword = request.GET.get('search', '')
|
||||
user_groups_list = UserGroup.objects.all()
|
||||
if keyword:
|
||||
request = user_groups_list.filter(Q(name=keyword) | Q(comment=keyword))
|
||||
user_groups_list, p, user_groups, page_range, current_page, show_first, show_end = pages(user_groups_list, request)
|
||||
return my_render('jperm/perm_group_list.html', locals(), request)
|
||||
|
||||
|
||||
|
||||
@require_role('admin')
|
||||
def perm_group_edit(request):
|
||||
header_title, path1, path2 = '用户组授权', '授权管理', '授权更改'
|
||||
user_group_id = request.GET.get('id', '')
|
||||
user_group = get_object(UserGroup, id=user_group_id)
|
||||
asset_all = Asset.objects.all()
|
||||
asset_group_all = AssetGroup.objects.all()
|
||||
asset_permed = user_group.asset.all() # 获取授权的资产对象列表
|
||||
asset_group_permed = user_group.asset_group.all() # 获取授权的资产组对象列表
|
||||
if request.method == 'GET' and user_group:
|
||||
assets = [asset for asset in asset_all if asset not in asset_permed]
|
||||
asset_groups = [asset_group for asset_group in asset_group_all if asset_group not in asset_group_permed]
|
||||
return my_render('jperm/perm_group_edit.html', locals(), request)
|
||||
elif request.method == 'POST' and user_group:
|
||||
asset_id_select = request.POST.getlist('asset_select', [])
|
||||
asset_group_id_select = request.POST.getlist('asset_groups_select', [])
|
||||
asset_select = get_object_list(Asset, asset_id_select)
|
||||
asset_group_select = get_object_list(AssetGroup, asset_group_id_select)
|
||||
asset_new = list(set(asset_select) - set(asset_permed)) # 计算的得到新授权的资产对象列表
|
||||
asset_del = list(set(asset_permed) - set(asset_select)) # 计算得到回收权限的资产对象列表
|
||||
asset_group_new = list(set(asset_group_select) - set(asset_group_permed)) # 新授权的资产组对象列表
|
||||
asset_group_del = list(set(asset_group_permed) - set(asset_group_select)) # 回收的资产组对象列表
|
||||
users = user_group.user_set.all()
|
||||
perm_info = {
|
||||
'action': 'perm group edit: ' + user_group.name,
|
||||
'del': {'users': users, 'assets': asset_del},
|
||||
'new': {'users': users, 'assets': asset_new}
|
||||
}
|
||||
results = perm_user_api(perm_info)
|
||||
unreachable_asset = []
|
||||
failures_asset = []
|
||||
for ip in results.get('unreachable'):
|
||||
unreachable_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip)))
|
||||
for ip in results.get('failures'):
|
||||
failures_asset.extend(filter(lambda x: x, Asset.objects.filter(ip=ip)))
|
||||
failures_asset.extend(unreachable_asset) # 失败的授权要统计
|
||||
for asset in failures_asset:
|
||||
if asset in asset_select:
|
||||
asset_select.remove(asset)
|
||||
else:
|
||||
asset_select.append(asset)
|
||||
user_group.asset = asset_select
|
||||
user_group.asset_group = asset_group_select
|
||||
user_group.save() # 保存到数据库
|
||||
return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json")
|
||||
else:
|
||||
return HttpResponse('输入错误')
|
||||
|
||||
|
||||
def log(request):
|
||||
header_title, path1, path2 = '授权记录', '授权管理', '授权记录'
|
||||
log_all = Log.objects.all().order_by('-datetime')
|
||||
log_all, p, logs, page_range, current_page, show_first, show_end = pages(log_all, request)
|
||||
return my_render('jperm/perm_log.html', locals(), request)
|
||||
|
||||
|
||||
def sys_user_add(request):
|
||||
asset_group_all = AssetGroup.objects.all()
|
||||
if request.method == 'POST':
|
||||
username = request.POST.get('username', '')
|
||||
password = request.POST.get('password', '')
|
||||
asset_groups_id = request.POST.getlist('asset_groups_select', [])
|
||||
comment = request.POST.get('comment')
|
||||
sys_user = SysUser(username=username, password=password, comment=comment)
|
||||
sys_user.save()
|
||||
gen_ssh_key(username, key_dir=os.path.join(SSH_KEY_DIR, 'sysuser'), authorized_keys=False)
|
||||
results = push_user(sys_user, asset_groups_id)
|
||||
return HttpResponse(json.dumps(results, sort_keys=True, indent=4), content_type="application/json")
|
||||
return my_render('jperm/sys_user_add.html', locals(), request)
|
||||
|
||||
|
||||
def sys_user_list(request):
|
||||
users_list = SysUser.objects.all()
|
||||
users_list, p, users, page_range, current_page, show_first, show_end = pages(users_list, request)
|
||||
return my_render('jperm/sys_user_list.html', locals(), request)
|
||||
|
||||
|
||||
def sys_user_edit(request):
|
||||
pass
|
||||
|
||||
|
||||
def sys_user_del(request):
|
||||
pass
|
||||
|
||||
|
|
|
@ -3,26 +3,27 @@
|
|||
import os, sys, time, re
|
||||
from Crypto.Cipher import AES
|
||||
import crypt
|
||||
import pwd
|
||||
from binascii import b2a_hex, a2b_hex
|
||||
import hashlib
|
||||
import datetime
|
||||
import random
|
||||
import subprocess
|
||||
from settings import *
|
||||
import json
|
||||
import logging
|
||||
|
||||
from settings import *
|
||||
from django.core.paginator import Paginator, EmptyPage, InvalidPage
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.template import RequestContext
|
||||
from juser.models import User, UserGroup
|
||||
from jasset.models import Asset, AssetGroup
|
||||
# from jlog.models import Log
|
||||
from jlog.models import Log, TtyLog
|
||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
||||
from jasset.models import Asset, AssetGroup
|
||||
from jperm.models import PermRule, PermRole
|
||||
from jumpserver.models import Setting
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render_to_response
|
||||
from django.core.mail import send_mail
|
||||
import json
|
||||
import logging
|
||||
|
||||
|
||||
def set_log(level):
|
||||
|
@ -30,11 +31,15 @@ def set_log(level):
|
|||
return a log file object
|
||||
根据提示设置log打印
|
||||
"""
|
||||
log_file = os.path.join(LOG_DIR, 'jumpserver.log')
|
||||
if not os.path.isfile(log_file):
|
||||
os.mknod(log_file)
|
||||
os.chmod(log_file, 0777)
|
||||
log_level_total = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARN, 'error': logging.ERROR,
|
||||
'critical': logging.CRITICAL}
|
||||
logger_f = logging.getLogger('jumpserver')
|
||||
logger_f.setLevel(logging.DEBUG)
|
||||
fh = logging.FileHandler(os.path.join(LOG_DIR, 'jumpserver.log'))
|
||||
fh = logging.FileHandler(log_file)
|
||||
fh.setLevel(log_level_total.get(level, logging.DEBUG))
|
||||
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s')
|
||||
fh.setFormatter(formatter)
|
||||
|
@ -42,6 +47,63 @@ def set_log(level):
|
|||
return logger_f
|
||||
|
||||
|
||||
def get_asset_info(asset):
|
||||
default = get_object(Setting, name='default')
|
||||
info = {'hostname': asset.hostname, 'ip': asset.ip}
|
||||
if asset.use_default_auth:
|
||||
if default:
|
||||
info['port'] = default.default_port
|
||||
info['username'] = default.default_user
|
||||
info['password'] = CRYPTOR.decrypt(default.default_password)
|
||||
info['ssh_key'] = default.default_pri_key_path
|
||||
else:
|
||||
info['port'] = asset.port
|
||||
info['username'] = asset.username
|
||||
info['password'] = asset.password
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def get_role(user, asset):
|
||||
roles = []
|
||||
rules = PermRule.objects.filter(user=user, asset=asset)
|
||||
for rule in rules:
|
||||
roles.extend(list(rule.role.all()))
|
||||
return roles
|
||||
|
||||
|
||||
def get_role_key(user, role):
|
||||
"""
|
||||
由于role的key的权限是所有人可以读的, ansible要求为600,所以拷贝一份到特殊目录
|
||||
:param user:
|
||||
:param role:
|
||||
:return: self key path
|
||||
"""
|
||||
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))
|
||||
mkdir(user_role_key_dir, mode=777)
|
||||
if not os.path.isfile(user_role_key_path):
|
||||
with open(os.path.join(role.key_path, 'id_rsa')) as fk:
|
||||
with open(user_role_key_path, 'w') as fu:
|
||||
fu.write(fk.read())
|
||||
|
||||
print user_role_key_path, user.username
|
||||
chown(user_role_key_path, user.username)
|
||||
os.chmod(user_role_key_path, 0600)
|
||||
return user_role_key_path
|
||||
|
||||
|
||||
def chown(path, user, group=''):
|
||||
if not group:
|
||||
group = user
|
||||
try:
|
||||
uid = pwd.getpwnam(user).pw_uid
|
||||
gid = pwd.getpwnam(group).pw_gid
|
||||
os.chown(path, uid, gid)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def page_list_return(total, current=1):
|
||||
"""
|
||||
page
|
||||
|
@ -159,8 +221,7 @@ class PyCrypt(object):
|
|||
try:
|
||||
plain_text = cryptor.decrypt(a2b_hex(text))
|
||||
except TypeError:
|
||||
# raise ServerError('Decrypt password error, TYpe error.')
|
||||
pass
|
||||
raise ServerError('Decrypt password error, TYpe error.')
|
||||
return plain_text.rstrip('\0')
|
||||
|
||||
|
||||
|
@ -197,9 +258,9 @@ def require_role(role='user'):
|
|||
|
||||
def _deco(func):
|
||||
def __deco(request, *args, **kwargs):
|
||||
request.session['pre_url'] = request.path
|
||||
if not request.user.is_authenticated():
|
||||
return HttpResponseRedirect('/login/')
|
||||
|
||||
if role == 'admin':
|
||||
# if request.session.get('role_id', 0) < 1:
|
||||
if request.user.role == 'CU':
|
||||
|
@ -388,15 +449,16 @@ def bash(cmd):
|
|||
return subprocess.call(cmd, shell=True)
|
||||
|
||||
|
||||
def mkdir(dir_name, username='root', mode=0755):
|
||||
def mkdir(dir_name, username='', mode=0755):
|
||||
"""
|
||||
insure the dir exist and mode ok
|
||||
目录存在,如果不存在就建立,并且权限正确
|
||||
"""
|
||||
if not os.path.isdir(dir_name):
|
||||
os.makedirs(dir_name)
|
||||
bash("chown %s:%s '%s'" % (username, username, dir_name))
|
||||
os.chmod(dir_name, mode)
|
||||
os.chmod(dir_name, mode)
|
||||
if username:
|
||||
chown(dir_name, username)
|
||||
|
||||
|
||||
def http_success(request, msg):
|
||||
|
@ -414,4 +476,3 @@ def my_render(template, data, request):
|
|||
|
||||
CRYPTOR = PyCrypt(KEY)
|
||||
logger = set_log(LOG_LEVEL)
|
||||
KEY_DIR = os.path.join(BASE_DIR, 'keys')
|
||||
|
|
|
@ -17,8 +17,8 @@ config = ConfigParser.ConfigParser()
|
|||
|
||||
BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
config.read(os.path.join(BASE_DIR, 'jumpserver.conf'))
|
||||
KEY_DIR = os.path.join(BASE_DIR, 'keys')
|
||||
|
||||
KEY_DIR = os.path.join(BASE_DIR, 'role_keys')
|
||||
|
||||
DB_HOST = config.get('db', 'host')
|
||||
DB_PORT = config.getint('db', 'port')
|
||||
|
@ -37,7 +37,7 @@ EMAIL_TIMEOUT = 5
|
|||
|
||||
# ======== Log ==========
|
||||
LOG_DIR = os.path.join(BASE_DIR, 'logs')
|
||||
SSH_KEY_DIR = os.path.join(BASE_DIR, 'role_keys')
|
||||
SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys/role_keys')
|
||||
KEY = config.get('base', 'key')
|
||||
URL = config.get('base', 'url')
|
||||
LOG_LEVEL = config.get('base', 'log')
|
||||
|
|
|
@ -226,3 +226,14 @@ def ip_str_to_list(ip_str):
|
|||
ip str to list
|
||||
"""
|
||||
return ip_str.split(',')
|
||||
|
||||
|
||||
@register.filter(name='key_exist')
|
||||
def key_exist(username):
|
||||
"""
|
||||
ssh key is exist or not
|
||||
"""
|
||||
if os.path.isfile(os.path.join(KEY_DIR, 'user', username)):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
|
@ -15,7 +15,6 @@ from jumpserver.api import *
|
|||
from jumpserver.models import Setting
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from settings import BASE_DIR
|
||||
from jlog.models import Log
|
||||
|
||||
|
||||
|
@ -80,18 +79,19 @@ def index_cu(request):
|
|||
# user = get_object(User, id=user_id)
|
||||
login_types = {'L': 'LDAP', 'M': 'MAP'}
|
||||
username = request.user.username
|
||||
posts = Asset.object.all()
|
||||
host_count = len(posts)
|
||||
|
||||
new_posts = []
|
||||
post_five = []
|
||||
for post in posts:
|
||||
if len(post_five) < 5:
|
||||
post_five.append(post)
|
||||
else:
|
||||
new_posts.append(post_five)
|
||||
post_five = []
|
||||
new_posts.append(post_five)
|
||||
# TODO: need fix,liuzheng need Asset help
|
||||
# posts = Asset.object.all()
|
||||
# host_count = len(posts)
|
||||
#
|
||||
# new_posts = []
|
||||
# post_five = []
|
||||
# for post in posts:
|
||||
# if len(post_five) < 5:
|
||||
# post_five.append(post)
|
||||
# else:
|
||||
# new_posts.append(post_five)
|
||||
# post_five = []
|
||||
# new_posts.append(post_five)
|
||||
return render_to_response('index_cu.html', locals(), context_instance=RequestContext(request))
|
||||
|
||||
|
||||
|
@ -235,7 +235,7 @@ def Login(request):
|
|||
request.session['role_id'] = 1
|
||||
else:
|
||||
request.session['role_id'] = 0
|
||||
return HttpResponseRedirect(request.GET.get('next', '/'), )
|
||||
return HttpResponseRedirect(request.session.get('pre_url', '/'))
|
||||
# response.set_cookie('username', username, expires=604800)
|
||||
# response.set_cookie('seed', PyCrypt.md5_crypt(password), expires=604800)
|
||||
# return response
|
||||
|
@ -268,7 +268,7 @@ def setting(request):
|
|||
if '' in [username, port] and ('' in password or '' in private_key):
|
||||
return HttpResponse('所填内容不能为空, 且密码和私钥填一个')
|
||||
else:
|
||||
private_key_path = os.path.join(BASE_DIR, 'role_keys', 'default', 'default_private_key.pem')
|
||||
private_key_path = os.path.join(BASE_DIR, 'keys/role_keys', 'default', 'default_private_key.pem')
|
||||
if private_key:
|
||||
with open(private_key_path, 'w') as f:
|
||||
f.write(private_key)
|
||||
|
|
|
@ -123,27 +123,27 @@ def db_del_user(username):
|
|||
|
||||
def gen_ssh_key(username, password='',
|
||||
key_dir=os.path.join(KEY_DIR, 'user'),
|
||||
|
||||
authorized_keys=True, home="/home", length=2048):
|
||||
"""
|
||||
generate a user ssh key in a property dir
|
||||
生成一个用户ssh密钥对
|
||||
"""
|
||||
logger.debug('生成ssh key, 并设置authorized_keys')
|
||||
private_key_file = os.path.join(key_dir, username)
|
||||
mkdir(private_key_file, username)
|
||||
mkdir(key_dir, mode=777)
|
||||
if os.path.isfile(private_key_file):
|
||||
os.unlink(private_key_file)
|
||||
ret = bash('echo -e "y\n"|ssh-keygen -t rsa -f %s -b %s -P "%s"' % (private_key_file, length, password))
|
||||
|
||||
if authorized_keys:
|
||||
auth_key_dir = os.path.join(home, username, '.ssh')
|
||||
mkdir(auth_key_dir, username, mode=0700)
|
||||
mkdir(auth_key_dir, mode=0700)
|
||||
authorized_key_file = os.path.join(auth_key_dir, 'authorized_keys')
|
||||
with open(private_key_file+'.pub') as pub_f:
|
||||
with open(authorized_key_file, 'w') as auth_f:
|
||||
auth_f.write(pub_f.read())
|
||||
os.chmod(authorized_key_file, 0600)
|
||||
bash('chown %s:%s %s' % (username, username, authorized_key_file))
|
||||
chown(authorized_key_file, username)
|
||||
|
||||
|
||||
def server_add_user(username, password, ssh_key_pwd, ssh_key_login_need):
|
||||
|
|
|
@ -96,36 +96,37 @@ def group_edit(request):
|
|||
|
||||
if request.method == 'GET':
|
||||
group_id = request.GET.get('id', '')
|
||||
user_group = get_object(UserGroup, id=group_id)
|
||||
if user_group:
|
||||
users_all = User.objects.all()
|
||||
users_selected = user_group.user_set.all()
|
||||
users_remain = [user for user in users_all if user not in users_selected]
|
||||
# user_group = get_object(UserGroup, id=group_id)
|
||||
user_group = UserGroup.objects.get(id=group_id)
|
||||
users_selected = User.objects.filter(group=user_group)
|
||||
users_remain = User.objects.filter(~Q(group=user_group))
|
||||
users_all = User.objects.all()
|
||||
|
||||
else:
|
||||
elif request.method == 'POST':
|
||||
group_id = request.POST.get('group_id', '')
|
||||
group_name = request.POST.get('group_name', '')
|
||||
comment = request.POST.get('comment', '')
|
||||
users_selected = request.POST.getlist('users_selected')
|
||||
|
||||
users = []
|
||||
try:
|
||||
if '' in [group_id, group_name]:
|
||||
raise ServerError('组名不能为空')
|
||||
|
||||
user_group = get_object(UserGroup, id=group_id)
|
||||
other_group = get_object(UserGroup, name=group_name)
|
||||
|
||||
if other_group and other_group.id != int(group_id):
|
||||
if len(UserGroup.objects.filter(name=group_name)) > 1:
|
||||
raise ServerError(u'%s 用户组已存在' % group_name)
|
||||
# add user group
|
||||
for user in User.objects.filter(id__in=users_selected):
|
||||
user.group.add(UserGroup.objects.get(id=group_id))
|
||||
# delete user group
|
||||
user_group = UserGroup.objects.get(id=group_id)
|
||||
for user in [user for user in User.objects.filter(group=user_group) if user not in User.objects.filter(id__in=users_selected)]:
|
||||
user_group_all = user.group.all()
|
||||
user.group.clear()
|
||||
for g in user_group_all:
|
||||
if g == user_group:
|
||||
continue
|
||||
user.group.add(g)
|
||||
|
||||
for user_id in users_selected:
|
||||
users.extend(User.objects.filter(id=user_id))
|
||||
|
||||
if user_group:
|
||||
user_group.update(name=group_name, comment=comment)
|
||||
user_group.user_set.clear()
|
||||
user_group.user_set = users
|
||||
|
||||
except ServerError, e:
|
||||
error = e
|
||||
|
@ -133,8 +134,8 @@ def group_edit(request):
|
|||
return HttpResponseRedirect('/juser/group_list/')
|
||||
else:
|
||||
users_all = User.objects.all()
|
||||
users_selected = user_group.user_set.all()
|
||||
users_remain = [user for user in users_all if user not in users_selected]
|
||||
users_selected = User.objects.filter(group=user_group)
|
||||
users_remain = User.objects.filter(~Q(group=user_group))
|
||||
|
||||
return my_render('juser/group_edit.html', locals(), request)
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
看山是山,看水是水
|
||||
看山不是山,看水不是水
|
||||
看山是山,看水是水
|
|
@ -0,0 +1 @@
|
|||
永远年轻,永远热泪盈眶
|
|
@ -1,17 +0,0 @@
|
|||
- hosts: the_del_group
|
||||
tasks:
|
||||
- name: del user
|
||||
user: name={{ item }} state=absent remove=yes
|
||||
with_items: [ the_del_users ]
|
||||
|
||||
- hosts: the_new_group
|
||||
tasks:
|
||||
- name: add user
|
||||
user: name={{ item }} state=present
|
||||
with_items: [ the_new_users ]
|
||||
- name: .ssh direcotory
|
||||
file: name=/home/{{ item }}/.ssh mode=700 owner={{ item }} group={{ item }} state=directory
|
||||
with_items: [ the_new_users ]
|
||||
- name: set authorizied_file
|
||||
copy: src=KEY_DIR/{{ item }}.pub dest=/home/{{ item }}/.ssh/authorizied_keys owner={{ item }} group={{ item }} mode=600
|
||||
with_items: [ the_new_users ]
|
|
@ -14,7 +14,6 @@
|
|||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/juser/user_list/">{{ users.count}}</a></h1>
|
||||
{# <div class="stat-percent font-bold text-success">{{ percent_user }} <i class="fa fa-bolt"></i></div>#}
|
||||
<small>All user</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -27,7 +26,6 @@
|
|||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/jasset/host_list/">{{ hosts.count }}</a></h1>
|
||||
{# <div class="stat-percent font-bold text-info">{{ percent_host }} <i class="fa fa-level-up"></i></div>#}
|
||||
<small>All host</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -37,7 +35,7 @@
|
|||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary pull-right">Online</span>
|
||||
<h5>实时在线用户</h5>
|
||||
<h5>在线用户</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_users">{{ online_user | length }}</span></a></h1>
|
||||
|
@ -55,7 +53,6 @@
|
|||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_hosts">{{ online_host | length }}</span></a></h1>
|
||||
{# <div class="stat-percent font-bold text-danger">{{ percent_online_host }} <i class="fa fa-level-down"></i></div>#}
|
||||
<small>Connected host</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -169,7 +166,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-user"></i> 一周Top10资产 </h3>
|
||||
<h3><i class="fa fa-inbox"></i> 一周Top10资产 </h3>
|
||||
<small><i class="fa fa-map-marker"></i> 登录次数及最近一次登录记录. </small>
|
||||
</div>
|
||||
<div class="ibox-content inspinia-timeline">
|
||||
|
@ -309,14 +306,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--</div>-->
|
||||
<!--<div class="col-xm-6" id="top10" style="width:50%;height:400px;"></div>-->
|
||||
<!--<div class="col-xm-6" id="usertop10" style="width:50%;height:400px;"></div>-->
|
||||
<!--<div class="row">-->
|
||||
<!--<div class="col-lg-6" id="hosttop10" style="width:50%;height:400px; margin-top: 20px"></div>-->
|
||||
<!--</div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
{{ 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>
|
||||
|
|
|
@ -54,17 +54,29 @@
|
|||
<div class="col-sm-2">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<<<<<<< HEAD
|
||||
<input type="radio" checked="" value="no_action" id="no" name="use_default_auth" class="auth"><span> 不修改 </span>
|
||||
=======
|
||||
<input type="radio" checked="" value="" id="no" name="use_default_auth" class="auth"><span> 不修改 </span>
|
||||
>>>>>>> cmdb
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<<<<<<< HEAD
|
||||
<input type="radio" id="default" name="use_default_auth" class="auth"><span> 使用默认 </span>
|
||||
=======
|
||||
<input type="radio" id="default" name="use_default_auth" class="auth" value="default"><span> 使用默认 </span>
|
||||
>>>>>>> cmdb
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<<<<<<< HEAD
|
||||
<input type="radio" id="pass" name="use_default_auth" class="auth"><span> 用户名密码 </span>
|
||||
=======
|
||||
<input type="radio" id="pass" name="use_default_auth" class="auth" value="user_passwd"><span> 用户名密码 </span>
|
||||
>>>>>>> cmdb
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -126,6 +138,21 @@
|
|||
</div>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
<<<<<<< HEAD
|
||||
$('#host_edit').click(function () {
|
||||
var args = {};
|
||||
var match = null;
|
||||
var uuid = decodeURIComponent(location.search.substring(1));
|
||||
var reg = /(?:([^&]+)=([^&]+))/g;
|
||||
while((match = reg.exec(uuid))!==null){
|
||||
args[match[1]] = match[2];
|
||||
}
|
||||
var ids = args['uuid'];
|
||||
$('#uuid').val(ids)
|
||||
});
|
||||
|
||||
=======
|
||||
>>>>>>> cmdb
|
||||
$('.auth').click(function(){
|
||||
if ($(this).attr('id') == 'pass'){
|
||||
$('#admin_account').css('display', 'block')
|
||||
|
|
|
@ -40,6 +40,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role_password_label" class="col-sm-2 control-label">角色密码<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="role_password" name="role_password" type="password" class="form-control" value="{{ role_pass }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="role_comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
<div class="row">
|
||||
<div class="col-lg-10">
|
||||
<div class="ibox float-e-margins">
|
||||
<div>
|
||||
{% if error %}
|
||||
<div class="alert alert-warning text-center">{{ error }}</div>
|
||||
{% endif %}
|
||||
{% if msg %}
|
||||
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="ibox-title">
|
||||
<h5> 所有系统角色</h5>
|
||||
<div class="ibox-tools">
|
||||
|
|
|
@ -67,16 +67,6 @@
|
|||
</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>
|
||||
<div class="col-sm-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="1" id="use_password" name="use_password">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用秘钥</label>
|
||||
<div class="col-sm-1">
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<form method="post" id="userForm" class="form-horizontal" action="">
|
||||
<form method="post" id="ruleForm" class="form-horizontal" action="">
|
||||
{% if error %}
|
||||
<div class="alert alert-warning text-center">{{ error }}</div>
|
||||
{% endif %}
|
||||
|
@ -34,7 +34,7 @@
|
|||
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="username" class="col-sm-2 control-label">授权名称<span class="red-fonts">*</span></label>
|
||||
<label for="rulename" class="col-sm-2 control-label">授权名称<span class="red-fonts">*</span></label>
|
||||
<div class="col-sm-8">
|
||||
<input id="rulename" name="rulename" placeholder="Rule Name" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
</div>
|
||||
|
@ -48,11 +48,11 @@
|
|||
<option value="{{ user.name }}">{{ user.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span class="help-block m-b-none">用户和用户组必选一个</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="usergroup" class="col-sm-2 control-label">用户组<span class="red-fonts">*</span></label>
|
||||
<label for="usergroup" class="col-sm-2 control-label">用户组</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="usergroup" data-placeholder="请选择用户组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user_group in user_groups %}
|
||||
|
@ -70,11 +70,11 @@
|
|||
<option value="{{ asset.ip }}">{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<span class="help-block m-b-none">资产和资产组必选一个</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="assetgroup" class="col-sm-2 control-label">资产组<span class="red-fonts">*</span></label>
|
||||
<label for="assetgroup" class="col-sm-2 control-label">资产组</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="assetgroup" data-placeholder="请选择资产组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset_group in asset_groups %}
|
||||
|
@ -95,51 +95,11 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用密码</label>
|
||||
<div class="col-sm-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="0" id="use_password" name="use_password">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_password" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用秘钥</label>
|
||||
<div class="col-sm-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="1" id="use_publicKey" name="use_publicKey">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_publicKey" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 秘钥<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
<input id="comment" name="comment" placeholder="Rule Comment" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
<input id="rule_comment" name="rule_comment" placeholder="Rule Comment" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
@ -158,6 +118,37 @@
|
|||
{% endblock %}
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
|
||||
$('#ruleForm').submit(function() {
|
||||
var result = {};
|
||||
var data = $(this).serializeArray();
|
||||
$.each(data, function (i, field) {
|
||||
result[field.name] = field.value;
|
||||
});
|
||||
if (result['user'] || result['usergroup'] || result['asset'] || result['assetgroup'] || result['rulename'] || result['role']) {
|
||||
if (result['rulename'] === '') {
|
||||
alert("请添加授权名称");
|
||||
return false
|
||||
}
|
||||
if (!result['user'] && !result['usergroup']) {
|
||||
alert("用户和用户组必选1个");
|
||||
return false
|
||||
}
|
||||
if (!result['asset'] && !result['assetgroup']) {
|
||||
alert("资产和资产组必选1个");
|
||||
return false
|
||||
}
|
||||
if (!result['role']) {
|
||||
alert("请填写角色");
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
alert("请填必选项");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function(){
|
||||
$("input.role").click(function(){
|
||||
if($("input.role[value=GA]").is( ":checked" )){
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<div class="col-sm-8">
|
||||
<select name="user" data-placeholder="用户名" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user in users %}
|
||||
<option value="{{ user.name }}">{{ user.name }}</option>
|
||||
<option value="{{ user.name }}" {% if user in users_select %} selected {% endif %}>{{ user.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -56,7 +56,7 @@
|
|||
<div class="col-sm-8">
|
||||
<select name="usergroup" data-placeholder="请选择用户组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for user_group in user_groups %}
|
||||
<option value="{{ user_group.name }}">{{ user_group.name }}</option>
|
||||
<option value="{{ user_group.name }}"{% if user_group in users_groups_select %} selected {% endif %}>{{ user_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -67,7 +67,7 @@
|
|||
<div class="col-sm-8">
|
||||
<select name="asset" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset in assets %}
|
||||
<option value="{{ asset.ip }}">{{ asset.ip }}</option>
|
||||
<option value="{{ asset.ip }}"{% if asset in assets_select %} selected {% endif %}>{{ asset.ip }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -78,7 +78,7 @@
|
|||
<div class="col-sm-8">
|
||||
<select name="assetgroup" data-placeholder="请选择资产组" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for asset_group in asset_groups %}
|
||||
<option value="{{ asset_group.name }}">{{ asset_group.name }}</option>
|
||||
<option value="{{ asset_group.name }}"{% if asset_group in asset_groups_select %} selected {% endif %}>{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -89,57 +89,17 @@
|
|||
<div class="col-sm-8">
|
||||
<select name="role" data-placeholder="请选择角色" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||
{% for role in roles %}
|
||||
<option value="{{ role.name }}">{{ role.name }}</option>
|
||||
<option value="{{ role.name }}"{% if role in roles_select %} selected {% endif %}>{{ role.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用密码</label>
|
||||
<div class="col-sm-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="0" id="use_password" name="use_password">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_password" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="j_group" class="col-sm-2 control-label">使用秘钥</label>
|
||||
<div class="col-sm-1">
|
||||
<div class="radio i-checks">
|
||||
<label>
|
||||
<input type="checkbox" value="1" id="use_publicKey" name="use_publicKey">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="admin_account_publicKey" style="display: none">
|
||||
<label class="col-sm-1 control-label"> 秘钥<span class="red-fonts">*</span> </label>
|
||||
<div class="col-sm-4">
|
||||
<input type="password" name="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<label for="comment" class="col-sm-2 control-label">备注</label>
|
||||
<div class="col-sm-8">
|
||||
<input id="comment" name="comment" placeholder="Comment" type="text" class="form-control" {% if error %}value="{{ username }}" {% endif %}>
|
||||
<input id="role_comment" name="role_comment" placeholder="Rule Comment" type="text" class="form-control" value="{{ rule_comment }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
|
|
@ -3,10 +3,20 @@
|
|||
{% block content %}
|
||||
{% include 'nav_cat_bar.html' %}
|
||||
|
||||
|
||||
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-lg-10">
|
||||
<div class="ibox float-e-margins">
|
||||
<div>
|
||||
{% if error %}
|
||||
<div class="alert alert-warning text-center">{{ error }}</div>
|
||||
{% endif %}
|
||||
{% if msg %}
|
||||
<div class="alert alert-success text-center">{{ msg }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="ibox-title">
|
||||
<h5> 所有规则</h5>
|
||||
<div class="ibox-tools">
|
||||
|
@ -55,19 +65,19 @@
|
|||
<tr class="gradeX" id={{ rule.id }}>
|
||||
<td class="text-center"> {{ rule.name }} </td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/asset_list/?gid={{ user.id }}">{{ rule | rule_member_count:"user" }} </a>
|
||||
{{ rule | rule_member_count:"user" }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"user_group" }}</a>
|
||||
{{ rule | rule_member_count:"user_group" }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"asset" }}</a>
|
||||
{{ rule | rule_member_count:"asset" }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"asset_group" }}</a>
|
||||
{{ rule | rule_member_count:"asset_group" }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jasset/group_list/?gid={{ user.id }}">{{ rule | rule_member_count:"role" }}</a>
|
||||
{{ rule | rule_member_count:"role" }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="/jperm/perm_rule_detail/?id={{ rule.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||
|
|
|
@ -93,6 +93,7 @@ type="checkbox" name="selected" value="{{ group.id }}">
|
|||
$(document).ready(function(){
|
||||
$('.del').click(function(){
|
||||
var row = $(this).closest('tr');
|
||||
if (confirm("确定删除")) {
|
||||
$.get(
|
||||
$(this).attr('value'),
|
||||
{},
|
||||
|
@ -101,7 +102,7 @@ type="checkbox" name="selected" value="{{ group.id }}">
|
|||
alert(data);
|
||||
}
|
||||
|
||||
)
|
||||
)}
|
||||
});
|
||||
|
||||
$('#del_btn').click(function(){
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<div class="col-sm-8">
|
||||
<input id="password" name="password" placeholder="Password" type="password" class="form-control">
|
||||
<span class="help-block m-b-none">
|
||||
登陆web的密码
|
||||
登陆web的密码(如不修改请留空)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -64,7 +64,13 @@
|
|||
<td class="text-center" title="{% for user_group in user.group.all %} {{ user_group.name }} {% endfor %}"> {{ user.group.all | groups2str }} </td>
|
||||
<td class="text-center"> {{ user.id | get_role }}</td>
|
||||
<td class="text-center">{{ user.is_active | bool2str }}</td>
|
||||
<td class="text-center"><a href="/juser/down_key/?id={{ user.id }}">下载</a></td>
|
||||
<td class="text-center">
|
||||
{% if user.username|key_exist %}
|
||||
<a href="/juser/down_key/?id={{ user.id }}" >下载</a>
|
||||
{% else %}
|
||||
<span style="color: #586b7d">下载</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="../user_detail/?id={{ user.id }}" class="btn btn-xs btn-primary">详情</a>
|
||||
<a href="../user_edit/?id={{ user.id }}" class="btn btn-xs btn-info">编辑</a>
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
<ul class="nav" id="side-menu">
|
||||
{% include 'nav_li_profile.html' %}
|
||||
<li id="index">
|
||||
<a href="/"><i class="fa fa-th-large"></i> <span class="nav-label">仪表盘</span><span class="label label-info pull-right"></span></a>
|
||||
<a href="/"><i class="fa fa-dashboard"></i> <span class="nav-label">仪表盘</span><span class="label label-info pull-right"></span></a>
|
||||
</li>
|
||||
<li id="juser">
|
||||
<a href="#"><i class="fa fa-rebel"></i> <span class="nav-label">用户管理</span><span class="fa arrow"></span></a>
|
||||
<a href="#"><i class="fa fa-group"></i> <span class="nav-label">用户管理</span><span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li class="group_list group_edit"><a href="/juser/group_list/">查看用户组</a></li>
|
||||
<li class="group_add"><a href="/juser/group_add/">添加用户组</a></li>
|
||||
|
@ -16,7 +16,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li id="jasset">
|
||||
<a><i class="fa fa-cube"></i> <span class="nav-label">资产管理</span><span class="fa arrow"></span></a>
|
||||
<a><i class="fa fa-inbox"></i> <span class="nav-label">资产管理</span><span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li class="group_add"><a href="/jasset/group_add/">添加资产组</a></li>
|
||||
<li class="group_list group_detail group_edit"><a href="/jasset/group_list/">查看资产组</a></li>
|
||||
|
@ -29,11 +29,11 @@
|
|||
<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="dept_perm_list dept_perm_edit">
|
||||
<li class="rule ">
|
||||
<a href="/jperm/rule/">授权规则</a>
|
||||
</li>
|
||||
|
||||
<li class="sudo_list sudo_edit sudo_add cmd_list cmd_edit cmd_add sudo_detail">
|
||||
<li class="role">
|
||||
<a href="/jperm/role/">系统角色</a>
|
||||
</li>
|
||||
<li class="apply_show online"><a href="/jperm/apply_show/online/">权限审批</a></li>
|
||||
|
@ -44,7 +44,7 @@
|
|||
<a href="/jlog/log_list/online/"><i class="fa fa-files-o"></i> <span class="nav-label">日志审计</span><span class="label label-info pull-right"></span></a>
|
||||
</li>
|
||||
<li id="setting">
|
||||
<a href="/setting/"><i class="fa fa-files-o"></i> <span class="nav-label">设置</span><span class="label label-info pull-right"></span></a>
|
||||
<a href="/setting/"><i class="fa fa-gears"></i> <span class="nav-label">设置</span><span class="label label-info pull-right"></span></a>
|
||||
</li>
|
||||
<li class="special_link">
|
||||
<a href="http://www.jumpserver.org" target="_blank"><i class="fa fa-database"></i> <span class="nav-label">访问官网</span></a>
|
||||
|
|
Loading…
Reference in New Issue