Commit 36016ccf authored by ibuler's avatar ibuler

[Update] 修改httpd支持token

parent 3319818f
...@@ -3,12 +3,10 @@ ...@@ -3,12 +3,10 @@
# #
import os import os
import socket import socket
from flask_socketio import SocketIO, Namespace, emit, join_room, leave_room
from flask import Flask, send_from_directory, render_template, request, jsonify
import uuid import uuid
from flask_socketio import SocketIO, Namespace, join_room, leave_room
from flask import Flask, request, current_app, redirect
# Todo: Remove for future
from jms.models import User
from .models import Request, Client, WSProxy from .models import Request, Client, WSProxy
from .proxy import ProxyServer from .proxy import ProxyServer
from .utils import get_logger from .utils import get_logger
...@@ -19,31 +17,31 @@ BASE_DIR = os.path.dirname(os.path.dirname(__file__)) ...@@ -19,31 +17,31 @@ BASE_DIR = os.path.dirname(os.path.dirname(__file__))
logger = get_logger(__file__) logger = get_logger(__file__)
class BaseWebSocketHandler: class BaseNamespace(Namespace):
clients = None clients = None
current_user = None current_user = None
def app(self, app): @property
self.app = app def app(self):
return self app = current_app.config['coco']
return app
def prepare(self, request): def on_connect(self):
# self.app = self.settings["app"] self.current_user = self.get_current_user()
x_forwarded_for = request.headers.get("X-Forwarded-For", '').split(',') if self.current_user is None:
if x_forwarded_for and x_forwarded_for[0]: return redirect(current_app.config['LOGIN_URL'])
remote_ip = x_forwarded_for[0] logger.debug("{} connect websocket".format(self.current_user))
else:
remote_ip = request.remote_addr def get_current_user(self):
req = Request((remote_ip, 0)) session_id = request.cookies.get('sessionid', '')
req.user = self.current_user csrf_token = request.cookies.get('csrftoken', '')
req.meta = { token = request.headers.get("Authorization")
"width": self.clients[request.sid]["cols"], user = None
"height": self.clients[request.sid]["rows"] if session_id and csrf_token:
} user = self.app.service.check_user_cookie(session_id, csrf_token)
self.clients[request.sid]["request"] = req if token:
user = self.app.service.check_user_with_token(token)
def check_origin(self, origin): return user
return True
def close(self): def close(self):
try: try:
...@@ -52,52 +50,96 @@ class BaseWebSocketHandler: ...@@ -52,52 +50,96 @@ class BaseWebSocketHandler:
pass pass
class SSHws(Namespace, BaseWebSocketHandler): class ProxyNamespace(BaseNamespace):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.clients = dict() self.clients = dict()
self.rooms = dict() self.rooms = dict()
super().__init__(*args, **kwargs)
def on_connect(self): def new_client(self):
room = str(uuid.uuid4()) room = str(uuid.uuid4())
self.clients[request.sid] = { client = {
"cols": int(request.cookies.get('cols', 80)), "cols": int(request.cookies.get('cols', 80)),
"rows": int(request.cookies.get('rows', 24)), "rows": int(request.cookies.get('rows', 24)),
"room": room, "room": room,
# "chan": dict(),
"proxy": dict(), "proxy": dict(),
"client": dict(), "client": dict(),
"forwarder": dict(), "forwarder": dict(),
"request": None, "request": self.make_coco_request()
}
return client
def make_coco_request(self):
x_forwarded_for = request.headers.get("X-Forwarded-For", '').split(',')
if x_forwarded_for and x_forwarded_for[0]:
remote_ip = x_forwarded_for[0]
else:
remote_ip = request.remote_addr
width_request = request.cookies.get('cols')
rows_request = request.cookies.get('rows')
if width_request and width_request.isdigit():
width = int(width_request)
else:
width = 80
if rows_request and rows_request.isdigit():
rows = int(rows_request)
else:
rows = 24
req = Request((remote_ip, 0))
req.user = self.current_user
req.meta = {
"width": width,
"height": rows,
} }
self.rooms[room] = { return req
def on_connect(self):
logger.debug("On connect event trigger")
super().on_connect()
client = self.new_client()
self.clients[request.sid] = client
self.rooms[client['room']] = {
"admin": request.sid, "admin": request.sid,
"member": [], "member": [],
"rw": [] "rw": []
} }
join_room(room) join_room(client['room'])
self.current_user = self.app.service.check_user_cookie(
session_id=request.cookies.get('sessionid', ''),
csrf_token=request.cookies.get('csrftoken', '')
)
self.prepare(request)
def on_data(self, message): def on_data(self, message):
if message['room'] and self.clients[request.sid]["proxy"][message['room']]: """
self.clients[request.sid]["proxy"][message['room']].send({"data": message['data']}) 收到浏览器请求
:param message: {"data": "xxx", "room": "xxx"}
:return:
"""
room = message.get('room')
if not room:
return
room_proxy = self.clients[request.sid]['proxy'].get(room)
if room_proxy:
room_proxy.send({"data": message['data']})
def on_host(self, message): def on_host(self, message):
# 此处获取主机的信息 # 此处获取主机的信息
logger.debug("On host event trigger")
connection = str(uuid.uuid4()) connection = str(uuid.uuid4())
asset_id = message.get('uuid', None) asset_id = message.get('uuid', None)
user_id = message.get('userid', None) user_id = message.get('userid', None)
self.emit('room', {'room': connection, 'secret': message['secret']}) self.emit('room', {'room': connection, 'secret': message['secret']})
if asset_id and user_id: if not asset_id or not user_id:
self.on_connect()
return
asset = self.app.service.get_asset(asset_id) asset = self.app.service.get_asset(asset_id)
system_user = self.app.service.get_system_user(user_id) system_user = self.app.service.get_system_user(user_id)
if system_user: if not asset or not system_user:
self.on_connect()
return
child, parent = socket.socketpair() child, parent = socket.socketpair()
self.clients[request.sid]["client"][connection] = Client( self.clients[request.sid]["client"][connection] = Client(
parent, self.clients[request.sid]["request"] parent, self.clients[request.sid]["request"]
...@@ -105,46 +147,52 @@ class SSHws(Namespace, BaseWebSocketHandler): ...@@ -105,46 +147,52 @@ class SSHws(Namespace, BaseWebSocketHandler):
self.clients[request.sid]["proxy"][connection] = WSProxy( self.clients[request.sid]["proxy"][connection] = WSProxy(
self, child, self.clients[request.sid]["room"], connection self, child, self.clients[request.sid]["room"], connection
) )
self.clients[request.sid]["forwarder"][ self.clients[request.sid]["forwarder"][connection] = ProxyServer(
connection] = ProxyServer(
self.app, self.clients[request.sid]["client"][connection] self.app, self.clients[request.sid]["client"][connection]
) )
self.app.clients.append(self.clients[request.sid]["client"][connection])
self.socketio.start_background_task( self.socketio.start_background_task(
self.clients[request.sid]["forwarder"][connection].proxy, self.clients[request.sid]["forwarder"][connection].proxy,
asset, system_user asset, system_user
) )
# self.forwarder.proxy(self.asset, system_user)
else:
self.on_disconnect()
else:
self.on_disconnect()
def on_resize(self, message): def on_resize(self, message):
if self.clients[request.sid]["request"]: cols = message.get('cols')
self.clients[request.sid]["request"].meta['width'] = message.get('cols', 80) rows = message.get('rows')
self.clients[request.sid]["request"].meta['height'] = message.get('rows', 24) logger.debug("On resize event trigger: {}*{}".format(cols, rows))
if cols and rows and self.clients[request.sid]["request"]:
self.clients[request.sid]["request"].meta['width'] = cols
self.clients[request.sid]["request"].meta['height'] = rows
self.clients[request.sid]["request"].change_size_event.set() self.clients[request.sid]["request"].change_size_event.set()
def on_room(self, sessionid): def on_room(self, session_id):
if sessionid not in self.clients.keys(): logger.debug("On room event trigger")
self.emit('error', "no such session", room=self.clients[request.sid]["room"]) if session_id not in self.clients.keys():
self.emit(
'error', "no such session",
room=self.clients[request.sid]["room"]
)
else: else:
self.emit('room', self.clients[sessionid]["room"], room=self.clients[request.sid]["room"]) self.emit(
'room', self.clients[session_id]["room"],
room=self.clients[request.sid]["room"]
)
def on_join(self, room): def on_join(self, room):
logger.debug("On join room event trigger")
self.on_leave(self.clients[request.id]["room"]) self.on_leave(self.clients[request.id]["room"])
self.clients[request.sid]["room"] = room self.clients[request.sid]["room"] = room
self.rooms[room]["member"].append(request.sid) self.rooms[room]["member"].append(request.sid)
join_room(room=room) join_room(room=room)
def on_leave(self, room): def on_leave(self, room):
logger.debug("On leave room event trigger")
if self.rooms[room]["admin"] == request.sid: if self.rooms[room]["admin"] == request.sid:
self.emit("data", "\nAdmin leave", room=room) self.emit("data", "\nAdmin leave", room=room)
del self.rooms[room] del self.rooms[room]
leave_room(room=room) leave_room(room=room)
def on_disconnect(self): def on_disconnect(self):
logger.debug("On disconnect event trigger")
self.on_leave(self.clients[request.sid]["room"]) self.on_leave(self.clients[request.sid]["room"])
try: try:
for connection in self.clients[request.sid]["client"]: for connection in self.clients[request.sid]["client"]:
...@@ -154,9 +202,11 @@ class SSHws(Namespace, BaseWebSocketHandler): ...@@ -154,9 +202,11 @@ class SSHws(Namespace, BaseWebSocketHandler):
pass pass
def on_logout(self, connection): def on_logout(self, connection):
logger.debug("On logout event trigger")
if connection: if connection:
if connection in self.clients[request.sid]["proxy"].keys(): if connection in self.clients[request.sid]["proxy"].keys():
self.clients[request.sid]["proxy"][connection].close() self.clients[request.sid]["proxy"][connection].close()
del self.clients[request.sid]['proxy'][connection]
def logout(self, connection): def logout(self, connection):
if connection and (request.sid in self.clients.keys()): if connection and (request.sid in self.clients.keys()):
...@@ -170,28 +220,31 @@ class SSHws(Namespace, BaseWebSocketHandler): ...@@ -170,28 +220,31 @@ class SSHws(Namespace, BaseWebSocketHandler):
class HttpServer: class HttpServer:
# prepare may be rewrite it # prepare may be rewrite it
settings = { config = {
'cookie_secret': '', 'SECRET_KEY': '',
'app': None, 'coco': None,
'login_url': '/login' 'LOGIN_URL': '/login'
} }
async_mode = "threading"
def __init__(self, app): def __init__(self, coco):
self.app = app config = coco.config
# self.settings['cookie_secret'] = self.app.config['SECRET_KEY'] config.update(self.config)
# self.settings['app'] = self.app config['coco'] = coco
self.flask_app = Flask(__name__, template_folder='dist')
self.flask_app.config.update(config)
self.socket_io = SocketIO()
self.register_routes()
self.flask = Flask(__name__, template_folder='dist') def register_routes(self):
self.flask.config['SECRET_KEY'] = self.app.config['SECRET_KEY'] self.socket_io.on_namespace(ProxyNamespace('/ssh'))
self.socketio = SocketIO()
def run(self): def run(self):
host = self.app.config["BIND_HOST"] host = self.flask_app.config["BIND_HOST"]
port = self.app.config["HTTPD_PORT"] port = self.flask_app.config["HTTPD_PORT"]
print('Starting websocket server at {}:{}'.format(host, port)) print('Starting websocket server at {}:{}'.format(host, port))
self.socketio.on_namespace(SSHws('/ssh').app(self.app)) self.socket_io.init_app(self.flask_app, async_mode=self.async_mode)
self.socketio.init_app(self.flask, async_mode="threading") self.socket_io.run(self.flask_app, port=port, host=host, debug=False)
self.socketio.run(self.flask, port=port, host=host)
def shutdown(self): def shutdown(self):
pass pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment