[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Added HTTPS support to Xend. There are new configuration options for the
# HG changeset patch # User Ewan Mellor <ewan@xxxxxxxxxxxxx> # Date 1175034181 -3600 # Node ID 966c65f0ddba39d45c34480a9395d828028cda26 # Parent 94b873fb033a3ba7b7f991d389bce8caa49d43e9 Added HTTPS support to Xend. There are new configuration options for the Xen-API and legacy XML-RPC servers to set key and certificate files, and xm simply needs to be configured use an https rather than an http URL. Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx> --- tools/examples/xend-config.sxp | 14 +++ tools/python/xen/util/xmlrpcclient.py | 30 ++++++ tools/python/xen/xend/XendOptions.py | 8 + tools/python/xen/xend/server/SSLXMLRPCServer.py | 103 ++++++++++++++++++++++++ tools/python/xen/xend/server/SrvServer.py | 83 ++++++++++++------- tools/python/xen/xend/server/XMLRPCServer.py | 51 ++++++++++- 6 files changed, 249 insertions(+), 40 deletions(-) diff -r 94b873fb033a -r 966c65f0ddba tools/examples/xend-config.sxp --- a/tools/examples/xend-config.sxp Tue Mar 27 23:03:32 2007 +0100 +++ b/tools/examples/xend-config.sxp Tue Mar 27 23:23:01 2007 +0100 @@ -46,6 +46,11 @@ # (xen-api-server ((9363 pam '^localhost$ example\\.com$') # (unix none))) # +# Optionally, the TCP Xen-API server can use SSL by specifying the private +# key and certificate location: +# +# (9367 pam '' /etc/xen/xen-api.key /etc/xen/xen-api.crt) +# # Default: # (xen-api-server ((unix))) @@ -59,10 +64,17 @@ #(xend-unix-path /var/lib/xend/xend-socket) -# Address and port xend should use for the TCP XMLRPC interface, + +# Address and port xend should use for the legacy TCP XMLRPC interface, # if xen-tcp-xmlrpc-server is set. #(xen-tcp-xmlrpc-server-address 'localhost') #(xen-tcp-xmlrpc-server-port 8006) + +# SSL key and certificate to use for the legacy TCP XMLRPC interface. +# Setting these will mean that this port serves only SSL connections as +# opposed to plaintext ones. +#(xend-tcp-xmlrpc-server-ssl-key-file /etc/xen/xmlrpc.key) +#(xend-tcp-xmlrpc-server-ssl-cert-file /etc/xen/xmlrpc.crt) # Port xend should use for the HTTP interface, if xend-http-server is set. diff -r 94b873fb033a -r 966c65f0ddba tools/python/xen/util/xmlrpcclient.py --- a/tools/python/xen/util/xmlrpcclient.py Tue Mar 27 23:03:32 2007 +0100 +++ b/tools/python/xen/util/xmlrpcclient.py Tue Mar 27 23:23:01 2007 +0100 @@ -30,7 +30,6 @@ except ImportError: # SSHTransport is disabled on Python <2.4, because it uses the subprocess # package. ssh_enabled = False - # A new ServerProxy that also supports httpu urls. An http URL comes in the @@ -57,6 +56,33 @@ class UnixTransport(xmlrpclib.Transport) return HTTPUnix(self.__handler) +# We need our own transport for HTTPS, because xmlrpclib.SafeTransport is +# broken -- it does not handle ERROR_ZERO_RETURN properly. +class HTTPSTransport(xmlrpclib.SafeTransport): + def _parse_response(self, file, sock): + p, u = self.getparser() + while 1: + try: + if sock: + response = sock.recv(1024) + else: + response = file.read(1024) + except socket.sslerror, exn: + if exn[0] == socket.SSL_ERROR_ZERO_RETURN: + break + raise + + if not response: + break + if self.verbose: + print 'body:', repr(response) + p.feed(response) + + file.close() + p.close() + return u.close() + + # See xmlrpclib2.TCPXMLRPCServer._marshalled_dispatch. def conv_string(x): if isinstance(x, StringTypes): @@ -75,6 +101,8 @@ class ServerProxy(xmlrpclib.ServerProxy) if protocol == 'httpu': uri = 'http:' + rest transport = UnixTransport() + elif protocol == 'https': + transport = HTTPSTransport() elif protocol == 'ssh': global ssh_enabled if ssh_enabled: diff -r 94b873fb033a -r 966c65f0ddba tools/python/xen/xend/XendOptions.py --- a/tools/python/xen/xend/XendOptions.py Tue Mar 27 23:03:32 2007 +0100 +++ b/tools/python/xen/xend/XendOptions.py Tue Mar 27 23:23:01 2007 +0100 @@ -165,7 +165,13 @@ class XendOptions: def get_xend_tcp_xmlrpc_server_address(self): return self.get_config_string("xend-tcp-xmlrpc-server-address", - self.xend_tcp_xmlrpc_server_address_default) + self.xend_tcp_xmlrpc_server_address_default) + + def get_xend_tcp_xmlrpc_server_ssl_key_file(self): + return self.get_config_string("xend-tcp-xmlrpc-server-ssl-key-file") + + def get_xend_tcp_xmlrpc_server_ssl_cert_file(self): + return self.get_config_string("xend-tcp-xmlrpc-server-ssl-cert-file") def get_xend_unix_xmlrpc_server(self): return self.get_config_bool("xend-unix-xmlrpc-server", diff -r 94b873fb033a -r 966c65f0ddba tools/python/xen/xend/server/SSLXMLRPCServer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xend/server/SSLXMLRPCServer.py Tue Mar 27 23:23:01 2007 +0100 @@ -0,0 +1,103 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2007 XenSource Inc. +#============================================================================ + + +""" +HTTPS wrapper for an XML-RPC server interface. Requires PyOpenSSL (Debian +package python-pyopenssl). +""" + +import socket + +from OpenSSL import SSL + +from xen.util.xmlrpclib2 import XMLRPCRequestHandler, TCPXMLRPCServer + + +class SSLXMLRPCRequestHandler(XMLRPCRequestHandler): + def setup(self): + self.connection = self.request + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + +# +# Taken from pyOpenSSL-0.6 examples (public-domain) +# + +class SSLWrapper: + """ + """ + def __init__(self, conn): + """ + Connection is not yet a new-style class, + so I'm making a proxy instead of subclassing. + """ + 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 close(self): + self.shutdown() + return self.__dict__["conn"].close() + + def shutdown(self, how=1): + """ + SimpleXMLRpcServer.doPOST calls shutdown(1), + and Connection.shutdown() doesn't take + an argument. So we just discard the argument. + """ + # Block until the shutdown is complete + self.__dict__["conn"].shutdown() + 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 (SSLWrapper(c), a) + +# +# End of pyOpenSSL-0.6 example code. +# + +class SSLXMLRPCServer(TCPXMLRPCServer): + def __init__(self, addr, allowed, xenapi, logRequests = 1, + ssl_key_file = None, ssl_cert_file = None): + + TCPXMLRPCServer.__init__(self, addr, allowed, xenapi, + SSLXMLRPCRequestHandler, logRequests) + + if not ssl_key_file or not ssl_cert_file: + raise ValueError("SSLXMLRPCServer requires ssl_key_file " + "and ssl_cert_file to be set.") + + # make a SSL socket + ctx = SSL.Context(SSL.SSLv23_METHOD) + ctx.set_options(SSL.OP_NO_SSLv2) + ctx.use_privatekey_file (ssl_key_file) + ctx.use_certificate_file(ssl_cert_file) + self.socket = SSLWrapper(SSL.Connection(ctx, + socket.socket(self.address_family, + self.socket_type))) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.server_bind() + self.server_activate() diff -r 94b873fb033a -r 966c65f0ddba tools/python/xen/xend/server/SrvServer.py --- a/tools/python/xen/xend/server/SrvServer.py Tue Mar 27 23:03:32 2007 +0100 +++ b/tools/python/xen/xend/server/SrvServer.py Tue Mar 27 23:23:01 2007 +0100 @@ -185,33 +185,49 @@ def _loadConfig(servers, root, reload): api_cfg = xoptions.get_xen_api_server() if api_cfg: try: - addrs = [(str(x[0]).split(':'), - len(x) > 1 and x[1] or XendAPI.AUTH_PAM, - len(x) > 2 and x[2] and map(re.compile, x[2].split(" ")) - or None) - for x in api_cfg] - for addrport, auth, allowed in addrs: - if auth not in [XendAPI.AUTH_PAM, XendAPI.AUTH_NONE]: - log.error('Xen-API server configuration %s is invalid, ' + - 'as %s is not a valid authentication type.', - api_cfg, auth) - break - - if len(addrport) == 1: - if addrport[0] == 'unix': - servers.add(XMLRPCServer(auth, True, - path = XEN_API_SOCKET, - hosts_allowed = allowed)) - else: - servers.add( - XMLRPCServer(auth, True, True, '', - int(addrport[0]), - hosts_allowed = allowed)) - else: - addr, port = addrport - servers.add(XMLRPCServer(auth, True, True, addr, - int(port), - hosts_allowed = allowed)) + for server_cfg in api_cfg: + # Parse the xen-api-server config + + host = 'localhost' + port = 0 + use_tcp = False + ssl_key_file = None + ssl_cert_file = None + auth_method = XendAPI.AUTH_NONE + hosts_allowed = None + + host_addr = server_cfg[0].split(':', 1) + if len(host_addr) == 1 and host_addr[0].lower() == 'unix': + use_tcp = False + elif len(host_addr) == 1: + use_tcp = True + port = int(host_addr[0]) + elif len(host_addr) == 2: + use_tcp = True + host = str(host_addr[0]) + port = int(host_addr[1]) + + if len(server_cfg) > 1: + if server_cfg[1] in [XendAPI.AUTH_PAM, XendAPI.AUTH_NONE]: + auth_method = server_cfg[1] + + if len(server_cfg) > 2: + hosts_allowed = server_cfg[2] or None + + + if len(server_cfg) > 4: + # SSL key and cert file + ssl_key_file = server_cfg[3] + ssl_cert_file = server_cfg[4] + + + servers.add(XMLRPCServer(auth_method, True, use_tcp = use_tcp, + ssl_key_file = ssl_key_file, + ssl_cert_file = ssl_cert_file, + host = host, port = port, + path = XEN_API_SOCKET, + hosts_allowed = hosts_allowed)) + except (ValueError, TypeError), exn: log.exception('Xen API Server init failed') log.error('Xen-API server configuration %s is invalid.', api_cfg) @@ -219,8 +235,17 @@ def _loadConfig(servers, root, reload): if xoptions.get_xend_tcp_xmlrpc_server(): addr = xoptions.get_xend_tcp_xmlrpc_server_address() port = xoptions.get_xend_tcp_xmlrpc_server_port() - servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, use_tcp = True, - host = addr, port = port)) + ssl_key_file = xoptions.get_xend_tcp_xmlrpc_server_ssl_key_file() + ssl_cert_file = xoptions.get_xend_tcp_xmlrpc_server_ssl_cert_file() + + if ssl_key_file and ssl_cert_file: + servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, use_tcp = True, + ssl_key_file = ssl_key_file, + ssl_cert_file = ssl_cert_file, + host = addr, port = port)) + else: + servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False, use_tcp = True, + host = addr, port = port)) if xoptions.get_xend_unix_xmlrpc_server(): servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False)) diff -r 94b873fb033a -r 966c65f0ddba tools/python/xen/xend/server/XMLRPCServer.py --- a/tools/python/xen/xend/server/XMLRPCServer.py Tue Mar 27 23:03:32 2007 +0100 +++ b/tools/python/xen/xend/server/XMLRPCServer.py Tue Mar 27 23:23:01 2007 +0100 @@ -21,6 +21,11 @@ import types import types import xmlrpclib from xen.util.xmlrpclib2 import UnixXMLRPCServer, TCPXMLRPCServer +try: + from SSLXMLRPCServer import SSLXMLRPCServer + ssl_enabled = True +except ImportError: + ssl_enabled = False from xen.xend import XendAPI, XendDomain, XendDomainInfo, XendNode from xen.xend import XendLogging, XendDmesg @@ -87,14 +92,20 @@ exclude = ['domain_create', 'domain_rest exclude = ['domain_create', 'domain_restore'] class XMLRPCServer: - def __init__(self, auth, use_xenapi, use_tcp=False, host = "localhost", - port = 8006, path = XML_RPC_SOCKET, hosts_allowed = None): + def __init__(self, auth, use_xenapi, use_tcp = False, + ssl_key_file = None, ssl_cert_file = None, + host = "localhost", port = 8006, path = XML_RPC_SOCKET, + hosts_allowed = None): + self.use_tcp = use_tcp self.port = port self.host = host self.path = path self.hosts_allowed = hosts_allowed + self.ssl_key_file = ssl_key_file + self.ssl_cert_file = ssl_cert_file + self.ready = False self.running = True self.auth = auth @@ -107,14 +118,33 @@ class XMLRPCServer: try: if self.use_tcp: - log.info("Opening TCP XML-RPC server on %s%d%s", + using_ssl = self.ssl_key_file and self.ssl_cert_file + + log.info("Opening %s XML-RPC server on %s%d%s", + using_ssl and 'HTTPS' or 'TCP', self.host and '%s:' % self.host or 'all interfaces, port ', self.port, authmsg) - self.server = TCPXMLRPCServer((self.host, self.port), - self.hosts_allowed, - self.xenapi is not None, - logRequests = False) + + if not ssl_enabled: + raise ValueError("pyOpenSSL not installed. " + "Unable to start HTTPS XML-RPC server") + + if using_ssl: + self.server = SSLXMLRPCServer( + (self.host, self.port), + self.hosts_allowed, + self.xenapi is not None, + logRequests = False, + ssl_key_file = self.ssl_key_file, + ssl_cert_file = self.ssl_cert_file) + else: + self.server = TCPXMLRPCServer( + (self.host, self.port), + self.hosts_allowed, + self.xenapi is not None, + logRequests = False) + else: log.info("Opening Unix domain socket XML-RPC server on %s%s", self.path, authmsg) @@ -126,7 +156,12 @@ class XMLRPCServer: ready = True running = False return - + except Exception, e: + log.exception('Cannot start server: %s!', e) + ready = True + running = False + return + # Register Xen API Functions # ------------------------------------------------------------------- # exportable functions are ones that do not begin with '_' _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |