diff --git a/CHANGELOG.md b/CHANGELOG.md index ca32ec6f..e17ae139 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support [crud module](https://github.com/tarantool/crud) native API (#205). - Support `ssl_password` and `ssl_password_file` options to decrypt private SSL key file (#224). +- Support specifying authentication method with `auth_type` + and Tarantool EE `pap-sha256` authentication method (#269). ### Changed diff --git a/tarantool/connection.py b/tarantool/connection.py index 4d82369e..7fd43b9e 100644 --- a/tarantool/connection.py +++ b/tarantool/connection.py @@ -69,7 +69,11 @@ IPROTO_FEATURE_TRANSACTIONS, IPROTO_FEATURE_ERROR_EXTENSION, IPROTO_FEATURE_WATCHERS, + IPROTO_AUTH_TYPE, IPROTO_CHUNK, + AUTH_TYPE_CHAP_SHA1, + AUTH_TYPE_PAP_SHA256, + AUTH_TYPES, ) from tarantool.error import ( Error, @@ -574,7 +578,8 @@ def __init__(self, host, port, ssl_password=DEFAULT_SSL_PASSWORD, ssl_password_file=DEFAULT_SSL_PASSWORD_FILE, packer_factory=default_packer_factory, - unpacker_factory=default_unpacker_factory): + unpacker_factory=default_unpacker_factory, + auth_type=None): """ :param host: Server hostname or IP address. Use ``None`` for Unix sockets. @@ -723,6 +728,14 @@ def __init__(self, host, port, callable[[:obj:`~tarantool.Connection`], :obj:`~msgpack.Unpacker`], optional + :param auth_type: Authentication method: ``"chap-sha1"`` (supported in + Tarantool CE and EE) or ``"pap-sha256"`` (supported in Tarantool EE, + ``"ssl"`` :paramref:`~tarantool.Connection.transport` must be used). + If `None`, use authentication method provided by server in IPROTO_ID + exchange. If server does not provide an authentication method, use + ``"chap-sha1"``. + :type auth_type: :obj:`None` or :obj:`str`, optional + :raise: :exc:`~tarantool.error.ConfigurationError`, :meth:`~tarantool.Connection.connect` exceptions @@ -778,6 +791,8 @@ def __init__(self, host, port, } self._packer_factory_impl = packer_factory self._unpacker_factory_impl = unpacker_factory + self._client_auth_type = auth_type + self._server_auth_type = None if connect_now: self.connect() @@ -985,6 +1000,7 @@ def handshake(self): if greeting.protocol != "Binary": raise NetworkError("Unsupported protocol: " + greeting.protocol) self.version_id = greeting.version_id + self._check_features() self.uuid = greeting.uuid self._salt = greeting.salt if self.user: @@ -1008,7 +1024,6 @@ def connect(self): self.wrap_socket_ssl() self.handshake() self.load_schema() - self._check_features() except SslError as e: raise e except Exception as e: @@ -1390,13 +1405,44 @@ def authenticate(self, user, password): if not self._socket: return self._opt_reconnect() - request = RequestAuthenticate(self, self._salt, self.user, - self.password) + request = RequestAuthenticate(self, + salt=self._salt, + user=self.user, + password=self.password, + auth_type=self._get_auth_type()) auth_response = self._send_request_wo_reconnect(request) if auth_response.return_code == 0: self.flush_schema() return auth_response + def _get_auth_type(self): + """ + Get authentication method based on client and server settings. + + :rtype: :obj:`str` + + :raise: :exc:`~tarantool.error.DatabaseError` + + :meta private: + """ + + if self._client_auth_type is None: + if self._server_auth_type is None: + auth_type = AUTH_TYPE_CHAP_SHA1 + else: + if self._server_auth_type not in AUTH_TYPES: + raise ConfigurationError(f'Unknown server authentication type {self._server_auth_type}') + auth_type = self._server_auth_type + else: + if self._client_auth_type not in AUTH_TYPES: + raise ConfigurationError(f'Unknown client authentication type {self._client_auth_type}') + auth_type = self._client_auth_type + + if auth_type == AUTH_TYPE_PAP_SHA256 and self.transport != SSL_TRANSPORT: + raise ConfigurationError('Use PAP-SHA256 only with ssl transport') + + return auth_type + def _join_v16(self, server_uuid): """ Execute a JOIN request for Tarantool 1.6 and older. @@ -2037,11 +2083,13 @@ def _check_features(self): response = self._send_request(request) server_protocol_version = response.protocol_version server_features = response.features + server_auth_type = response.auth_type except DatabaseError as exc: ER_UNKNOWN_REQUEST_TYPE = 48 if exc.code == ER_UNKNOWN_REQUEST_TYPE: server_protocol_version = None server_features = [] + server_auth_type = None else: raise exc @@ -2054,6 +2102,8 @@ def _check_features(self): for val in features_list: self._features[val] = True + self._server_auth_type = server_auth_type + def _packer_factory(self): return self._packer_factory_impl(self) diff --git a/tarantool/connection_pool.py b/tarantool/connection_pool.py index a57d7284..362b7618 100644 --- a/tarantool/connection_pool.py +++ b/tarantool/connection_pool.py @@ -394,6 +394,7 @@ def __init__(self, "ssl_ciphers": "str" # optional "ssl_password": "str", # optional "ssl_password_file": "str" # optional + "auth_type": "str" # optional } Refer to corresponding :class:`~tarantool.Connection` @@ -498,7 +499,8 @@ def __init__(self, ssl_ca_file=addr['ssl_ca_file'], ssl_ciphers=addr['ssl_ciphers'], ssl_password=addr['ssl_password'], - ssl_password_file=addr['ssl_password_file']) + ssl_password_file=addr['ssl_password_file'], + auth_type=addr['auth_type']) ) if connect_now: diff --git a/tarantool/const.py b/tarantool/const.py index b23e5c68..6b12598d 100644 --- a/tarantool/const.py +++ b/tarantool/const.py @@ -40,6 +40,7 @@ # IPROTO_VERSION = 0x54 IPROTO_FEATURES = 0x55 +IPROTO_AUTH_TYPE = 0x5b IPROTO_CHUNK = 0x80 IPROTO_GREETING_SIZE = 128 @@ -134,3 +135,10 @@ CONNECTOR_IPROTO_VERSION = 3 # List of connector-supported features CONNECTOR_FEATURES = [IPROTO_FEATURE_ERROR_EXTENSION,] + +# Authenticate with CHAP-SHA1 (Tarantool CE and EE) +AUTH_TYPE_CHAP_SHA1 = "chap-sha1" +# Authenticate with PAP-SHA256 (Tarantool EE) +AUTH_TYPE_PAP_SHA256 = "pap-sha256" +# List of supported auth types. +AUTH_TYPES = [AUTH_TYPE_CHAP_SHA1, AUTH_TYPE_PAP_SHA256] diff --git a/tarantool/mesh_connection.py b/tarantool/mesh_connection.py index 214890dd..cc4def5a 100644 --- a/tarantool/mesh_connection.py +++ b/tarantool/mesh_connection.py @@ -41,6 +41,7 @@ 'ssl_ciphers': DEFAULT_SSL_CIPHERS, 'ssl_password': DEFAULT_SSL_PASSWORD, 'ssl_password_file': DEFAULT_SSL_PASSWORD_FILE, + 'auth_type': None, } @@ -194,6 +195,7 @@ def update_connection(conn, address): conn.ssl_ciphers = address['ssl_ciphers'] conn.ssl_password = address['ssl_password'] conn.ssl_password_file = address['ssl_password_file'] + conn.auth_type = address['auth_type'] class RoundRobinStrategy(object): @@ -277,6 +279,7 @@ def __init__(self, host=None, port=None, ssl_ciphers=DEFAULT_SSL_CIPHERS, ssl_password=DEFAULT_SSL_PASSWORD, ssl_password_file=DEFAULT_SSL_PASSWORD_FILE, + auth_type=None, addrs=None, strategy_class=RoundRobinStrategy, cluster_discovery_function=None, @@ -357,6 +360,11 @@ def __init__(self, host=None, port=None, Value would be used to add one more server in :paramref:`~tarantool.MeshConnection.params.addrs` list. + :param auth_type: Refer to + :paramref:`~tarantool.Connection.params.auth_type`. + Value would be used to add one more server in + :paramref:`~tarantool.MeshConnection.params.addrs` list. + :param addrs: Cluster servers addresses list. Refer to :paramref:`~tarantool.ConnectionPool.params.addrs`. @@ -437,7 +445,8 @@ def __init__(self, host=None, port=None, 'ssl_ca_file': ssl_ca_file, 'ssl_ciphers': ssl_ciphers, 'ssl_password': ssl_password, - 'ssl_password_file': ssl_password_file}) + 'ssl_password_file': ssl_password_file, + 'auth_type': auth_type}) # Verify that at least one address is provided. if not addrs: @@ -479,7 +488,8 @@ def __init__(self, host=None, port=None, ssl_ca_file=addr['ssl_ca_file'], ssl_ciphers=addr['ssl_ciphers'], ssl_password=addr['ssl_password'], - ssl_password_file=addr['ssl_password_file']) + ssl_password_file=addr['ssl_password_file'], + auth_type=addr['auth_type']) def connect(self): """ @@ -588,7 +598,8 @@ def _opt_refresh_instances(self): 'ssl_ca_file': self.ssl_ca_file, 'ssl_ciphers': self.ssl_ciphers, 'ssl_password': self.ssl_password, - 'ssl_password_file': self.ssl_password_file} + 'ssl_password_file': self.ssl_password_file, + 'auth_type': self._client_auth_type} if current_addr not in self.strategy.addrs: self.close() addr = self.strategy.getnext() diff --git a/tarantool/request.py b/tarantool/request.py index e9ea6e01..f6f6dfcb 100644 --- a/tarantool/request.py +++ b/tarantool/request.py @@ -51,6 +51,8 @@ REQUEST_TYPE_JOIN, REQUEST_TYPE_SUBSCRIBE, REQUEST_TYPE_ID, + AUTH_TYPE_CHAP_SHA1, + AUTH_TYPE_PAP_SHA256, ) from tarantool.response import ( Response, @@ -223,6 +225,26 @@ def __init__(self, conn, space_no, values): self._body = request_body +def sha1(values): + """ + Compute hash. + + :param values: Values to hash. + :type values: :obj:`tuple` + + :rtype: :obj:`str` + + :meta private: + """ + + sha = hashlib.sha1() + for i in values: + if i is not None: + if isinstance(i, bytes): + sha.update(i) + else: + sha.update(i.encode()) + return sha.digest() class RequestAuthenticate(Request): """ @@ -231,7 +253,7 @@ class RequestAuthenticate(Request): request_type = REQUEST_TYPE_AUTHENTICATE - def __init__(self, conn, salt, user, password): + def __init__(self, conn, salt, user, password, auth_type=AUTH_TYPE_CHAP_SHA1): """ :param conn: Request sender. :type conn: :class:`~tarantool.Connection` @@ -246,27 +268,25 @@ def __init__(self, conn, salt, user, password): :param password: User password for authentication on the Tarantool server. :type password: :obj:`str` + + :param auth_type: Refer to :paramref:`~tarantool.Connection.auth_type`. + :type auth_type: :obj:`str`, optional """ super(RequestAuthenticate, self).__init__(conn) - def sha1(values): - sha = hashlib.sha1() - for i in values: - if i is not None: - if isinstance(i, bytes): - sha.update(i) - else: - sha.update(i.encode()) - return sha.digest() - - hash1 = sha1((password,)) - hash2 = sha1((hash1,)) - scramble = sha1((salt, hash2)) - scramble = strxor(hash1, scramble) - request_body = self._dumps({IPROTO_USER_NAME: user, - IPROTO_TUPLE: ("chap-sha1", scramble)}) - self._body = request_body + if auth_type == AUTH_TYPE_CHAP_SHA1: + hash1 = sha1((password,)) + hash2 = sha1((hash1,)) + scramble = sha1((salt, hash2)) + scramble = strxor(hash1, scramble) + elif auth_type == AUTH_TYPE_PAP_SHA256: + scramble = password + else: + raise ValueError(f'Unexpected auth_type {auth_type}') + + self._body = self._dumps({IPROTO_USER_NAME: user, + IPROTO_TUPLE: (auth_type, scramble)}) def header(self, length): """ diff --git a/tarantool/response.py b/tarantool/response.py index 3ef931df..07a37cc5 100644 --- a/tarantool/response.py +++ b/tarantool/response.py @@ -21,6 +21,7 @@ IPROTO_SQL_INFO_AUTOINCREMENT_IDS, IPROTO_VERSION, IPROTO_FEATURES, + IPROTO_AUTH_TYPE, ) from tarantool.types import decode_box_error from tarantool.error import ( @@ -386,3 +387,14 @@ def features(self): return [] return self._body.get(IPROTO_FEATURES) + @property + def auth_type(self): + """ + Server expected authentication method. + + :rtype: :obj:`str` or :obj:`None` + """ + + if self._return_code != 0: + return None + return self._body.get(IPROTO_AUTH_TYPE) diff --git a/test/suites/box.lua b/test/suites/box.lua index ecd12499..f551bd1c 100644 --- a/test/suites/box.lua +++ b/test/suites/box.lua @@ -4,10 +4,12 @@ local os = require('os') local admin_listen = os.getenv("ADMIN") local primary_listen = os.getenv("LISTEN") +local auth_type = os.getenv("AUTH_TYPE") require('console').listen(admin_listen) box.cfg{ listen = primary_listen, memtx_memory = 0.1 * 1024^3, -- 0.1 GiB pid_file = "box.pid", + auth_type = (auth_type:len() > 0) and auth_type or nil, } diff --git a/test/suites/lib/skip.py b/test/suites/lib/skip.py index b7690782..5cc40d65 100644 --- a/test/suites/lib/skip.py +++ b/test/suites/lib/skip.py @@ -221,3 +221,18 @@ def skip_or_run_ssl_password_test_call(self): return skip_or_run_test_tarantool_call(self, '2.11.0', 'does not support SSL passwords') + +def skip_or_run_auth_type_test_call(self): + """Function to skip or run tests related to configuring + authentication method. + + Tarantool supports auth_type only in current master since + commit 2574ff1a (after 2.11.0-entrypoint). + See https://github.com/tarantool/tarantool/issues/7988 + https://github.com/tarantool/tarantool/issues/7989 + https://github.com/tarantool/tarantool-ee/issues/295 + https://github.com/tarantool/tarantool-ee/issues/322 + """ + + return skip_or_run_test_tarantool_call(self, '2.11.0', + 'does not support auth type') diff --git a/test/suites/lib/tarantool_server.py b/test/suites/lib/tarantool_server.py index 6c4c3398..ceecb5a7 100644 --- a/test/suites/lib/tarantool_server.py +++ b/test/suites/lib/tarantool_server.py @@ -127,7 +127,8 @@ def __new__(cls, ssl_ciphers=None, ssl_password=None, ssl_password_file=None, - create_unix_socket=False): + create_unix_socket=False, + auth_type=None): if os.name == 'nt': from .remote_tarantool_server import RemoteTarantoolServer return RemoteTarantoolServer() @@ -141,7 +142,8 @@ def __init__(self, ssl_ciphers=None, ssl_password=None, ssl_password_file=None, - create_unix_socket=False): + create_unix_socket=False, + auth_type=None): os.popen('ulimit -c unlimited').close() if create_unix_socket: @@ -168,6 +170,7 @@ def __init__(self, self.ssl_ciphers = ssl_ciphers self.ssl_password = ssl_password self.ssl_password_file = ssl_password_file + self.auth_type = auth_type def find_exe(self): if 'TARANTOOL_BOX_PATH' in os.environ: @@ -204,6 +207,10 @@ def generate_configuration(self): admin_listen = self.generate_listen(self.args['admin'], True) os.putenv("LISTEN", primary_listen) os.putenv("ADMIN", admin_listen) + if self.auth_type is not None: + os.putenv("AUTH_TYPE", self.auth_type) + else: + os.putenv("AUTH_TYPE", "") def prepare_args(self): return shlex.split(self.binary if not self.script else self.script_dst) diff --git a/test/suites/test_ssl.py b/test/suites/test_ssl.py index 65072b59..71d075d7 100644 --- a/test/suites/test_ssl.py +++ b/test/suites/test_ssl.py @@ -7,13 +7,16 @@ ) from tarantool.const import ( DEFAULT_TRANSPORT, - SSL_TRANSPORT + SSL_TRANSPORT, + AUTH_TYPE_CHAP_SHA1, + AUTH_TYPE_PAP_SHA256, ) import tarantool from .lib.tarantool_server import TarantoolServer from .lib.skip import ( fetch_tarantool_version, skip_or_run_ssl_password_test_call, + skip_or_run_auth_type_test_call, ) @@ -29,6 +32,7 @@ class SslTestCase: def __init__(self, name="", ok=False, + expected_error=tarantool.error.SslError, server_transport=SSL_TRANSPORT, server_key_file=None, server_cert_file=None, @@ -36,14 +40,18 @@ def __init__(self, server_ciphers=None, server_password=None, server_password_file=None, + server_auth_type=None, + client_transport=SSL_TRANSPORT, client_cert_file=None, client_key_file=None, client_ca_file=None, client_ciphers=None, client_password=None, - client_password_file=None): + client_password_file=None, + client_auth_type=None): self.name = name self.ok = ok + self.expected_error = expected_error self.server_transport = server_transport self.server_key_file = server_key_file self.server_cert_file = server_cert_file @@ -51,12 +59,15 @@ def __init__(self, self.server_ciphers = server_ciphers self.server_password = server_password self.server_password_file = server_password_file + self.server_auth_type = server_auth_type + self.client_transport = client_transport self.client_cert_file = client_cert_file self.client_key_file = client_key_file self.client_ca_file = client_ca_file self.client_ciphers = client_ciphers self.client_password = client_password self.client_password_file = client_password_file + self.client_auth_type = client_auth_type @unittest.skipIf(not is_test_ssl(), "TEST_TNT_SSL is not set.") class TestSuite_Ssl(unittest.TestCase): @@ -398,6 +409,46 @@ def test_single(self): client_ca_file=self.ca_file, client_ciphers="ECDHE-RSA-AES256-GCM-SHA384", client_password=self.password), + SslTestCase( + name="pap-sha256_auth", + ok=True, + server_key_file=self.key_file, + server_cert_file=self.cert_file, + server_auth_type=AUTH_TYPE_PAP_SHA256, + client_auth_type=AUTH_TYPE_PAP_SHA256), + SslTestCase( + name="chap-sha1_auth", + ok=True, + server_key_file=self.key_file, + server_cert_file=self.cert_file, + server_auth_type=AUTH_TYPE_CHAP_SHA1, + client_auth_type=AUTH_TYPE_CHAP_SHA1), + SslTestCase( + name="pap-sha256_auth_no_ssl", + ok=False, + expected_error=tarantool.error.NetworkError, + server_key_file=self.key_file, + server_cert_file=self.cert_file, + server_auth_type=AUTH_TYPE_CHAP_SHA1, + client_transport=DEFAULT_TRANSPORT, + client_auth_type=AUTH_TYPE_CHAP_SHA1), + SslTestCase( + name="auth_type_mismatch", + ok=False, + expected_error=tarantool.error.DatabaseError, + server_key_file=self.key_file, + server_cert_file=self.cert_file, + server_auth_type=AUTH_TYPE_PAP_SHA256, + client_auth_type=AUTH_TYPE_CHAP_SHA1), + # uncomment after this Tarantool EE SDK will be available on CI: + # tarantool-enterprise-sdk-nogc64-2.11.0-entrypoint-110 + # + # SslTestCase( + # name="auth_type_use_server_id", + # ok=True, + # server_key_file=self.key_file, + # server_cert_file=self.cert_file, + # server_auth_type=AUTH_TYPE_PAP_SHA256), ] for t in testcases: with self.subTest(msg=t.name): @@ -407,6 +458,10 @@ def test_single(self): or t.server_password_file is not None: skip_or_run_ssl_password_test_call(self) + if t.server_auth_type is not None \ + or t.client_auth_type is not None: + skip_or_run_auth_type_test_call(self) + srv = TarantoolServer( transport=t.server_transport, ssl_key_file=t.server_key_file, @@ -414,7 +469,8 @@ def test_single(self): ssl_ca_file=t.server_ca_file, ssl_ciphers=t.server_ciphers, ssl_password=t.server_password, - ssl_password_file=t.server_password_file) + ssl_password_file=t.server_password_file, + auth_type=t.server_auth_type) srv.script = 'test/suites/box.lua' srv.start() @@ -439,7 +495,7 @@ def test_single(self): srv.host, srv.args['primary'], user="test", password="test", - transport="ssl", + transport=t.client_transport, ssl_key_file=t.client_key_file, ssl_cert_file=t.client_cert_file, ssl_ca_file=t.client_ca_file, @@ -447,12 +503,13 @@ def test_single(self): ssl_password=t.client_password, ssl_password_file=t.client_password_file, connection_timeout=0.5, - socket_timeout=0.5) + socket_timeout=0.5, + auth_type=t.client_auth_type) self.assertEqual(con.insert('space_1', [1])[0], [1]) self.assertEqual(len(con.select('space_1')), 1) self.assertTrue(t.ok) - except tarantool.error.SslError: + except t.expected_error: self.assertFalse(t.ok) finally: self.stop_srv(srv) @@ -491,6 +548,26 @@ def test_pool(self): client_key_file=self.key_enc_file, client_cert_file=self.cert_file, client_password_file=self.password_file), + SslTestCase( + name="pap-sha256_auth", + ok=True, + server_key_file=self.key_file, + server_cert_file=self.cert_file, + server_ca_file=self.ca_file, + server_auth_type=AUTH_TYPE_PAP_SHA256, + client_key_file=self.key_file, + client_cert_file=self.cert_file, + client_ca_file=self.ca_file, + client_auth_type=AUTH_TYPE_PAP_SHA256), + # uncomment after this Tarantool EE SDK will be available on CI: + # tarantool-enterprise-sdk-nogc64-2.11.0-entrypoint-110 + # + # SslTestCase( + # name="auth_type_use_server_id", + # ok=True, + # server_key_file=self.key_file, + # server_cert_file=self.cert_file, + # server_auth_type=AUTH_TYPE_PAP_SHA256), ] for t in testcases: cnt = 5 @@ -501,17 +578,22 @@ def test_pool(self): or t.server_password_file is not None: skip_or_run_ssl_password_test_call(self) + if t.server_auth_type is not None \ + or t.client_auth_type is not None: + skip_or_run_auth_type_test_call(self) + addrs = [] servers = [] for i in range(cnt): srv = TarantoolServer( - transport='ssl', + transport=t.server_transport, ssl_key_file=t.server_key_file, ssl_cert_file=t.server_cert_file, ssl_ca_file=t.server_ca_file, ssl_ciphers=t.server_ciphers, ssl_password=t.server_password, - ssl_password_file=t.server_password_file) + ssl_password_file=t.server_password_file, + auth_type=t.server_auth_type) srv.script = 'test/suites/box.lua' srv.start() srv.admin(""" @@ -524,7 +606,7 @@ def test_pool(self): addr = { 'host': srv.host, 'port': srv.args['primary'], - 'transport': 'ssl', + 'transport': t.client_transport, } if t.client_key_file is not None: addr['ssl_key_file'] = t.client_key_file @@ -538,6 +620,8 @@ def test_pool(self): addr['ssl_password'] = t.client_password if t.client_password_file is not None: addr['ssl_password_file'] = t.client_password_file + if t.client_auth_type is not None: + addr['auth_type'] = t.client_auth_type addrs.append(addr) pool = None @@ -551,7 +635,7 @@ def test_pool(self): self.assertSequenceEqual( pool.eval('return box.info().ro', mode=tarantool.Mode.RW), [False]) - except tarantool.error.SslError: + except t.expected_error: self.assertFalse(t.ok) finally: self.stop_pool(pool) @@ -588,6 +672,30 @@ def test_mesh(self): client_key_file=self.key_enc_file, client_cert_file=self.cert_file, client_password_file=self.password_file), + SslTestCase( + name="pap-sha256_auth", + ok=True, + server_key_file=self.key_file, + server_cert_file=self.cert_file, + server_ca_file=self.ca_file, + server_auth_type=AUTH_TYPE_PAP_SHA256, + client_key_file=self.key_file, + client_cert_file=self.cert_file, + client_ca_file=self.ca_file, + client_auth_type=AUTH_TYPE_PAP_SHA256), + # uncomment after this Tarantool EE SDK will be available on CI: + # tarantool-enterprise-sdk-nogc64-2.11.0-entrypoint-110 + # + # SslTestCase( + # name="auth_type_use_server_id", + # ok=True, + # server_key_file=self.key_file, + # server_cert_file=self.cert_file, + # server_ca_file=self.ca_file, + # server_auth_type=AUTH_TYPE_PAP_SHA256 + # client_key_file=self.key_file, + # client_cert_file=self.cert_file, + # client_ca_file=self.ca_file,), ] for t in testcases: cnt = 5 @@ -598,17 +706,22 @@ def test_mesh(self): or t.server_password_file is not None: skip_or_run_ssl_password_test_call(self) + if t.server_auth_type is not None \ + or t.client_auth_type is not None: + skip_or_run_auth_type_test_call(self) + addrs = [] servers = [] for i in range(cnt): srv = TarantoolServer( - transport='ssl', + transport=t.server_transport, ssl_key_file=t.server_key_file, ssl_cert_file=t.server_cert_file, ssl_ca_file=t.server_ca_file, ssl_ciphers=t.server_ciphers, ssl_password=t.server_password, - ssl_password_file=t.server_password_file) + ssl_password_file=t.server_password_file, + auth_type=t.server_auth_type) srv.script = 'test/suites/box.lua' srv.start() srv.admin(""" @@ -622,7 +735,7 @@ def test_mesh(self): addr = { 'host': srv.host, 'port': srv.args['primary'], - 'transport': 'ssl', + 'transport': t.client_transport, } if t.client_key_file is not None: addr['ssl_key_file'] = t.client_key_file @@ -636,6 +749,8 @@ def test_mesh(self): addr['ssl_password'] = t.client_password if t.client_password_file is not None: addr['ssl_password_file'] = t.client_password_file + if t.client_auth_type is not None: + addr['auth_type'] = t.client_auth_type addrs.append(addr) mesh = None @@ -652,7 +767,9 @@ def test_mesh(self): resp = mesh.call('srv_id') self.assertEqual(resp.data and resp.data[0], i) servers[i].stop() - except tarantool.error.SslError: + servers[i].clean() + servers = [] + except t.expected_error: self.assertFalse(t.ok) finally: self.stop_mesh(mesh)