def connect(self, message, id): self.message.reply_channel.send({"accept": True}) client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) try: data = ServerInfor.objects.get(id=id) if data.credential.protocol in ['vnc', 'rdp', 'telnet']: pass else: self.message.reply_channel.send({"accept": False}) except ObjectDoesNotExist: #server info not exist self.message.reply_channel.send({"accept": False}) client.handshake(protocol=data.credential.protocol, hostname=data.ip, port=data.credential.port, username=data.credential.username, password=data.credential.password) #security='any',) cache_key = str(uuid.uuid4()) self.message.reply_channel.send( {"text": '0.,{0}.{1};'.format(len(cache_key), cache_key)}, immediately=True) #'0.,36.83940151-b2f9-4743-b5e4-b6eb85a97743;' guacamolethread = GuacamoleThread(self.message, client) guacamolethread.setDaemon = True guacamolethread.start() guacamolethreadwrite = GuacamoleThreadWrite(self.message, client) guacamolethreadwrite.setDaemon = True guacamolethreadwrite.start()
def _do_connect(request): # Connect to guacd daemon client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) # client.handshake(protocol='rdp', # hostname=settings.SSH_HOST, # port=settings.SSH_PORT, # username=settings.SSH_USER, # password=settings.SSH_PASSWORD) # security='any',) client.handshake(protocol='ssh', hostname='192.168.0.165', port=8787, username='******', password='******') # security='any',) cache_key = str(uuid.uuid4()) with sockets_lock: logger.info('Saving socket with key %s', cache_key) sockets[cache_key] = client response = HttpResponse(content=cache_key) response['Cache-Control'] = 'no-cache' return response
def _do_connect(request): # Connect to guacd daemon vcdUser = str(request.user) client = GuacamoleClient('guacd', 4822) #command = requests.get(backendServer) #logging.warning(str(command.content)) #if not vcdUser in command.content: # logging.warning("sleeping 2 seconds") time.sleep(2) #logging.warning("continueeeee") client.handshake(protocol='rdp', hostname='vcd-' + vcdUser, port=3389, username= vcdUser, password= vcdUser, width=request.POST.get("width"), height=request.POST.get("height")) cache_key = str(uuid.uuid4()) with sockets_lock: logger.info('Saving socket with key %s', cache_key) sockets[cache_key] = client response = HttpResponse(content=cache_key) response['Cache-Control'] = 'no-cache' return response
class AdminGuacamole(WebsocketConsumer): def __init__(self, *args, **kwargs): super(AdminGuacamole, self).__init__(*args, **kwargs) self.client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) self.group_name = self.scope['url_route']['kwargs']['group_name'] self.fort_server = ServerAssets.objects.select_related('assets').get( id=self.scope['path'].split('/')[3]) self.guacamole_thread = GuacamoleThread(self) def connect(self): self.accept('guacamole') self.client.handshake( protocol='rdp', hostname=self.fort_server.assets.asset_management_ip, port=self.fort_server.port, password=CryptPwd().decrypt_pwd(self.fort_server.password), username=self.fort_server.username) self.send('0.,{0}.{1};'.format(len(self.group_name), self.group_name)) self.guacamole_thread.setDaemon(True) self.guacamole_thread.start() def disconnect(self, event): self.guacamole_thread.stop() def receive(self, text_data=None, bytes_data=None): with self.guacamole_thread.write_lock: self.client.send(text_data)
class MainNamespace(Namespace): def __init__(self, namespace): super(MainNamespace, self).__init__(namespace) self.remote_ip = None self.remote_protocol = None self.remote_port = None self.username = None self.width = None self.height = None self.password = None self.client = None self.connect_status = False def on_connect(self): current_app.logger.debug('Socket connected.') self.client = GuacamoleClient(GUACD_PATH, GUACD_PORT) def on_disconnect(self): self.client.close() def on_remote(self, data): self.remote_ip = data.get('ip') self.remote_protocol = data.get('protocol') self.remote_port = data.get('port') self.width = data.get('width') self.height = data.get('height') self.username = data.get('username') self.password = data.get('password') if self.username and self.password: self.client.handshake(protocol=self.remote_protocol, hostname=self.remote_ip, port=self.remote_port, width=self.width, height=self.height, username=self.username, password=self.password) else: self.client.handshake(protocol=self.remote_protocol, hostname=self.remote_ip, port=self.remote_port, width=self.width, height=self.height) self.connect_status = True # emit('connect_status', {'status': self.connect_status}, Namespace='/data') while True: instruction = self.client.receive() if instruction: if 'disconnect' in instruction: emit('message', instruction, namespace='/data') self.client.close() # emit('connect_status', {'status': False}, Namespace='/data') break emit('message', instruction, namespace='/data') def on_message(self, message): if self.connect_status: self.client.send(message)
class GuacamoleConsumer(WebsocketConsumer): def __init__(self, *args, **kwargs): super(GuacamoleConsumer, self).__init__(*args, **kwargs) self.client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT, timeout=5) self.group_name = self.scope['url_route']['kwargs']['group_name'] 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.guacamole_thread = GuacamoleThread(self) self.query_list = self.scope['query_string'].decode('utf8').split(',') self.remote_ip = self.query_list[0].strip() self.width = self.query_list[1].strip() self.height = self.query_list[2].strip() self.dpi = self.query_list[3].strip() self.fort = None def connect(self): self.accept('guacamole') host_ip = self.fort_server.assets.asset_management_ip username = self.fort_user.fort_username self.fort = r'{}@{}'.format(username, host_ip) server_protocol = self.fort_user.fort_server.server_protocol if server_protocol == 'vnc': self.client.handshake(protocol=server_protocol, hostname=host_ip, port=self.fort_user.fort_vnc_port, password=self.fort_user.fort_password, width=self.width, height=self.height, dpi=self.dpi) elif server_protocol == 'rdp': self.client.handshake(protocol=server_protocol, hostname=host_ip, port=self.fort_server.port, password=self.fort_user.fort_password, username=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() def disconnect(self, event): try: self.guacamole_thread.record() finally: self.guacamole_thread.stop() self.client.close() def receive(self, text_data=None, bytes_data=None): with self.guacamole_thread.write_lock: self.client.send(text_data)
def connect(self, message, id): self.message.reply_channel.send({"accept": True}) client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) try: data = ServerInfor.objects.get(id=id) if data.credential.protocol in ['vnc', 'rdp', 'telnet']: pass else: self.message.reply_channel.send({"accept": False}) except ObjectDoesNotExist: #server info not exist self.message.reply_channel.send({"accept": False}) cache_key = str(uuid.uuid4()) directory_date_time = now() recording_path = os.path.join( MEDIA_ROOT, '{0}-{1}-{2}'.format(directory_date_time.year, directory_date_time.month, directory_date_time.day)) client.handshake( width=data.credential.width, height=data.credential.height, protocol=data.credential.protocol, hostname=data.ip, port=data.credential.port, username=data.credential.username, password=data.credential.password, recording_path=recording_path, recording_name=cache_key, create_recording_path='true', enable_wallpaper='true', ignore_cert='true', ) #security='tls',) self.message.reply_channel.send( {"text": '0.,{0}.{1};'.format(len(cache_key), cache_key)}, immediately=True) #'0.,36.83940151-b2f9-4743-b5e4-b6eb85a97743;' audit_log = Log.objects.create( user=User.objects.get(username=self.message.user), server=data, channel=self.message.reply_channel.name, width=data.credential.width, height=data.credential.height, log=cache_key) audit_log.save() guacamolethread = GuacamoleThread(self.message, client) guacamolethread.setDaemon = True guacamolethread.start() guacamolethreadwrite = GuacamoleThreadWrite(self.message, client) guacamolethreadwrite.setDaemon = True guacamolethreadwrite.start()
class MyGuacamole(WebsocketConsumer): def __init__(self, *args, **kwargs): super(MyGuacamole, self).__init__(*args, **kwargs) self.client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT, timeout=5) self.group_name = self.scope['url_route']['kwargs']['group_name'] self.guacamole_thread = GuacamoleThread(self) self.query_list = self.scope['query_string'].decode('utf8').split(',') self.remote_ip = self.query_list[0].strip() self.width = self.query_list[1].strip() self.height = self.query_list[2].strip() self.dpi = self.query_list[3].strip() self.ip = None self.port = None self.username = None self.password = None self.record_dir = 'admin_guacamole_records' if self.scope[ 'user'].is_superuser else 'fort_guacamole_records' def connect(self): if self.scope["user"].is_anonymous: self.close(code=1007) else: self.accept('guacamole') self.client.handshake(protocol='rdp', hostname=self.ip, port=self.port, password=self.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() def disconnect(self, event): try: self.guacamole_thread.record() finally: self.guacamole_thread.stop() self.client.close() def receive(self, text_data=None, bytes_data=None): with self.guacamole_thread.write_lock: self.client.send(text_data)
def _do_connect(request): # Connect to guacd daemon client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) client.handshake(protocol='vnc', hostname='10.1.19.11', port=5901, password='******') cache_key = str(uuid.uuid4()) with sockets_lock: logger.info('Saving socket with key %s', cache_key) sockets[cache_key] = client response = HttpResponse(content=cache_key) response['Cache-Control'] = 'no-cache' return response
class GuacamoleApplication(WebSocketApplication): def __init__(self, ws): self.client = None super(GuacamoleApplication, self).__init__(ws) self.config = configparser.ConfigParser() self.config.read('config.ini') # self.fernet = Fernet(bytes(self.config['DEFAULT']['FERNET_KEY'])) logging.basicConfig(filename='crowbar-guacamole.log', level=logging.DEBUG) @classmethod def protocol_name(cls): return "guacamole" def on_message(self, message, **kwargs): self.client.send(message) def on_open(self): # TODO implement check for token parameters = parse_qs(self.ws.environ['QUERY_STRING']) self.client = GuacamoleClient( str(self.config['DEFAULT']['GUACD_HOST']), 4822) self.client.handshake(protocol='rdp', hostname=parameters['hostname'][0], port=3389, width=parameters['width'][0], height=parameters['height'][0]) self.start_read_listener() def on_close(self, reason): self.client.close() self.client = None def start_read_listener(self): listener = Thread(target=self.read_listener) listener.start() def read_listener(self): """ A listener that would handle any messages sent from Guacamole server and push directly to browser client (over websocket). """ while True: instruction = self.client.receive() self.ws.send(instruction)
def _do_connect(request): # Connect to guacd daemon client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) client.handshake(protocol='ssh', hostname=settings.SSH_HOST, port=settings.SSH_PORT, username=settings.SSH_USER, password=settings.SSH_PASSWORD) cache_key = str(uuid.uuid4()) with sockets_lock: logger.info('Saving socket with key %s', cache_key) sockets[cache_key] = client response = HttpResponse(content=cache_key) response['Cache-Control'] = 'no-cache' return response
def connect(self, message): self.message.reply_channel.send({"accept": True}) client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) client.handshake(protocol='rdp', hostname=settings.SSH_HOST, port=settings.SSH_PORT, username=settings.SSH_USER, password=settings.SSH_PASSWORD) #security='any',) cache_key = str(uuid.uuid4()) self.message.reply_channel.send({"text":'0.,{0}.{1};'.format(len(cache_key),cache_key)},immediately=True) #'0.,36.83940151-b2f9-4743-b5e4-b6eb85a97743;' guacamolethread=GuacamoleThread(self.message,client) guacamolethread.setDaemon = True guacamolethread.start() guacamolethreadwrite=GuacamoleThreadWrite(self.message,client) guacamolethreadwrite.setDaemon = True guacamolethreadwrite.start()
def connect(self, message, id): self.message.reply_channel.send({"accept": True}) if not self.authenticate: self.message.reply_channel.send( { "text": json.dumps({ 'status': False, 'message': 'You must login to the system!' }) }, immediately=True) self.message.reply_channel.send({"accept": False}) else: client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) log_object = Log.objects.get(id=id) cache_key = str(log_object.gucamole_client_id) data = log_object.server print 'cache_key', cache_key client.handshake( width=data.credential.width, height=data.credential.height, protocol=data.credential.protocol, hostname=data.ip, port=data.credential.port, username=data.credential.username, password=data.credential.password, read_only=True, ) client.send_instruction(Instruction('select', cache_key)) #self.message.reply_channel.send({"text":'0.,{0}.{1};'.format(len(cache_key),cache_key)},immediately=True) guacamolethread = GuacamoleThread(self.message, client) guacamolethread.setDaemon = True guacamolethread.start() guacamolethreadwrite = GuacamoleThreadWrite(self.message, client) guacamolethreadwrite.setDaemon = True guacamolethreadwrite.start()
def _do_connect(task): if not task.guest: return JsonResponse( { "status": "failed", "message": "task is not assigned to a machine yet", }, status=500) machine = db.view_machine_by_label(task.guest.label) rcparams = machine.rcparams protocol = rcparams.get("protocol") host = rcparams.get("host") port = rcparams.get("port") guacd_host = config("cuckoo:remotecontrol:guacd_host") guacd_port = config("cuckoo:remotecontrol:guacd_port") try: guac = GuacamoleClient(guacd_host, guacd_port, debug=False) guac.handshake(protocol=protocol, hostname=host, port=port) except (socket.error, GuacamoleError) as e: log.error("Failed to connect to guacd on %s:%d -> %s", guacd_host, guacd_port, e) return JsonResponse( { "status": "failed", "message": "connection failed", }, status=500) cache_key = str(uuid.uuid4()) with sockets_lock: sockets[cache_key] = guac response = HttpResponse(content=cache_key) response["Cache-Control"] = "no-cache" return response
def _do_connect(task): if not task.guest: return JsonResponse({ "status": "failed", "message": "task is not assigned to a machine yet", }, status=500) machine = db.view_machine_by_label(task.guest.label) rcparams = machine.rcparams protocol = rcparams.get("protocol") host = rcparams.get("host") port = rcparams.get("port") guacd_host = config("cuckoo:remotecontrol:guacd_host") guacd_port = config("cuckoo:remotecontrol:guacd_port") try: guac = GuacamoleClient(guacd_host, guacd_port, debug=False) guac.handshake(protocol=protocol, hostname=host, port=port) except (socket.error, GuacamoleError) as e: log.error( "Failed to connect to guacd on %s:%d -> %s", guacd_host, guacd_port, e ) return JsonResponse({ "status": "failed", "message": "connection failed", }, status=500) cache_key = str(uuid.uuid4()) with sockets_lock: sockets[cache_key] = guac response = HttpResponse(content=cache_key) response["Cache-Control"] = "no-cache" return response
def websocket_receive(self, text=None, bytes=None, **kwargs): client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) client.handshake(protocol='vnc', hostname='10.1.19.11', port=5901, password='******') cache_key = str(uuid.uuid4()) self.send( json.dumps({ "type": "websocket.send", "text": '0.,{0}.{1};'.format(len(cache_key), cache_key), })) # '0.,36.83940151-b2f9-4743-b5e4-b6eb85a97743;' guacamolethread = GuacamoleThread(self, client) guacamolethread.setDaemon = True guacamolethread.start() guacamolethreadwrite = GuacamoleThreadWrite(self, client) guacamolethreadwrite.setDaemon = True guacamolethreadwrite.start() print(text) # print 'receive',text self.queue().publish(self.channel_name, text['text'])
class GuacamoleWebSocketConsumer(AsyncWebsocketConsumer): client = None task = None async def connect(self): """ Initiate the GuacamoleClient and create a connection to it. """ guacd_hostname = web_cfg.guacamole.guacd_host or "localhost" guacd_port = int(web_cfg.guacamole.guacd_port) or 4822 guacd_recording_path = web_cfg.guacamole.guacd_recording_path or "" guest_protocol = web_cfg.guacamole.guest_protocol or "vnc" guest_width = int(web_cfg.guacamole.guest_width) or 1280 guest_height = int(web_cfg.guacamole.guest_height) or 1024 guest_username = web_cfg.guacamole.username or "" guest_password = web_cfg.guacamole.password or "" params = urllib.parse.parse_qs(self.scope["query_string"].decode()) if "rdp" in guest_protocol: guest_host = params.get("guest_ip", "") guest_port = int(web_cfg.guacamole.guest_rdp_port) or 3389 else: guest_host = "localhost" ports = params.get("vncport", ["5900"]) guest_port = int(ports[0]) guacd_recording_name = params.get("recording_name", ["task-recording"])[0] self.client = GuacamoleClient(guacd_hostname, guacd_port) self.client.handshake( protocol=guest_protocol, width=guest_width, height=guest_height, hostname=guest_host, port=guest_port, username=guest_username, password=guest_password, recording_path=guacd_recording_path, recording_name=guacd_recording_name, ) if self.client.connected: # start receiving data from GuacamoleClient loop = asyncio.get_event_loop() self.task = loop.create_task(self.open()) # Accept connection await self.accept(subprotocol="guacamole") else: await self.close() async def disconnect(self, code): """ Close the GuacamoleClient connection on WebSocket disconnect. """ self.task.cancel() await sync_to_async(self.client.close)() async def receive(self, text_data=None, bytes_data=None): """ Handle data received in the WebSocket, send to GuacamoleClient. """ if text_data is not None: logger.debug("To server: %s", text_data) self.client.send(text_data) async def open(self): """ Receive data from GuacamoleClient and pass it to the WebSocket """ while True: content = await sync_to_async(self.client.receive)() if content: logger.debug("From server: %s", content) await self.send(text_data=content)
class Client: def __init__(self, websocker): self.websocker = websocker self.start_time = time.time() self.last_save_time = self.start_time tmp_date1 = time.strftime("%Y-%m-%d", time.localtime(int(self.start_time))) tmp_date2 = time.strftime("%Y%m%d%H%M%S", time.localtime(int(self.start_time))) if not os.path.isdir(os.path.join(settings.RECORD_ROOT, tmp_date1)): os.makedirs(os.path.join(settings.RECORD_ROOT, tmp_date1)) self.res_file = settings.RECORD_DIR + '/' + tmp_date1 + '/' + 'webguacamole_' + \ tmp_date2 + '_' + gen_rand_char(16) + '.txt' self.res = [] self.guacamoleclient = None def connect(self, protocol, hostname, port, username, password, width, height, dpi): try: self.guacamoleclient = GuacamoleClient( settings.GUACD.get('host'), settings.GUACD.get('port'), settings.GUACD.get('timeout'), ) if protocol == 'vnc': # vnc 登陆不需要账号 self.guacamoleclient.handshake( protocol=protocol, hostname=hostname, port=port, password=password, width=width, height=height, dpi=dpi, ) elif protocol == 'rdp': self.guacamoleclient.handshake( protocol=protocol, hostname=hostname, port=port, username=username, password=password, width=width, height=height, dpi=dpi, ) Thread(target=self.websocket_to_django).start() except Exception: self.websocker.close(3001) def django_to_guacd(self, data): try: self.guacamoleclient.send(data) except Exception: self.close() def websocket_to_django(self): try: while True: time.sleep(0.0001) data = self.guacamoleclient.receive() if not data: return if self.websocker.send_flag == 0: self.websocker.send(data) elif self.websocker.send_flag == 1: async_to_sync(self.websocker.channel_layer.group_send)( self.websocker.group, { "type": "group.message", "text": data, }) self.res.append(data) # 指定条结果或者指定秒数就保存一次 if len(self.res) > 2000 or int(time.time() - self.last_save_time) > 60 or \ sys.getsizeof(self.res) > 2097152: tmp = list(self.res) self.res = [] self.last_save_time = time.time() res(self.res_file, tmp, False) except Exception: print(traceback.format_exc()) if self.websocker.send_flag == 0: self.websocker.send('0.;') elif self.websocker.send_flag == 1: async_to_sync(self.websocker.channel_layer.group_send)( self.websocker.group, { "type": "group.message", "text": '0.;', }) finally: self.close() def close(self): self.websocker.close() self.guacamoleclient.close() def shell(self, data): self.django_to_guacd(data)
class GuacamoleApp(WebSocketApplication): def __init__(self, ws): self.client = None self._listener = None super(GuacamoleApp, self).__init__(ws) @classmethod def protocol_name(cls): """ Return our protocol. """ return PROTOCOL_NAME def on_open(self, *args, **kwargs): """ New Web socket connection opened. """ if self.client: # we have a running client?! self.client.close() # @TODO: get guacd host and port! self.client = GuacamoleClient('localhost', 4822) # @TODO: get Remote server connection properties self.client.handshake(protocol=PROTOCOL, hostname=HOST, port=PORT, username=USERNAME, password=PASSWORD, domain=DOMAIN, security=SEC, remote_app=APP) self._start_listener() def on_message(self, message): """ New message received on the websocket. """ # send message to guacd server self.client.send(message) def on_close(self, reason): """ Websocket closed. """ # @todo: consider reconnect from client. (network glitch?!) self._stop_listener() self.client.close() self.client = None def _start_listener(self): if self._listener: self._stop_listener() self._listener = gevent.spawn(self.guacd_listener) self._listener.start() def _stop_listener(self): if self._listener: self._listener.kill() self._listener = None def guacd_listener(self): """ A listener that would handle any messages sent from Guacamole server and push directly to browser client (over websocket). """ while True: instruction = self.client.receive() self.ws.send(instruction)
class GuacamoleClientTest(TestCase): def setUp(self): self.client = GuacamoleClient('127.0.0.1', 4822) # patch `send` self.client.send = MagicMock() self.client.close = MagicMock() def test_handshake(self): """ Test successful handshake. """ global step step = 0 client_id = '$260d01da-779b-4ee9-afc1-c16bae885cc7' expected = ['select', 'size', 'audio', 'video', 'image', 'connect'] def mock_send_instruction_handshake(instruction): global step assert instruction.opcode == expected[step] step += 1 # mock and vaidate send_instruction in handshake self.client.send_instruction = MagicMock( side_effect=mock_send_instruction_handshake) # successful `args` response for `select` instruction self.client.receive = MagicMock(side_effect=[ '4.args,8.hostname,4.port,6.domain,8.username;', '5.ready,37.%s;' % client_id ]) self.client.handshake(protocol='rdp') self.assertTrue(self.client.connected) self.assertEqual(self.client.id, client_id) def test_handshake_with_connectionid(self): """ Test successful handshake with existing connectionid """ global step step = 0 client_id = '$260d01da-779b-4ee9-afc1-c16bae885cc7' connection_id = '$260d01da-779b-4ee9-afc1-c16bae885cc7' expected = ['select', 'size', 'audio', 'video', 'image', 'connect'] def mock_send_instruction_handshake(instruction): global step assert instruction.opcode == expected[step] step += 1 # mock and vaidate send_instruction in handshake self.client.send_instruction = MagicMock( side_effect=mock_send_instruction_handshake) # successful `args` response for `select` instruction self.client.receive = MagicMock(side_effect=[ '4.args,8.hostname,4.port,6.domain,8.username;', '5.ready,37.%s;' % client_id ]) self.client.handshake(connectionids=connection_id) self.assertTrue(self.client.connected) self.assertEqual(self.client.id, connection_id) def test_handshake_invalid_protocol(self): """ Test invalid handshake (invalid protocol and no connectionid in kwargs) """ with self.assertRaises(GuacamoleError): self.client.handshake(protocol='invalid') def test_handshake_protocol_failure(self): """ Test invalid protocol instruction. """ # expected `args` self.client.receive = MagicMock( side_effect=['7.invalid,8.hostname,4.port,6.domain,8.username;']) with self.assertRaises(GuacamoleError): self.client.handshake(protocol='rdp') def test_handshake_invalid_instruction(self): """ Test invalid instruction. """ self.client.receive = MagicMock() self.client.receive.return_value = '' with self.assertRaises(InvalidInstruction): self.client.handshake(protocol='rdp') def test_handshake_invalid_instruction_args(self): """ Test invalid instruction. """ # invalid arg length self.client.receive = MagicMock() self.client.receive.return_value = '5.args;' with self.assertRaises(InvalidInstruction): self.client.handshake(protocol='rdp') def test_handshake_invalid_instruction_termination(self): """ Test invalid instruction. """ # invalid instruction terminator `;` self.client.receive = MagicMock( side_effect=['4.args,8.hostname,4.port,6.domain,8.username']) with self.assertRaises(InvalidInstruction): self.client.handshake(protocol='rdp')
def connect(self, message, id): self.message.reply_channel.send({"accept": True}) user = get_redis_instance().get(id) if not self.authenticate(id): self.message.reply_channel.send({"text": json.dumps( {'status': False, 'message': 'You must login to the system!'})}, immediately=True) self.message.reply_channel.send({"accept": False}) else: # permission auth username = get_redis_instance().get(id) try: Permission.objects.get( user__username=username, groups__servers__id=int(id[-1])) except ObjectDoesNotExist: self.message.reply_channel.send({"text": json.dumps( '\033[1;3;31mYou have not permission to connect server !\033[0m')}, immediately=True) self.message.reply_channel.send({"accept": False}) return except MultipleObjectsReturned: pass client = GuacamoleClient( settings.GUACD_HOST, settings.GUACD_PORT) try: data = ServerInfor.objects.get(id=int(id[-1])) if data.credential.protocol in ['vnc', 'rdp', 'telnet']: pass else: self.message.reply_channel.send({"accept": False}) except ObjectDoesNotExist: # server info not exist self.message.reply_channel.send({"accept": False}) cache_key = str(uuid.uuid4()) directory_date_time = now() recording_path = os.path.join(MEDIA_ROOT, '{0}-{1}-{2}'.format( directory_date_time.year, directory_date_time.month, directory_date_time.day)) if isinstance(username, bytes): username = username.decode() drive_path = os.path.join(MEDIA_ROOT, str(username), 'Download') """ Create recording media file and drive path """ mkdir_p(recording_path) mkdir_p(drive_path) try: client.handshake(width=data.credential.width, height=data.credential.height, protocol=data.credential.protocol, hostname=data.ip, port=data.credential.port, username=data.credential.username, password=data.credential.password, recording_path=recording_path, recording_name=cache_key, create_recording_path='true', enable_wallpaper='true', ignore_cert='true', enable_drive='true', drive_path=drive_path, create_drive_path='true', security=data.credential.security, # console_audio='true', # enable_audio_input='true', # disable_audio='false', # console='true', enable_full_window_drag='true', resize_method="reconnect" # display-update ) except Exception as e: print(e) print(traceback.print_exc()) self.message.reply_channel.send({"accept": False}) return self.message.reply_channel.send( {"text": '0.,{0}.{1};'.format(len(cache_key), cache_key)}, immediately=True) audit_log = Log.objects.create(user=User.objects.get(username=username), server=data, channel=self.message.reply_channel.name, width=data.credential.width, height=data.credential.height, log=cache_key, gucamole_client_id=client._id) audit_log.save() guacamolethread = GuacamoleThread(self.message, client) guacamolethread.setDaemon = True guacamolethread.start() guacamolethreadwrite = GuacamoleThreadWrite(self.message, client) guacamolethreadwrite.setDaemon = True guacamolethreadwrite.start()
class GuacamoleClientTest(TestCase): def setUp(self): self.client = GuacamoleClient('127.0.0.1', 4822) # patch `send` self.client.send = MagicMock() self.client.close = MagicMock() def test_handshake(self): """ Test successful handshake. """ global step step = 0 client_id = '$260d01da-779b-4ee9-afc1-c16bae885cc7' expected = ['select', 'size', 'audio', 'video', 'image', 'connect'] def mock_send_instruction_handshake(instruction): global step assert instruction.opcode == expected[step] step += 1 # mock and vaidate send_instruction in handshake self.client.send_instruction = MagicMock( side_effect=mock_send_instruction_handshake) # successful `args` response for `select` instruction self.client.receive = MagicMock( side_effect=[ '4.args,8.hostname,4.port,6.domain,8.username;', '5.ready,37.%s;' % client_id ]) self.client.handshake(protocol='rdp') self.assertTrue(self.client.connected) self.assertEqual(self.client.id, client_id) def test_handshake_invalid_protocol(self): """ Test invalid handshake. """ with self.assertRaises(GuacamoleError): self.client.handshake(protocol='invalid') def test_handshake_protocol_failure(self): """ Test invalid protocol instruction. """ # expected `args` self.client.receive = MagicMock( side_effect=['7.invalid,8.hostname,4.port,6.domain,8.username;']) with self.assertRaises(GuacamoleError): self.client.handshake(protocol='rdp') def test_handshake_invalid_instruction(self): """ Test invalid instruction. """ self.client.receive = MagicMock() self.client.receive.return_value = '' with self.assertRaises(InvalidInstruction): self.client.handshake(protocol='rdp') def test_handshake_invalid_instruction_args(self): """ Test invalid instruction. """ # invalid arg length self.client.receive = MagicMock() self.client.receive.return_value = '5.args;' with self.assertRaises(InvalidInstruction): self.client.handshake(protocol='rdp') def test_handshake_invalid_instruction_termination(self): """ Test invalid instruction. """ # invalid instruction terminator `;` self.client.receive = MagicMock( side_effect=['4.args,8.hostname,4.port,6.domain,8.username']) with self.assertRaises(InvalidInstruction): self.client.handshake(protocol='rdp')
class Client: def __init__(self, websocker): self.websocker = websocker self.start_time = time.time() self.last_save_time = self.start_time self.res_file = 'webguacamole_' + str(int( self.start_time)) + '_' + gen_rand_char(16) + '.txt' self.res = [] self.guacamoleclient = None def connect(self, protocol, hostname, port, username, password, width, height, dpi): try: self.guacamoleclient = GuacamoleClient( settings.GUACD.get('host'), settings.GUACD.get('port'), settings.GUACD.get('timeout'), ) if protocol == 'vnc': # vnc 登陆不需要账号 self.guacamoleclient.handshake( protocol=protocol, hostname=hostname, port=port, password=password, width=width, height=height, dpi=dpi, ) elif protocol == 'rdp': self.guacamoleclient.handshake( protocol=protocol, hostname=hostname, port=port, username=username, password=password, width=width, height=height, dpi=dpi, ) Thread(target=self.websocket_to_django).start() except Exception: self.websocker.close(3001) def django_to_guacd(self, data): try: self.guacamoleclient.send(data) except Exception: self.close() def websocket_to_django(self): try: while True: time.sleep(0.001) data = self.guacamoleclient.receive() if not data: return if self.websocker.send_flag == 0: self.websocker.send(data) elif self.websocker.send_flag == 1: async_to_sync(self.websocker.channel_layer.group_send)( self.websocker.group, { "type": "group.message", "text": data, }) self.res.append(data) # 指定条结果或者指定秒数就保存一次 if len(self.res) > 1000 or int(time.time() - self.last_save_time) > 50: tmp = list(self.res) self.res = [] self.last_save_time = time.time() # windows无法正常支持celery任务 if platform.system().lower() == 'linux': celery_save_res_asciinema.delay( settings.MEDIA_ROOT + '/' + self.res_file, tmp, False) else: with open(settings.MEDIA_ROOT + '/' + self.res_file, 'a+') as f: for line in tmp: f.write('{}'.format(line)) except Exception: if self.websocker.send_flag == 0: self.websocker.send('0.;') elif self.websocker.send_flag == 1: async_to_sync(self.websocker.channel_layer.group_send)( self.websocker.group, { "type": "group.message", "text": '0.;', }) finally: self.close() def close(self): self.websocker.close() self.guacamoleclient.close() def shell(self, data): self.django_to_guacd(data)
def connect(self, message, id): self.message.reply_channel.send({"accept": True}) if not self.authenticate: self.message.reply_channel.send( { "text": json.dumps({ 'status': False, 'message': 'You must login to the system!' }) }, immediately=True) self.message.reply_channel.send({"accept": False}) else: #permission auth try: Permission.objects.get( user__username=self.message.user.username, groups__servers__id=id) except ObjectDoesNotExist: self.message.reply_channel.send( { "text": json.dumps( '\033[1;3;31mYou have not permission to connect server !\033[0m' ) }, immediately=True) self.message.reply_channel.send({"accept": False}) return client = GuacamoleClient(settings.GUACD_HOST, settings.GUACD_PORT) try: data = ServerInfor.objects.get(id=id) if data.credential.protocol in ['vnc', 'rdp', 'telnet']: pass else: self.message.reply_channel.send({"accept": False}) except ObjectDoesNotExist: #server info not exist self.message.reply_channel.send({"accept": False}) cache_key = str(uuid.uuid4()) directory_date_time = now() recording_path = os.path.join( MEDIA_ROOT, '{0}-{1}-{2}'.format(directory_date_time.year, directory_date_time.month, directory_date_time.day)) drive_path = os.path.join(MEDIA_ROOT, self.message.user.username) """ Create recording media file and drive path """ mkdir_p(recording_path) mkdir_p(drive_path) try: client.handshake(width=data.credential.width, height=data.credential.height, protocol=data.credential.protocol, hostname=data.ip, port=data.credential.port, username=data.credential.username, password=data.credential.password, recording_path=recording_path, recording_name=cache_key, create_recording_path='true', enable_wallpaper='true', ignore_cert='true', enable_drive='true', drive_path=drive_path, create_drive_path='true') #security='tls',) except Exception: self.message.reply_channel.send({"accept": False}) return self.message.reply_channel.send( {"text": '0.,{0}.{1};'.format(len(cache_key), cache_key)}, immediately=True) audit_log = Log.objects.create( user=User.objects.get(username=self.message.user), server=data, channel=self.message.reply_channel.name, width=data.credential.width, height=data.credential.height, log=cache_key, gucamole_client_id=client._id) audit_log.save() guacamolethread = GuacamoleThread(self.message, client) guacamolethread.setDaemon = True guacamolethread.start() guacamolethreadwrite = GuacamoleThreadWrite(self.message, client) guacamolethreadwrite.setDaemon = True guacamolethreadwrite.start()
class GuacamoleWebSocketConsumer(AsyncWebsocketConsumer): client = None task = None read_only = False async def connect(self): """ Initiate the GuacamoleClient and create a connection to it. """ guacd_hostname = os.getenv('GUACD_SERVICE_HOST', 'guacd') guacd_port = int(os.getenv('GUACD_SERVICE_PORT', '4822')) settings = get_xblock_settings() params = urllib.parse.parse_qs(self.scope['query_string'].decode()) stack_name = params.get('stack')[0] stack = await database_sync_to_async(self.get_stack)(stack_name) default_port = 3389 if stack.protocol == 'rdp' else 22 self.read_only = bool(strtobool(params.get('read_only')[0])) self.client = GuacamoleClient(guacd_hostname, guacd_port) self.client.handshake( protocol=stack.protocol, width=params.get('width', [1024])[0], height=params.get('height', [768])[0], hostname=stack.ip, port=params.get('port', [default_port])[0], username=stack.user, password=stack.password, private_key=stack.key, color_scheme=settings.get("terminal_color_scheme"), font_name=settings.get("terminal_font_name"), font_size=settings.get("terminal_font_size"), ) if self.client.connected: # start receiving data from GuacamoleClient loop = asyncio.get_event_loop() self.task = loop.create_task(self.open()) # Accept connection await self.accept(subprotocol='guacamole') else: await self.close() def get_stack(self, stack_name): return Stack.objects.get(name=stack_name) async def disconnect(self, code): """ Close the GuacamoleClient connection on WebSocket disconnect. """ self.task.cancel() await sync_to_async(self.client.close)() async def receive(self, text_data=None, bytes_data=None): """ Handle data received in the WebSocket, send to GuacamoleClient. """ if text_data is not None: # ignore all 'key' and 'mouse' events when set to 'read_only" mode if self.read_only and ('key' in text_data or 'mouse' in text_data): pass else: self.client.send(text_data) async def open(self): """ Receive data from GuacamoleClient and pass it to the WebSocket """ while True: content = await sync_to_async(self.client.receive)() if content: await self.send(text_data=content)
class Client: def __init__(self, websocker): self.websocker = websocker self.start_time = time.time() self.last_save_time = self.start_time tmp_date1 = time.strftime("%Y-%m-%d", time.localtime(int(self.start_time))) tmp_date2 = time.strftime("%Y%m%d%H%M%S", time.localtime(int(self.start_time))) if not os.path.isdir(os.path.join(settings.RECORD_ROOT, tmp_date1)): os.makedirs(os.path.join(settings.RECORD_ROOT, tmp_date1)) self.res_file = settings.RECORD_DIR + '/' + tmp_date1 + '/' + 'webguacamole_' + \ tmp_date2 + '_' + gen_rand_char(16) + '.txt' self.res = [] self.guacamoleclient = None self.file_index = {} self.file_cmd = '' def connect(self, protocol, hostname, port, username, password, width, height, dpi, **kwargs): try: self.guacamoleclient = GuacamoleClient( settings.GUACD.get('host'), settings.GUACD.get('port'), settings.GUACD.get('timeout'), ) if protocol == 'vnc': # vnc 登陆不需要账号 self.guacamoleclient.handshake( protocol=protocol, hostname=hostname, port=port, password=password, width=width, height=height, dpi=dpi, ignore_cert="true", disable_audio="true", client_name="devops", **kwargs, ) elif protocol == 'rdp': self.guacamoleclient.handshake( protocol=protocol, port=port, username=username, password=password, hostname=hostname, width=width, height=height, dpi=dpi, security='tls', # rdp,nla,tls,any ignore_cert="true", disable_audio="true", client_name="devops", **kwargs, ) Thread(target=self.websocket_to_django).start() except Exception: logger.error(traceback.format_exc()) self.websocker.close(3001) def django_to_guacd(self, data): try: self.guacamoleclient.send(data) except Exception: self.close() def websocket_to_django(self): try: while 1: # time.sleep(0.00001) data = self.guacamoleclient.receive() if not data: message = str( base64.b64encode('连接被断开或者协议不支持'.encode('utf-8')), 'utf-8') self.websocker.send('6.toastr,1.2,{0}.{1};'.format( len(message), message)) break save_res = True if data.startswith("4.file,"): tmp = data.split(",") file_index = tmp[1].split(".")[1] file_type = tmp[2].split(".")[1] file_name_tmp = tmp[3].rstrip(";").split(".") del file_name_tmp[0] file_name = '.'.join(file_name_tmp) self.file_index[file_index] = [file_name, file_type] message = str( base64.b64encode( '开始下载文件 - {}'.format(file_name).encode('utf-8')), 'utf-8') self.websocker.send('6.toastr,1.3,{0}.{1};'.format( len(message), message)) save_res = False if self.file_index: if data.startswith("4.blob,"): tmp = data.split(",") index = tmp[1].split(".")[1] if index in self.file_index: # lenx = tmp[2].split(".")[0] # logger.info("file: {} len: {}".format(self.file_index[index][0], lenx)) save_res = False if data.startswith("3.end,"): tmp = data.split(",") index = tmp[1].rstrip(";").split(".")[1] if index in self.file_index: cmd_time = time.strftime( "%Y-%m-%d %H:%M:%S", time.localtime(int(time.time()))) self.file_cmd += cmd_time + "\t" + '下载文件 - {}'.format( self.file_index[index][0]) + '\n' message = str( base64.b64encode('文件下载完成 - {}'.format( self.file_index[index][0]).encode( 'utf-8')), 'utf-8') self.websocker.send('6.toastr,1.3,{0}.{1};'.format( len(message), message)) save_res = False del self.file_index[index] if self.websocker.send_flag == 0: self.websocker.send(data) elif self.websocker.send_flag == 1: async_to_sync(self.websocker.channel_layer.group_send)( self.websocker.group, { "type": "group.message", "text": data, }) if save_res: # 不保存下载文件时的数据到录像 self.res.append(data) # 指定条结果或者指定秒数就保存一次 if len(self.res) > 2000 or int(time.time() - self.last_save_time) > 60 or \ sys.getsizeof(self.res) > 2097152: tmp = list(self.res) self.res = [] self.last_save_time = time.time() res(self.res_file, tmp, False) except Exception: if self.websocker.send_flag == 0: self.websocker.send('0.;') elif self.websocker.send_flag == 1: async_to_sync(self.websocker.channel_layer.group_send)( self.websocker.group, { "type": "group.message", "text": '0.;', }) finally: self.close() def close(self): try: self.websocker.close() self.guacamoleclient.close() except Exception: logger.error(traceback.format_exc()) def shell(self, data): self.django_to_guacd(data)