1 | #============================================================================ |
---|
2 | # This library is free software; you can redistribute it and/or |
---|
3 | # modify it under the terms of version 2.1 of the GNU Lesser General Public |
---|
4 | # License as published by the Free Software Foundation. |
---|
5 | # |
---|
6 | # This library is distributed in the hope that it will be useful, |
---|
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
9 | # Lesser General Public License for more details. |
---|
10 | # |
---|
11 | # You should have received a copy of the GNU Lesser General Public |
---|
12 | # License along with this library; if not, write to the Free Software |
---|
13 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
14 | #============================================================================ |
---|
15 | # Copyright (C) 2007 XenSource Inc. |
---|
16 | #============================================================================ |
---|
17 | |
---|
18 | |
---|
19 | """ |
---|
20 | HTTPS wrapper for an XML-RPC server interface. Requires PyOpenSSL (Debian |
---|
21 | package python-pyopenssl). |
---|
22 | """ |
---|
23 | |
---|
24 | import socket |
---|
25 | |
---|
26 | from OpenSSL import SSL |
---|
27 | |
---|
28 | from xen.util.xmlrpclib2 import XMLRPCRequestHandler, TCPXMLRPCServer |
---|
29 | |
---|
30 | |
---|
31 | class SSLXMLRPCRequestHandler(XMLRPCRequestHandler): |
---|
32 | def setup(self): |
---|
33 | self.connection = self.request |
---|
34 | self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) |
---|
35 | self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) |
---|
36 | |
---|
37 | # |
---|
38 | # Taken from pyOpenSSL-0.6 examples (public-domain) |
---|
39 | # |
---|
40 | |
---|
41 | class SSLWrapper: |
---|
42 | """ |
---|
43 | """ |
---|
44 | def __init__(self, conn): |
---|
45 | """ |
---|
46 | Connection is not yet a new-style class, |
---|
47 | so I'm making a proxy instead of subclassing. |
---|
48 | """ |
---|
49 | self.__dict__["conn"] = conn |
---|
50 | def __getattr__(self, name): |
---|
51 | return getattr(self.__dict__["conn"], name) |
---|
52 | def __setattr__(self, name, value): |
---|
53 | setattr(self.__dict__["conn"], name, value) |
---|
54 | |
---|
55 | def close(self): |
---|
56 | self.shutdown() |
---|
57 | return self.__dict__["conn"].close() |
---|
58 | |
---|
59 | def shutdown(self, how=1): |
---|
60 | """ |
---|
61 | SimpleXMLRpcServer.doPOST calls shutdown(1), |
---|
62 | and Connection.shutdown() doesn't take |
---|
63 | an argument. So we just discard the argument. |
---|
64 | """ |
---|
65 | # Block until the shutdown is complete |
---|
66 | self.__dict__["conn"].shutdown() |
---|
67 | self.__dict__["conn"].shutdown() |
---|
68 | |
---|
69 | def accept(self): |
---|
70 | """ |
---|
71 | This is the other part of the shutdown() workaround. |
---|
72 | Since servers create new sockets, we have to infect |
---|
73 | them with our magic. :) |
---|
74 | """ |
---|
75 | c, a = self.__dict__["conn"].accept() |
---|
76 | return (SSLWrapper(c), a) |
---|
77 | |
---|
78 | # |
---|
79 | # End of pyOpenSSL-0.6 example code. |
---|
80 | # |
---|
81 | |
---|
82 | class SSLXMLRPCServer(TCPXMLRPCServer): |
---|
83 | def __init__(self, addr, allowed, xenapi, logRequests = 1, |
---|
84 | ssl_key_file = None, ssl_cert_file = None): |
---|
85 | |
---|
86 | TCPXMLRPCServer.__init__(self, addr, allowed, xenapi, |
---|
87 | SSLXMLRPCRequestHandler, logRequests) |
---|
88 | |
---|
89 | if not ssl_key_file or not ssl_cert_file: |
---|
90 | raise ValueError("SSLXMLRPCServer requires ssl_key_file " |
---|
91 | "and ssl_cert_file to be set.") |
---|
92 | |
---|
93 | # make a SSL socket |
---|
94 | ctx = SSL.Context(SSL.SSLv23_METHOD) |
---|
95 | ctx.set_options(SSL.OP_NO_SSLv2) |
---|
96 | ctx.use_privatekey_file (ssl_key_file) |
---|
97 | ctx.use_certificate_file(ssl_cert_file) |
---|
98 | self.socket = SSLWrapper(SSL.Connection(ctx, |
---|
99 | socket.socket(self.address_family, |
---|
100 | self.socket_type))) |
---|
101 | self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
---|
102 | self.server_bind() |
---|
103 | self.server_activate() |
---|