1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
6 # This program 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
9 # GNU Library General Public License for more details.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 # Copyright 2005 Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
16 # Modifications by Seth Vidal - 2007
20 import SimpleXMLRPCServer
21 from func
import SSLCommon
26 class AuthedSimpleXMLRPCRequestHandler(SimpleXMLRPCServer
.SimpleXMLRPCRequestHandler
):
28 # For some reason, httplib closes the connection right after headers
29 # have been sent if the connection is _not_ HTTP/1.1, which results in
30 # a "Bad file descriptor" error when the client tries to read from the socket
31 protocol_version
= "HTTP/1.1"
35 We need to use socket._fileobject Because SSL.Connection
36 doesn't have a 'dup'. Not exactly sure WHY this is, but
37 this is backed up by comments in socket.py and SSL/connection.c
39 self
.connection
= self
.request
# for doPOST
40 self
.rfile
= socket
._fileobject
(self
.request
, "rb", self
.rbufsize
)
41 self
.wfile
= socket
._fileobject
(self
.request
, "wb", self
.wbufsize
)
44 self
.server
._this
_request
= (self
.request
, self
.client_address
)
46 SimpleXMLRPCServer
.SimpleXMLRPCRequestHandler
.do_POST(self
)
47 except socket
.timeout
:
49 except (socket
.error
, OpenSSL
.SSL
.SysCallError
), e
:
50 print "Error (%s): socket error - '%s'" % (self
.client_address
, e
)
53 class BaseAuthedXMLRPCServer(SocketServer
.ThreadingMixIn
):
54 def __init__(self
, address
, authinfo_callback
=None):
55 self
.allow_reuse_address
= 1
57 self
.authinfo_callback
= authinfo_callback
62 def get_authinfo(self
, request
, client_address
):
64 if self
.authinfo_callback
:
65 return self
.authinfo_callback(request
, client_address
)
69 class AuthedSSLXMLRPCServer(BaseAuthedXMLRPCServer
, SSLCommon
.BaseSSLServer
, SimpleXMLRPCServer
.SimpleXMLRPCServer
):
70 """ Extension to allow more fine-tuned SSL handling """
72 def __init__(self
, address
, pkey
, cert
, ca_cert
, authinfo_callback
=None, timeout
=None):
73 BaseAuthedXMLRPCServer
.__init
__(self
, address
, authinfo_callback
)
74 SimpleXMLRPCServer
.SimpleXMLRPCServer
.__init
__(self
, address
, AuthedSimpleXMLRPCRequestHandler
)
75 SSLCommon
.BaseSSLServer
.__init
__(self
, address
, AuthedSimpleXMLRPCRequestHandler
, pkey
, cert
, ca_cert
, timeout
=timeout
)
79 class AuthedXMLRPCServer(BaseAuthedXMLRPCServer
, SSLCommon
.BaseServer
, SimpleXMLRPCServer
.SimpleXMLRPCServer
):
81 def __init__(self
, address
, authinfo_callback
=None):
82 BaseAuthedXMLRPCServer
.__init
__(self
, address
, authinfo_callback
)
83 SSLCommon
.BaseServer
.__init
__(self
, address
, AuthedSimpleXMLRPCRequestHandler
)
86 ###########################################################
88 ###########################################################
91 def ping(self
, callerid
, trynum
):
95 return "pong %d / %d" % (callerid
, trynum
)
97 class TestServer(AuthedSSLXMLRPCServer
):
99 SSL XMLRPC server that authenticates clients based on their certificate.
102 def __init__(self
, address
, pkey
, cert
, ca_cert
):
103 AuthedSSLXMLRPCServer
.__init
__(self
, address
, pkey
, cert
, ca_cert
, self
.auth_cb
)
105 def _dispatch(self
, method
, params
):
106 if method
== 'trait_names' or method
== '_getAttributeNames':
108 # if we have _this_request then we get the peer cert from it
109 # handling all the authZ checks in _dispatch() means we don't even call the method
110 # for whatever it wants to do and we have the method name.
112 if hasattr(self
, '_this_request'):
113 r
,a
= self
._this
_request
114 p
= r
.get_peer_certificate()
116 print p
.get_subject()
122 def auth_cb(self
, request
, client_address
):
123 peer_cert
= request
.get_peer_certificate()
124 return peer_cert
.get_subject().CN
127 if __name__
== '__main__':
128 if len(sys
.argv
) < 4:
129 print "Usage: python AuthdXMLRPCServer.py key cert ca_cert"
134 ca_cert
= sys
.argv
[3]
136 print "Starting the server."
137 server
= TestServer(('localhost', 51234), pkey
, cert
, ca_cert
)
139 server
.register_instance(h
)
140 server
.serve_forever()