2 # This module implements a general-purpose server layer for sfa.
3 # The same basic server should be usable on the registry, component, or
6 # TODO: investigate ways to combine this with existing PLC server?
11 import SimpleXMLRPCServer
13 from sfa.util.sfalogging import logger
14 from sfa.trust.certificate import Keypair, Certificate
15 from sfa.plc.api import ComponentAPI
16 from sfa.server.threadedserver import ThreadedServer
20 # taken from the web (XXX find reference). Implents HTTPS xmlrpc request handler
22 class SecureXMLRpcRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
23 """Secure XML-RPC request handler class.
25 It it very similar to SimpleXMLRPCRequestHandler but it uses HTTPS for transporting XML data.
28 self.connection = self.request
29 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
30 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
33 """Handles the HTTPS POST request.
35 It was copied out from SimpleXMLRPCServer.py and modified to shutdown the socket cleanly.
38 peer_cert = Certificate()
39 peer_cert.load_from_pyopenssl_x509(self.connection.get_peer_certificate())
40 self.api = ComponentAPI(peer_cert = peer_cert,
41 interface = self.server.interface,
42 key_file = self.server.key_file,
43 cert_file = self.server.cert_file)
45 request = self.rfile.read(int(self.headers["content-length"]))
46 # In previous versions of SimpleXMLRPCServer, _dispatch
47 # could be overridden in this class, instead of in
48 # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
49 # check to see if a subclass implements _dispatch and dispatch
50 # using that method if present.
51 #response = self.server._marshaled_dispatch(request, getattr(self, '_dispatch', None))
52 # XX TODO: Need to get the real remote address
53 remote_addr = (remote_ip, remote_port) = self.connection.getpeername()
54 self.api.remote_addr = remote_addr
55 #remote_addr = (self.rfile.connection.remote_ip, remote_port)
56 #self.api.remote_addr = remote_addr
57 response = self.api.handle(remote_addr, request)
60 except Exception, fault:
62 # This should only happen if the module is buggy
63 # internal error, report as HTTP server error
64 self.send_response(500)
66 logger.log_exc("componentserver.SecureXMLRpcRequestHandler.do_POST")
68 # got a valid XML RPC response
69 self.send_response(200)
70 self.send_header("Content-type", "text/xml")
71 self.send_header("Content-length", str(len(response)))
73 self.wfile.write(response)
75 # shut down the connection
77 self.connection.shutdown() # Modified here!
80 # Implements an HTTPS XML-RPC server. Generally it is expected that SFA
81 # functions will take a credential string, which is passed to
82 # decode_authentication. Decode_authentication() will verify the validity of
83 # the credential, and verify that the user is using the key that matches the
84 # GID supplied in the credential.
86 class ComponentServer(threading.Thread):
89 # Create a new SfaServer object.
91 # @param ip the ip address to listen on
92 # @param port the port to listen on
93 # @param key_file private key filename of registry
94 # @param cert_file certificate filename containing public key
95 # (could be a GID file)
97 def __init__(self, ip, port, key_file, cert_file, api=None):
98 threading.Thread.__init__(self)
99 self.key = Keypair(filename = key_file)
100 self.cert = Certificate(filename = cert_file)
101 self.server = ThreadedServer((ip, port), SecureXMLRpcRequestHandler, key_file, cert_file)
102 self.trusted_cert_list = None
103 self.register_functions()
107 # Register functions that will be served by the XMLRPC server. This
108 # function should be overrided by each descendant class.
110 def register_functions(self):
111 self.server.register_function(self.noop)
114 # Sample no-op server function. The no-op function decodes the credential
115 # that was passed to it.
117 def noop(self, cred, anything):
121 # Execute the server, serving requests forever.
124 self.server.serve_forever()