Piotr Kliczewski has uploaded a new change for review. Change subject: ssl: configurable implementation ......................................................................
ssl: configurable implementation We want to choose ssl implementation during build process. Change-Id: I6501981bbd5276c49731b0d9eba4794286b0f823 Signed-off-by: pkliczewski <[email protected]> --- M debian/vdsm-python.install M lib/vdsm/Makefile.am M lib/vdsm/jsonrpcvdscli.py A lib/vdsm/sslutils.py M lib/vdsm/utils.py M lib/vdsm/vdscli.py M lib/yajsonrpc/stompreactor.py M tests/crossImportsTests.py.in M tests/integration/Makefile.am M tests/integration/jsonRpcHelper.py M tests/integration/m2chelper.py A tests/integration/sslhelper.py M tests/protocoldetectorTests.py M tests/sslTests.py M tests/stompTests.py M tests/vdscliTests.py M vdsm.spec.in M vdsm/clientIF.py M vdsm/kaxmlrpclib.py M vdsm/protocoldetector.py M vdsm/virt/migration.py 21 files changed, 562 insertions(+), 88 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/94/44494/1 diff --git a/debian/vdsm-python.install b/debian/vdsm-python.install index 36c0d9f..d9402c3 100644 --- a/debian/vdsm-python.install +++ b/debian/vdsm-python.install @@ -12,7 +12,6 @@ ./usr/lib/python2.7/dist-packages/vdsm/ipwrapper.py ./usr/lib/python2.7/dist-packages/vdsm/jsonrpcvdscli.py ./usr/lib/python2.7/dist-packages/vdsm/libvirtconnection.py -./usr/lib/python2.7/dist-packages/vdsm/m2cutils.py ./usr/lib/python2.7/dist-packages/vdsm/netconfpersistence.py ./usr/lib/python2.7/dist-packages/vdsm/netinfo.py ./usr/lib/python2.7/dist-packages/vdsm/netlink/__init__.py @@ -30,6 +29,7 @@ ./usr/lib/python2.7/dist-packages/vdsm/qemuimg.py ./usr/lib/python2.7/dist-packages/vdsm/response.py ./usr/lib/python2.7/dist-packages/vdsm/schedule.py +./usr/lib/python2.7/dist-packages/vdsm/sslutils.py ./usr/lib/python2.7/dist-packages/vdsm/tool/__init__.py ./usr/lib/python2.7/dist-packages/vdsm/tool/dummybr.py ./usr/lib/python2.7/dist-packages/vdsm/tool/dump_bonding_defaults.py diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am index ec1a140..4a2bcb1 100644 --- a/lib/vdsm/Makefile.am +++ b/lib/vdsm/Makefile.am @@ -40,6 +40,7 @@ qemuimg.py \ response.py \ schedule.py \ + sslutils.py \ sysctl.py \ udevadm.py \ utils.py \ diff --git a/lib/vdsm/jsonrpcvdscli.py b/lib/vdsm/jsonrpcvdscli.py index 1687b6f..391d79e 100644 --- a/lib/vdsm/jsonrpcvdscli.py +++ b/lib/vdsm/jsonrpcvdscli.py @@ -22,7 +22,6 @@ from uuid import uuid4 import socket -from . import m2cutils from yajsonrpc import stompreactor from yajsonrpc import \ JsonRpcRequest, \ @@ -30,6 +29,10 @@ from vdsm import response from .config import config +try: + from . import m2cutils as sslutils +except ImportError: + from . import sslutils _COMMAND_CONVERTER = { diff --git a/lib/vdsm/sslutils.py b/lib/vdsm/sslutils.py new file mode 100644 index 0000000..63fc9cc --- /dev/null +++ b/lib/vdsm/sslutils.py @@ -0,0 +1,302 @@ +# +# Copyright 2014 Red Hat, Inc. +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# +from __future__ import absolute_import +import httplib +import logging +import os +import socket +import ssl +import xmlrpclib + +from vdsm.utils import ( + monotonic_time, +) +from .config import config + + +DEFAULT_ACCEPT_TIMEOUT = 5 +SOCKET_DEFAULT_TIMEOUT = socket._GLOBAL_DEFAULT_TIMEOUT + + +class SSLSocket(object): + def __init__(self, sock): + self.sock = sock + self._data = '' + + # ssl do not accept flag other than 0 + def read(self, size=4096, flag=None): + result = None + if flag == socket.MSG_PEEK: + bytes_left = size - len(self._data) + if bytes_left > 0: + self._data += self.sock.read(bytes_left) + result = self._data + else: + if self._data: + result = self._data + self._data = '' + else: + result = self.sock.read(size) + return result + recv = read + + def pending(self): + pending = self.sock.pending() + if self._data: + pending = pending + len(self._data) + return pending + + def __getattr__(self, name): + return getattr(self.sock, name) + + def makefile(self, mode='rb', bufsize=-1): + if mode == 'rb': + return socket._fileobject(self, mode, bufsize) + else: + return self.sock.makefile(mode, bufsize) + + +class SSLContext(object): + def __init__(self, cert_file, key_file, ca_certs=None, + protocol=ssl.PROTOCOL_TLSv1): + self.cert_file = cert_file + self.key_file = key_file + self.ca_certs = ca_certs + self.protocol = protocol + + +class VerifyingHTTPSConnection(httplib.HTTPSConnection): + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=SOCKET_DEFAULT_TIMEOUT, + ca_certs=None, cert_reqs=ssl.CERT_REQUIRED): + httplib.HTTPSConnection.__init__(self, host, port, key_file, cert_file, + strict, timeout) + self.ca_certs = ca_certs + self.cert_reqs = cert_reqs + + def connect(self): + "Connect to a host on a given (SSL) port." + + sock = socket.create_connection((self.host, self.port), self.timeout) + if self._tunnel_host: + self.sock = sock + self._tunnel() + # DK added: pass ca_cert to sslsocket + self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, + ca_certs=self.ca_certs, server_side=False, + cert_reqs=self.cert_reqs) + + +class VerifyingSafeTransport(xmlrpclib.SafeTransport): + def __init__(self, use_datetime=0, key_file=None, cert_file=None, + ca_certs=None, cert_reqs=ssl.CERT_REQUIRED, + timeout=SOCKET_DEFAULT_TIMEOUT): + xmlrpclib.SafeTransport.__init__(self, use_datetime) + self.key_file = key_file + self.cert_file = cert_file + self.ca_certs = ca_certs + self.cert_reqs = cert_reqs + self._timeout = timeout + + def make_connection(self, host): + """Return VerifyingHTTPS object that is aware of ca_certs, and will + create VerifyingHTTPSConnection. + In Python 2.7, return VerifyingHTTPSConnection object + """ + chost, self._extra_headers, x509 = self.get_host_info(host) + if hasattr(xmlrpclib.SafeTransport, "single_request"): # Python 2.7 + return VerifyingHTTPSConnection( + chost, None, key_file=self.key_file, strict=None, + cert_file=self.cert_file, timeout=self._timeout, + ca_certs=self.ca_certs, + cert_reqs=self.cert_reqs) + else: + return VerifyingHTTPS( + chost, None, key_file=self.key_file, + cert_file=self.cert_file, timeout=self._timeout, + ca_certs=self.ca_certs, + cert_reqs=self.cert_reqs) + + +class VerifyingHTTPS(httplib.HTTPS): + _connection_class = VerifyingHTTPSConnection + + def __init__(self, host='', port=None, key_file=None, cert_file=None, + strict=None, timeout=SOCKET_DEFAULT_TIMEOUT, + ca_certs=None, cert_reqs=ssl.CERT_REQUIRED): + """A ca_cert-aware HTTPS object, + that creates a VerifyingHTTPSConnection + """ + # provide a default host, pass the X509 cert info + + # urf. compensate for bad input. + if port == 0: + port = None + self._setup(self._connection_class(host=host, + port=port, + key_file=key_file, + cert_file=cert_file, + strict=strict, + timeout=timeout, + ca_certs=ca_certs, + cert_reqs=cert_reqs)) + + # we never actually use these for anything, but we keep them + # here for compatibility with post-1.5.2 CVS. + self.key_file = key_file + self.cert_file = cert_file + + +class SSLHandshakeDispatcher(object): + """ + SSLHandshakeDispatcher is dispatcher implementation to process ssl + handshake in asynchronous way. Once we are done with handshaking we + we need to swap our dispatcher implementation with message processing + dispatcher. We use handshake_finished_handler function to perform + swapping. The handler implementation need to invoke + + dispatcher.switch_implementation() + + where we provide message processing dispatcher as parameter. + """ + log = logging.getLogger("ProtocolDetector.SSLHandshakeDispatcher") + SSL_HANDSHAKE_TIMEOUT = 10 + + def __init__( + self, + sslinfo, + handshake_finished_handler, + handshake_timeout=SSL_HANDSHAKE_TIMEOUT, + ): + self._give_up_at = monotonic_time() + handshake_timeout + self._has_been_set_up = False + self._is_handshaking = True + self.want_read = True + self.want_write = True + self._sslinfo = sslinfo + self._handshake_finished_handler = handshake_finished_handler + + def _set_up_socket(self, dispatcher): + client_socket = dispatcher.socket + client_socket = SSLSocket( + ssl.wrap_socket(client_socket, + keyfile=self._sslinfo.key_file, + certfile=self._sslinfo.cert_file, + server_side=True, + cert_reqs=ssl.CERT_REQUIRED, + ssl_version=self._sslinfo.protocol, + ca_certs=self._sslinfo.ca_certs, + do_handshake_on_connect=False)) + + dispatcher.socket = client_socket + self._has_been_set_up = True + + def next_check_interval(self): + return max(self._give_up_at - monotonic_time(), 0) + + def readable(self, dispatcher): + if self.has_expired(): + dispatcher.close() + return False + + return self.want_read + + def writable(self, dispatcher): + if self.has_expired(): + dispatcher.close() + return False + + return self.want_write + + def has_expired(self): + return monotonic_time() >= self._give_up_at + + def handle_read(self, dispatcher): + self._handle_io(dispatcher) + + def handle_write(self, dispatcher): + self._handle_io(dispatcher) + + def _handle_io(self, dispatcher): + if not self._has_been_set_up: + self._set_up_socket(dispatcher) + + if self._is_handshaking: + self._handshake(dispatcher) + else: + if not self._verify_host(dispatcher.socket.getpeercert(), + dispatcher.socket.getpeername()[0]): + self.log.error("peer certificate does not match host name") + dispatcher.socket.close() + return + + self._handshake_finished_handler(dispatcher) + + def _verify_host(self, peercert, addr): + if not peercert: + return False + + for sub in peercert.get("subject", ()): + for key, value in sub: + if key == "commonName": + return self._compare_names(addr, value) + + return False + + def _compare_names(self, addr, name): + if addr == name or addr == '127.0.0.1': + return True + else: + return name.lower() == socket.gethostbyaddr(addr)[0].lower() + + def _handshake(self, dispatcher): + try: + dispatcher.socket.do_handshake() + except ssl.SSLError as err: + self.want_read = self.want_write = False + if err.args[0] == ssl.SSL_ERROR_WANT_READ: + self.want_read = True + elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: + self.want_write = True + else: + dispatcher.close() + raise + else: + self.want_read = self.want_write = True + self._is_handshaking = False + + +def create_ssl_context(): + sslinfo = None + if config.getboolean('vars', 'ssl'): + truststore_path = config.get('vars', 'trust_store_path') + protocol = ( + ssl.PROTOCOL_SSLv23 + if config.get('vars', 'ssl_protocol') == 'sslv23' + else ssl.PROTOCOL_TLSv1 + ) + sslinfo = SSLContext( + key_file=os.path.join(truststore_path, 'keys', 'vdsmkey.pem'), + cert_file=os.path.join(truststore_path, 'certs', + 'vdsmcert.pem'), + ca_certs=os.path.join(truststore_path, 'certs', 'cacert.pem'), + protocol=protocol + ) + return sslinfo diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py index d847a23..b7818eb 100644 --- a/lib/vdsm/utils.py +++ b/lib/vdsm/utils.py @@ -54,11 +54,16 @@ import threading import time import vdsm.infra.zombiereaper as zombiereaper -from M2Crypto import SSL from cpopen import CPopen from . import cmdutils from . import constants +try: + from M2Crypto import SSL + _m2cEnabled = True +except ImportError: + import ssl + _m2cEnabled = False try: # If failing to import old code, then try importing the legacy code @@ -1251,11 +1256,18 @@ def create_connected_socket(host, port, sslctx=None, timeout=None): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if sslctx: - sock = SSL.Connection(sslctx.context) - else: - sock = socket.socket(socket.AF_INET, - socket.SOCK_STREAM) + if _m2cEnabled: + sock = SSL.Connection(sslctx.context) + else: + sock = ssl.wrap_socket(sock, + keyfile=sslctx.key_file, + certfile=sslctx.cert_file, + server_side=False, + cert_reqs=ssl.CERT_REQUIRED, + ssl_version=sslctx.protocol, + ca_certs=sslctx.ca_certs) sock.settimeout(timeout) sock.connect((host, port)) return sock diff --git a/lib/vdsm/vdscli.py b/lib/vdsm/vdscli.py index a78a67a..cf083e3 100644 --- a/lib/vdsm/vdscli.py +++ b/lib/vdsm/vdscli.py @@ -26,7 +26,10 @@ import re import sys from xml.parsers.expat import ExpatError -from . import m2cutils +try: + from . import m2cutils as sslutils +except ImportError: + from . import sslutils _USE_SSL = False @@ -60,7 +63,7 @@ self.timeout = kwargs['timeout'] del kwargs['timeout'] else: - self.timeout = m2cutils.SOCKET_DEFAULT_TIMEOUT + self.timeout = sslutils.SOCKET_DEFAULT_TIMEOUT xmlrpclib.Transport.__init__(self, *args, **kwargs) @@ -107,8 +110,8 @@ def connect(hostPort=None, useSSL=None, tsPath=None, - TransportClass=m2cutils.VerifyingSafeTransport, - timeout=m2cutils.SOCKET_DEFAULT_TIMEOUT): + TransportClass=sslutils.VerifyingSafeTransport, + timeout=sslutils.SOCKET_DEFAULT_TIMEOUT): hostPort = cannonizeHostPort(hostPort) if useSSL is None: diff --git a/lib/yajsonrpc/stompreactor.py b/lib/yajsonrpc/stompreactor.py index ee710f5..5dfa805 100644 --- a/lib/yajsonrpc/stompreactor.py +++ b/lib/yajsonrpc/stompreactor.py @@ -23,10 +23,14 @@ from vdsm import utils from vdsm.config import config from vdsm.compat import json -from vdsm.m2cutils import SSLSocket from . import JsonRpcClient, JsonRpcServer from . import stomp from .betterAsyncore import Dispatcher, Reactor +try: + from vdsm.m2cutils import SSLSocket +except ImportError: + from ssl import SSLSocket + _STATE_LEN = "Waiting for message length" _STATE_MSG = "Waiting for message" diff --git a/tests/crossImportsTests.py.in b/tests/crossImportsTests.py.in index a3e1d81..a997211 100644 --- a/tests/crossImportsTests.py.in +++ b/tests/crossImportsTests.py.in @@ -51,4 +51,7 @@ else: mods = get_mods(os.path.join(get_python_lib(), pkg_name)) + # ignore M2Crypto + mods.remove('m2cutils') + __import__(pkg_name, fromlist=mods) diff --git a/tests/integration/Makefile.am b/tests/integration/Makefile.am index 525ddd8..7fd327d 100644 --- a/tests/integration/Makefile.am +++ b/tests/integration/Makefile.am @@ -25,4 +25,5 @@ jsonRpcHelper.py \ jsonRpcTests.py \ m2chelper.py \ + sslhelper.py \ $(NULL) diff --git a/tests/integration/jsonRpcHelper.py b/tests/integration/jsonRpcHelper.py index 65ec5e3..fbb74c1 100644 --- a/tests/integration/jsonRpcHelper.py +++ b/tests/integration/jsonRpcHelper.py @@ -37,7 +37,10 @@ from protocoldetector import MultiProtocolAcceptor from rpc.bindingjsonrpc import BindingJsonRpc from vdsm import utils -from m2chelper import DEAFAULT_SSL_CONTEXT +try: + from integration.m2chelper import DEAFAULT_SSL_CONTEXT +except ImportError: + from integration.sslhelper import DEAFAULT_SSL_CONTEXT PERMUTATIONS = tuple(product((True, False), ("xml", "stomp"))) diff --git a/tests/integration/m2chelper.py b/tests/integration/m2chelper.py index 77a2767..7ece453 100644 --- a/tests/integration/m2chelper.py +++ b/tests/integration/m2chelper.py @@ -17,9 +17,11 @@ # # Refer to the README and COPYING files for full details of the license # - import os -from vdsm.m2cutils import SSLContext +import SimpleXMLRPCServer +import threading +from M2Crypto import SSL +from vdsm.m2cutils import SSLContext, SSLServerSocket CERT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), '..') CRT_FILE = os.path.join(CERT_DIR, "server.crt") @@ -29,3 +31,43 @@ DEAFAULT_SSL_CONTEXT = SSLContext( CRT_FILE, KEY_FILE, session_id="server-tests") + + +def get_server_socket(key_file, cert_file, socket): + return SSLServerSocket(raw=socket, + keyfile=key_file, + certfile=cert_file, + ca_certs=cert_file) + + +class TestServer(): + + def __init__(self, host, service): + self.server = SimpleXMLRPCServer.SimpleXMLRPCServer((host, 0), + logRequests=False) + self.server.socket = SSLServerSocket(raw=self.server.socket, + keyfile=KEY_FILE, + certfile=CRT_FILE, + ca_certs=CRT_FILE) + _, self.port = self.server.socket.getsockname() + self.server.register_instance(service) + + def start(self): + self.thread = threading.Thread(target=self.serve_forever) + self.thread.daemon = True + self.thread.start() + + def serve_forever(self): + try: + self.server.serve_forever() + except SSL.SSLError: + # expected sslerror is thrown in server side during test_invalid + # method we do not want to pollute test console output + pass + + def stop(self): + self.server.shutdown() + + def get_timeout(self): + self.server.socket.accept_timeout = 1 + return self.server.socket.accept_timeout + 1 diff --git a/tests/integration/sslhelper.py b/tests/integration/sslhelper.py new file mode 100644 index 0000000..acc2516 --- /dev/null +++ b/tests/integration/sslhelper.py @@ -0,0 +1,82 @@ +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# +import os +import SimpleXMLRPCServer +import ssl +import threading +from vdsm.sslutils import SSLContext + +CERT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), '..') +CRT_FILE = os.path.join(CERT_DIR, "server.crt") +KEY_FILE = os.path.join(CERT_DIR, "server.key") +OTHER_CRT_FILE = os.path.join(CERT_DIR, "other.crt") +OTHER_KEY_FILE = os.path.join(CERT_DIR, "other.key") + +DEAFAULT_SSL_CONTEXT = SSLContext(cert_file=CRT_FILE, key_file=KEY_FILE, + ca_certs=CRT_FILE) + + +def get_server_socket(key_file, cert_file, socket): + return ssl.wrap_socket(socket, + keyfile=key_file, + certfile=cert_file, + server_side=False, + cert_reqs=ssl.CERT_REQUIRED, + ssl_version=ssl.PROTOCOL_TLSv1, + ca_certs=cert_file) + + +class TestServer(SimpleXMLRPCServer.SimpleXMLRPCServer): + + def __init__(self, host, service): + SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, (host, 0), + logRequests=False, + bind_and_activate=False) + + self.socket = ssl.wrap_socket(self.socket, + keyfile=KEY_FILE, + certfile=CRT_FILE, + server_side=True, + cert_reqs=ssl.CERT_REQUIRED, + ssl_version=ssl.PROTOCOL_TLSv1, + ca_certs=CRT_FILE, + do_handshake_on_connect=False) + + self.server_bind() + self.server_activate() + + _, self.port = self.socket.getsockname() + self.register_instance(service) + + def finish_request(self, request, client_address): + if self.timeout is not None: + request.settimeout(self.timeout) + + request.do_handshake() + + return SimpleXMLRPCServer.SimpleXMLRPCServer.finish_request( + self, + request, + client_address) + + def handle_error(self, request, client_address): + # ignored due to expected sslerrors when perorming plain connection + pass + + def start(self): + self.thread = threading.Thread(target=self.serve_forever) + self.thread.daemon = True + self.thread.start() + + def stop(self): + self.shutdown() + + def get_timeout(self): + self.timeout = 1 + return self.timeout + 1 diff --git a/tests/protocoldetectorTests.py b/tests/protocoldetectorTests.py index f90eb43..927b44a 100644 --- a/tests/protocoldetectorTests.py +++ b/tests/protocoldetectorTests.py @@ -26,10 +26,12 @@ from contextlib import contextmanager from yajsonrpc.betterAsyncore import Reactor -from vdsm import m2cutils from protocoldetector import MultiProtocolAcceptor -from integration.m2chelper import KEY_FILE, CRT_FILE from testlib import VdsmTestCase, expandPermutations, permutations +try: + from integration.m2chelper import KEY_FILE, CRT_FILE, DEAFAULT_SSL_CONTEXT +except: + from integration.sslhelper import KEY_FILE, CRT_FILE, DEAFAULT_SSL_CONTEXT class Detector(object): @@ -97,7 +99,7 @@ GRACETIME = 0.5 CONCURRENCY = 5 PERMUTATIONS = ((False,), (True,)) - SSLCTX = m2cutils.SSLContext(CRT_FILE, KEY_FILE, ca_cert=CRT_FILE) + SSLCTX = DEAFAULT_SSL_CONTEXT BUFSIZE = 512 def setUp(self): diff --git a/tests/sslTests.py b/tests/sslTests.py index b40f263..b7a4bfb 100644 --- a/tests/sslTests.py +++ b/tests/sslTests.py @@ -22,7 +22,6 @@ import errno import os import re -import SimpleXMLRPCServer import socket import ssl import subprocess @@ -31,12 +30,21 @@ import xmlrpclib from contextlib import contextmanager, closing -from M2Crypto import SSL -from integration.m2chelper import KEY_FILE, \ - CRT_FILE, OTHER_KEY_FILE, OTHER_CRT_FILE from testlib import VdsmTestCase as TestCaseBase -from vdsm.m2cutils import SSLServerSocket -from vdsm.m2cutils import VerifyingSafeTransport +from nose.plugins.skip import SkipTest +try: + from vdsm.m2cutils import VerifyingSafeTransport + from integration.m2chelper import TestServer, \ + get_server_socket, KEY_FILE, \ + CRT_FILE, OTHER_KEY_FILE, OTHER_CRT_FILE + _m2cEnabled = True +except ImportError: + from vdsm.sslutils import VerifyingSafeTransport + from integration.sslhelper import TestServer, \ + get_server_socket, KEY_FILE, \ + CRT_FILE, OTHER_KEY_FILE, OTHER_CRT_FILE + _m2cEnabled = False + HOST = '127.0.0.1' @@ -45,35 +53,6 @@ def add(self, x, y): return x + y - - -class TestServer(): - - def __init__(self): - self.server = SimpleXMLRPCServer.SimpleXMLRPCServer((HOST, 0), - logRequests=False) - self.server.socket = SSLServerSocket(raw=self.server.socket, - keyfile=KEY_FILE, - certfile=CRT_FILE, - ca_certs=CRT_FILE) - _, self.port = self.server.socket.getsockname() - self.server.register_instance(MathService()) - - def start(self): - self.thread = threading.Thread(target=self.serve_forever) - self.thread.daemon = True - self.thread.start() - - def serve_forever(self): - try: - self.server.serve_forever() - except SSL.SSLError: - # expected sslerror is thrown in server side during test_invalid - # method we do not want to pollute test console output - pass - - def stop(self): - self.server.shutdown() class VerifyingClient(): @@ -97,7 +76,7 @@ @contextmanager def verifyingclient(key_file, crt_file): - server = TestServer() + server = TestServer(HOST, MathService()) server.start() try: client = VerifyingClient(server.port, key_file, crt_file) @@ -112,9 +91,8 @@ class SocketTests(TestCaseBase): def test_block_socket(self): - server = TestServer() - server.server.socket.accept_timeout = 1 - timeout = server.server.socket.accept_timeout + 1 + server = TestServer(HOST, MathService()) + timeout = server.get_timeout() server.start() try: with closing(socket.socket(socket.AF_INET, @@ -222,11 +200,8 @@ # Create the server socket: self.server = socket.socket() - self.server = SSLServerSocket( - raw=self.server, - keyfile=self.keyfile, - certfile=self.certfile, - ca_certs=self.certfile) + self.server = get_server_socket(self.keyfile, self.certfile, + self.server) self.address = self.tryBind(ADDRESS) self.server.listen(5) @@ -357,6 +332,11 @@ Verify that SSL the session identifier is preserved when connecting two times without stopping the server. """ + if not _m2cEnabled: + raise SkipTest( + 'support for SSL sessions discontinued and may be reintroduced' + ' when we move to python 3' + ) # Create a temporary file to store the session details: sessionDetailsFile = tempfile.NamedTemporaryFile(delete=False) diff --git a/tests/stompTests.py b/tests/stompTests.py index 3b38c95..3eabbb7 100644 --- a/tests/stompTests.py +++ b/tests/stompTests.py @@ -26,9 +26,12 @@ dummyTextGenerator from integration.jsonRpcHelper import constructAcceptor -from integration.m2chelper import DEAFAULT_SSL_CONTEXT from yajsonrpc.stompreactor import StandAloneRpcClient -from vdsm.utils import running +from vdsm import utils +try: + from integration.m2chelper import DEAFAULT_SSL_CONTEXT +except ImportError: + from integration.sslhelper import DEAFAULT_SSL_CONTEXT CALL_TIMEOUT = 15 @@ -61,9 +64,11 @@ with constructAcceptor(self.log, use_ssl, _SampleBridge()) as acceptor: sslctx = DEAFAULT_SSL_CONTEXT if use_ssl else None - with running(StandAloneRpcClient(acceptor._host, acceptor._port, - 'jms.topic.vdsm_requests', - str(uuid4()), sslctx)) as client: + with utils.running(StandAloneRpcClient(acceptor._host, + acceptor._port, + 'jms.topic.vdsm_requests', + str(uuid4()), + sslctx)) as client: self.assertEquals(client.callMethod('echo', (data,), str(uuid4())), data) @@ -75,7 +80,6 @@ with constructAcceptor(self.log, use_ssl, _SampleBridge(), 'jms.queue.events') as acceptor: sslctx = DEAFAULT_SSL_CONTEXT if use_ssl else None - client = StandAloneRpcClient(acceptor._host, acceptor._port, 'jms.topic.vdsm_requests', 'jms.queue.events', sslctx, False) diff --git a/tests/vdscliTests.py b/tests/vdscliTests.py index ba2cf36..bfcbddf 100644 --- a/tests/vdscliTests.py +++ b/tests/vdscliTests.py @@ -29,9 +29,14 @@ from testlib import VdsmTestCase as TestCaseBase from testValidation import ValidateRunningAsRoot - -from vdsm import m2cutils from vdsm import vdscli +try: + from vdsm import m2cutils as sslutils + from integration.m2chelper import get_server_socket +except ImportError: + from vdsm import sslutils + from integration.sslhelper import get_server_socket + HOST = '127.0.0.1' @@ -51,11 +56,8 @@ if useSSL: KEY_FILE = os.path.join(path, 'keys/vdsmkey.pem') CRT_FILE = os.path.join(path, 'certs/vdsmcert.pem') - self.server.socket = m2cutils.SSLServerSocket( - raw=self.server.socket, - keyfile=KEY_FILE, - certfile=CRT_FILE, - ca_certs=CRT_FILE) + self.server.socket = get_server_socket(KEY_FILE, CRT_FILE, + self.server.socket) _, self.port = self.server.socket.getsockname() self.server.register_instance(TestingService()) @@ -74,7 +76,7 @@ @contextmanager def setupclient(useSSL, tsPath, - timeout=m2cutils.SOCKET_DEFAULT_TIMEOUT): + timeout=sslutils.SOCKET_DEFAULT_TIMEOUT): server = TestServer(useSSL, tsPath) server.start() hostPort = '0:' + str(server.port) diff --git a/vdsm.spec.in b/vdsm.spec.in index ddb3184..7bcea09 100644 --- a/vdsm.spec.in +++ b/vdsm.spec.in @@ -42,6 +42,9 @@ %global _polkitdir %{_localstatedir}/lib/polkit-1/localauthority/10-vendor.d %endif +# enable m2crypto by default +%global with_m2c 1 + # Gluster should not be shipped with RHEV %if ! 0%{?rhev_build} %global with_gluster 1 @@ -83,7 +86,9 @@ BuildRequires: libnl3 BuildRequires: libselinux-python BuildRequires: libvirt-python +%if %{with_m2c} BuildRequires: m2crypto +%endif BuildRequires: mom >= 0.4.5 BuildRequires: openssl BuildRequires: policycoreutils-python @@ -129,7 +134,9 @@ Requires: %{name}-infra = %{version}-%{release} Requires: rpm-python Requires: nfs-utils +%if %{with_m2c} Requires: m2crypto +%endif Requires: libnl3 Requires: curl Requires: %{name}-xmlrpc = %{version}-%{release} @@ -295,7 +302,9 @@ %package reg Summary: VDSM registration package Requires: %{name} = %{version}-%{release} +%if %{with_m2c} Requires: m2crypto +%endif Requires: openssl Conflicts: ovirt-node < 3.0.4 @@ -307,7 +316,9 @@ Summary: VDSM python libraries Requires: %{name}-infra = %{version}-%{release} Requires: python-cpopen >= 1.2.3-5 +%if %{with_m2c} Requires: m2crypto +%endif Requires: python-ioprocess >= 0.14 %description python @@ -1049,7 +1060,6 @@ %{python_sitelib}/%{vdsm_name}/ipwrapper.py* %{python_sitelib}/%{vdsm_name}/jsonrpcvdscli.py* %{python_sitelib}/%{vdsm_name}/libvirtconnection.py* -%{python_sitelib}/%{vdsm_name}/m2cutils.py* %{python_sitelib}/%{vdsm_name}/netinfo.py* %{python_sitelib}/%{vdsm_name}/netlink/__init__.py* %{python_sitelib}/%{vdsm_name}/netlink/addr.py* @@ -1067,6 +1077,13 @@ %{python_sitelib}/%{vdsm_name}/response.py* %{python_sitelib}/%{vdsm_name}/netconfpersistence.py* %{python_sitelib}/%{vdsm_name}/schedule.py* +%if %{with_m2c} +%{python_sitelib}/%{vdsm_name}/m2cutils.py* +%exclude %{python_sitelib}/%{vdsm_name}/sslutils.py* +%else +%exclude %{python_sitelib}/%{vdsm_name}/m2cutils.py* +%{python_sitelib}/%{vdsm_name}/sslutils.py* +%endif %{python_sitelib}/%{vdsm_name}/sysctl.py* %{python_sitelib}/%{vdsm_name}/udevadm.py* %{python_sitelib}/%{vdsm_name}/utils.py* diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py index 5590db0..578b349 100644 --- a/vdsm/clientIF.py +++ b/vdsm/clientIF.py @@ -37,7 +37,6 @@ from vdsm.compat import pickle from vdsm.define import doneCode, errCode import libvirt -from vdsm import m2cutils from vdsm import libvirtconnection from vdsm import constants from vdsm import utils @@ -55,6 +54,10 @@ from virt.vmchannels import Listener from virt.vmdevices import hwclass from virt.utils import isVdsmImage +try: + from vdsm import m2cutils as sslutils +except ImportError: + from vdsm import sslutils try: import gluster.api as gapi _glusterEnabled = True @@ -193,7 +196,7 @@ return cls._instance def _createAcceptor(self, host, port): - sslctx = m2cutils.create_ssl_context() + sslctx = sslutils.create_ssl_context() self._reactor = Reactor() self._acceptor = MultiProtocolAcceptor(self._reactor, host, @@ -205,7 +208,7 @@ broker_port = config.getint('addresses', 'broker_port') request_queues = config.get('addresses', 'request_queues') - sslctx = m2cutils.create_ssl_context() + sslctx = sslutils.create_ssl_context() sock = socket.socket() sock.connect((broker_address, broker_port)) if sslctx: diff --git a/vdsm/kaxmlrpclib.py b/vdsm/kaxmlrpclib.py index b38031e..b0640e8 100644 --- a/vdsm/kaxmlrpclib.py +++ b/vdsm/kaxmlrpclib.py @@ -110,7 +110,10 @@ ################### # the same, for ssl -from vdsm import m2cutils +try: + from vdsm import m2cutils as sslutils +except ImportError: + from vdsm import sslutils import ssl @@ -122,7 +125,7 @@ SslServerProxy = SslServer -class TcpkeepSafeTransport(m2cutils.VerifyingSafeTransport): +class TcpkeepSafeTransport(sslutils.VerifyingSafeTransport): def make_connection(self, host): chost, self._extra_headers, x509 = self.get_host_info(host) @@ -139,17 +142,17 @@ cert_reqs=self.cert_reqs) -class TcpkeepHTTPSConnection(m2cutils.VerifyingHTTPSConnection): +class TcpkeepHTTPSConnection(sslutils.VerifyingHTTPSConnection): def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=CONNECTTIMEOUT, ca_certs=None, cert_reqs=ssl.CERT_REQUIRED): - m2cutils.VerifyingHTTPSConnection.__init__( + sslutils.VerifyingHTTPSConnection.__init__( self, host, port=port, key_file=key_file, cert_file=cert_file, strict=strict, timeout=timeout, ca_certs=ca_certs, cert_reqs=cert_reqs) def connect(self): - m2cutils.VerifyingHTTPSConnection.connect(self) + sslutils.VerifyingHTTPSConnection.connect(self) # after TCP_KEEPIDLE seconds of silence, TCP_KEEPCNT probes would be # sent, TCP_KEEPINTVL seconds apart of each other. If all of them fail, @@ -160,5 +163,5 @@ self.sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, KEEPCNT) -class TcpkeepHTTPS(m2cutils.VerifyingHTTPS): +class TcpkeepHTTPS(sslutils.VerifyingHTTPS): _connection_class = TcpkeepHTTPSConnection diff --git a/vdsm/protocoldetector.py b/vdsm/protocoldetector.py index 6d01a1c..dbdc730 100644 --- a/vdsm/protocoldetector.py +++ b/vdsm/protocoldetector.py @@ -24,7 +24,10 @@ import vdsm.infra.filecontrol as filecontrol from vdsm.utils import monotonic_time -from vdsm.m2cutils import SSLHandshakeDispatcher +try: + from vdsm.m2cutils import SSLHandshakeDispatcher +except ImportError: + from vdsm.sslutils import SSLHandshakeDispatcher def _create_socket(host, port): diff --git a/vdsm/virt/migration.py b/vdsm/virt/migration.py index 32caccb..6c41114 100644 --- a/vdsm/virt/migration.py +++ b/vdsm/virt/migration.py @@ -28,7 +28,6 @@ from vdsm import utils from vdsm import vdscli from vdsm import jsonrpcvdscli -from vdsm import m2cutils from vdsm.compat import pickle from vdsm.config import config from vdsm.define import NORMAL, Mbytes @@ -40,6 +39,11 @@ from . import vmexitreason from . import vmstatus +try: + from vdsm import m2cutils as sslutils +except ImportError: + from vdsm import sslutils + MODE_REMOTE = 'remote' MODE_FILE = 'file' -- To view, visit https://gerrit.ovirt.org/44494 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6501981bbd5276c49731b0d9eba4794286b0f823 Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Piotr Kliczewski <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
