[FIX] XML-RPC SSL
bzr revid: stephane@tinyerp.com-20081218235433-cnsc5a4iyfzqvbdx
This commit is contained in:
parent
70bd7ea91a
commit
12e2aef08c
|
@ -21,27 +21,23 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import SimpleXMLRPCServer
|
import SimpleXMLRPCServer
|
||||||
from ssl import SecureXMLRPCServer
|
|
||||||
|
|
||||||
import signal
|
|
||||||
import sys
|
|
||||||
import xmlrpclib
|
|
||||||
import SocketServer
|
import SocketServer
|
||||||
import socket
|
|
||||||
import logging
|
import logging
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import xmlrpclib
|
||||||
|
|
||||||
_service = {}
|
_service = {}
|
||||||
_group = {}
|
_group = {}
|
||||||
_res_id = 1
|
_res_id = 1
|
||||||
_res = {}
|
_res = {}
|
||||||
|
|
||||||
|
|
||||||
class ServiceEndPointCall(object):
|
class ServiceEndPointCall(object):
|
||||||
def __init__(self, id, method):
|
def __init__(self, id, method):
|
||||||
self._id = id
|
self._id = id
|
||||||
|
@ -280,7 +276,45 @@ class GenericXMLRPCRequestHandler:
|
||||||
pdb.post_mortem(tb)
|
pdb.post_mortem(tb)
|
||||||
raise xmlrpclib.Fault(s, tb_s)
|
raise xmlrpclib.Fault(s, tb_s)
|
||||||
|
|
||||||
|
# refactoring from Tryton (B2CK, Cedric Krier, Bertrand Chenal)
|
||||||
|
class SSLSocket(object):
|
||||||
|
def __init__(self, socket):
|
||||||
|
if not hasattr(socket, 'sock_shutdown'):
|
||||||
|
from OpenSSL import SSL
|
||||||
|
ctx = SSL.Context(SSL.SSLv23_METHOD)
|
||||||
|
ctx.use_privatekey_file('server.pkey')
|
||||||
|
ctx.use_certificate_file('server.cert')
|
||||||
|
self.socket = SSL.Connection(ctx, socket)
|
||||||
|
else:
|
||||||
|
self.socket = socket
|
||||||
|
|
||||||
|
def shutdown(self, how):
|
||||||
|
return self.socket.sock_shutdown(how)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self.socket, name)
|
||||||
|
|
||||||
|
class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler, SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
|
||||||
|
rpc_paths = map(lambda s: '/xmlrpc/%s' % s, _service)
|
||||||
|
|
||||||
|
class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
|
def setup(self):
|
||||||
|
self.connection = SSLSocket(self.request)
|
||||||
|
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
|
||||||
|
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
|
||||||
|
|
||||||
|
class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer):
|
||||||
|
def server_bind(self):
|
||||||
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
|
||||||
|
|
||||||
|
class SecureThreadedXMLRPCServer(SimpleThreadedXMLRPCServer):
|
||||||
|
def __init__(self, server_address, HandlerClass, logRequests=1):
|
||||||
|
SimpleThreadedXMLRPCServer.__init__(self, server_address, HandlerClass, logRequests)
|
||||||
|
self.socket = SSLSocket(socket.socket(self.address_family, self.socket_type))
|
||||||
|
self.server_bind()
|
||||||
|
self.server_activate()
|
||||||
|
# end of refactoring from Tryton
|
||||||
|
|
||||||
class HttpDaemon(threading.Thread):
|
class HttpDaemon(threading.Thread):
|
||||||
def __init__(self, interface, port, secure=False):
|
def __init__(self, interface, port, secure=False):
|
||||||
|
@ -288,22 +322,9 @@ class HttpDaemon(threading.Thread):
|
||||||
self.__port = port
|
self.__port = port
|
||||||
self.__interface = interface
|
self.__interface = interface
|
||||||
self.secure = bool(secure)
|
self.secure = bool(secure)
|
||||||
|
handler_class = (SimpleXMLRPCRequestHandler, SecureXMLRPCRequestHandler)[self.secure]
|
||||||
base_handler_class = [SimpleXMLRPCServer.SimpleXMLRPCRequestHandler, SecureXMLRPCServer.SecureXMLRPCRequestHandler][self.secure]
|
server_class = (SimpleThreadedXMLRPCServer, SecureThreadedXMLRPCServer)[self.secure]
|
||||||
class OpenERPXMLRPCRequestHandler(GenericXMLRPCRequestHandler, base_handler_class):
|
self.server = server_class((interface, port), handler_class, 0)
|
||||||
base_handler_class.rpc_paths = map(lambda s: '/xmlrpc/%s' % s, _service)
|
|
||||||
|
|
||||||
base_server_class = [SimpleXMLRPCServer.SimpleXMLRPCServer, SecureXMLRPCServer.SecureXMLRPCServer][self.secure]
|
|
||||||
class OpenERPThreadedXMLRPCServer(SocketServer.ThreadingMixIn, base_server_class):
|
|
||||||
def server_bind(self):
|
|
||||||
try:
|
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
base_server_class.server_bind(self)
|
|
||||||
except:
|
|
||||||
Logger().notifyChannel('init', LOG_CRITICAL, 'Address already in use')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
self.server = OpenERPThreadedXMLRPCServer((interface, port), OpenERPXMLRPCRequestHandler, 0)
|
|
||||||
|
|
||||||
def attach(self, path, gw):
|
def attach(self, path, gw):
|
||||||
pass
|
pass
|
||||||
|
@ -311,11 +332,7 @@ class HttpDaemon(threading.Thread):
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.running = False
|
self.running = False
|
||||||
if os.name != 'nt':
|
if os.name != 'nt':
|
||||||
value = hasattr(socket, 'SHUT_RDWR') and socket.SHUT_RDWR or 2
|
self.server.socket.shutdown( hasattr(socket, 'SHUT_RDWR') and socket.SHUT_RDWR or 2 )
|
||||||
if self.secure:
|
|
||||||
self.server.socket.sock_shutdown(value)
|
|
||||||
else:
|
|
||||||
self.server.socket.shutdown(value)
|
|
||||||
self.server.socket.close()
|
self.server.socket.close()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
# -*- encoding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
|
||||||
# $Id$
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
"""
|
|
||||||
SecureXMLRPCServer module using pyOpenSSL 0.5
|
|
||||||
Extremely kludgey code written 0907.2002
|
|
||||||
by Michal Wallace ( http://www.sabren.net/ )
|
|
||||||
|
|
||||||
This acts as a drop-in replacement for
|
|
||||||
SimpleXMLRPCServer from the standard python
|
|
||||||
library.
|
|
||||||
|
|
||||||
This code is in the public domain and is
|
|
||||||
provided AS-IS WITH NO WARRANTY WHATSOEVER.
|
|
||||||
"""
|
|
||||||
import SocketServer
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import SimpleXMLRPCServer
|
|
||||||
from OpenSSL import SSL
|
|
||||||
|
|
||||||
|
|
||||||
class SSLBugFix:
|
|
||||||
"""
|
|
||||||
SSL Connection tends to die on sendall,
|
|
||||||
so I use send() as a workaround. This is
|
|
||||||
called by socket._fileobject, which is needed
|
|
||||||
so SocketServer (and kids) can treat the connection
|
|
||||||
as a regular file.
|
|
||||||
"""
|
|
||||||
def __init__(self, conn):
|
|
||||||
"""
|
|
||||||
For some reason, I can't subclass Connection,
|
|
||||||
so I'm making a proxy, instead.
|
|
||||||
"""
|
|
||||||
self.__dict__["conn"] = conn
|
|
||||||
def __getattr__(self,name):
|
|
||||||
return getattr(self.__dict__["conn"], name)
|
|
||||||
def __setattr__(self,name, value):
|
|
||||||
setattr(self.__dict__["conn"], name, value)
|
|
||||||
|
|
||||||
|
|
||||||
# def sendall(self, data):
|
|
||||||
# """
|
|
||||||
# This is the bugfix. Connection.sendall() segfaults
|
|
||||||
# on socket._fileobject.flush(), so just rewire it
|
|
||||||
# to use send() instead.
|
|
||||||
# """
|
|
||||||
# self.__dict__["conn"].send(data)
|
|
||||||
|
|
||||||
def shutdown(self, how=1):
|
|
||||||
"""
|
|
||||||
This isn't part of the bugfix. SimpleXMLRpcServer.doPOST
|
|
||||||
calls shutdown(1), and Connection.shutdown() doesn't take
|
|
||||||
an argument. So we just discard it:
|
|
||||||
"""
|
|
||||||
self.__dict__["conn"].shutdown()
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
"""
|
|
||||||
This is the other part of the shutdown() workaround.
|
|
||||||
Since servers create new sockets, we have to infect
|
|
||||||
them with our magic. :)
|
|
||||||
"""
|
|
||||||
c, a = self.__dict__["conn"].accept()
|
|
||||||
return (SSLBugFix(c), a)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SecureTCPServer(SocketServer.TCPServer):
|
|
||||||
"""
|
|
||||||
Just like TCPServer, but use a socket.
|
|
||||||
This really ought to let you specify the key and certificate files.
|
|
||||||
"""
|
|
||||||
def __init__(self, server_address, RequestHandlerClass):
|
|
||||||
SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass)
|
|
||||||
|
|
||||||
## Same as normal, but make it secure:
|
|
||||||
ctx = SSL.Context(SSL.SSLv23_METHOD)
|
|
||||||
ctx.set_options(SSL.OP_NO_SSLv2)
|
|
||||||
|
|
||||||
dir = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]))
|
|
||||||
ctx.use_privatekey_file (os.path.join(dir, 'server.pkey'))
|
|
||||||
ctx.use_certificate_file(os.path.join(dir, 'server.cert'))
|
|
||||||
|
|
||||||
self.socket = SSLBugFix(SSL.Connection(ctx, socket.socket(self.address_family,
|
|
||||||
self.socket_type)))
|
|
||||||
self.server_bind()
|
|
||||||
self.server_activate()
|
|
||||||
|
|
||||||
|
|
||||||
class SecureXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
|
|
||||||
def setup(self):
|
|
||||||
"""
|
|
||||||
We need to use socket._fileobject Because SSL.Connection
|
|
||||||
doesn't have a 'dup'. Not exactly sure WHY this is, but
|
|
||||||
this is backed up by comments in socket.py and SSL/connection.c
|
|
||||||
"""
|
|
||||||
self.connection = self.request # for doPOST
|
|
||||||
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
|
|
||||||
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
|
|
||||||
|
|
||||||
|
|
||||||
class SecureXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer, SecureTCPServer):
|
|
||||||
def __init__(self, addr,
|
|
||||||
requestHandler=SecureXMLRPCRequestHandler,
|
|
||||||
logRequests=1):
|
|
||||||
"""
|
|
||||||
This is the exact same code as SimpleXMLRPCServer.__init__
|
|
||||||
except it calls SecureTCPServer.__init__ instead of plain
|
|
||||||
old TCPServer.__init__
|
|
||||||
"""
|
|
||||||
self.funcs = {}
|
|
||||||
self.logRequests = logRequests
|
|
||||||
self.instance = None
|
|
||||||
SecureTCPServer.__init__(self, addr, requestHandler)
|
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
# -*- encoding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
|
||||||
# $Id$
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
|
|
||||||
import SecureXMLRPCServer
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIICNDCCAZ0CAQEwDQYJKoZIhvcNAQEEBQAweTEQMA4GA1UEChMHVGlueUVSUDEM
|
|
||||||
MAoGA1UECxMDRVJQMRkwFwYJKoZIhvcNAQkBFgpmcEB0aW55LmJlMRAwDgYDVQQH
|
|
||||||
EwdXYWxoYWluMQswCQYDVQQIEwJCVzELMAkGA1UEBhMCQkUxEDAOBgNVBAMTB1Rp
|
|
||||||
bnlFUlAwHhcNMDYwNTI0MDgzODUxWhcNMDcwNTI0MDgzODUxWjBMMQswCQYDVQQG
|
|
||||||
EwJCRTELMAkGA1UECBMCQlcxEDAOBgNVBAoTB1RpbnlFUlAxDDAKBgNVBAsTA0VS
|
|
||||||
UDEQMA4GA1UEAxMHVGlueUVSUDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
|
|
||||||
xzIDlU2PrczPsgXtxCskYxuwMPgNCNSCBfWsUZ9nJzlZfRAEXEq4LxaTPIgkzkIF
|
|
||||||
82bmJLgFz6/CyCFid4mkBLQBj30Opp2Vco39WRncNKHKxbk+/wZpZtQ0bSpvf+F4
|
|
||||||
MBqCLldYIqsoyenombVCb8X62IUu0ENF1wR22owvyKcCAwEAATANBgkqhkiG9w0B
|
|
||||||
AQQFAAOBgQB2yUqJ3gbQ8I6rcmaVJlcLDHfC5w1Jr1cUzcJevOPh3wygSZYYoUoe
|
|
||||||
yeYlzEag/DpPSHyRiJJVOKdiwU0yfmZPhfDNtDiBr47bz8qzIsYq5VeMmSeXrq/f
|
|
||||||
AA3iI4xE8YFzJHWtiBCqqyUok+j9pVad7iV7+UVIePHZLEkGGWIjDA==
|
|
||||||
-----END CERTIFICATE-----
|
|
|
@ -1,15 +0,0 @@
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIICXAIBAAKBgQDHMgOVTY+tzM+yBe3EKyRjG7Aw+A0I1IIF9axRn2cnOVl9EARc
|
|
||||||
SrgvFpM8iCTOQgXzZuYkuAXPr8LIIWJ3iaQEtAGPfQ6mnZVyjf1ZGdw0ocrFuT7/
|
|
||||||
Bmlm1DRtKm9/4XgwGoIuV1giqyjJ6eiZtUJvxfrYhS7QQ0XXBHbajC/IpwIDAQAB
|
|
||||||
AoGAVwAxMHS/3FkoHckZICT3r5HYUosEpmaqo4+5w6yrkSYrP8RPI0A/UdG6XSXZ
|
|
||||||
bXzIvJakzkTRxPQvTtnF+A/V4rF9hxwB8cGXSywv5eDGmZ91qIsxY7Sv99VqSKNH
|
|
||||||
dNr9aZHloTvI51e/oramIJ/O3A+TbAS5i+u1DJC2IIFJcAECQQD8iRPTlPIqzjYD
|
|
||||||
Lg7KYGvwW9TE4ONAhC86kJbzV5o3amlV5duJgnkl/mNlfN1ihA7f3Gx9dfCjfRKp
|
|
||||||
V1rcjtCBAkEAye2aMw2v1m+MEqcPxyTUzVf5Y8BIXWbk15T43czXec9YclZSOBCX
|
|
||||||
Dgv4a3Fk+yxQUE0cZUH0U4FJq6mTgpuFJwJASFqZ9KATNlJ4xTZ4BGHV6zrUXkg0
|
|
||||||
tDJrObNdnID37XKulW7TFLXuMgWNwvEgmO5POLJ13whglubp5tzhapn8gQJAJz9Z
|
|
||||||
U0b7wFAaB54VAP31ppvMy0iaSB0xqX05CdNAplpYtJB2lpMS6RYGiMuXdwJb8d+q
|
|
||||||
/ztcg8aDTSw+kYoszQJBAPBrt694VkGT1k9Be6e5wyVDrE05bkHhFxPk/HMeWMDX
|
|
||||||
sZqHPs9vVaLBqu/uU84FdwRMOV71RG90g6eUEl7HWsg=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
Loading…
Reference in New Issue