blob: 56bfaea44bc391aff9cca8fd711ddc69ad1aad37 [file] [log] [blame]
Jean-Paul Calderone897bc252008-02-18 20:50:23 -05001"""
2SecureXMLRPCServer module using pyOpenSSL 0.5
3Written 0907.2002
4by Michal Wallace
5http://www.sabren.net/
6
7This acts exactly like SimpleXMLRPCServer
8from the standard python library, but
9uses secure connections. The technique
10and classes should work for any SocketServer
11style server. However, the code has not
12been extensively tested.
13
14This code is in the public domain.
15It is provided AS-IS WITH NO WARRANTY WHATSOEVER.
16"""
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010017
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050018import SimpleXMLRPCServer
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010019import SocketServer
20import os
21import socket
22
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050023from OpenSSL import SSL
24
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010025
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050026class SSLWrapper:
27 """
28 This whole class exists just to filter out a parameter
29 passed in to the shutdown() method in SimpleXMLRPC.doPOST()
30 """
31 def __init__(self, conn):
32 """
33 Connection is not yet a new-style class,
34 so I'm making a proxy instead of subclassing.
35 """
36 self.__dict__["conn"] = conn
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010037
38 def __getattr__(self, name):
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050039 return getattr(self.__dict__["conn"], name)
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010040
41 def __setattr__(self, name, value):
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050042 setattr(self.__dict__["conn"], name, value)
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010043
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050044 def shutdown(self, how=1):
45 """
46 SimpleXMLRpcServer.doPOST calls shutdown(1),
47 and Connection.shutdown() doesn't take
48 an argument. So we just discard the argument.
49 """
50 self.__dict__["conn"].shutdown()
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010051
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050052 def accept(self):
53 """
54 This is the other part of the shutdown() workaround.
55 Since servers create new sockets, we have to infect
56 them with our magic. :)
57 """
58 c, a = self.__dict__["conn"].accept()
59 return (SSLWrapper(c), a)
60
61
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050062class SecureTCPServer(SocketServer.TCPServer):
63 """
64 Just like TCPServer, but use a socket.
65 This really ought to let you specify the key and certificate files.
66 """
67 def __init__(self, server_address, RequestHandlerClass):
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010068 SocketServer.BaseServer.__init__(
69 self, server_address, RequestHandlerClass
70 )
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050071
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010072 # Same as normal, but make it secure:
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050073 ctx = SSL.Context(SSL.SSLv23_METHOD)
74 ctx.set_options(SSL.OP_NO_SSLv2)
75
76 dir = os.curdir
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010077 ctx.use_privatekey_file(os.path.join(dir, 'server.pkey'))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050078 ctx.use_certificate_file(os.path.join(dir, 'server.cert'))
79
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010080 self.socket = SSLWrapper(
81 SSL.Connection(
82 ctx, socket.socket(self.address_family, self.socket_type)
83 )
84 )
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050085 self.server_bind()
86 self.server_activate()
87
88
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010089class SecureXMLRPCRequestHandler(
90 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050091 def setup(self):
92 """
93 We need to use socket._fileobject Because SSL.Connection
94 doesn't have a 'dup'. Not exactly sure WHY this is, but
95 this is backed up by comments in socket.py and SSL/connection.c
96 """
Hynek Schlawack8b7e4552016-03-13 07:51:09 +010097 self.connection = self.request # for doPOST
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050098 self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
99 self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500100
Hynek Schlawack8b7e4552016-03-13 07:51:09 +0100101
102class SecureXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer,
103 SecureTCPServer):
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500104 def __init__(self, addr,
105 requestHandler=SecureXMLRPCRequestHandler,
106 logRequests=1):
107 """
108 This is the exact same code as SimpleXMLRPCServer.__init__
109 except it calls SecureTCPServer.__init__ instead of plain
110 old TCPServer.__init__
111 """
112 self.funcs = {}
113 self.logRequests = logRequests
114 self.instance = None
115 SecureTCPServer.__init__(self, addr, requestHandler)