source: cred_printer/cred_printer/server.py

Last change on this file was ab52de1, checked in by Mike Ryan <mikeryan@…>, 12 years ago

bump to version 0.2.0

  • Property mode set to 100644
File size: 4.8 KB
Line 
1#!/usr/local/bin/python
2
3import sys
4
5from BaseHTTPServer import BaseHTTPRequestHandler
6
7from M2Crypto import SSL
8from M2Crypto.SSL.SSLServer import SSLServer
9from SocketServer import TCPServer
10
11from service_error import service_error
12import xmlrpclib
13
14import os.path
15
16import logging
17import traceback
18
19# The SSL server here is based on the implementation described at
20# http://www.xml.com/pub/a/ws/2004/01/20/salz.html
21
22# Turn off the matching of hostname to certificate ID
23SSL.Connection.clientPostConnectionCheck = None
24
25class error_handlers:
26    """
27    Class to encapsulate the debugging and non-debugging error handlers.
28    """
29    def __init__(self, debug):
30        """
31        Set the error handler
32        """
33        if debug: self.handle_error = self.handle_error_debug
34        else: self.handle_error = self.handle_error_standard
35
36    def handle_error_debug(self, request=None, client_address=None):
37        """
38        Debugging error handler.  Prints a stack trace.
39        """
40        print '-'*40
41        traceback.print_exc()
42        print '-'*40
43
44
45    def handle_error_standard(self, request=None, address=None):
46        """
47        Print standard error output, suitable for human consumption.
48        """
49        if request or address:
50            self.log.warn("[credd] Error on incoming connection: %s %s" % \
51                    (request or "", address or ""))
52        else:
53            self.log.warn("[credd] Error on incoming connection " + \
54                    "(Likely SSL error)")
55
56
57
58class server(SSLServer, error_handlers):
59    """
60    Overloads a TCPServer to hold an XMLRPC implementation.  The implementation
61    needs to inclide an xmlrpc_services dist that maps from method name to
62    callable mamber that takes a single parameter (usually a list or dict) and
63    a certificate.
64    """
65    def __init__(self, ME, handler, ssl_ctx, impl, debug=False):
66        """
67        Create an SSL server that handles the transport in handler using the
68        credentials in ssl_ctx, and interfacing to the implementation of fedd
69        services in fedd.  ME is the host port pair on which to bind.
70        """
71        SSLServer.__init__(self, ME, handler, ssl_ctx)
72        error_handlers.__init__(self, debug)
73        self.impl = impl
74        self.xmlrpc_methods = impl.xmlrpc_services
75        self.log = logging.getLogger("creds")
76
77class simpleServer(TCPServer, error_handlers):
78    """
79    Presents the same interface as server to a threaded TCP server.  Allows a
80    binding of the same implementation and handler classes to
81    unencrypted/authenticated connections.
82    """
83    def __init__(self, ME, handler, impl, debug=False):
84        TCPServer.__init__(self, ME, handler)
85        error_handlers.__init__(self, debug)
86        self.impl = impl
87        self.xmlrpc_methods = impl.xmlrpc_services
88        self.log = logging.getLogger("creds")
89
90
91class xmlrpc_handler(BaseHTTPRequestHandler):
92    """
93    Standard connection between XMLRPC and the services in impl.
94
95    Much of this is boilerplate from
96    http://www.xml.com/pub/a/ws/2004/01/20/salz.html
97    """
98    server_version = "credd/0.2 " + BaseHTTPRequestHandler.server_version
99
100    def send_xml(self, text, code=200):
101        """Send an XML document as reply"""
102        self.send_response(code)
103        self.send_header('Content-type', 'text/xml; charset="utf-8"')
104        self.send_header('Content-Length', str(len(text)))
105        self.end_headers()
106        self.wfile.write(text)
107        self.wfile.flush()
108        # Make sure to close the socket when we're done
109        self.request.close()
110        #self.request.socket.close()
111
112    def do_POST(self):
113        """Treat an HTTP POST request as an XMLRPC service call"""
114        # NB: XMLRPC faults are not HTTP errors, so the code is always 200,
115        # unless an HTTP error occurs, which we don't handle.
116
117        resp = None
118        data = None
119        method = None
120        cl = int(self.headers['content-length'])
121        data = self.rfile.read(cl)
122
123        try:
124            params, method = xmlrpclib.loads(data)
125        except xmlrpclib.ResponseError:
126            data = xmlrpclib.dumps(xmlrpclib.Fault("Client", 
127                "Malformed request"), methodresponse=True)
128
129        # Simple servers don't have peer certificates.
130        if getattr(self.request, 'get_peer_cert', None):
131            fid = self.request.get_peer_cert()
132        else:
133            fid = None
134
135
136        if method != None:
137            try:
138                resp = self.xmlrpc_dispatch(method, params, fid)
139                data = xmlrpclib.dumps((resp,), encoding='UTF-8', 
140                        methodresponse=True)
141            except xmlrpclib.Fault, f:
142                data = xmlrpclib.dumps(f, methodresponse=True)
143                resp = None
144
145        self.send_xml(data)
146
147    def log_request(self, code=0, size=0):
148        """
149        Log request to the fedd logger
150        """
151        self.server.log.info("Successful XMLRPC request code %d" % code)
152
153
154    def xmlrpc_dispatch(self, method, req, fid):
155        """
156        The connection to the implementation, using the  method maps
157
158        The implementation provides a mapping from XMLRPC method name to the
159        method in the implementation that provides the service.
160        """
161        if self.server.xmlrpc_methods.has_key(method):
162            try:
163                return self.server.xmlrpc_methods[method](req, fid)
164            except service_error, e:
165                raise xmlrpclib.Fault(e.code_string(), e.desc)
166
167        else:
168            raise xmlrpclib.Fault(100, "Unknown method: %s" % method)
169
Note: See TracBrowser for help on using the repository browser.