From 026836ebc54e217a2f9350478d678b0e218e64e5 Mon Sep 17 00:00:00 2001 From: guanghongwei Date: Sat, 14 Mar 2015 17:54:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=8A=E5=A4=A9=E5=B0=B1=E8=BF=99=E6=A0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- connect.py | 6 +- jasset/models.py | 4 +- jperm/models.py | 8 -- jperm/views.py | 23 +--- jumpserver/api.py | 211 +++++++++++++++++++++++------- jumpserver/templatetags/mytags.py | 2 +- jumpserver/views.py | 110 +++------------- juser/urls.py | 5 +- juser/views.py | 45 ++++--- templates/juser/dept_list.html | 11 +- templates/juser/group_list.html | 12 +- templates/juser/user_list.html | 19 +-- templates/paginator.html | 2 +- 13 files changed, 238 insertions(+), 220 deletions(-) diff --git a/connect.py b/connect.py index 0c6e8134d..62849f99d 100755 --- a/connect.py +++ b/connect.py @@ -24,8 +24,7 @@ django.setup() from juser.models import User from jasset.models import Asset from jlog.models import Log -from jumpserver.views import PyCrypt -from jumpserver.api import user_perm_asset_api +from jumpserver.api import user_perm_asset_api, PyCrypt, BASE_DIR, CONF, CRYPTOR, KEY try: import termios @@ -35,13 +34,10 @@ except ImportError: time.sleep(3) sys.exit() -BASE_DIR = os.path.abspath(os.path.dirname(__file__)) -CONF = ConfigParser() CONF.read(os.path.join(BASE_DIR, 'jumpserver.conf')) LOG_DIR = os.path.join(BASE_DIR, 'logs') SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys') SERVER_KEY_DIR = os.path.join(SSH_KEY_DIR, 'server') -KEY = CONF.get('web', 'key') LOGIN_NAME = getpass.getuser() diff --git a/jasset/models.py b/jasset/models.py index d0e6cd425..37f45f6b2 100644 --- a/jasset/models.py +++ b/jasset/models.py @@ -1,6 +1,6 @@ import datetime from django.db import models -from juser.models import UserGroup +from juser.models import UserGroup, DEPT class IDC(models.Model): @@ -34,8 +34,8 @@ class Asset(models.Model): ip = models.IPAddressField(unique=True) port = models.SmallIntegerField(max_length=5) idc = models.ForeignKey(IDC) - user_group = models.ManyToManyField(UserGroup) bis_group = models.ManyToManyField(BisGroup) + dept = models.ManyToManyField(DEPT) login_type = models.CharField(max_length=1, choices=LOGIN_TYPE_CHOICES, default='L') username = models.CharField(max_length=20, blank=True, null=True) password = models.CharField(max_length=80, blank=True, null=True) diff --git a/jperm/models.py b/jperm/models.py index 84cd6716e..ca5b0e687 100644 --- a/jperm/models.py +++ b/jperm/models.py @@ -11,14 +11,6 @@ class Perm(models.Model): return '%s_%s' % (self.user_group.name, self.asset_group.name) -class DeptPerm(models.Model): - dept = models.ForeignKey(DEPT) - asset = models.ForeignKey(Asset) - - def __unicode__(self): - return '%s_%s' % (self.dept.name, self.asset.ip) - - class CmdGroup(models.Model): name = models.CharField(max_length=50) cmd = models.CharField(max_length=999) diff --git a/jperm/views.py b/jperm/views.py index b43633665..bca1ea05e 100644 --- a/jperm/views.py +++ b/jperm/views.py @@ -5,18 +5,11 @@ from django.http import HttpResponseRedirect, HttpResponse from django.template import RequestContext from juser.models import User, UserGroup, DEPT from jasset.models import Asset, BisGroup -from jperm.models import Perm, SudoPerm, CmdGroup, DeptPerm +from jperm.models import Perm, SudoPerm, CmdGroup from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.db.models import Q from jumpserver.views import LDAP_ENABLE, ldap_conn, CONF, page_list_return, pages -from jumpserver.api import user_perm_asset_api, require_admin, require_super_user, require_login - - -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') +from jumpserver.api import * def user_asset_cmd_groups_get(user_groups_select='', asset_groups_select='', cmd_groups_select=''): @@ -65,19 +58,13 @@ def dept_add_asset(dept_id, asset_list): dept = DEPT.objects.filter(id=dept_id) if dept: dept = dept[0] - old_perm_asset = [perm.asset for perm in dept.deptperm_set.all()] new_perm_asset = [] for asset_id in asset_list: asset = Asset.objects.filter(id=asset_id) new_perm_asset.extend(asset) - asset_add = [asset for asset in new_perm_asset if asset not in old_perm_asset] - asset_del = [asset for asset in old_perm_asset if asset not in new_perm_asset] - - for asset in asset_del: - DeptPerm.objects.filter(dept=dept, asset=asset).delete() - for asset in asset_add: - DeptPerm(dept=dept, asset=asset).save() + dept.asset_set.clear() + dept.asset_set = new_perm_asset @require_super_user @@ -89,7 +76,7 @@ def dept_perm_edit(request): if dept: dept = dept[0] asset_all = Asset.objects.all() - asset_select = [perm.asset for perm in dept.deptperm_set.all()] + asset_select = dept.asset_set.all() assets = [asset for asset in asset_all if asset not in asset_select] else: dept_id = request.POST.get('dept_id') diff --git a/jumpserver/api.py b/jumpserver/api.py index 4e64c6a81..d59529c7c 100644 --- a/jumpserver/api.py +++ b/jumpserver/api.py @@ -2,14 +2,176 @@ from django.http import HttpResponseRedirect import json +import os +from ConfigParser import ConfigParser +import getpass +from Crypto.Cipher import AES +from binascii import b2a_hex, a2b_hex +import ldap +from ldap import modlist -from django.http import HttpResponse +from django.http import HttpResponse, Http404 from juser.models import User, UserGroup from jasset.models import Asset, BisGroup from jlog.models import Log +BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) +CONF = ConfigParser() +CONF.read(os.path.join(BASE_DIR, 'jumpserver.conf')) +LOG_DIR = os.path.join(BASE_DIR, 'logs') +SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys') +SERVER_KEY_DIR = os.path.join(SSH_KEY_DIR, 'server') +KEY = CONF.get('web', 'key') +LOGIN_NAME = getpass.getuser() + + +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) + + +CRYPTOR = PyCrypt(KEY) + + +class ServerError(Exception): + pass + + +class LDAPMgmt(): + def __init__(self, + host_url, + base_dn, + root_cn, + root_pw): + self.ldap_host = host_url + self.ldap_base_dn = base_dn + self.conn = ldap.initialize(host_url) + self.conn.set_option(ldap.OPT_REFERRALS, 0) + self.conn.protocol_version = ldap.VERSION3 + self.conn.simple_bind_s(root_cn, root_pw) + + def list(self, filter, scope=ldap.SCOPE_SUBTREE, attr=None): + result = {} + try: + ldap_result = self.conn.search_s(self.ldap_base_dn, scope, filter, attr) + for entry in ldap_result: + name, data = entry + for k, v in data.items(): + print '%s: %s' % (k, v) + result[k] = v + return result + except ldap.LDAPError, e: + print e + + def add(self, dn, attrs): + try: + ldif = modlist.addModlist(attrs) + self.conn.add_s(dn, ldif) + except ldap.LDAPError, e: + print e + + def modify(self, dn, attrs): + try: + attr_s = [] + for k, v in attrs.items(): + attr_s.append((2, k, v)) + self.conn.modify_s(dn, attr_s) + except ldap.LDAPError, e: + print e + + def delete(self, dn): + try: + self.conn.delete_s(dn) + except ldap.LDAPError, e: + print e + + 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 require_login(func): + """要求登录的装饰器""" + def _deco(request, *args, **kwargs): + if not request.session.get('user_id'): + return HttpResponseRedirect('/login/') + return func(request, *args, **kwargs) + return _deco + + +def require_super_user(func): + def _deco(request, *args, **kwargs): + if request.session.get('role_id', 0) != 2: + print "##########%s" % request.session.get('role_id', 0) + return HttpResponseRedirect('/') + return func(request, *args, **kwargs) + return _deco + + +def require_admin(func): + def _deco(request, *args, **kwargs): + if request.session.get('role_id', 0) < 1: + return HttpResponseRedirect('/') + return func(request, *args, **kwargs) + return _deco + + +def is_super_user(request): + if request.session.get('role_id') == 2: + return True + else: + return False + + +def is_group_admin(request): + if request.session.get('role_id') == 1: + return True + else: + return False + + +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): + if is_super_user(request): + return su(request) + elif is_group_admin(request): + return adm(request) + raise Http404 + + + def user_perm_group_api(user): if user: perm_list = [] @@ -50,50 +212,3 @@ def asset_perm_api(asset): for user_group in user_group_list: user_permed_list.extend(user_group.user_set.all()) return user_permed_list - - -def require_login(func): - """要求登录的装饰器""" - def _deco(request, *args, **kwargs): - if not request.session.get('user_id'): - return HttpResponseRedirect('/login/') - return func(request, *args, **kwargs) - return _deco - - -def require_super_user(func): - def _deco(request, *args, **kwargs): - if request.session.get('role_id', 0) != 2: - print "##########%s" % request.session.get('role_id', 0) - return HttpResponseRedirect('/') - return func(request, *args, **kwargs) - return _deco - - -def require_admin(func): - def _deco(request, *args, **kwargs): - if request.session.get('role_id', 0) < 1: - return HttpResponseRedirect('/') - return func(request, *args, **kwargs) - return _deco - - -def is_super_user(request): - if request.session.get('role_id') == '2': - return True - else: - return False - - -def is_group_admin(request): - if request.session.get('role_id') == '1': - return True - else: - return False - -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) diff --git a/jumpserver/templatetags/mytags.py b/jumpserver/templatetags/mytags.py index bd2dc09db..97fa3d800 100644 --- a/jumpserver/templatetags/mytags.py +++ b/jumpserver/templatetags/mytags.py @@ -115,7 +115,7 @@ def dept_asset_num(dept_id): dept = DEPT.objects.filter(id=dept_id) if dept: dept = dept[0] - return dept.deptperm_set.all().count() + return dept.asset_set.all().count() return 0 diff --git a/jumpserver/views.py b/jumpserver/views.py index d67445df5..3bd0b88d1 100644 --- a/jumpserver/views.py +++ b/jumpserver/views.py @@ -1,10 +1,6 @@ #coding: utf-8 import hashlib -import ldap -from ldap import modlist -from Crypto.Cipher import AES -from binascii import b2a_hex, a2b_hex from ConfigParser import ConfigParser import os import datetime @@ -21,18 +17,23 @@ from django.template import RequestContext from juser.models import User, UserGroup from jlog.models import Log from jasset.models import Asset, BisGroup, IDC -from jumpserver.api import require_admin, require_super_user, require_login +from jumpserver.api import require_admin, require_super_user, require_login, CRYPTOR, LDAPMgmt 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') + ldap_conn = LDAPMgmt(LDAP_HOST_URL, LDAP_BASE_DN, LDAP_ROOT_DN, LDAP_ROOT_PW) +else: + ldap_conn = None def md5_crypt(string): @@ -114,10 +115,6 @@ def jasset_group_add(name, comment, jtype): smg = u'业务组%s添加成功' % name -class ServerError(Exception): - pass - - def page_list_return(total, current=1): min_page = current - 2 if current - 4 > 0 else 1 max_page = min_page + 4 if min_page + 4 < total else total @@ -217,83 +214,6 @@ def logout(request): return HttpResponseRedirect('/login/') -class LDAPMgmt(): - def __init__(self, - host_url, - base_dn, - root_cn, - root_pw): - self.ldap_host = host_url - self.ldap_base_dn = base_dn - self.conn = ldap.initialize(host_url) - self.conn.set_option(ldap.OPT_REFERRALS, 0) - self.conn.protocol_version = ldap.VERSION3 - self.conn.simple_bind_s(root_cn, root_pw) - - def list(self, filter, scope=ldap.SCOPE_SUBTREE, attr=None): - result = {} - try: - ldap_result = self.conn.search_s(self.ldap_base_dn, scope, filter, attr) - for entry in ldap_result: - name, data = entry - for k, v in data.items(): - print '%s: %s' % (k, v) - result[k] = v - return result - except ldap.LDAPError, e: - print e - - def add(self, dn, attrs): - try: - ldif = modlist.addModlist(attrs) - self.conn.add_s(dn, ldif) - except ldap.LDAPError, e: - print e - - def modify(self, dn, attrs): - try: - attr_s = [] - for k, v in attrs.items(): - attr_s.append((2, k, v)) - self.conn.modify_s(dn, attr_s) - except ldap.LDAPError, e: - print e - - def delete(self, dn): - try: - self.conn.delete_s(dn) - except ldap.LDAPError, 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') - - def filter_ajax_api(request): attr = request.GET.get('attr', 'user') value = request.GET.get('value', '') @@ -331,15 +251,15 @@ def filter_ajax_api(request): # return assets -if LDAP_ENABLE: - ldap_conn = LDAPMgmt(LDAP_HOST_URL, LDAP_BASE_DN, LDAP_ROOT_DN, LDAP_ROOT_PW) -else: - ldap_conn = None - - def install(request): - from juser.models import DEPT - DEPT(id=1, name="跨部门", comment="跨部门小组使用").save() - DEPT(id=2, name="默认", comment="默认部门").save() + from juser.models import DEPT, User + dept = DEPT(id=1, name="超管部", comment="超级管理员部门") + dept.save() + dept2 = DEPT(id=2, name="默认", comment="默认部门") + dept2.save() + User(id=5000, username="admin", password=md5_crypt('admin'), + name='admin', email='admin@jumpserver.org', role='SU', is_active=True, dept=dept).save() + User(id=5001, username="group_admin", password=md5_crypt('group_admin'), + name='group_admin', email='group_admin@jumpserver.org', role='DA', is_active=True, dept=dept2).save() return HttpResponse('Ok') diff --git a/juser/urls.py b/juser/urls.py index 8bc6c6f6e..1a5f78dc3 100644 --- a/juser/urls.py +++ b/juser/urls.py @@ -1,5 +1,6 @@ from django.conf.urls import patterns, include, url - +from jumpserver.api import view_splitter +from juser.views import * urlpatterns = patterns('juser.views', # Examples: @@ -14,7 +15,7 @@ urlpatterns = patterns('juser.views', (r'^dept_del_ajax/$', 'dept_del_ajax'), (r'^dept_edit/$', 'dept_edit'), (r'^group_add/$', 'group_add'), - (r'^group_list/$', 'group_list'), + (r'^group_list/$', view_splitter, {'su': group_list_su, 'adm': group_list_adm}), (r'^group_detail/$', 'group_detail'), (r'^group_del/$', 'group_del'), (r'^group_del_ajax/$', 'group_del_ajax'), diff --git a/juser/views.py b/juser/views.py index 7da0e2532..e3c5a33e2 100644 --- a/juser/views.py +++ b/juser/views.py @@ -16,15 +16,13 @@ from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q from django.template import RequestContext from django.http import HttpResponse -from django.core.paginator import Paginator, EmptyPage, InvalidPage from juser.models import UserGroup, User, DEPT -from connect import PyCrypt, KEY from connect import BASE_DIR from connect import CONF from jumpserver.views import md5_crypt, LDAPMgmt, LDAP_ENABLE, ldap_conn, page_list_return, pages from jumpserver.api import user_perm_group_api, require_login, require_super_user, \ - require_admin, is_group_admin, is_super_user + require_admin, is_group_admin, is_super_user, CRYPTOR if LDAP_ENABLE: LDAP_HOST_URL = CONF.get('ldap', 'host_url') @@ -32,10 +30,8 @@ if LDAP_ENABLE: LDAP_ROOT_DN = CONF.get('ldap', 'root_dn') LDAP_ROOT_PW = CONF.get('ldap', 'root_pw') -CRYPTOR = PyCrypt(KEY) - -def gen_rand_pwd(num): +def gen_rand_wd(num): """生成随机密码""" seed = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" salt_list = [] @@ -366,25 +362,28 @@ def group_add(request): return render_to_response('juser/group_add.html', locals(), context_instance=RequestContext(request)) -@require_admin -def group_list(request): +@require_super_user +def group_list_su(request): header_title, path1, path2 = '查看小组', '用户管理', '查看小组' keyword = request.GET.get('search', '') - contact_list = [] - if is_super_user(request): - if keyword: - contact_list = UserGroup.objects.filter(Q(name__icontains=keyword) | Q(comment__icontains=keyword)) - else: - contact_list = UserGroup.objects.all().order_by('name') - elif is_group_admin(request): - user_id = request.session.get('user_id', '') - user = User.objects.filter(id=user_id) - if user: - user = user[0] - if keyword: - contact_list = UserGroup.objects.filter(Q(dept=user.dept) & Q(name__icontains=keyword) | Q(comment__icontains=keyword)) - else: - contact_list = UserGroup.objects.filter(dept=user.dept).order_by('name') + if keyword: + contact_list = UserGroup.objects.filter(Q(name__icontains=keyword) | Q(comment__icontains=keyword)) + else: + contact_list = UserGroup.objects.all().order_by('name') + + contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(contact_list, request) + return render_to_response('juser/group_list.html', locals(), context_instance=RequestContext(request)) + + +@require_admin +def group_list_adm(request): + header_title, path1, path2 = '查看部门小组', '用户管理', '查看小组' + keyword = request.GET.get('search', '') + user_id = request.session.get('user_id') + if keyword: + contact_list = UserGroup.objects.filter(Q(name__icontains=keyword) | Q(comment__icontains=keyword)) + else: + contact_list = UserGroup.objects.all().order_by('name') contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(contact_list, request) return render_to_response('juser/group_list.html', locals(), context_instance=RequestContext(request)) diff --git a/templates/juser/dept_list.html b/templates/juser/dept_list.html index ee5d9b1f3..faa3afeb5 100644 --- a/templates/juser/dept_list.html +++ b/templates/juser/dept_list.html @@ -96,14 +96,17 @@ $(".iframe").colorbox({iframe:true, width:"70%", height:"70%"}); var check_array = [] $('#del_btn').click(function(){ - $(".gradeX input:checked").each(function() {check_array.push($(this).attr("value")) }) - $(".gradeX input:checked").closest("tr").remove() - $.post("/juser/dept_del_ajax/", + if (confirm("确定删除")) { + $(".gradeX input:checked").each(function() {check_array.push($(this).attr("value")) }) + $(".gradeX input:checked").closest("tr").remove() + $.post("/juser/dept_del_ajax/", {dept_ids: check_array.join(",")}, function(data){ alert(data) } - ) + ) + } + }) }); diff --git a/templates/juser/group_list.html b/templates/juser/group_list.html index 9f94c171a..649ac5a7e 100644 --- a/templates/juser/group_list.html +++ b/templates/juser/group_list.html @@ -95,14 +95,16 @@ $(".iframe").colorbox({iframe:true, width:"70%", height:"70%"}); var check_array = [] $('#del_btn').click(function(){ - $(".gradeX input:checked").each(function() {check_array.push($(this).attr("value")) }) - $(".gradeX input:checked").closest("tr").remove() - $.post("/juser/group_del_ajax/", + if (confirm("确定删除")) { + $(".gradeX input:checked").each(function() {check_array.push($(this).attr("value")) }) + $(".gradeX input:checked").closest("tr").remove() + $.post("/juser/group_del_ajax/", {group_ids: check_array.join(",")}, function(data){ - alert(data) } - ) + ) + } + }) }); diff --git a/templates/juser/user_list.html b/templates/juser/user_list.html index 18759b6be..47b8f6e10 100644 --- a/templates/juser/user_list.html +++ b/templates/juser/user_list.html @@ -99,14 +99,17 @@ $(".iframe").colorbox({iframe:true, width:"70%", height:"70%"}); var check_array = [] $('#del_btn').click(function(){ - $(".gradeX input:checked").each(function() {check_array.push($(this).attr("value")) }) - $(".gradeX input:checked").closest("tr").remove() - $.post("/juser/user_del_ajax/", - {ids: check_array.join(",")}, - function(data){ - alert(data) - } - ) + if (confirm("确定删除")) { + $(".gradeX input:checked").each(function() {check_array.push($(this).attr("value")) }) + $(".gradeX input:checked").closest("tr").remove() + $.post("/juser/user_del_ajax/", + {ids: check_array.join(",")}, + function(data){ + window.open("/juser/user_list/", "_self"); + } + ) + } + }) }); diff --git a/templates/paginator.html b/templates/paginator.html index 3288ff5e5..653e89045 100644 --- a/templates/paginator.html +++ b/templates/paginator.html @@ -12,7 +12,7 @@ {% endif %} {% ifequal show_first 1 %} -
  • 1...
  • +
  • 1...
  • {% endifequal %} {% for page in page_range %} {% ifequal current_page page %}