diff options
author | Nobuaki Sukegawa <nsuke@apache.org> | 2015-12-23 23:32:09 +0900 |
---|---|---|
committer | Nobuaki Sukegawa <nsuke@apache.org> | 2016-01-03 02:39:51 +0900 |
commit | ad8358664e6aa2de9094ca68c8b626b953b572c0 (patch) | |
tree | 677c369a367b0f451a929b661f84d4c28b9edae1 | |
parent | b78d781b2e55a066d53577402e42b4d509998978 (diff) | |
download | thrift-ad8358664e6aa2de9094ca68c8b626b953b572c0.tar.gz |
THRIFT-3505 Enhance Python TSSLSocket
This closes #760
-rwxr-xr-x | appveyor.yml | 2 | ||||
-rwxr-xr-x | lib/py/CMakeLists.txt | 5 | ||||
-rwxr-xr-x | lib/py/Makefile.am | 6 | ||||
-rw-r--r-- | lib/py/src/transport/TSSLSocket.py | 327 | ||||
-rw-r--r-- | lib/py/test/_import_local_thrift.py | 13 | ||||
-rw-r--r-- | lib/py/test/test_sslsocket.py | 275 | ||||
-rw-r--r-- | lib/py/test/thrift_json.py | 25 | ||||
-rwxr-xr-x | test/keys/README.md | 8 | ||||
-rw-r--r-- | test/keys/client.crt | 27 | ||||
-rw-r--r-- | test/keys/client.key | 38 | ||||
-rw-r--r-- | test/keys/client.p12 | bin | 1877 -> 2589 bytes | |||
-rw-r--r-- | test/keys/client.pem | 74 | ||||
-rw-r--r-- | test/known_failures_Linux.json | 6 |
13 files changed, 653 insertions, 153 deletions
diff --git a/appveyor.yml b/appveyor.yml index 711654e8b..ee114ae01 100755 --- a/appveyor.yml +++ b/appveyor.yml @@ -74,6 +74,6 @@ build_script: - cmake --build . --config Release # TODO: Fix cpack # - cpack -- ctest -C Release -VV -E "(concurrency_test|processor_test|python_test$)" +- ctest -C Release -VV -E "(concurrency_test|processor_test|python_test$|^Python)" #TODO make it perfect ;-r diff --git a/lib/py/CMakeLists.txt b/lib/py/CMakeLists.txt index ef987b67b..7bb91fe67 100755 --- a/lib/py/CMakeLists.txt +++ b/lib/py/CMakeLists.txt @@ -24,3 +24,8 @@ add_custom_target(python_build ALL WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Building Python library" ) + +if(BUILD_TESTING) + add_test(PythonTestSSLSocket ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/test_sslsocket.py) + add_test(PythonThriftJson ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/thrift_json.py) +endif() diff --git a/lib/py/Makefile.am b/lib/py/Makefile.am index c0db8711f..5183b9c5e 100755 --- a/lib/py/Makefile.am +++ b/lib/py/Makefile.am @@ -23,7 +23,8 @@ if WITH_PY3 py3-build: $(PYTHON3) setup.py build py3-test: py3-build - PYTHONPATH=build/lib $(PYTHON3) test/thrift_json.py + $(PYTHON3) test/thrift_json.py + $(PYTHON3) test/test_sslsocket.py else py3-build: py3-test: @@ -43,7 +44,8 @@ clean-local: $(RM) -r build check-local: all py3-test - PYTHONPATH=$(shell ls build/lib* -dr | head -n1) $(PYTHON) test/thrift_json.py + $(PYTHON) test/thrift_json.py + $(PYTHON) test/test_sslsocket.py EXTRA_DIST = \ CMakeLists.txt \ diff --git a/lib/py/src/transport/TSSLSocket.py b/lib/py/src/transport/TSSLSocket.py index 6ad8d5064..9be0912f9 100644 --- a/lib/py/src/transport/TSSLSocket.py +++ b/lib/py/src/transport/TSSLSocket.py @@ -17,73 +17,221 @@ # under the License. # +import logging import os import socket import ssl +import sys +import warnings from thrift.transport import TSocket from thrift.transport.TTransport import TTransportException +logger = logging.getLogger(__name__) +warnings.filterwarnings('default', category=DeprecationWarning, module=__name__) -class TSSLSocket(TSocket.TSocket): + +class TSSLBase(object): + # SSLContext is not available for Python < 2.7.9 + _has_ssl_context = sys.hexversion >= 0x020709F0 + + # ciphers argument is not available for Python < 2.7.0 + _has_ciphers = sys.hexversion >= 0x020700F0 + + # For pythoon >= 2.7.9, use latest TLS that both client and server supports. + # SSL 2.0 and 3.0 are disabled via ssl.OP_NO_SSLv2 and ssl.OP_NO_SSLv3. + # For pythoon < 2.7.9, use TLS 1.0 since TLSv1_X nare OP_NO_SSLvX are unavailable. + _default_protocol = ssl.PROTOCOL_SSLv23 if _has_ssl_context else ssl.PROTOCOL_TLSv1 + + def _init_context(self, ssl_version): + if self._has_ssl_context: + self._context = ssl.SSLContext(ssl_version) + if self._context.protocol == ssl.PROTOCOL_SSLv23: + self._context.options |= ssl.OP_NO_SSLv2 + self._context.options |= ssl.OP_NO_SSLv3 + else: + self._context = None + self._ssl_version = ssl_version + + @property + def ssl_version(self): + if self._has_ssl_context: + return self.ssl_context.protocol + else: + return self._ssl_version + + @property + def ssl_context(self): + return self._context + + SSL_VERSION = _default_protocol """ - SSL implementation of client-side TSocket + Default SSL version. + For backword compatibility, it can be modified. + Use __init__ keywoard argument "ssl_version" instead. + """ + + def _deprecated_arg(self, args, kwargs, pos, key): + if len(args) <= pos: + return + real_pos = pos + 3 + warnings.warn( + '%dth positional argument is deprecated. Use keyward argument insteand.' % real_pos, + DeprecationWarning) + if key in kwargs: + raise TypeError('Duplicate argument: %dth argument and %s keyward argument.', (real_pos, key)) + kwargs[key] = args[pos] + + def _unix_socket_arg(self, host, port, args, kwargs): + key = 'unix_socket' + if host is None and port is None and len(args) == 1 and key not in kwargs: + kwargs[key] = args[0] + return True + return False + + def __getattr__(self, key): + if key == 'SSL_VERSION': + warnings.warn('Use ssl_version attribute instead.', DeprecationWarning) + return self.ssl_version + + def __init__(self, server_side, host, ssl_opts): + self._server_side = server_side + if TSSLBase.SSL_VERSION != self._default_protocol: + warnings.warn('SSL_VERSION is deprecated. Use ssl_version keyward argument instead.', DeprecationWarning) + self._context = ssl_opts.pop('ssl_context', None) + self._server_hostname = None + if not self._server_side: + self._server_hostname = ssl_opts.pop('server_hostname', host) + if self._context: + self._custom_context = True + if ssl_opts: + raise ValueError('Incompatible arguments: ssl_context and %s' % ' '.join(ssl_opts.keys())) + if not self._has_ssl_context: + raise ValueError('ssl_context is not available for this version of Python') + else: + self._custom_context = False + ssl_version = ssl_opts.pop('ssl_version', TSSLBase.SSL_VERSION) + self._init_context(ssl_version) + self.cert_reqs = ssl_opts.pop('cert_reqs', ssl.CERT_REQUIRED) + self.ca_certs = ssl_opts.pop('ca_certs', None) + self.keyfile = ssl_opts.pop('keyfile', None) + self.certfile = ssl_opts.pop('certfile', None) + self.ciphers = ssl_opts.pop('ciphers', None) + + if ssl_opts: + raise ValueError('Unknown keyword arguments: ', ' '.join(ssl_opts.keys())) + + if self.cert_reqs != ssl.CERT_NONE: + if not self.ca_certs: + raise ValueError('ca_certs is needed when cert_reqs is not ssl.CERT_NONE') + if not os.access(self.ca_certs, os.R_OK): + raise IOError('Certificate Authority ca_certs file "%s" ' + 'is not readable, cannot validate SSL ' + 'certificates.' % (self.ca_certs)) + + @property + def certfile(self): + return self._certfile + + @certfile.setter + def certfile(self, certfile): + if self._server_side and not certfile: + raise ValueError('certfile is needed for server-side') + if certfile and not os.access(certfile, os.R_OK): + raise IOError('No such certfile found: %s' % (certfile)) + self._certfile = certfile + + def _wrap_socket(self, sock): + if self._has_ssl_context: + if not self._custom_context: + self.ssl_context.verify_mode = self.cert_reqs + if self.certfile: + self.ssl_context.load_cert_chain(self.certfile, self.keyfile) + if self.ciphers: + self.ssl_context.set_ciphers(self.ciphers) + if self.ca_certs: + self.ssl_context.load_verify_locations(self.ca_certs) + return self.ssl_context.wrap_socket(sock, server_side=self._server_side, + server_hostname=self._server_hostname) + else: + ssl_opts = { + 'ssl_version': self._ssl_version, + 'server_side': self._server_side, + 'ca_certs': self.ca_certs, + 'keyfile': self.keyfile, + 'certfile': self.certfile, + 'cert_reqs': self.cert_reqs, + } + if self.ciphers: + if self._has_ciphers: + ssl_opts['ciphers'] = self.ciphers + else: + logger.warning('ciphers is specified but ignored due to old Python version') + return ssl.wrap_socket(sock, **ssl_opts) + + +class TSSLSocket(TSocket.TSocket, TSSLBase): + """ + SSL implementation of TSocket This class creates outbound sockets wrapped using the python standard ssl module for encrypted connections. - - The protocol used is set using the class variable - SSL_VERSION, which must be one of ssl.PROTOCOL_* and - defaults to ssl.PROTOCOL_TLSv1 for greatest security. """ - SSL_VERSION = ssl.PROTOCOL_TLSv1 - - def __init__(self, - host='localhost', - port=9090, - validate=True, - ca_certs=None, - keyfile=None, - certfile=None, - unix_socket=None, - ciphers=None): - """Create SSL TSocket - - @param validate: Set to False to disable SSL certificate validation - @type validate: bool - @param ca_certs: Filename to the Certificate Authority pem file, possibly a - file downloaded from: http://curl.haxx.se/ca/cacert.pem This is passed to - the ssl_wrap function as the 'ca_certs' parameter. - @type ca_certs: str - @param keyfile: The private key - @type keyfile: str - @param certfile: The cert file - @type certfile: str - @param ciphers: The cipher suites to allow. This is passed to - the ssl_wrap function as the 'ciphers' parameter. - @type ciphers: str - - Raises an IOError exception if validate is True and the ca_certs file is - None, not present or unreadable. + + # New signature + # def __init__(self, host='localhost', port=9090, unix_socket=None, **ssl_args): + # Deprecated signature + # def __init__(self, host='localhost', port=9090, validate=True, ca_certs=None, keyfile=None, certfile=None, unix_socket=None, ciphers=None): + def __init__(self, host='localhost', port=9090, *args, **kwargs): + """Positional arguments: ``host``, ``port``, ``unix_socket`` + + Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, ``ssl_version``, + ``ca_certs``, ``ciphers`` (Python 2.7.0 or later), + ``server_hostname`` (Python 2.7.9 or later) + Passed to ssl.wrap_socket. See ssl.wrap_socket documentation. + + Alternative keywoard arguments: (Python 2.7.9 or later) + ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket + ``server_hostname``: Passed to SSLContext.wrap_socket """ - self.validate = validate self.is_valid = False self.peercert = None - if not validate: - self.cert_reqs = ssl.CERT_NONE - else: - self.cert_reqs = ssl.CERT_REQUIRED - self.ca_certs = ca_certs - self.keyfile = keyfile - self.certfile = certfile - self.ciphers = ciphers - if validate: - if ca_certs is None or not os.access(ca_certs, os.R_OK): - raise IOError('Certificate Authority ca_certs file "%s" ' - 'is not readable, cannot validate SSL ' - 'certificates.' % (ca_certs)) + + if args: + if len(args) > 6: + raise TypeError('Too many positional argument') + if not self._unix_socket_arg(host, port, args, kwargs): + self._deprecated_arg(args, kwargs, 0, 'validate') + self._deprecated_arg(args, kwargs, 1, 'ca_certs') + self._deprecated_arg(args, kwargs, 2, 'keyfile') + self._deprecated_arg(args, kwargs, 3, 'certfile') + self._deprecated_arg(args, kwargs, 4, 'unix_socket') + self._deprecated_arg(args, kwargs, 5, 'ciphers') + + validate = kwargs.pop('validate', None) + if validate is not None: + cert_reqs_name = 'CERT_REQUIRED' if validate else 'CERT_NONE' + warnings.warn( + 'validate is deprecated. Use cert_reqs=ssl.%s instead' % cert_reqs_name, + DeprecationWarning) + if 'cert_reqs' in kwargs: + raise TypeError('Cannot specify both validate and cert_reqs') + kwargs['cert_reqs'] = ssl.CERT_REQUIRED if validate else ssl.CERT_NONE + + unix_socket = kwargs.pop('unix_socket', None) + TSSLBase.__init__(self, False, host, kwargs) TSocket.TSocket.__init__(self, host, port, unix_socket) + @property + def validate(self): + warnings.warn('Use cert_reqs instead', DeprecationWarning) + return self.cert_reqs != ssl.CERT_NONE + + @validate.setter + def validate(self, value): + warnings.warn('Use cert_reqs instead', DeprecationWarning) + self.cert_reqs = ssl.CERT_REQUIRED if value else ssl.CERT_NONE + def open(self): try: res0 = self._resolveAddr() @@ -91,29 +239,24 @@ class TSSLSocket(TSocket.TSocket): sock_family, sock_type = res[0:2] ip_port = res[4] plain_sock = socket.socket(sock_family, sock_type) - self.handle = ssl.wrap_socket(plain_sock, - ssl_version=self.SSL_VERSION, - do_handshake_on_connect=True, - ca_certs=self.ca_certs, - keyfile=self.keyfile, - certfile=self.certfile, - cert_reqs=self.cert_reqs, - ciphers=self.ciphers) + self.handle = self._wrap_socket(plain_sock) self.handle.settimeout(self._timeout) try: self.handle.connect(ip_port) except socket.error as e: if res is not res0[-1]: + logger.warning('Error while connecting with %s. Trying next one.', ip_port, exc_info=True) continue else: - raise e + raise break except socket.error as e: if self._unix_socket: message = 'Could not connect to secure socket %s: %s' \ - % (self._unix_socket, e) + % (self._unix_socket, e) else: message = 'Could not connect to %s:%d: %s' % (self.host, self.port, e) + logger.error('Error while connecting with %s.', ip_port, exc_info=True) raise TTransportException(type=TTransportException.NOT_OPEN, message=message) if self.validate: @@ -161,38 +304,46 @@ class TSSLSocket(TSocket.TSocket): 'host "%s". Cert=%s' % (self.host, cert)) -class TSSLServerSocket(TSocket.TServerSocket): +class TSSLServerSocket(TSocket.TServerSocket, TSSLBase): """SSL implementation of TServerSocket This uses the ssl module's wrap_socket() method to provide SSL negotiated encryption. """ - SSL_VERSION = ssl.PROTOCOL_TLSv1 - def __init__(self, - host=None, - port=9090, - certfile='cert.pem', - unix_socket=None, - ciphers=None): - """Initialize a TSSLServerSocket + # New signature + # def __init__(self, host='localhost', port=9090, unix_socket=None, **ssl_args): + # Deprecated signature + # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None): + def __init__(self, host=None, port=9090, *args, **kwargs): + """Positional arguments: ``host``, ``port``, ``unix_socket`` - @param certfile: filename of the server certificate, defaults to cert.pem - @type certfile: str - @param host: The hostname or IP to bind the listen socket to, - i.e. 'localhost' for only allowing local network connections. - Pass None to bind to all interfaces. - @type host: str - @param port: The port to listen on for inbound connections. - @type port: int - @param ciphers: The cipher suites to allow. This is passed to - the ssl_wrap function as the 'ciphers' parameter. - @type ciphers: str + Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, ``ssl_version``, + ``ca_certs``, ``ciphers`` (Python 2.7.0 or later) + See ssl.wrap_socket documentation. + Alternative keywoard arguments: (Python 2.7.9 or later) + ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket + ``server_hostname``: Passed to SSLContext.wrap_socket """ - self.setCertfile(certfile) - TSocket.TServerSocket.__init__(self, host, port) - self.ciphers = ciphers + if args: + if len(args) > 3: + raise TypeError('Too many positional argument') + if not self._unix_socket_arg(host, port, args, kwargs): + self._deprecated_arg(args, kwargs, 0, 'certfile') + self._deprecated_arg(args, kwargs, 1, 'unix_socket') + self._deprecated_arg(args, kwargs, 2, 'ciphers') + + if 'ssl_context' not in kwargs: + # Preserve existing behaviors for default values + if 'cert_reqs' not in kwargs: + kwargs['cert_reqs'] = ssl.CERT_NONE + if'certfile' not in kwargs: + kwargs['certfile'] = 'cert.pem' + + unix_socket = kwargs.pop('unix_socket', None) + TSSLBase.__init__(self, True, None, kwargs) + TSocket.TServerSocket.__init__(self, host, port, unix_socket) def setCertfile(self, certfile): """Set or change the server certificate file used to wrap new connections. @@ -203,20 +354,18 @@ class TSSLServerSocket(TSocket.TServerSocket): Raises an IOError exception if the certfile is not present or unreadable. """ - if not os.access(certfile, os.R_OK): - raise IOError('No such certfile found: %s' % (certfile)) + warnings.warn('Use certfile property instead.', DeprecationWarning) self.certfile = certfile def accept(self): plain_client, addr = self.handle.accept() try: - client = ssl.wrap_socket(plain_client, certfile=self.certfile, - server_side=True, ssl_version=self.SSL_VERSION, - ciphers=self.ciphers) - except ssl.SSLError as ssl_exc: + client = self._wrap_socket(plain_client) + except ssl.SSLError: + logger.error('Error while accepting from %s', addr, exc_info=True) # failed handshake/ssl wrap, close socket to client plain_client.close() - # raise ssl_exc + # raise # We can't raise the exception, because it kills most TServer derived # serve() methods. # Instead, return None, and let the TServer instance deal with it in diff --git a/lib/py/test/_import_local_thrift.py b/lib/py/test/_import_local_thrift.py new file mode 100644 index 000000000..30c1abcc0 --- /dev/null +++ b/lib/py/test/_import_local_thrift.py @@ -0,0 +1,13 @@ +import os +import sys + + +SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) +ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))) + +if sys.version_info[0] == 2: + import glob + libdir = glob.glob(os.path.join(ROOT_DIR, 'lib', 'py', 'build', 'lib.*'))[0] + sys.path.insert(0, libdir) +else: + sys.path.insert(0, os.path.join(ROOT_DIR, 'lib', 'py', 'build', 'lib')) diff --git a/lib/py/test/test_sslsocket.py b/lib/py/test/test_sslsocket.py new file mode 100644 index 000000000..bd2a70aef --- /dev/null +++ b/lib/py/test/test_sslsocket.py @@ -0,0 +1,275 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import os +import platform +import select +import ssl +import sys +import threading +import time +import unittest +import warnings + +import _import_local_thrift +from thrift.transport.TSSLSocket import TSSLSocket, TSSLServerSocket + +SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) +ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(SCRIPT_DIR))) +SERVER_PEM = os.path.join(ROOT_DIR, 'test', 'keys', 'server.pem') +SERVER_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'server.crt') +SERVER_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'server.key') +CLIENT_CERT = os.path.join(ROOT_DIR, 'test', 'keys', 'client.crt') +CLIENT_KEY = os.path.join(ROOT_DIR, 'test', 'keys', 'client.key') + +TEST_PORT = 23458 +TEST_ADDR = '/tmp/.thrift.domain.sock.%d' % TEST_PORT +CONNECT_TIMEOUT = 10.0 +TEST_CIPHERS = 'DES-CBC3-SHA' + + +class ServerAcceptor(threading.Thread): + def __init__(self, server): + super(ServerAcceptor, self).__init__() + self._server = server + self.client = None + + def run(self): + self._server.listen() + self.client = self._server.accept() + + +# Python 2.6 compat +class AssertRaises(object): + def __init__(self, expected): + self._expected = expected + + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + if not exc_type or not issubclass(exc_type, self._expected): + raise Exception('fail') + return True + + +class TSSLSocketTest(unittest.TestCase): + def _assert_connection_failure(self, server, client): + try: + acc = ServerAcceptor(server) + acc.start() + time.sleep(0.15) + client.setTimeout(CONNECT_TIMEOUT) + with self._assert_raises(Exception): + client.open() + select.select([], [client.handle], [], CONNECT_TIMEOUT) + # self.assertIsNone(acc.client) + self.assertTrue(acc.client is None) + finally: + server.close() + client.close() + + def _assert_raises(self, exc): + if sys.hexversion >= 0x020700F0: + return self.assertRaises(exc) + else: + return AssertRaises(exc) + + def _assert_connection_success(self, server, client): + try: + acc = ServerAcceptor(server) + acc.start() + time.sleep(0.15) + client.setTimeout(CONNECT_TIMEOUT) + client.open() + select.select([], [client.handle], [], CONNECT_TIMEOUT) + # self.assertIsNotNone(acc.client) + self.assertTrue(acc.client is not None) + finally: + server.close() + client.close() + + # deprecated feature + def test_deprecation(self): + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module='thrift.*SSL.*') + TSSLSocket('localhost', TEST_PORT, validate=True, ca_certs=SERVER_CERT) + self.assertEqual(len(w), 1) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module='thrift.*SSL.*') + # Deprecated signature + # def __init__(self, host='localhost', port=9090, validate=True, ca_certs=None, keyfile=None, certfile=None, unix_socket=None, ciphers=None): + client = TSSLSocket('localhost', TEST_PORT, True, SERVER_CERT, CLIENT_KEY, CLIENT_CERT, None, TEST_CIPHERS) + self.assertEqual(len(w), 7) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning, module='thrift.*SSL.*') + # Deprecated signature + # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None): + server = TSSLServerSocket(None, TEST_PORT, SERVER_PEM, None, TEST_CIPHERS) + self.assertEqual(len(w), 3) + + self._assert_connection_success(server, client) + + # deprecated feature + def test_set_cert_reqs_by_validate(self): + c1 = TSSLSocket('localhost', TEST_PORT, validate=True, ca_certs=SERVER_CERT) + self.assertEqual(c1.cert_reqs, ssl.CERT_REQUIRED) + + c1 = TSSLSocket('localhost', TEST_PORT, validate=False) + self.assertEqual(c1.cert_reqs, ssl.CERT_NONE) + + # deprecated feature + def test_set_validate_by_cert_reqs(self): + c1 = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_NONE) + self.assertFalse(c1.validate) + + c2 = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) + self.assertTrue(c2.validate) + + c3 = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_OPTIONAL, ca_certs=SERVER_CERT) + self.assertTrue(c3.validate) + + def test_unix_domain_socket(self): + if platform.system() == 'Windows': + print('skipping test_unix_domain_socket') + return + server = TSSLServerSocket(unix_socket=TEST_ADDR, keyfile=SERVER_KEY, certfile=SERVER_CERT) + client = TSSLSocket(None, None, TEST_ADDR, cert_reqs=ssl.CERT_NONE) + self._assert_connection_success(server, client) + + def test_server_cert(self): + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT) + client = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) + self._assert_connection_success(server, client) + + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT) + # server cert on in ca_certs + client = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_REQUIRED, ca_certs=CLIENT_CERT) + self._assert_connection_failure(server, client) + + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT) + client = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_NONE) + self._assert_connection_success(server, client) + + def test_set_server_cert(self): + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=CLIENT_CERT) + with self._assert_raises(Exception): + server.certfile = 'foo' + with self._assert_raises(Exception): + server.certfile = None + server.certfile = SERVER_CERT + client = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_REQUIRED, ca_certs=SERVER_CERT) + self._assert_connection_success(server, client) + + def test_client_cert(self): + server = TSSLServerSocket( + port=TEST_PORT, cert_reqs=ssl.CERT_REQUIRED, keyfile=SERVER_KEY, + certfile=SERVER_CERT, ca_certs=CLIENT_CERT) + client = TSSLSocket('localhost', TEST_PORT, cert_reqs=ssl.CERT_NONE, certfile=CLIENT_CERT, keyfile=CLIENT_KEY) + self._assert_connection_success(server, client) + + def test_ciphers(self): + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ciphers=TEST_CIPHERS) + self._assert_connection_success(server, client) + + if not TSSLSocket._has_ciphers: + # unittest.skip is not available for Python 2.6 + print('skipping test_ciphers') + return + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ciphers='NULL') + self._assert_connection_failure(server, client) + + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT, ciphers=TEST_CIPHERS) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ciphers='NULL') + self._assert_connection_failure(server, client) + + def test_ssl2_and_ssl3_disabled(self): + if not hasattr(ssl, 'PROTOCOL_SSLv3'): + print('PROTOCOL_SSLv3 is not available') + else: + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3) + self._assert_connection_failure(server, client) + + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv3) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT) + self._assert_connection_failure(server, client) + + if not hasattr(ssl, 'PROTOCOL_SSLv2'): + print('PROTOCOL_SSLv2 is not available') + else: + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2) + self._assert_connection_failure(server, client) + + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_SSLv2) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT) + self._assert_connection_failure(server, client) + + def test_newer_tls(self): + if not TSSLSocket._has_ssl_context: + # unittest.skip is not available for Python 2.6 + print('skipping test_newer_tls') + return + if not hasattr(ssl, 'PROTOCOL_TLSv1_2'): + print('PROTOCOL_TLSv1_2 is not available') + else: + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) + self._assert_connection_success(server, client) + + if not hasattr(ssl, 'PROTOCOL_TLSv1_1'): + print('PROTOCOL_TLSv1_1 is not available') + else: + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) + self._assert_connection_success(server, client) + + if not hasattr(ssl, 'PROTOCOL_TLSv1_1') or not hasattr(ssl, 'PROTOCOL_TLSv1_2'): + print('PROTOCOL_TLSv1_1 and/or PROTOCOL_TLSv1_2 is not available') + else: + server = TSSLServerSocket(port=TEST_PORT, keyfile=SERVER_KEY, certfile=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_2) + client = TSSLSocket('localhost', TEST_PORT, ca_certs=SERVER_CERT, ssl_version=ssl.PROTOCOL_TLSv1_1) + self._assert_connection_failure(server, client) + + def test_ssl_context(self): + if not TSSLSocket._has_ssl_context: + # unittest.skip is not available for Python 2.6 + print('skipping test_ssl_context') + return + server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + server_context.load_cert_chain(SERVER_CERT, SERVER_KEY) + server_context.load_verify_locations(CLIENT_CERT) + + client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + client_context.load_cert_chain(CLIENT_CERT, CLIENT_KEY) + client_context.load_verify_locations(SERVER_CERT) + + server = TSSLServerSocket(port=TEST_PORT, ssl_context=server_context) + client = TSSLSocket('localhost', TEST_PORT, ssl_context=client_context) + self._assert_connection_success(server, client) + +if __name__ == '__main__': + # import logging + # logging.basicConfig(level=logging.DEBUG) + unittest.main() diff --git a/lib/py/test/thrift_json.py b/lib/py/test/thrift_json.py index 6d6c8fa42..e60aabacf 100644 --- a/lib/py/test/thrift_json.py +++ b/lib/py/test/thrift_json.py @@ -1,10 +1,29 @@ -from thrift import Thrift -from thrift.protocol.TJSONProtocol import TJSONProtocol -from thrift.transport import TTransport +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# import sys import unittest +import _import_local_thrift +from thrift.protocol.TJSONProtocol import TJSONProtocol +from thrift.transport import TTransport + # # In order to run the test under Windows. We need to create symbolic link # name 'thrift' to '../src' folder by using: diff --git a/test/keys/README.md b/test/keys/README.md index 53fe0cc0b..15faa5106 100755 --- a/test/keys/README.md +++ b/test/keys/README.md @@ -26,7 +26,7 @@ we use the following parameters for test key and certificate creation openssl x509 -in server.crt -text > CA.pem cat server.crt server.key > server.pem -Export password is **thrift** +Export password is "thrift" without the quotes openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out server.p12 @@ -40,9 +40,9 @@ create a signing request: sign the client certificate with the server.key - openssl x509 -req -days 365 -in client.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client.crt + openssl x509 -req -days 3000 -in client.csr -CA CA.pem -CAkey server.key -set_serial 01 -out client.crt -export certificate in PKCS12 format (Export password is **thrift**) +export certificate in PKCS12 format (Export password is "thrift" without the quotes) openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12 @@ -52,7 +52,7 @@ export certificate in PEM format for OpenSSL usage ## Java key and certificate import -Java Test Environment uses key and trust store password **thrift** +Java Test Environment uses key and trust store password "thrift" without the quotes list keystore entries diff --git a/test/keys/client.crt b/test/keys/client.crt index 64526f6aa..80a9ad0e2 100644 --- a/test/keys/client.crt +++ b/test/keys/client.crt @@ -1,20 +1,23 @@ -----BEGIN CERTIFICATE----- -MIIDVDCCAjwCAQEwDQYJKoZIhvcNAQEFBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD +MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy -aWZ0LmFwYWNoZS5vcmcwHhcNMTQwNDA3MTkwMDMzWhcNMTUwNDA3MTkwMDMzWjCB +aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi -BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEArrM2HiTf5LT1Qh1JAALWUlJxVJNc1uC8//wZIW8Ekk6z -H2XkrAOW8Cs7rVfz6Q+x00q7xSH825v9RL6pv4l7sPDSGK5lvc+WkTxDpiR2EjIm -uWStUzCRq7EXhV50pUno6MFABVtqpRP87TiE1l7Yb8S33v+gAVdsrpJewYIDwWcC -AwEAATANBgkqhkiG9w0BAQUFAAOCAQEAbGjHLamDm1FQpgatYiZ/ic7Z8DFB+CJo -FcZH4hww27BD/WpQLsj6T1540B35hsmZ73yev4xgLybc/SEIducT9BHyc1DrDZtf -CFeSq6OOJu/1pJZ9m/d0i+sBJaWg5w1yT8+aEKJaWYfF+C9jZ6+3+I9agID5OplE -Wwwzg3xXllz3jfmtNlc0f+hE1/XLWFE2nY+5cBhlxReWH3HAhU/qZL9n/WdxCjHd -NyeWxlDlmzc2+uOeVF5sIGzFOj/qjGxc+UyUXaaEuSvh7j3rvYlZtnhvhJ+tMkoR -Kbxl1VUYxx+jzfhBy+bKu5uGZB3F1qtyY9fI5DQut75nNbueQPG+qw== +BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH +dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug +eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3 +PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE +mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG +sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG +9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR +J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk +XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS +UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve +21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U +VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg== -----END CERTIFICATE----- diff --git a/test/keys/client.key b/test/keys/client.key index 703e04559..25dcfd713 100644 --- a/test/keys/client.key +++ b/test/keys/client.key @@ -1,15 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/keys/client.p12 b/test/keys/client.p12 Binary files differindex a7d95df41..5d2669c12 100644 --- a/test/keys/client.p12 +++ b/test/keys/client.p12 diff --git a/test/keys/client.pem b/test/keys/client.pem index ee5bc6159..66ef626d9 100644 --- a/test/keys/client.pem +++ b/test/keys/client.pem @@ -1,44 +1,60 @@ Bag Attributes - localKeyID: 05 3C 6A 9D 6D EC A0 FA 2F AE 41 32 0D 24 3A 21 34 F6 08 15 + localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD subject=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org issuer=/C=US/ST=Maryland/L=Forest Hill/O=The Apache Software Foundation/OU=Apache Thrift/CN=localhost/emailAddress=dev@thrift.apache.org -----BEGIN CERTIFICATE----- -MIIDVDCCAjwCAQEwDQYJKoZIhvcNAQEFBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD +MIID2DCCAsACAQEwDQYJKoZIhvcNAQELBQAwgbExCzAJBgNVBAYTAlVTMREwDwYD VQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0IEhpbGwxJzAlBgNVBAoMHlRo ZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbjEWMBQGA1UECwwNQXBhY2hlIFRo cmlmdDESMBAGA1UEAwwJbG9jYWxob3N0MSQwIgYJKoZIhvcNAQkBFhVkZXZAdGhy -aWZ0LmFwYWNoZS5vcmcwHhcNMTQwNDA3MTkwMDMzWhcNMTUwNDA3MTkwMDMzWjCB +aWZ0LmFwYWNoZS5vcmcwHhcNMTUxMjIzMDcwNzUwWhcNMjQwMzEwMDcwNzUwWjCB sTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRQwEgYDVQQHDAtGb3Jl c3QgSGlsbDEnMCUGA1UECgweVGhlIEFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9u MRYwFAYDVQQLDA1BcGFjaGUgVGhyaWZ0MRIwEAYDVQQDDAlsb2NhbGhvc3QxJDAi -BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEArrM2HiTf5LT1Qh1JAALWUlJxVJNc1uC8//wZIW8Ekk6z -H2XkrAOW8Cs7rVfz6Q+x00q7xSH825v9RL6pv4l7sPDSGK5lvc+WkTxDpiR2EjIm -uWStUzCRq7EXhV50pUno6MFABVtqpRP87TiE1l7Yb8S33v+gAVdsrpJewYIDwWcC -AwEAATANBgkqhkiG9w0BAQUFAAOCAQEAbGjHLamDm1FQpgatYiZ/ic7Z8DFB+CJo -FcZH4hww27BD/WpQLsj6T1540B35hsmZ73yev4xgLybc/SEIducT9BHyc1DrDZtf -CFeSq6OOJu/1pJZ9m/d0i+sBJaWg5w1yT8+aEKJaWYfF+C9jZ6+3+I9agID5OplE -Wwwzg3xXllz3jfmtNlc0f+hE1/XLWFE2nY+5cBhlxReWH3HAhU/qZL9n/WdxCjHd -NyeWxlDlmzc2+uOeVF5sIGzFOj/qjGxc+UyUXaaEuSvh7j3rvYlZtnhvhJ+tMkoR -Kbxl1VUYxx+jzfhBy+bKu5uGZB3F1qtyY9fI5DQut75nNbueQPG+qw== +BgkqhkiG9w0BCQEWFWRldkB0aHJpZnQuYXBhY2hlLm9yZzCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALl/bJhg17Pu1t785JIuwlh7e2E51eoWFvuxMWfH +dsUAVqDaOz99O5sv8pgWKXrkPBttE98T+Mx/Pwz5JHs4Qcre3A5adm6cdab0AKug +eVG1PvHrWzV4aheg4KUfVSiMz8BG2K3Q1VGvZkgMRa/Q409FKjU6Z4D9vBG4Pas3 +PN5FxnAL6P70yWCEr2Vu/tWJlCN+qrRDfSaE2hqmT1irxaoPa61GvuRVsGQ3TeoE +mGfENtvFqC6qQWuSCbG5aI47Rv66pqoWWxqkrcolNc7+vhx6rW+wdFO3IlqIT8IG +sdQVp+Y4ir/dGp2ejzqGZCremPJ1uEKjLMpIukdg25ymHC0CAwEAATANBgkqhkiG +9w0BAQsFAAOCAQEABcRdwc9mdY9zOvTixtThHrciVvqwp6RaiQqMEVomozYilZDR +J90M3H6KnlADJbCv0FXujsaApB53awq5I7sObAYWFhDJZ9LKlw0lDF7KchLXiAlk +XVyvL2nJjuJcxPCFPWktwrw5bTguRCBzG12Hzikn+xs6uPur7VQYM33jbXEda5PS +UEqvAVWaONJCX8MDYOscVoJF0ESyI+fN92ipFaXR7fGajod/rc0AfeN2GVMZETve +21pkUyDwwCGA44uvNUCd1e32NxE3ah9UApCRn5sGJ64R6urpFTXT3IALF3kaOO7U +VsMhFrUiZ7+Bw5nIeiK0QOF6Eipj+bJvrLZpSg== -----END CERTIFICATE----- Bag Attributes - localKeyID: 05 3C 6A 9D 6D EC A0 FA 2F AE 41 32 0D 24 3A 21 34 F6 08 15 + localKeyID: 39 EC 3D 5B 28 17 DA DD 09 7A 62 68 D5 44 1F C7 E2 F8 E0 CD Key Attributes: <No Attributes> -----BEGIN ENCRYPTED PRIVATE KEY----- -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 +zLc= -----END ENCRYPTED PRIVATE KEY----- diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json index aabbfbf86..648215a63 100644 --- a/test/known_failures_Linux.json +++ b/test/known_failures_Linux.json @@ -41,6 +41,12 @@ "csharp-nodejs_json_framed-ip-ssl", "csharp-perl_binary_buffered-ip-ssl", "csharp-perl_binary_framed-ip-ssl", + "csharp-py3_binary_buffered-ip-ssl", + "csharp-py3_binary_framed-ip-ssl", + "csharp-py3_compact_buffered-ip-ssl", + "csharp-py3_compact_framed-ip-ssl", + "csharp-py3_json_buffered-ip-ssl", + "csharp-py3_json_framed-ip-ssl", "erl-cpp_compact_buffered-ip", "erl-cpp_compact_buffered-ip-ssl", "erl-cpp_compact_framed-ip", |