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?
18 import SimpleHTTPServer
19 import SimpleXMLRPCServer
20 from OpenSSL import SSL
22 from sfa.util.sfalogging import logger
23 from sfa.trust.certificate import Keypair, Certificate
24 from sfa.trust.credential import *
25 from sfa.util.faults import *
26 from sfa.plc.api import ComponentAPI
27 from sfa.util.server import verify_callback, ThreadedServer
31 # taken from the web (XXX find reference). Implents HTTPS xmlrpc request handler
33 class SecureXMLRpcRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
34 """Secure XML-RPC request handler class.
36 It it very similar to SimpleXMLRPCRequestHandler but it uses HTTPS for transporting XML data.
39 self.connection = self.request
40 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
41 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
44 """Handles the HTTPS POST request.
46 It was copied out from SimpleXMLRPCServer.py and modified to shutdown the socket cleanly.
49 peer_cert = Certificate()
50 peer_cert.load_from_pyopenssl_x509(self.connection.get_peer_certificate())
51 self.api = ComponentAPI(peer_cert = peer_cert,
52 interface = self.server.interface,
53 key_file = self.server.key_file,
54 cert_file = self.server.cert_file)
56 request = self.rfile.read(int(self.headers["content-length"]))
57 # In previous versions of SimpleXMLRPCServer, _dispatch
58 # could be overridden in this class, instead of in
59 # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
60 # check to see if a subclass implements _dispatch and dispatch
61 # using that method if present.
62 #response = self.server._marshaled_dispatch(request, getattr(self, '_dispatch', None))
63 # XX TODO: Need to get the real remote address
64 remote_addr = (remote_ip, remote_port) = self.connection.getpeername()
65 self.api.remote_addr = remote_addr
66 #remote_addr = (self.rfile.connection.remote_ip, remote_port)
67 #self.api.remote_addr = remote_addr
68 response = self.api.handle(remote_addr, request)
71 except Exception, fault:
73 # This should only happen if the module is buggy
74 # internal error, report as HTTP server error
75 self.send_response(500)
77 logger.log_exc("componentserver.SecureXMLRpcRequestHandler.do_POST")
79 # got a valid XML RPC response
80 self.send_response(200)
81 self.send_header("Content-type", "text/xml")
82 self.send_header("Content-length", str(len(response)))
84 self.wfile.write(response)
86 # shut down the connection
88 self.connection.shutdown() # Modified here!
91 # Implements an HTTPS XML-RPC server. Generally it is expected that SFA
92 # functions will take a credential string, which is passed to
93 # decode_authentication. Decode_authentication() will verify the validity of
94 # the credential, and verify that the user is using the key that matches the
95 # GID supplied in the credential.
97 class ComponentServer(threading.Thread):
100 # Create a new SfaServer object.
102 # @param ip the ip address to listen on
103 # @param port the port to listen on
104 # @param key_file private key filename of registry
105 # @param cert_file certificate filename containing public key
106 # (could be a GID file)
108 def __init__(self, ip, port, key_file, cert_file, api=None):
109 threading.Thread.__init__(self)
110 self.key = Keypair(filename = key_file)
111 self.cert = Certificate(filename = cert_file)
112 self.server = ThreadedServer((ip, port), SecureXMLRpcRequestHandler, key_file, cert_file)
113 self.trusted_cert_list = None
114 self.register_functions()
118 # Register functions that will be served by the XMLRPC server. This
119 # function should be overrided by each descendant class.
121 def register_functions(self):
122 self.server.register_function(self.noop)
125 # Sample no-op server function. The no-op function decodes the credential
126 # that was passed to it.
128 def noop(self, cred, anything):
129 self.decode_authentication(cred)
134 # Execute the server, serving requests forever.
137 self.server.serve_forever()