removed another bunch of references to geni
[sfa.git] / sfa / util / componentserver.py
1 ##
2 # This module implements a general-purpose server layer for sfa.
3 # The same basic server should be usable on the registry, component, or
4 # other interfaces.
5 #
6 # TODO: investigate ways to combine this with existing PLC server?
7 ##
8
9 ### $Id$
10 ### $URL$
11
12 import sys
13 import traceback
14 import threading
15 import socket, os
16
17 import SocketServer
18 import BaseHTTPServer
19 import SimpleHTTPServer
20 import SimpleXMLRPCServer
21
22 from OpenSSL import SSL
23
24 from sfa.trust.certificate import Keypair, Certificate
25 from sfa.trust.credential import *
26
27 from sfa.util.faults import *
28 from sfa.plc.api import ComponentAPI 
29 from sfa.util.server import verify_callback, SecureXMLRPCServer
30 from sfa.util.debug import log
31
32
33 ##
34 # taken from the web (XXX find reference). Implents HTTPS xmlrpc request handler
35
36 class SecureXMLRpcRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
37     """Secure XML-RPC request handler class.
38
39     It it very similar to SimpleXMLRPCRequestHandler but it uses HTTPS for transporting XML data.
40     """
41     def setup(self):
42         self.connection = self.request
43         self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
44         self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
45
46     def do_POST(self):
47         """Handles the HTTPS POST request.
48
49         It was copied out from SimpleXMLRPCServer.py and modified to shutdown the socket cleanly.
50         """
51         try:
52             self.api = ComponentAPI(peer_cert = self.server.peer_cert, 
53                            interface = self.server.interface, 
54                            key_file = self.server.key_file, 
55                            cert_file = self.server.cert_file)
56             # get arguments
57             request = self.rfile.read(int(self.headers["content-length"]))
58             # In previous versions of SimpleXMLRPCServer, _dispatch
59             # could be overridden in this class, instead of in
60             # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
61             # check to see if a subclass implements _dispatch and dispatch
62             # using that method if present.
63             #response = self.server._marshaled_dispatch(request, getattr(self, '_dispatch', None))
64             # XX TODO: Need to get the real remote address
65             remote_addr = (remote_ip, remote_port) = self.connection.getpeername()
66             self.api.remote_addr = remote_addr
67             #remote_addr = (self.rfile.connection.remote_ip, remote_port)
68             #self.api.remote_addr = remote_addr
69             response = self.api.handle(remote_addr, request)
70
71         
72         except Exception, fault:
73             raise
74             # This should only happen if the module is buggy
75             # internal error, report as HTTP server error
76             self.send_response(500)
77             self.end_headers()
78         else:
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)))
83             self.end_headers()
84             self.wfile.write(response)
85
86             # shut down the connection
87             self.wfile.flush()
88             self.connection.shutdown() # Modified here!
89
90 ##
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.
96
97 class ComponentServer(threading.Thread):
98
99     ##
100     # Create a new SfaServer object.
101     #
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)
107
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 = SecureXMLRPCServer((ip, port), SecureXMLRpcRequestHandler, key_file, cert_file)
113         self.trusted_cert_list = None
114         self.register_functions()
115
116
117     ##
118     # Register functions that will be served by the XMLRPC server. This
119     # function should be overrided by each descendant class.
120
121     def register_functions(self):
122         self.server.register_function(self.noop)
123
124     ##
125     # Sample no-op server function. The no-op function decodes the credential
126     # that was passed to it.
127
128     def noop(self, cred, anything):
129         self.decode_authentication(cred)
130
131         return anything
132
133     ##
134     # Execute the server, serving requests forever. 
135
136     def run(self):
137         self.server.serve_forever()
138
139