Skip to content

Commit

Permalink
webssh添加命令记录
Browse files Browse the repository at this point in the history
  • Loading branch information
pythonzm committed Nov 6, 2019
1 parent 0d37061 commit de2d5c3
Show file tree
Hide file tree
Showing 25 changed files with 548 additions and 431 deletions.
Binary file modified Ops/__pycache__/routing.cpython-36.opt-1.pyc
Binary file not shown.
Binary file modified Ops/__pycache__/settings.cpython-36.opt-1.pyc
Binary file not shown.
8 changes: 4 additions & 4 deletions Ops/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-------------------------------------------------
File Name: routing
Description:
Author: Administrator
Author: pythonzm
date: 2018/6/6
-------------------------------------------------
Change Activity:
Expand All @@ -14,10 +14,10 @@
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from projs.utils.log_websocket import LogConsumer
from fort.utils.webssh_websocket import FortConsumer
from fort.utils.webssh import FortConsumer
from assets.utils.webssh import SSHConsumer
from fort.utils.guacamole_websocket import GuacamoleConsumer
from assets.utils.guacamole import AdminGuacamole
from fort.utils.webguacamole import GuacamoleConsumer
from assets.utils.webguacamole import AdminGuacamole
from task.utils.ans_module_websocket import AnsModuleConsumer
from task.utils.ans_playbook_websocket import AnsPlaybookConsumer
from projs.utils.deploy_websocket import DeployConsumer
Expand Down
Binary file modified assets/__pycache__/models.cpython-36.opt-1.pyc
Binary file not shown.
1 change: 1 addition & 0 deletions assets/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ class AdminRecord(models.Model):
admin_login_status_time = models.CharField(max_length=16, verbose_name='登录时长')
admin_record_file = models.CharField(max_length=256, verbose_name='操作记录')
admin_record_mode = models.CharField(max_length=10, choices=record_modes, verbose_name='登录协议', default='ssh')
admin_record_cmds = models.TextField(verbose_name='命令记录', default='')

class Meta:
db_table = 'ops_admin_record'
Expand Down
25 changes: 25 additions & 0 deletions assets/utils/webguacamole.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
File Name: root_rdp
Description:
Author: Administrator
date: 2019-01-21
-------------------------------------------------
Change Activity:
2019-01-21:
-------------------------------------------------
"""
from utils.guacamole import MyGuacamole
from utils.crypt_pwd import CryptPwd
from assets.models import ServerAssets


class AdminGuacamole(MyGuacamole):
def __init__(self, *args, **kwargs):
super(AdminGuacamole, self).__init__(*args, **kwargs)
self.server = ServerAssets.objects.select_related('assets').get(id=self.scope['path'].split('/')[3])
self.ip = self.server.assets.asset_management_ip
self.port = self.server.port
self.username = self.server.username
self.password = CryptPwd().decrypt_pwd(self.server.password)
126 changes: 7 additions & 119 deletions assets/utils/webssh.py
Original file line number Diff line number Diff line change
@@ -1,126 +1,14 @@
# -*- coding: utf-8 -*-
import paramiko
import threading
import time
import os
from socket import timeout
from assets.tasks import admin_file
from channels.generic.websocket import WebsocketConsumer
from assets.models import ServerAssets, AdminRecord
from django.conf import settings
from utils.ssh import MySSH
from utils.crypt_pwd import CryptPwd
from conf.logger import fort_logger
from assets.models import ServerAssets


class MyThread(threading.Thread):
def __init__(self, chan):
super(MyThread, self).__init__()
self.chan = chan
self._stop_event = threading.Event()
self.start_time = time.time()
self.current_time = time.strftime(settings.TIME_FORMAT)
self.stdout = []

def stop(self):
self._stop_event.set()

def run(self):
while not self._stop_event.is_set() or not self.chan.chan.exit_status_ready():
time.sleep(0.1)
try:
data = self.chan.chan.recv(1024)
if data:
str_data = data.decode('utf-8', 'ignore')
self.chan.send(str_data)
self.stdout.append([time.time() - self.start_time, 'o', str_data])
except timeout:
self.chan.send('\n由于长时间没有操作,连接已断开!', close=True)
self.stdout.append([time.time() - self.start_time, 'o', '\n由于长时间没有操作,连接已断开!'])
break

def record(self):
record_path = os.path.join(settings.MEDIA_ROOT, 'admin_ssh_records', self.chan.scope['user'].username,
time.strftime('%Y-%m-%d'))
if not os.path.exists(record_path):
os.makedirs(record_path, exist_ok=True)
record_file_name = '{}.{}.cast'.format(self.chan.host_ip, time.strftime('%Y%m%d%H%M%S'))
record_file_path = os.path.join(record_path, record_file_name)

header = {
"version": 2,
"width": self.chan.width,
"height": self.chan.height,
"timestamp": round(self.start_time),
"title": "Demo",
"env": {
"TERM": os.environ.get('TERM'),
"SHELL": os.environ.get('SHELL', '/bin/bash')
},
}

admin_file.delay(record_file_path, self.stdout, header)

login_status_time = time.time() - self.start_time
if login_status_time >= 60:
login_status_time = '{} m'.format(round(login_status_time / 60, 2))
elif login_status_time >= 3600:
login_status_time = '{} h'.format(round(login_status_time / 3660, 2))
else:
login_status_time = '{} s'.format(round(login_status_time))

try:
AdminRecord.objects.create(
admin_login_user=self.chan.scope['user'],
admin_server=self.chan.host_ip,
admin_remote_ip=self.chan.remote_ip,
admin_start_time=self.current_time,
admin_login_status_time=login_status_time,
admin_record_file=record_file_path.split('media/')[1]
)
except Exception as e:
fort_logger.error('数据库添加用户操作记录失败,原因:{}'.format(e))


class SSHConsumer(WebsocketConsumer):
class SSHConsumer(MySSH):
def __init__(self, *args, **kwargs):
super(SSHConsumer, self).__init__(*args, **kwargs)
self.ssh = paramiko.SSHClient()
self.server = ServerAssets.objects.select_related('assets').get(id=self.scope['path'].split('/')[3])
self.host_ip = self.server.assets.asset_management_ip
self.width = 150
self.height = 30
self.t1 = MyThread(self)
self.remote_ip = self.scope['query_string'].decode('utf8')
self.chan = None

def connect(self):
if self.scope["user"].is_anonymous:
self.close(code=1007)
else:
self.accept()

username = self.server.username
try:
self.ssh.load_system_host_keys()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(self.host_ip, int(self.server.port), username,
CryptPwd().decrypt_pwd(self.server.password), timeout=5)
except Exception as e:
fort_logger.error('用户{}通过webssh连接{}失败!原因:{}'.format(username, self.host_ip, e))
self.send('用户{}通过webssh连接{}失败!原因:{}'.format(username, self.host_ip, e))
self.close()
self.chan = self.ssh.invoke_shell(term='xterm', width=self.width, height=self.height)
# 设置如果3分钟没有任何输入,就断开连接
self.chan.settimeout(60 * 3)
self.t1.setDaemon(True)
self.t1.start()

def receive(self, text_data=None, bytes_data=None):
self.chan.send(text_data)

def disconnect(self, close_code):
try:
self.t1.record()
self.t1.stop()
finally:
self.ssh.close()
self.ip = self.server.assets.asset_management_ip
self.port = self.server.port
self.username = self.server.username
self.password = CryptPwd().decrypt_pwd(self.server.password)
4 changes: 2 additions & 2 deletions assets/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,6 @@ def guacamole_terminal(request, pk):
return render(request, 'assets/admin_guacamole.html', locals())


# 已整合至系统日志
@admin_auth
def login_record(request):
if request.method == 'GET':
Expand All @@ -382,7 +381,8 @@ def login_record(request):
'admin_remote_ip': search_record.admin_remote_ip,
'admin_start_time': search_record.admin_start_time,
'admin_login_status_time': search_record.admin_login_status_time,
'admin_record_mode': search_record.get_admin_record_mode_display()
'admin_record_mode': search_record.get_admin_record_mode_display(),
'admin_record_cmds': search_record.admin_record_cmds
}
records.append(record)
return JsonResponse({'code': 200, 'records': records})
Expand Down
1 change: 1 addition & 0 deletions fort/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class FortRecord(models.Model):
login_status_time = models.CharField(max_length=16, verbose_name='登录时长')
record_file = models.CharField(max_length=256, verbose_name='操作记录')
record_mode = models.CharField(max_length=10, choices=record_modes, verbose_name='登录协议', default='ssh')
record_cmds = models.TextField(verbose_name='命令记录', default='')

class Meta:
db_table = 'ops_fort_record'
Expand Down
131 changes: 0 additions & 131 deletions fort/utils/guacamole_websocket.py

This file was deleted.

35 changes: 35 additions & 0 deletions fort/utils/webguacamole.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from utils.guacamole import MyGuacamole
from assets.models import ServerAssets
from fort.models import FortServerUser


class GuacamoleConsumer(MyGuacamole):
def __init__(self, *args, **kwargs):
super(GuacamoleConsumer, self).__init__(*args, **kwargs)
self.fort_server = ServerAssets.objects.select_related('assets').get(id=self.scope['path'].split('/')[3])
self.fort_user = FortServerUser.objects.get(id=self.scope['path'].split('/')[4])
self.ip = self.fort_server.assets.asset_management_ip
self.username = self.fort_user.fort_username
self.password = self.fort_user.fort_password

def connect(self):
if self.scope["user"].is_anonymous:
self.close(code=1007)
else:
self.accept('guacamole')

server_protocol = self.fort_user.fort_server.server_protocol
if server_protocol == 'vnc':
self.client.handshake(protocol=server_protocol,
hostname=self.ip,
port=self.fort_user.fort_vnc_port,
password=self.password, width=self.width, height=self.height,
dpi=self.dpi)
elif server_protocol == 'rdp':
self.client.handshake(protocol=server_protocol,
hostname=self.ip, port=self.fort_server.port,
password=self.fort_user.fort_password,
username=self.username, width=self.width, height=self.height, dpi=self.dpi)
self.send('0.,{0}.{1};'.format(len(self.group_name), self.group_name))
self.guacamole_thread.setDaemon(True)
self.guacamole_thread.start()
Loading

0 comments on commit de2d5c3

Please sign in to comment.