mirror of https://github.com/jumpserver/jumpserver
418 lines
11 KiB
Python
418 lines
11 KiB
Python
# coding: utf-8
|
|
|
|
import os, sys, time, re
|
|
from Crypto.Cipher import AES
|
|
import crypt
|
|
from binascii import b2a_hex, a2b_hex
|
|
import hashlib
|
|
import datetime
|
|
import random
|
|
import subprocess
|
|
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 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):
|
|
"""
|
|
return a log file object
|
|
根据提示设置log打印
|
|
"""
|
|
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.setLevel(log_level_total.get(level, logging.DEBUG))
|
|
formatter = logging.Formatter('%(asctime)s - %(filename)s - %(levelname)s - %(message)s')
|
|
fh.setFormatter(formatter)
|
|
logger_f.addHandler(fh)
|
|
return logger_f
|
|
|
|
|
|
def page_list_return(total, current=1):
|
|
"""
|
|
page
|
|
分页,返回本次分页的最小页数到最大页数列表
|
|
"""
|
|
min_page = current - 2 if current - 4 > 0 else 1
|
|
max_page = min_page + 4 if min_page + 4 < total else total
|
|
|
|
return range(min_page, max_page + 1)
|
|
|
|
|
|
def pages(post_objects, request):
|
|
"""
|
|
page public function , return page's object tuple
|
|
分页公用函数,返回分页的对象元组
|
|
"""
|
|
paginator = Paginator(post_objects, 10)
|
|
try:
|
|
current_page = int(request.GET.get('page', '1'))
|
|
except ValueError:
|
|
current_page = 1
|
|
|
|
page_range = page_list_return(len(paginator.page_range), current_page)
|
|
|
|
try:
|
|
page_objects = paginator.page(current_page)
|
|
except (EmptyPage, InvalidPage):
|
|
page_objects = paginator.page(paginator.num_pages)
|
|
|
|
if current_page >= 5:
|
|
show_first = 1
|
|
else:
|
|
show_first = 0
|
|
|
|
if current_page <= (len(paginator.page_range) - 3):
|
|
show_end = 1
|
|
else:
|
|
show_end = 0
|
|
|
|
# 所有对象, 分页器, 本页对象, 所有页码, 本页页码,是否显示第一页,是否显示最后一页
|
|
return post_objects, paginator, page_objects, page_range, current_page, show_first, show_end
|
|
|
|
|
|
class PyCrypt(object):
|
|
"""
|
|
This class used to encrypt and decrypt password.
|
|
加密类
|
|
"""
|
|
|
|
def __init__(self, key):
|
|
self.key = key
|
|
self.mode = AES.MODE_CBC
|
|
|
|
@staticmethod
|
|
def gen_rand_pass(length, especial=False):
|
|
"""
|
|
random password
|
|
随机生成密码
|
|
"""
|
|
salt_key = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
|
|
symbol = '!@$%^&*()_'
|
|
salt_list = []
|
|
if especial:
|
|
for i in range(length - 4):
|
|
salt_list.append(random.choice(salt_key))
|
|
for i in range(4):
|
|
salt_list.append(random.choice(symbol))
|
|
else:
|
|
for i in range(length):
|
|
salt_list.append(random.choice(salt_key))
|
|
salt = ''.join(salt_list)
|
|
return salt
|
|
|
|
@staticmethod
|
|
def md5_crypt(string):
|
|
"""
|
|
md5 encrypt method
|
|
md5非对称加密方法
|
|
"""
|
|
return hashlib.new("md5", string).hexdigest()
|
|
|
|
@staticmethod
|
|
def gen_sha512(salt, password):
|
|
"""
|
|
generate sha512 format password
|
|
生成sha512加密密码
|
|
"""
|
|
return crypt.crypt(password, '$6$%s$' % salt)
|
|
|
|
def encrypt(self, passwd=None, length=32):
|
|
"""
|
|
encrypt gen password
|
|
对称加密之加密生成密码
|
|
"""
|
|
if not passwd:
|
|
passwd = self.gen_rand_pass()
|
|
|
|
cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1')
|
|
try:
|
|
count = len(passwd)
|
|
except TypeError:
|
|
raise ServerError('Encrypt password error, TYpe error.')
|
|
|
|
add = (length - (count % length))
|
|
passwd += ('\0' * add)
|
|
cipher_text = cryptor.encrypt(passwd)
|
|
return b2a_hex(cipher_text)
|
|
|
|
def decrypt(self, text):
|
|
"""
|
|
decrypt pass base the same key
|
|
对称加密之解密,同一个加密随机数
|
|
"""
|
|
cryptor = AES.new(self.key, self.mode, b'8122ca7d906ad5e1')
|
|
try:
|
|
plain_text = cryptor.decrypt(a2b_hex(text))
|
|
except TypeError:
|
|
# raise ServerError('Decrypt password error, TYpe error.')
|
|
pass
|
|
return plain_text.rstrip('\0')
|
|
|
|
|
|
class ServerError(Exception):
|
|
"""
|
|
self define exception
|
|
自定义异常
|
|
"""
|
|
pass
|
|
|
|
|
|
def get_object(model, **kwargs):
|
|
"""
|
|
use this function for query
|
|
使用改封装函数查询数据库
|
|
"""
|
|
for value in kwargs.values():
|
|
if not value:
|
|
return None
|
|
|
|
the_object = model.objects.filter(**kwargs)
|
|
if len(the_object) == 1:
|
|
the_object = the_object[0]
|
|
else:
|
|
the_object = None
|
|
return the_object
|
|
|
|
|
|
def require_role(role='user'):
|
|
"""
|
|
decorator for require user role in ["super", "admin", "user"]
|
|
要求用户是某种角色 ["super", "admin", "user"]的装饰器
|
|
"""
|
|
|
|
def _deco(func):
|
|
def __deco(request, *args, **kwargs):
|
|
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':
|
|
return HttpResponseRedirect('/')
|
|
elif role == 'super':
|
|
# if request.session.get('role_id', 0) < 2:
|
|
if request.user.role in ['CU', 'GA']:
|
|
return HttpResponseRedirect('/')
|
|
return func(request, *args, **kwargs)
|
|
|
|
return __deco
|
|
|
|
return _deco
|
|
|
|
|
|
def is_role_request(request, role='user'):
|
|
"""
|
|
require this request of user is right
|
|
要求请求角色正确
|
|
"""
|
|
role_all = {'user': 'CU', 'admin': 'GA', 'super': 'SU'}
|
|
if request.user.role == role_all.get(role, 'CU'):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def get_session_user_dept(request):
|
|
"""
|
|
get department of the user in session
|
|
获取session中用户的部门
|
|
"""
|
|
# user_id = request.session.get('user_id', 0)
|
|
# print '#' * 20
|
|
# print user_id
|
|
# user = User.objects.filter(id=user_id)
|
|
# if user:
|
|
# user = user[0]
|
|
# return user, None
|
|
return request.user, None
|
|
|
|
|
|
@require_role
|
|
def get_session_user_info(request):
|
|
"""
|
|
get the user info of the user in session, for example id, username etc.
|
|
获取用户的信息
|
|
"""
|
|
# user_id = request.session.get('user_id', 0)
|
|
# user = get_object(User, id=user_id)
|
|
# if user:
|
|
# return [user.id, user.username, user]
|
|
return [request.user.id, request.user.username, request.user]
|
|
|
|
|
|
def get_user_dept(request):
|
|
"""
|
|
get the user dept id
|
|
获取用户的部门id
|
|
"""
|
|
user_id = request.user.id
|
|
if user_id:
|
|
user_dept = User.objects.get(id=user_id).dept
|
|
return user_dept.id
|
|
|
|
|
|
def api_user(request):
|
|
hosts = Log.objects.filter(is_finished=0).count()
|
|
users = Log.objects.filter(is_finished=0).values('user').distinct().count()
|
|
ret = {'users': users, 'hosts': hosts}
|
|
json_data = json.dumps(ret)
|
|
return HttpResponse(json_data)
|
|
|
|
|
|
def view_splitter(request, su=None, adm=None):
|
|
"""
|
|
for different user use different view
|
|
视图分页器
|
|
"""
|
|
if is_role_request(request, 'super'):
|
|
return su(request)
|
|
elif is_role_request(request, 'admin'):
|
|
return adm(request)
|
|
else:
|
|
return HttpResponseRedirect('/login/')
|
|
|
|
|
|
def validate(request, user_group=None, user=None, asset_group=None, asset=None, edept=None):
|
|
"""
|
|
validate the user request
|
|
判定用户请求是否合法
|
|
"""
|
|
dept = get_session_user_dept(request)[1]
|
|
if edept:
|
|
if dept.id != int(edept[0]):
|
|
return False
|
|
|
|
if user_group:
|
|
dept_user_groups = dept.usergroup_set.all()
|
|
user_group_ids = []
|
|
for group in dept_user_groups:
|
|
user_group_ids.append(str(group.id))
|
|
|
|
if not set(user_group).issubset(set(user_group_ids)):
|
|
return False
|
|
|
|
if user:
|
|
dept_users = dept.user_set.all()
|
|
user_ids = []
|
|
for dept_user in dept_users:
|
|
user_ids.append(str(dept_user.id))
|
|
|
|
if not set(user).issubset(set(user_ids)):
|
|
return False
|
|
|
|
if asset_group:
|
|
dept_asset_groups = dept.bisgroup_set.all()
|
|
asset_group_ids = []
|
|
for group in dept_asset_groups:
|
|
asset_group_ids.append(str(group.id))
|
|
|
|
if not set(asset_group).issubset(set(asset_group_ids)):
|
|
return False
|
|
|
|
if asset:
|
|
dept_assets = dept.asset_set.all()
|
|
asset_ids = []
|
|
for dept_asset in dept_assets:
|
|
asset_ids.append(str(dept_asset.id))
|
|
|
|
if not set(asset).issubset(set(asset_ids)):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def verify(request, user_group=None, user=None, asset_group=None, asset=None, edept=None):
|
|
dept = get_session_user_dept(request)[1]
|
|
if edept:
|
|
if dept.id != int(edept[0]):
|
|
return False
|
|
|
|
if user_group:
|
|
dept_user_groups = dept.usergroup_set.all()
|
|
user_groups = []
|
|
for user_group_id in user_group:
|
|
user_groups.extend(UserGroup.objects.filter(id=user_group_id))
|
|
if not set(user_groups).issubset(set(dept_user_groups)):
|
|
return False
|
|
|
|
if user:
|
|
dept_users = dept.user_set.all()
|
|
users = []
|
|
for user_id in user:
|
|
users.extend(User.objects.filter(id=user_id))
|
|
|
|
if not set(users).issubset(set(dept_users)):
|
|
return False
|
|
|
|
if asset_group:
|
|
dept_asset_groups = dept.bisgroup_set.all()
|
|
asset_group_ids = []
|
|
for group in dept_asset_groups:
|
|
asset_group_ids.append(str(group.id))
|
|
|
|
if not set(asset_group).issubset(set(asset_group_ids)):
|
|
return False
|
|
|
|
if asset:
|
|
dept_assets = dept.asset_set.all()
|
|
asset_ids = []
|
|
for a in dept_assets:
|
|
asset_ids.append(str(a.id))
|
|
print asset, asset_ids
|
|
if not set(asset).issubset(set(asset_ids)):
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def bash(cmd):
|
|
"""
|
|
run a bash shell command
|
|
执行bash命令
|
|
"""
|
|
return subprocess.call(cmd, shell=True)
|
|
|
|
|
|
def mkdir(dir_name, username='root', 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)
|
|
|
|
|
|
def http_success(request, msg):
|
|
return render_to_response('success.html', locals())
|
|
|
|
|
|
def http_error(request, emg):
|
|
message = emg
|
|
return render_to_response('error.html', locals())
|
|
|
|
|
|
def my_render(template, data, request):
|
|
return render_to_response(template, data, context_instance=RequestContext(request))
|
|
|
|
|
|
CRYPTOR = PyCrypt(KEY)
|
|
logger = set_log(LOG_LEVEL)
|
|
KEY_DIR = os.path.join(BASE_DIR, 'keys')
|