class HttpsServerCommunicator(SecureServerCommunicator): def __init__(self, remote, ctrl, communicator=None): (addr, self.ssl_ctx) = remote self.f_ctrl = ctrl self.http = HttpMessage(self) self.http_communicator = None SecureServerCommunicator.__init__(self, addr, communicator=communicator) self.parent_http = None if communicator is not None: self.parent_http = self.communicator.http def handle_read(self): # Read data in buffer SecureServerCommunicator.handle_read(self) # Fetch the Http request from parent communicator if (self.http_communicator is None) and (len( self.communicator.http_history) > 0): self.http_communicator = self.communicator.http_history.pop(0) if self.http_communicator.path in Config.force_buffering: Logger.debug("Force buffering : " + self.http_communicator.path) self.http.force_full_buffering = True if not self.http.is_ready(): # Parse it until ready if self.make_http_message(): # Now it is ready self._buffer = self.process() # Stream it self.http_communicator = None else: # Data is streamed "on-the-fly" self._buffer = self._buffer # Stream it if self.http.is_complete(): self.http = HttpMessage(self) def make_http_message(self): # Do we have headers ? if not self.http.have_headers(): if self.http.put_headers() is None: return False # Now we have valid headers # Push data self.http.put_body() return self.http.is_ready() def process(self): # in any case of redirection with HTTP protocol use if self.http.have_redirection(): location = self.http.get_header("Location") if location is not None and location.startswith("http://"): location = location.replace("http", "https", 1) self.http.set_header("Location", location) # XML rewriting on start request if (self.http_communicator is not None) and (self.http_communicator.path == "/ovd/client/start"): body = self.http.get_body() xml = self.rewrite_xml(body) self.http.set_body(xml) return self.http.show() def rewrite_xml(self, body): try: session = parser.XML(body) if session.tag.lower() != 'session': raise Exception("not a 'session' XML response") except Exception: Logger.exception("Gateway:: parsing XML session failed") return None session.set('mode_gateway', 'on') for server in session.findall('server'): port = Protocol.RDP if server.attrib.has_key("port"): try: port = int(server.attrib["port"]) except ValueError, err: Logger.warn( "Gateway:: Invalid protocol: server port attribute is not a digit (%s)" % (server.attrib["port"])) token = self.f_ctrl.send( ('insert_token', (server.attrib['fqdn'], port))) server.set('token', token) del server.attrib['fqdn'] if server.attrib.has_key("port"): del server.attrib["port"] for server in session.findall('webapp-server'): if server.attrib.has_key("webapps-url"): url = server.attrib["webapps-url"] if url is not None: token = self.f_ctrl.send(('assign_token', url)) host = self.parent_http.get_header("Host") server.attrib[ "webapps-url"] = "https://" + host + "/webapps-" + token return parser.tostring(session)
class HttpsServerCommunicator(SecureServerCommunicator): def __init__(self, remote, ctrl, communicator=None): (addr, self.ssl_ctx) = remote self.f_ctrl = ctrl self.http = HttpMessage(self) self.http_communicator = None SecureServerCommunicator.__init__(self, addr, communicator=communicator) self.parent_http = None if communicator is not None: self.parent_http = self.communicator.http def handle_read(self): # Read data in buffer SecureServerCommunicator.handle_read(self) # Fetch the Http request from parent communicator if (self.http_communicator is None) and (len(self.communicator.http_history) > 0): self.http_communicator = self.communicator.http_history.pop(0) if self.http_communicator.path in Config.force_buffering: Logger.debug("Force buffering : "+self.http_communicator.path) self.http.force_full_buffering = True if not self.http.is_ready(): # Parse it until ready if self.make_http_message(): # Now it is ready self._buffer = self.process() # Stream it self.http_communicator = None else: # Data is streamed "on-the-fly" self._buffer = self._buffer # Stream it if self.http.is_complete() : self.http = HttpMessage(self) def make_http_message(self): # Do we have headers ? if not self.http.have_headers(): if self.http.put_headers() is None: return False # Now we have valid headers # Push data self.http.put_body() return self.http.is_ready() def process(self): # in any case of redirection with HTTP protocol use if self.http.have_redirection(): location = self.http.get_header("Location") if location is not None and location.startswith("http://"): location = location.replace("http", "https", 1) self.http.set_header("Location", location) # XML rewriting on start request if (self.http_communicator is not None) and (self.http_communicator.path == "/ovd/client/start"): body = self.http.get_body() xml = self.rewrite_xml(body) self.http.set_body(xml) return self.http.show() def rewrite_xml(self, body): try: session = parser.XML(body) if session.tag.lower() != 'session': raise Exception("not a 'session' XML response") except Exception: Logger.exception("Gateway:: parsing XML session failed") return None session.set('mode_gateway', 'on') for server in session.findall('server'): port = Protocol.RDP if server.attrib.has_key("port"): try: port = int(server.attrib["port"]) except ValueError,err: Logger.warn("Gateway:: Invalid protocol: server port attribute is not a digit (%s)"%(server.attrib["port"])) token = self.f_ctrl.send(('insert_token', (server.attrib['fqdn'], port))) server.set('token', token) del server.attrib['fqdn'] if server.attrib.has_key("port"): del server.attrib["port"] for server in session.findall('webapp-server'): if server.attrib.has_key("webapps-url"): url = server.attrib["webapps-url"] if url is not None: token = self.f_ctrl.send(('assign_token', url)) host = self.parent_http.get_header("Host") server.attrib["webapps-url"] = "https://"+host+"/webapps-"+token return parser.tostring(session)
class HttpClientCommunicator(SSLCommunicator): def __init__(self, sock, ctrl=None, ssl_ctx=None): self.f_ctrl = ctrl self.ssl_ctx = ssl_ctx self.http = HttpMessage(self) self.http_history = [] self.last_service = None SSLCommunicator.__init__(self, sock) def handle_read(self, data=None): if data is None: # Read data from socket SSLCommunicator.handle_read(self) else: # Data has already been read by ProtocolDetectDispatcher self._buffer = data if not self.http.is_ready(): # Parse it until ready if self.make_http_message(): # Now it is ready self.http_history.append( self.http) # Push http object in history self._buffer = self.process() # Stream it else: # Data is streamed "on-the-fly" self._buffer = self._buffer # Stream it if self.http.is_complete(): self.http = HttpMessage(self) def make_http_message(self): # Do we have headers ? if not self.http.have_headers(): if self.http.put_headers() is None: return False # Now we have valid headers # Push data self.http.put_body() return self.http.is_ready() def process(self): # Rewrite GET on /ovd/guacamole/ovdlogin if self.http.path.startswith("/ovd/guacamole/ovdlogin"): match = re.search("(?P<separator>[?&])token=(?P<token>[^&]*)", self.http.path) if Licensing.check_license() is not True: raise ProtocolException("No valid license") if match is not None: token = match.group("token") address = self.f_ctrl.send(("digest_token", token)) if not address or type(address) != tuple or len(address) < 2: raise Exception('token authorization failed for: ' + token) host, port = address path = self.http.path[0:match.start("separator")] path += match.group( "separator") + "server=" + host + "&port=" + str(port) path += self.http.path[match.end("token"):] match = HttpMessage.http_req_ptn.search(self.http.headers) if match is not None: headers = self.http.headers[0:match.start("url")] headers += path headers += self.http.headers[match.end("url"):] self.http.path = path self.http.headers = headers ## manage webapps referer = self.http.get_header("Referer") if self.http.path.startswith("/webapps/"): command = self.http.path[len("/webapps/"):] command_header = self.http.get_header("x-ovd-service") params_header = self.http.get_header("x-ovd-param") server_header = self.http.get_header("x-ovd-webappsserver") url = urlparse.urlparse(server_header) token = url.path[len("/webapps-"):] if not command == command_header: Logger.error("%s:: invalid webapps command" % (self.__class__.__name__)) return '' new_path = self.http.path + "?" + params_header self.http.headers = self.http.headers.replace( self.http.path, new_path) self.http.path = new_path elif self.http.path.startswith("/webapps-"): components = self.http.path.split("/") new_path = "/" + "/".join(components[2:]) if not new_path.startswith("/webapps/"): new_path = "/webapps" + new_path self.http.headers = self.http.headers.replace( self.http.path, new_path) elif referer is not None: url = urlparse.urlparse(referer) if url.path.startswith("/webapps-"): webapps_prefix = url.path.split("/")[1] self.http.service = Service.WEBAPPS new_path = "/" + webapps_prefix + self.http.path self.http.headers = self.http.headers.replace( webapps_prefix, "webapps") self.http.path = new_path # Check last service. If different, a new serverCommunicator must be created reconnect = False if self.last_service is not None and self.http.service is not None and self.last_service != self.http.service: names = [ 'SESSION_MANAGER', 'ADMINISTRATION', 'WEB_CLIENT', 'ROOT', 'WEBAPPS' ] Logger.debug("Gateway:: Client service type switched from " + names[self.last_service] + " to " + names[self.http.service]) reconnect = True # test path permission http_code = self.http.auth() if http_code is not httplib.OK: host = self.http.get_header("Host") if host is None: host = "%s:%d" % (self.socket.getsockname()) self.send(page_error(http_code, addr=host)) self.socket.sock_shutdown(socket.SHUT_WR) self.handle_close() return '' # path redirection if self.communicator is None or reconnect is True: addr = None else: addr = self.communicator.getpeername()[0] redirection = self.http.redirect(addr) if redirection is not None: (protocol, addr) = redirection # Update service self.last_service = self.http.service if self.communicator is not None: self.communicator.close() if protocol is Protocol.HTTP: self.communicator = HttpServerCommunicator(addr, self.f_ctrl, communicator=self) elif protocol is Protocol.HTTPS: self.communicator = HttpsServerCommunicator( (addr, self.ssl_ctx), self.f_ctrl, communicator=self) # gateway header's tag self.http.set_header('OVD-Gateway', 'on') # keep alive header handle if not Config.http_keep_alive: self.http.set_header('Connection', 'close') return self.http.show()
class HttpClientCommunicator(SSLCommunicator): def __init__(self, sock, ctrl=None, ssl_ctx=None): self.f_ctrl = ctrl self.ssl_ctx = ssl_ctx self.http = HttpMessage(self) self.http_history = [] self.last_service = None SSLCommunicator.__init__(self, sock) def handle_read(self, data=None): if data is None: # Read data from socket SSLCommunicator.handle_read(self) else: # Data has already been read by ProtocolDetectDispatcher self._buffer = data if not self.http.is_ready(): # Parse it until ready if self.make_http_message(): # Now it is ready self.http_history.append(self.http) # Push http object in history self._buffer = self.process() # Stream it else: # Data is streamed "on-the-fly" self._buffer = self._buffer # Stream it if self.http.is_complete() : self.http = HttpMessage(self) def make_http_message(self): # Do we have headers ? if not self.http.have_headers(): if self.http.put_headers() is None: return False # Now we have valid headers # Push data self.http.put_body() return self.http.is_ready() def process(self): # Rewrite GET on /ovd/guacamole/ovdlogin if self.http.path.startswith("/ovd/guacamole/ovdlogin"): match = re.search("(?P<separator>[?&])token=(?P<token>[^&]*)", self.http.path) if Licensing.check_license() is not True: raise ProtocolException("No valid license") if match is not None: token = match.group("token") address = self.f_ctrl.send(("digest_token", token)) if not address or type(address) != tuple or len(address)<2: raise Exception('token authorization failed for: ' + token) host, port = address path = self.http.path[0:match.start("separator")] path+= match.group("separator")+"server="+host+"&port="+str(port) path+= self.http.path[match.end("token"):] match = HttpMessage.http_req_ptn.search(self.http.headers) if match is not None: headers = self.http.headers[0:match.start("url")] headers+= path headers+= self.http.headers[match.end("url"):] self.http.path = path self.http.headers = headers ## manage webapps referer= self.http.get_header("Referer") if self.http.path.startswith("/webapps/"): command = self.http.path[len("/webapps/"):] command_header = self.http.get_header("x-ovd-service") params_header = self.http.get_header("x-ovd-param") server_header = self.http.get_header("x-ovd-webappsserver") url = urlparse.urlparse(server_header) token = url.path[len("/webapps-"):] if not command == command_header: Logger.error("%s:: invalid webapps command"% (self.__class__.__name__)) return '' new_path = self.http.path+"?"+params_header self.http.headers = self.http.headers.replace(self.http.path, new_path) self.http.path = new_path elif self.http.path.startswith("/webapps-"): components = self.http.path.split("/") new_path = "/" + "/".join(components[2:]) if not new_path.startswith("/webapps/"): new_path = "/webapps" + new_path self.http.headers = self.http.headers.replace(self.http.path, new_path) elif referer is not None: url = urlparse.urlparse(referer) if url.path.startswith("/webapps-"): webapps_prefix = url.path.split("/")[1] self.http.service = Service.WEBAPPS new_path = "/" + webapps_prefix + self.http.path self.http.headers = self.http.headers.replace(webapps_prefix, "webapps") self.http.path = new_path # Check last service. If different, a new serverCommunicator must be created reconnect = False if self.last_service is not None and self.http.service is not None and self.last_service != self.http.service : names = ['SESSION_MANAGER', 'ADMINISTRATION', 'WEB_CLIENT', 'ROOT', 'WEBAPPS'] Logger.debug("Gateway:: Client service type switched from "+names[self.last_service]+" to "+names[self.http.service]) reconnect = True # test path permission http_code = self.http.auth() if http_code is not httplib.OK: host = self.http.get_header("Host") if host is None: host = "%s:%d" % (self.socket.getsockname()) self.send(page_error(http_code, addr=host)) self.socket.sock_shutdown(socket.SHUT_WR) self.handle_close() return '' # path redirection if self.communicator is None or reconnect is True : addr = None else: addr = self.communicator.getpeername()[0] redirection = self.http.redirect(addr) if redirection is not None: (protocol, addr) = redirection # Update service self.last_service = self.http.service if self.communicator is not None: self.communicator.close() if protocol is Protocol.HTTP: self.communicator = HttpServerCommunicator( addr, self.f_ctrl, communicator=self) elif protocol is Protocol.HTTPS: self.communicator = HttpsServerCommunicator( (addr, self.ssl_ctx), self.f_ctrl, communicator=self) # gateway header's tag self.http.set_header('OVD-Gateway', 'on') # keep alive header handle if not Config.http_keep_alive: self.http.set_header('Connection', 'close') return self.http.show()