Source code for mxcubecore.HardwareObjects.SecureXMLRpcRequestHandler

"""
Secure XML RPC request handler for workflow execution based on tokens.
Inspired from this code:
http://code.activestate.com/recipes/496786-simple-xml-rpc-server-over-https
"""

import sys

if sys.version_info > (3, 0):
    from xmlrpc.server import SimpleXMLRPCRequestHandler
else:
    from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler


__author__ = "Olof Svensson"
__copyright__ = "Copyright 2012, ESRF"
__credits__ = ["MxCuBE collaboration"]

__version__ = ""
__maintainer__ = "Marcus Oskarsson"
__email__ = "marcus.oscarsson@esrf.fr"
__status__ = "Draft"


[docs]class SecureXMLRpcRequestHandler(SimpleXMLRPCRequestHandler): """ Secure XML-RPC request handler class. It it very similar to SimpleXMLRPCRequestHandler but it checks for a "Token" entry in the header. If this token doesn't correspond to a reference token the server sends a "401" (Unauthorized) reply. """ __referenceToken = None @staticmethod def setReferenceToken(token): SecureXMLRpcRequestHandler.__referenceToken = token def setup(self): self.connection = self.request self.rfile = self.connection.makefile("rb", self.rbufsize) self.wfile = self.connection.makefile("wb", self.wbufsize)
[docs] def do_POST(self): """ Handles the HTTPS POST request. It was copied out from SimpleXMLRPCServer.py and modified to check for "Token" in the headers. """ # Check that the path is legal if not self.is_rpc_path_valid(): self.report_404() return referenceToken = SecureXMLRpcRequestHandler.__referenceToken if ( referenceToken is not None and "Token" in self.headers and referenceToken == self.headers["Token"] ): try: # Get arguments by reading body of request. # We read this in chunks to avoid straining # socket.read(); around the 10 or 15Mb mark, some platforms # begin to have problems (bug #792570). max_chunk_size = 10 * 1024 * 1024 size_remaining = int(self.headers["content-length"]) L = [] while size_remaining: chunk_size = min(size_remaining, max_chunk_size) chunk = self.rfile.read(chunk_size) if not chunk: break L.append(chunk.decode("utf-8")) size_remaining -= len(L[-1]) data = "".join(L) # In previous versions of SimpleXMLRPCServer, _dispatch # could be overridden in this class, instead of in # SimpleXMLRPCDispatcher. To maintain backwards compatibility, # check to see if a subclass implements _dispatch and dispatch # using that method if present. response = self.server._marshaled_dispatch( data, getattr(self, "_dispatch", None) ) except Exception: # This should only happen if the module is buggy # internal error, report as HTTP server error self.send_response(500) logging.getLogger("HWR").exception("Exception during request.") self.end_headers() else: # got a valid XML RPC response self.send_response(200) self.send_header("Content-type", "text/xml") self.send_header("Content-length", str(len(response))) self.end_headers() self.wfile.write(response) # shut down the connection self.wfile.flush() self.connection.shutdown(1) else: # Unrecognized token - access unauthorized self.send_response(401) self.end_headers()