����sudo�޸�Ȩ��

pull/6/head
guanghongwei 2015-02-09 18:50:21 +08:00
parent b9e2c9aa95
commit d7de3edcf4
7 changed files with 245 additions and 139 deletions

View File

@ -16,8 +16,6 @@ import getpass
import fnmatch import fnmatch
import readline import readline
from multiprocessing import Pool from multiprocessing import Pool
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
@ -27,6 +25,7 @@ from juser.models import User
from jasset.models import Asset from jasset.models import Asset
from jlog.models import Log from jlog.models import Log
from jperm.views import perm_user_asset from jperm.views import perm_user_asset
from jumpserver.views import PyCrypt
try: try:
import termios import termios
@ -75,34 +74,6 @@ class ServerError(Exception):
pass pass
class PyCrypt(object):
"""This class used to encrypt and decrypt password."""
def __init__(self, key):
self.key = key
self.mode = AES.MODE_CBC
def encrypt(self, text):
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
length = 16
try:
count = len(text)
except TypeError:
raise ServerError('Encrypt password error, TYpe error.')
add = (length - (count % length))
text += ('\0' * add)
ciphertext = cryptor.encrypt(text)
return b2a_hex(ciphertext)
def decrypt(self, text):
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
try:
plain_text = cryptor.decrypt(a2b_hex(text))
except TypeError:
raise ServerError('Decrypt password error, TYpe error.')
return plain_text.rstrip('\0')
def get_win_size(): def get_win_size():
"""This function use to get the size of the windows!""" """This function use to get the size of the windows!"""
if 'TIOCGWINSZ' in dir(termios): if 'TIOCGWINSZ' in dir(termios):

View File

@ -18,7 +18,8 @@ class CmdGroup(models.Model):
class SudoPerm(models.Model): class SudoPerm(models.Model):
name = models.CharField(max_length=20)
user_group = models.ManyToManyField(UserGroup) user_group = models.ManyToManyField(UserGroup)
asset_group = models.ManyToManyField(BisGroup) asset_group = models.ManyToManyField(BisGroup)
cmd_group = models.ManyToManyField(CmdGroup) cmd_group = models.ManyToManyField(CmdGroup)
comment = models.CharField(max_length=30) comment = models.CharField(max_length=30, null=True, blank=True)

View File

@ -7,6 +7,14 @@ from jasset.models import Asset, BisGroup
from jperm.models import Perm, SudoPerm, CmdGroup from jperm.models import Perm, SudoPerm, CmdGroup
from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.db.models import Q from django.db.models import Q
from jumpserver.views import LDAP_ENABLE, ldap_conn, CONF
if LDAP_ENABLE:
LDAP_HOST_URL = CONF.get('ldap', 'host_url')
LDAP_BASE_DN = CONF.get('ldap', 'base_dn')
LDAP_ROOT_DN = CONF.get('ldap', 'root_dn')
LDAP_ROOT_PW = CONF.get('ldap', 'root_pw')
def perm_group_update(user_group_name='', user_group_id='', asset_groups_name='', asset_groups_id=''): def perm_group_update(user_group_name='', user_group_id='', asset_groups_name='', asset_groups_id=''):
@ -138,7 +146,6 @@ def perm_asset_detail(request):
return render_to_response('jperm/perm_asset_detail.html', locals()) return render_to_response('jperm/perm_asset_detail.html', locals())
def user_asset_cmd_groups_get(user_groups_select, asset_groups_select, cmd_groups_select): def user_asset_cmd_groups_get(user_groups_select, asset_groups_select, cmd_groups_select):
user_groups_select_list = [] user_groups_select_list = []
asset_groups_select_list = [] asset_groups_select_list = []
@ -167,10 +174,41 @@ def sudo_db_add(user_groups_select, asset_groups_select, cmd_groups_select, comm
sudo_perm.cmd_group = cmd_groups_select_list sudo_perm.cmd_group = cmd_groups_select_list
def sudo_ldap_add(user_groups_select, asset_groups_select, cmd_groups_select): def unicode2str(unicode_list):
return [str(i) for i in unicode_list]
def sudo_ldap_add(name, users_runas, user_groups_select, asset_groups_select, cmd_groups_select):
user_groups_select_list, asset_groups_select_list, cmd_groups_select_list = \ user_groups_select_list, asset_groups_select_list, cmd_groups_select_list = \
user_asset_cmd_groups_get(user_groups_select, asset_groups_select, cmd_groups_select) user_asset_cmd_groups_get(user_groups_select, asset_groups_select, cmd_groups_select)
users = []
assets = []
cmds = []
for user_group in user_groups_select_list:
users.extend(user_group.user_set.all())
for asset_group in asset_groups_select_list:
assets.extend(asset_group.asset_set.all())
for cmd_group in cmd_groups_select_list:
cmds.extend(cmd_group.cmd.split(','))
users_name = [user.name for user in users]
assets_ip = [asset.ip for asset in assets]
sudo_dn = 'cn=%s,ou=Sudoers,%s' % (name, LDAP_BASE_DN)
sudo_attr = {'objectClass': ['top', 'sudoRole'],
'cn': ['%s' % str(name)],
'sudoCommand': unicode2str(cmds),
'sudoHost': unicode2str(assets_ip),
'sudoOption': ['!authenticate'],
'sudoRunAsUser': unicode2str(users_runas),
'sudoUser': unicode2str(users_name)}
ldap_conn.add(sudo_dn, sudo_attr)
def sudo_add(request): def sudo_add(request):
header_title, path1, path2 = u'Sudo授权 | Perm Sudo Add.', u'jperm', u'sudo_add' header_title, path1, path2 = u'Sudo授权 | Perm Sudo Add.', u'jperm', u'sudo_add'
@ -179,16 +217,17 @@ def sudo_add(request):
cmd_groups = CmdGroup.objects.all() cmd_groups = CmdGroup.objects.all()
if request.method == 'POST': if request.method == 'POST':
name = request.POST.get('name')
users_runas = request.POST.get('runas', 'root').split(',')
user_groups_select = request.POST.getlist('user_groups_select') user_groups_select = request.POST.getlist('user_groups_select')
asset_groups_select = request.POST.getlist('asset_groups_select') asset_groups_select = request.POST.getlist('asset_groups_select')
cmd_groups_select = request.POST.getlist('cmd_groups_select') cmd_groups_select = request.POST.getlist('cmd_groups_select')
comment = request.POST.get('comment', '') comment = request.POST.get('comment', '')
sudo_db_add(user_groups_select, asset_groups_select, cmd_groups_select, comment) sudo_db_add(user_groups_select, asset_groups_select, cmd_groups_select, comment)
sudo_ldap_add(name, users_runas, user_groups_select, asset_groups_select, cmd_groups_select)
msg = '添加成功' msg = '添加成功'
return render_to_response('jperm/sudo_add.html', locals()) return render_to_response('jperm/sudo_add.html', locals())

View File

@ -3,15 +3,29 @@
import hashlib import hashlib
import ldap import ldap
from ldap import modlist from ldap import modlist
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
from ConfigParser import ConfigParser
import os
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from juser.models import User from juser.models import User
from connect import PyCrypt, KEY
from jasset.models import Asset, BisGroup, IDC from jasset.models import Asset, BisGroup, IDC
BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
CONF = ConfigParser()
CONF.read(os.path.join(BASE_DIR, 'jumpserver.conf'))
LDAP_ENABLE = CONF.getint('ldap', 'ldap_enable')
if LDAP_ENABLE:
LDAP_HOST_URL = CONF.get('ldap', 'host_url')
LDAP_BASE_DN = CONF.get('ldap', 'base_dn')
LDAP_ROOT_DN = CONF.get('ldap', 'root_dn')
LDAP_ROOT_PW = CONF.get('ldap', 'root_pw')
def md5_crypt(string): def md5_crypt(string):
return hashlib.new("md5", string).hexdigest() return hashlib.new("md5", string).hexdigest()
@ -30,7 +44,7 @@ def jasset_group_add(name, comment, type):
emg = u'该业务组已存在!' emg = u'该业务组已存在!'
else: else:
BisGroup.objects.create(name=name, comment=comment, type=type) BisGroup.objects.create(name=name, comment=comment, type=type)
smg = u'业务组%s添加成功' %name smg = u'业务组%s添加成功' % name
def jasset_host_edit(j_id, j_ip, j_idc, j_port, j_type, j_group, j_active, j_comment): def jasset_host_edit(j_id, j_ip, j_idc, j_port, j_type, j_group, j_active, j_comment):
@ -151,3 +165,38 @@ class LDAPMgmt():
print e print e
class PyCrypt(object):
"""This class used to encrypt and decrypt password."""
def __init__(self, key):
self.key = key
self.mode = AES.MODE_CBC
def encrypt(self, text):
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
length = 16
try:
count = len(text)
except TypeError:
raise ServerError('Encrypt password error, TYpe error.')
add = (length - (count % length))
text += ('\0' * add)
ciphertext = cryptor.encrypt(text)
return b2a_hex(ciphertext)
def decrypt(self, text):
cryptor = AES.new(self.key, self.mode, b'0000000000000000')
try:
plain_text = cryptor.decrypt(a2b_hex(text))
except TypeError:
raise ServerError('Decrypt password error, TYpe error.')
return plain_text.rstrip('\0')
if LDAP_ENABLE:
ldap_conn = LDAPMgmt(LDAP_HOST_URL, LDAP_BASE_DN, LDAP_ROOT_DN, LDAP_ROOT_PW)
else:
ldap_conn = None

View File

@ -20,17 +20,16 @@ from juser.models import UserGroup, User
from connect import PyCrypt, KEY from connect import PyCrypt, KEY
from connect import BASE_DIR from connect import BASE_DIR
from connect import CONF from connect import CONF
from jumpserver.views import md5_crypt,LDAPMgmt from jumpserver.views import md5_crypt, LDAPMgmt, LDAP_ENABLE, ldap_conn
CRYPTOR = PyCrypt(KEY)
LDAP_ENABLE = CONF.getint('ldap', 'ldap_enable')
if LDAP_ENABLE: if LDAP_ENABLE:
LDAP_HOST_URL = CONF.get('ldap', 'host_url') LDAP_HOST_URL = CONF.get('ldap', 'host_url')
LDAP_BASE_DN = CONF.get('ldap', 'base_dn') LDAP_BASE_DN = CONF.get('ldap', 'base_dn')
LDAP_ROOT_DN = CONF.get('ldap', 'root_dn') LDAP_ROOT_DN = CONF.get('ldap', 'root_dn')
LDAP_ROOT_PW = CONF.get('ldap', 'root_pw') LDAP_ROOT_PW = CONF.get('ldap', 'root_pw')
CRYPTOR = PyCrypt(KEY)
def gen_rand_pwd(num): def gen_rand_pwd(num):
"""生成随机密码""" """生成随机密码"""
@ -176,20 +175,18 @@ def ldap_add_user(username, ldap_pwd):
'userPassword': ['{crypt}x'], 'userPassword': ['{crypt}x'],
'gidNumber': [str(user.id)]} 'gidNumber': [str(user.id)]}
sudo_dn = 'cn=%s,ou=Sudoers,%s' % (username, LDAP_BASE_DN) # sudo_dn = 'cn=%s,ou=Sudoers,%s' % (username, LDAP_BASE_DN)
sudo_attr = {'objectClass': ['top', 'sudoRole'], # sudo_attr = {'objectClass': ['top', 'sudoRole'],
'cn': ['%s' % str(username)], # 'cn': ['%s' % str(username)],
'sudoCommand': ['/bin/pwd'], # 'sudoCommand': ['/bin/pwd'],
'sudoHost': ['192.168.1.1'], # 'sudoHost': ['192.168.1.1'],
'sudoOption': ['!authenticate'], # 'sudoOption': ['!authenticate'],
'sudoRunAsUser': ['root'], # 'sudoRunAsUser': ['root'],
'sudoUser': ['%s' % str(username)]} # 'sudoUser': ['%s' % str(username)]}
ldap_conn = LDAPMgmt(LDAP_HOST_URL, LDAP_BASE_DN, LDAP_ROOT_DN, LDAP_ROOT_PW)
ldap_conn.add(user_dn, user_attr) ldap_conn.add(user_dn, user_attr)
ldap_conn.add(group_dn, group_attr) ldap_conn.add(group_dn, group_attr)
ldap_conn.add(sudo_dn, sudo_attr) # ldap_conn.add(sudo_dn, sudo_attr)
def ldap_del_user(username): def ldap_del_user(username):
@ -197,12 +194,21 @@ def ldap_del_user(username):
group_dn = "cn=%s,ou=Group,%s" % (username, LDAP_BASE_DN) group_dn = "cn=%s,ou=Group,%s" % (username, LDAP_BASE_DN)
sudo_dn = 'cn=%s,ou=Sudoers,%s' % (username, LDAP_BASE_DN) sudo_dn = 'cn=%s,ou=Sudoers,%s' % (username, LDAP_BASE_DN)
ldap_conn = LDAPMgmt(LDAP_HOST_URL, LDAP_BASE_DN, LDAP_ROOT_DN, LDAP_ROOT_PW)
ldap_conn.delete(user_dn) ldap_conn.delete(user_dn)
ldap_conn.delete(group_dn) ldap_conn.delete(group_dn)
ldap_conn.delete(sudo_dn) ldap_conn.delete(sudo_dn)
# def ldap_group_add(group_name, username_list, gid):
# group_dn = "cn=%s,ou=Group,%s" % (group_name, LDAP_BASE_DN)
# group_attr = {'objectClass': ['posixGroup', 'top'],
# 'cn': [str(group_name)],
# 'userPassword': ['{crypt}x'],
# 'gidNumber': [gid],
# 'memberUid': username_list}
# ldap_conn.add(group_dn, group_attr)
def group_add(request, group_type_select='A'): def group_add(request, group_type_select='A'):
error = '' error = ''
msg = '' msg = ''

View File

@ -37,7 +37,29 @@
<div class="alert alert-success text-center">{{ msg }}</div> <div class="alert alert-success text-center">{{ msg }}</div>
{% endif %} {% endif %}
<div class="row"> <div class="row">
<div class="col-sm-5"><h4>用户组</h4> <div class="form-group">
<label for="name" class="col-sm-2 control-label">授权名</label>
<div class="col-sm-8">
<input id="name" name="name" placeholder="OnlyForEnglish" type="text" class="form-control">
<span class="help-block m-b-none">取个名字方便辨识,只支持英文</span>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="runas" class="col-sm-2 control-label">RunAsUser</label>
<div class="col-sm-8">
<input id="runas" name="runas" placeholder="RunAsUser" type="text" class="form-control">
<span class="help-block m-b-none">
允许以哪个用户允许sudo,逗号分隔,默认root
</span>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="" class="col-sm-2 control-label">用户组</label>
<div class="col-sm-4">
<div> <div>
<select id="user_groups" name="user_groups" class="form-control" size="5" multiple> <select id="user_groups" name="user_groups" class="form-control" size="5" multiple>
{% for user_group in user_groups %} {% for user_group in user_groups %}
@ -47,14 +69,15 @@
</div> </div>
</div> </div>
<div class="col-sm-1"> <div class="col-sm-1">
<div class="btn-group" style="margin-top: 50px;"> <div class="btn-group" style="margin-top: 12px;">
<button type="button" class="btn btn-white" onclick="move('user_groups', 'user_groups_select')"><i class="fa fa-chevron-right"></i></button> <button type="button" class="btn btn-white" onclick="move('user_groups', 'user_groups_select')"><i class="fa fa-chevron-right"></i></button>
<button type="button" class="btn btn-white" onclick="move('user_groups_select', 'user_groups')"><i class="fa fa-chevron-left"></i> </button> <button type="button" class="btn btn-white" onclick="move('user_groups_select', 'user_groups')"><i class="fa fa-chevron-left"></i> </button>
</div> </div>
</div> </div>
<div class="col-sm-5"><h4>授权用户组</h4> <div class="col-sm-3">
<div> <div>
<select id="user_groups_select" name="user_groups_select" class="form-control m-b" size="5" multiple> <select id="user_groups_select" name="user_groups_select" class="form-control m-b" size="5" multiple>
</select> </select>
@ -64,8 +87,9 @@
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="row"> <div class="form-group">
<div class="col-sm-5"><h4>主机组</h4> <label for="" class="col-sm-2 control-label">主机组</label>
<div class="col-sm-4">
<div> <div>
<select id="asset_groups" name="asset_groups" class="form-control m-b" size="5" multiple> <select id="asset_groups" name="asset_groups" class="form-control m-b" size="5" multiple>
{% for asset_group in asset_groups %} {% for asset_group in asset_groups %}
@ -76,13 +100,13 @@
</div> </div>
<div class="col-sm-1"> <div class="col-sm-1">
<div class="btn-group" style="margin-top: 50px;"> <div class="btn-group" style="margin-top: 12px;">
<button type="button" class="btn btn-white" onclick="move('asset_groups', 'asset_groups_select')"><i class="fa fa-chevron-right"></i></button> <button type="button" class="btn btn-white" onclick="move('asset_groups', 'asset_groups_select')"><i class="fa fa-chevron-right"></i></button>
<button type="button" class="btn btn-white" onclick="move('asset_groups_select', 'asset_groups')"><i class="fa fa-chevron-left"></i> </button> <button type="button" class="btn btn-white" onclick="move('asset_groups_select', 'asset_groups')"><i class="fa fa-chevron-left"></i> </button>
</div> </div>
</div> </div>
<div class="col-sm-5"><h4>授权主机组</h4> <div class="col-sm-3">
<div> <div>
<select id="asset_groups_select" name="asset_groups_select" class="form-control m-b" size="5" multiple> <select id="asset_groups_select" name="asset_groups_select" class="form-control m-b" size="5" multiple>
</select> </select>
@ -92,8 +116,9 @@
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="row"> <div class="form-group">
<div class="col-sm-5"><h4>命令组</h4> <label for="" class="col-sm-2 control-label">命令组</label>
<div class="col-sm-4">
<div> <div>
<select id="cmd_groups" name="cmd_groups" class="form-control m-b" size="5" multiple> <select id="cmd_groups" name="cmd_groups" class="form-control m-b" size="5" multiple>
{% for cmd_group in cmd_groups %} {% for cmd_group in cmd_groups %}
@ -104,13 +129,13 @@
</div> </div>
<div class="col-sm-1"> <div class="col-sm-1">
<div class="btn-group" style="margin-top: 50px;"> <div class="btn-group" style="margin-top: 12px;">
<button type="button" class="btn btn-white" onclick="move('cmd_groups', 'cmd_groups_select')"><i class="fa fa-chevron-right"></i></button> <button type="button" class="btn btn-white" onclick="move('cmd_groups', 'cmd_groups_select')"><i class="fa fa-chevron-right"></i></button>
<button type="button" class="btn btn-white" onclick="move('cmd_groups_select', 'cmd_groups')"><i class="fa fa-chevron-left"></i> </button> <button type="button" class="btn btn-white" onclick="move('cmd_groups_select', 'cmd_groups')"><i class="fa fa-chevron-left"></i> </button>
</div> </div>
</div> </div>
<div class="col-sm-5"><h4>命令组</h4> <div class="col-sm-3">
<div> <div>
<select id="cmd_groups_select" name="cmd_groups_select" class="form-control m-b" size="5" multiple> <select id="cmd_groups_select" name="cmd_groups_select" class="form-control m-b" size="5" multiple>
</select> </select>
@ -127,12 +152,12 @@
</div> </div>
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
</div>
<div class="row"> <div class="row">
<div class="form-group"> <div class="form-group">
<div class="col-sm-4 col-sm-offset-2"> <div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="submit">取消</button> <button class="btn btn-white" type="reset">取消</button>
<button class="btn btn-primary" type="submit" onclick="javascript: (function(){$('#sudoPerm option').each(function(){$(this).prop('selected', true)})})()">确认保存</button> <button class="btn btn-primary" type="submit" onclick="javascript: (function(){$('#sudoPerm option').each(function(){$(this).prop('selected', true)})})()">确认保存</button>
</div> </div>
</div> </div>

View File

@ -33,8 +33,23 @@
<a href="#"><i class="fa fa-edit"></i> <span class="nav-label">授权管理</span><span class="fa arrow"></span></a> <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"> <ul class="nav nav-second-level">
<li id="perm_list"><a href="/jperm/perm_list/">主机授权</a></li> <li id="perm_list"><a href="/jperm/perm_list/">主机授权</a></li>
<li id="perm_sudo"><a href="/jperm/sudo_add/">Sudo添加</a></li> <li class="active">
<li id="perm_sudo"><a href="/jperm/sudo_list/">Sudo查看</a></li> <a href="#">Sudo授权<span class="fa arrow"></span></a>
<ul class="nav nav-third-level">
<li id="cmd_add">
<a href="/jperm/cmd_add/">命令组添加</a>
</li>
<li id="cmd_list">
<a href="/jperm/cmd_list/">命令组查看</a>
</li>
<li id="sudo_add">
<a href="/jperm/sudo_add/">Sudo添加</a>
</li>
<li id="sudo_list">
<a href="/jperm/sudo_list/">Sudo查看</a>
</li>
</ul>
</li>
</ul> </ul>
</li> </li>
<li id="jlog"> <li id="jlog">