6969 IPROTO_FEATURE_TRANSACTIONS ,
7070 IPROTO_FEATURE_ERROR_EXTENSION ,
7171 IPROTO_FEATURE_WATCHERS ,
72+ IPROTO_AUTH_TYPE ,
7273 IPROTO_CHUNK ,
74+ AUTH_TYPE_CHAP_SHA1 ,
75+ AUTH_TYPE_PAP_SHA256 ,
76+ AUTH_TYPES ,
7377)
7478from tarantool .error import (
7579 Error ,
@@ -574,7 +578,8 @@ def __init__(self, host, port,
574578 ssl_password = DEFAULT_SSL_PASSWORD ,
575579 ssl_password_file = DEFAULT_SSL_PASSWORD_FILE ,
576580 packer_factory = default_packer_factory ,
577- unpacker_factory = default_unpacker_factory ):
581+ unpacker_factory = default_unpacker_factory ,
582+ auth_type = None ):
578583 """
579584 :param host: Server hostname or IP address. Use ``None`` for
580585 Unix sockets.
@@ -723,6 +728,14 @@ def __init__(self, host, port,
723728 callable[[:obj:`~tarantool.Connection`], :obj:`~msgpack.Unpacker`],
724729 optional
725730
731+ :param auth_type: Authentication method: ``"chap-sha1"`` (supported in
732+ Tarantool CE and EE) or ``"pap-sha256"`` (supported in Tarantool EE,
733+ ``"ssl"`` :paramref:`~tarantool.Connection.transport` must be used).
734+ If `None`, use authentication method provided by server in IPROTO_ID
735+ exchange. If server does not provide an authentication method, use
736+ ``"chap-sha1"``.
737+ :type auth_type: :obj:`None` or :obj:`str`, optional
738+
726739 :raise: :exc:`~tarantool.error.ConfigurationError`,
727740 :meth:`~tarantool.Connection.connect` exceptions
728741
@@ -778,6 +791,8 @@ def __init__(self, host, port,
778791 }
779792 self ._packer_factory_impl = packer_factory
780793 self ._unpacker_factory_impl = unpacker_factory
794+ self ._client_auth_type = auth_type
795+ self ._server_auth_type = None
781796
782797 if connect_now :
783798 self .connect ()
@@ -985,6 +1000,7 @@ def handshake(self):
9851000 if greeting .protocol != "Binary" :
9861001 raise NetworkError ("Unsupported protocol: " + greeting .protocol )
9871002 self .version_id = greeting .version_id
1003+ self ._check_features ()
9881004 self .uuid = greeting .uuid
9891005 self ._salt = greeting .salt
9901006 if self .user :
@@ -1008,7 +1024,6 @@ def connect(self):
10081024 self .wrap_socket_ssl ()
10091025 self .handshake ()
10101026 self .load_schema ()
1011- self ._check_features ()
10121027 except SslError as e :
10131028 raise e
10141029 except Exception as e :
@@ -1390,13 +1405,44 @@ def authenticate(self, user, password):
13901405 if not self ._socket :
13911406 return self ._opt_reconnect ()
13921407
1393- request = RequestAuthenticate (self , self ._salt , self .user ,
1394- self .password )
1408+ request = RequestAuthenticate (self ,
1409+ salt = self ._salt ,
1410+ user = self .user ,
1411+ password = self .password ,
1412+ auth_type = self ._get_auth_type ())
13951413 auth_response = self ._send_request_wo_reconnect (request )
13961414 if auth_response .return_code == 0 :
13971415 self .flush_schema ()
13981416 return auth_response
13991417
1418+ def _get_auth_type (self ):
1419+ """
1420+ Get authentication method based on client and server settings.
1421+
1422+ :rtype: :obj:`str`
1423+
1424+ :raise: :exc:`~tarantool.error.DatabaseError`
1425+
1426+ :meta private:
1427+ """
1428+
1429+ if self ._client_auth_type is None :
1430+ if self ._server_auth_type is None :
1431+ auth_type = AUTH_TYPE_CHAP_SHA1
1432+ else :
1433+ if self ._server_auth_type not in AUTH_TYPES :
1434+ raise ConfigurationError (f'Unknown server authentication type { self ._server_auth_type } ' )
1435+ auth_type = self ._server_auth_type
1436+ else :
1437+ if self ._client_auth_type not in AUTH_TYPES :
1438+ raise ConfigurationError (f'Unknown client authentication type { self ._client_auth_type } ' )
1439+ auth_type = self ._client_auth_type
1440+
1441+ if auth_type == AUTH_TYPE_PAP_SHA256 and self .transport != SSL_TRANSPORT :
1442+ raise ConfigurationError ('Use PAP-SHA256 only with ssl transport' )
1443+
1444+ return auth_type
1445+
14001446 def _join_v16 (self , server_uuid ):
14011447 """
14021448 Execute a JOIN request for Tarantool 1.6 and older.
@@ -2037,11 +2083,13 @@ def _check_features(self):
20372083 response = self ._send_request (request )
20382084 server_protocol_version = response .protocol_version
20392085 server_features = response .features
2086+ server_auth_type = response .auth_type
20402087 except DatabaseError as exc :
20412088 ER_UNKNOWN_REQUEST_TYPE = 48
20422089 if exc .code == ER_UNKNOWN_REQUEST_TYPE :
20432090 server_protocol_version = None
20442091 server_features = []
2092+ server_auth_type = None
20452093 else :
20462094 raise exc
20472095
@@ -2054,6 +2102,8 @@ def _check_features(self):
20542102 for val in features_list :
20552103 self ._features [val ] = True
20562104
2105+ self ._server_auth_type = server_auth_type
2106+
20572107 def _packer_factory (self ):
20582108 return self ._packer_factory_impl (self )
20592109
0 commit comments