blob: 896d69c14c9f77d25d15cae599b2b4f8add7d5a9 [file] [log] [blame]
Bryan Duxbury50409112011-03-21 17:59:49 +00001#
2# Licensed to the Apache Software Foundation (ASF) under one
3# or more contributor license agreements. See the NOTICE file
4# distributed with this work for additional information
5# regarding copyright ownership. The ASF licenses this file
6# to you under the Apache License, Version 2.0 (the
7# "License"); you may not use this file except in compliance
8# with the License. You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing,
13# software distributed under the License is distributed on an
14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15# KIND, either express or implied. See the License for the
16# specific language governing permissions and limitations
17# under the License.
18#
Bryan Duxbury69720412012-01-03 17:32:30 +000019
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090020import logging
Bryan Duxbury50409112011-03-21 17:59:49 +000021import os
22import socket
23import ssl
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090024import sys
25import warnings
Bryan Duxbury2b969ad2011-02-22 18:20:53 +000026
Susanne Lindgren7ec41772024-10-08 08:12:27 +020027from .sslcompat import _match_has_ipaddress
Bryan Duxbury2b969ad2011-02-22 18:20:53 +000028from thrift.transport import TSocket
Bryan Duxbury50409112011-03-21 17:59:49 +000029from thrift.transport.TTransport import TTransportException
Bryan Duxbury2b969ad2011-02-22 18:20:53 +000030
Dmytro Shteflyukacbcf102026-02-13 18:25:55 -050031
32def _match_hostname(cert, hostname):
33 return True
34
Susanne Lindgren7ec41772024-10-08 08:12:27 +020035
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090036logger = logging.getLogger(__name__)
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +090037warnings.filterwarnings(
38 'default', category=DeprecationWarning, module=__name__)
Bryan Duxbury69720412012-01-03 17:32:30 +000039
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090040
41class TSSLBase(object):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090042 # SSLContext is not available for Python < 2.7.9
43 _has_ssl_context = sys.hexversion >= 0x020709F0
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090044
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090045 # ciphers argument is not available for Python < 2.7.0
46 _has_ciphers = sys.hexversion >= 0x020700F0
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090047
James E. King, III36628a22017-02-13 15:25:41 -050048 # For python >= 2.7.9, use latest TLS that both client and server
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +090049 # supports.
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090050 # SSL 2.0 and 3.0 are disabled via ssl.OP_NO_SSLv2 and ssl.OP_NO_SSLv3.
James E. King, III36628a22017-02-13 15:25:41 -050051 # For python < 2.7.9, use TLS 1.0 since TLSv1_X nor OP_NO_SSLvX is
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +090052 # unavailable.
Carele720e6f2025-11-07 10:48:27 +020053 # For python < 3.6, use SSLv23 since TLS is not available
54 if sys.version_info < (3, 6):
55 _default_protocol = ssl.PROTOCOL_SSLv23 if _has_ssl_context else \
56 ssl.PROTOCOL_TLSv1
57 else:
58 _default_protocol = ssl.PROTOCOL_TLS_CLIENT if _has_ssl_context else \
59 ssl.PROTOCOL_TLSv1
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090060
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090061 def _init_context(self, ssl_version):
62 if self._has_ssl_context:
63 self._context = ssl.SSLContext(ssl_version)
64 if self._context.protocol == ssl.PROTOCOL_SSLv23:
65 self._context.options |= ssl.OP_NO_SSLv2
66 self._context.options |= ssl.OP_NO_SSLv3
67 else:
68 self._context = None
69 self._ssl_version = ssl_version
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090070
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090071 @property
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +090072 def _should_verify(self):
73 if self._has_ssl_context:
74 return self._context.verify_mode != ssl.CERT_NONE
75 else:
76 return self.cert_reqs != ssl.CERT_NONE
77
78 @property
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090079 def ssl_version(self):
80 if self._has_ssl_context:
81 return self.ssl_context.protocol
82 else:
83 return self._ssl_version
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090084
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090085 @property
86 def ssl_context(self):
87 return self._context
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090088
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090089 SSL_VERSION = _default_protocol
90 """
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090091 Default SSL version.
Tim Armstrong6b3f7d92019-02-14 14:59:22 -080092 For backwards compatibility, it can be modified.
93 Use __init__ keyword argument "ssl_version" instead.
Nobuaki Sukegawaad835862015-12-23 23:32:09 +090094 """
95
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +090096 def _deprecated_arg(self, args, kwargs, pos, key):
97 if len(args) <= pos:
98 return
99 real_pos = pos + 3
100 warnings.warn(
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900101 '%dth positional argument is deprecated.'
Tim Armstrong6b3f7d92019-02-14 14:59:22 -0800102 'please use keyword argument instead.'
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900103 % real_pos, DeprecationWarning, stacklevel=3)
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900104
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900105 if key in kwargs:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900106 raise TypeError(
Tim Armstrong6b3f7d92019-02-14 14:59:22 -0800107 'Duplicate argument: %dth argument and %s keyword argument.'
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900108 % (real_pos, key))
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900109 kwargs[key] = args[pos]
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900110
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900111 def _unix_socket_arg(self, host, port, args, kwargs):
112 key = 'unix_socket'
113 if host is None and port is None and len(args) == 1 and key not in kwargs:
114 kwargs[key] = args[0]
115 return True
116 return False
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900117
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900118 def __getattr__(self, key):
119 if key == 'SSL_VERSION':
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900120 warnings.warn(
121 'SSL_VERSION is deprecated.'
122 'please use ssl_version attribute instead.',
123 DeprecationWarning, stacklevel=2)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900124 return self.ssl_version
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900125
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900126 def __init__(self, server_side, host, ssl_opts):
127 self._server_side = server_side
128 if TSSLBase.SSL_VERSION != self._default_protocol:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900129 warnings.warn(
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900130 'SSL_VERSION is deprecated.'
Tim Armstrong6b3f7d92019-02-14 14:59:22 -0800131 'please use ssl_version keyword argument instead.',
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900132 DeprecationWarning, stacklevel=2)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900133 self._context = ssl_opts.pop('ssl_context', None)
134 self._server_hostname = None
135 if not self._server_side:
136 self._server_hostname = ssl_opts.pop('server_hostname', host)
137 if self._context:
138 self._custom_context = True
139 if ssl_opts:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900140 raise ValueError(
141 'Incompatible arguments: ssl_context and %s'
142 % ' '.join(ssl_opts.keys()))
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900143 if not self._has_ssl_context:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900144 raise ValueError(
145 'ssl_context is not available for this version of Python')
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900146 else:
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900147 self._custom_context = False
148 ssl_version = ssl_opts.pop('ssl_version', TSSLBase.SSL_VERSION)
149 self._init_context(ssl_version)
150 self.cert_reqs = ssl_opts.pop('cert_reqs', ssl.CERT_REQUIRED)
151 self.ca_certs = ssl_opts.pop('ca_certs', None)
152 self.keyfile = ssl_opts.pop('keyfile', None)
153 self.certfile = ssl_opts.pop('certfile', None)
154 self.ciphers = ssl_opts.pop('ciphers', None)
155
156 if ssl_opts:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900157 raise ValueError(
158 'Unknown keyword arguments: ', ' '.join(ssl_opts.keys()))
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900159
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900160 if self._should_verify:
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900161 if not self.ca_certs:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900162 raise ValueError(
163 'ca_certs is needed when cert_reqs is not ssl.CERT_NONE')
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900164 if not os.access(self.ca_certs, os.R_OK):
165 raise IOError('Certificate Authority ca_certs file "%s" '
166 'is not readable, cannot validate SSL '
167 'certificates.' % (self.ca_certs))
168
169 @property
170 def certfile(self):
171 return self._certfile
172
173 @certfile.setter
174 def certfile(self, certfile):
175 if self._server_side and not certfile:
176 raise ValueError('certfile is needed for server-side')
177 if certfile and not os.access(certfile, os.R_OK):
178 raise IOError('No such certfile found: %s' % (certfile))
179 self._certfile = certfile
180
181 def _wrap_socket(self, sock):
182 if self._has_ssl_context:
183 if not self._custom_context:
184 self.ssl_context.verify_mode = self.cert_reqs
185 if self.certfile:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900186 self.ssl_context.load_cert_chain(self.certfile,
187 self.keyfile)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900188 if self.ciphers:
189 self.ssl_context.set_ciphers(self.ciphers)
190 if self.ca_certs:
191 self.ssl_context.load_verify_locations(self.ca_certs)
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900192 return self.ssl_context.wrap_socket(
193 sock, server_side=self._server_side,
194 server_hostname=self._server_hostname)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900195 else:
196 ssl_opts = {
197 'ssl_version': self._ssl_version,
198 'server_side': self._server_side,
199 'ca_certs': self.ca_certs,
200 'keyfile': self.keyfile,
201 'certfile': self.certfile,
202 'cert_reqs': self.cert_reqs,
203 }
204 if self.ciphers:
205 if self._has_ciphers:
206 ssl_opts['ciphers'] = self.ciphers
207 else:
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900208 logger.warning(
209 'ciphers is specified but ignored due to old Python version')
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900210 return ssl.wrap_socket(sock, **ssl_opts)
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900211
212
213class TSSLSocket(TSocket.TSocket, TSSLBase):
Bryan Duxbury50409112011-03-21 17:59:49 +0000214 """
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900215 SSL implementation of TSocket
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900216
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900217 This class creates outbound sockets wrapped using the
218 python standard ssl module for encrypted connections.
219 """
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900220
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900221 # New signature
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900222 # def __init__(self, host='localhost', port=9090, unix_socket=None,
223 # **ssl_args):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900224 # Deprecated signature
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900225 # def __init__(self, host='localhost', port=9090, validate=True,
226 # ca_certs=None, keyfile=None, certfile=None,
227 # unix_socket=None, ciphers=None):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900228 def __init__(self, host='localhost', port=9090, *args, **kwargs):
229 """Positional arguments: ``host``, ``port``, ``unix_socket``
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900230
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900231 Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``,
232 ``ssl_version``, ``ca_certs``,
233 ``ciphers`` (Python 2.7.0 or later),
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900234 ``server_hostname`` (Python 2.7.9 or later)
235 Passed to ssl.wrap_socket. See ssl.wrap_socket documentation.
Bryan Duxbury50409112011-03-21 17:59:49 +0000236
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900237 Alternative keyword arguments: (Python 2.7.9 or later)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900238 ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket
239 ``server_hostname``: Passed to SSLContext.wrap_socket
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900240
241 Common keyword argument:
242 ``validate_callback`` (cert, hostname) -> None:
243 Called after SSL handshake. Can raise when hostname does not
244 match the cert.
Junf6511c92019-02-01 12:07:58 +0800245 ``socket_keepalive`` enable TCP keepalive, default off.
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900246 """
247 self.is_valid = False
248 self.peercert = None
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900249
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900250 if args:
251 if len(args) > 6:
252 raise TypeError('Too many positional argument')
253 if not self._unix_socket_arg(host, port, args, kwargs):
254 self._deprecated_arg(args, kwargs, 0, 'validate')
255 self._deprecated_arg(args, kwargs, 1, 'ca_certs')
256 self._deprecated_arg(args, kwargs, 2, 'keyfile')
257 self._deprecated_arg(args, kwargs, 3, 'certfile')
258 self._deprecated_arg(args, kwargs, 4, 'unix_socket')
259 self._deprecated_arg(args, kwargs, 5, 'ciphers')
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900260
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900261 validate = kwargs.pop('validate', None)
262 if validate is not None:
263 cert_reqs_name = 'CERT_REQUIRED' if validate else 'CERT_NONE'
264 warnings.warn(
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900265 'validate is deprecated. please use cert_reqs=ssl.%s instead'
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900266 % cert_reqs_name,
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900267 DeprecationWarning, stacklevel=2)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900268 if 'cert_reqs' in kwargs:
269 raise TypeError('Cannot specify both validate and cert_reqs')
270 kwargs['cert_reqs'] = ssl.CERT_REQUIRED if validate else ssl.CERT_NONE
271
272 unix_socket = kwargs.pop('unix_socket', None)
Junf6511c92019-02-01 12:07:58 +0800273 socket_keepalive = kwargs.pop('socket_keepalive', False)
Nobuaki Sukegawaf32bae72016-02-20 08:51:33 +0900274 self._validate_callback = kwargs.pop('validate_callback', _match_hostname)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900275 TSSLBase.__init__(self, False, host, kwargs)
Junf6511c92019-02-01 12:07:58 +0800276 TSocket.TSocket.__init__(self, host, port, unix_socket,
277 socket_keepalive=socket_keepalive)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900278
James E. King III638c91f2019-01-26 10:33:04 -0500279 def close(self):
280 try:
281 self.handle.settimeout(0.001)
282 self.handle = self.handle.unwrap()
283 except (ssl.SSLError, socket.error, OSError):
284 # could not complete shutdown in a reasonable amount of time. bail.
285 pass
286 TSocket.TSocket.close(self)
287
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900288 @property
289 def validate(self):
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900290 warnings.warn('validate is deprecated. please use cert_reqs instead',
291 DeprecationWarning, stacklevel=2)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900292 return self.cert_reqs != ssl.CERT_NONE
293
294 @validate.setter
295 def validate(self, value):
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900296 warnings.warn('validate is deprecated. please use cert_reqs instead',
297 DeprecationWarning, stacklevel=2)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900298 self.cert_reqs = ssl.CERT_REQUIRED if value else ssl.CERT_NONE
299
Nobuaki Sukegawa1c8b5cb2016-02-14 22:04:38 +0900300 def _do_open(self, family, socktype):
301 plain_sock = socket.socket(family, socktype)
Bryan Duxbury2b969ad2011-02-22 18:20:53 +0000302 try:
Nobuaki Sukegawa1c8b5cb2016-02-14 22:04:38 +0900303 return self._wrap_socket(plain_sock)
James E. King III3131fe92019-07-02 14:21:05 -0400304 except Exception as ex:
Nobuaki Sukegawa1c8b5cb2016-02-14 22:04:38 +0900305 plain_sock.close()
306 msg = 'failed to initialize SSL'
307 logger.exception(msg)
James E. King III3131fe92019-07-02 14:21:05 -0400308 raise TTransportException(type=TTransportException.NOT_OPEN, message=msg, inner=ex)
Bryan Duxbury50409112011-03-21 17:59:49 +0000309
Nobuaki Sukegawa1c8b5cb2016-02-14 22:04:38 +0900310 def open(self):
311 super(TSSLSocket, self).open()
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900312 if self._should_verify:
313 self.peercert = self.handle.getpeercert()
314 try:
315 self._validate_callback(self.peercert, self._server_hostname)
316 self.is_valid = True
317 except TTransportException:
318 raise
319 except Exception as ex:
James E. King III3131fe92019-07-02 14:21:05 -0400320 raise TTransportException(message=str(ex), inner=ex)
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900321
Bryan Duxbury2b969ad2011-02-22 18:20:53 +0000322
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900323class TSSLServerSocket(TSocket.TServerSocket, TSSLBase):
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900324 """SSL implementation of TServerSocket
Bryan Duxbury50409112011-03-21 17:59:49 +0000325
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900326 This uses the ssl module's wrap_socket() method to provide SSL
327 negotiated encryption.
Bryan Duxbury50409112011-03-21 17:59:49 +0000328 """
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900329
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900330 # New signature
331 # def __init__(self, host='localhost', port=9090, unix_socket=None, **ssl_args):
332 # Deprecated signature
333 # def __init__(self, host=None, port=9090, certfile='cert.pem', unix_socket=None, ciphers=None):
334 def __init__(self, host=None, port=9090, *args, **kwargs):
335 """Positional arguments: ``host``, ``port``, ``unix_socket``
Nobuaki Sukegawaad835862015-12-23 23:32:09 +0900336
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900337 Keyword arguments: ``keyfile``, ``certfile``, ``cert_reqs``, ``ssl_version``,
338 ``ca_certs``, ``ciphers`` (Python 2.7.0 or later)
339 See ssl.wrap_socket documentation.
Bryan Duxbury50409112011-03-21 17:59:49 +0000340
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900341 Alternative keyword arguments: (Python 2.7.9 or later)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900342 ``ssl_context``: ssl.SSLContext to be used for SSLContext.wrap_socket
343 ``server_hostname``: Passed to SSLContext.wrap_socket
Nobuaki Sukegawaf39f7db2016-02-04 15:09:41 +0900344
345 Common keyword argument:
346 ``validate_callback`` (cert, hostname) -> None:
347 Called after SSL handshake. Can raise when hostname does not
348 match the cert.
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900349 """
350 if args:
351 if len(args) > 3:
352 raise TypeError('Too many positional argument')
353 if not self._unix_socket_arg(host, port, args, kwargs):
354 self._deprecated_arg(args, kwargs, 0, 'certfile')
355 self._deprecated_arg(args, kwargs, 1, 'unix_socket')
356 self._deprecated_arg(args, kwargs, 2, 'ciphers')
Bryan Duxbury69720412012-01-03 17:32:30 +0000357
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900358 if 'ssl_context' not in kwargs:
359 # Preserve existing behaviors for default values
360 if 'cert_reqs' not in kwargs:
361 kwargs['cert_reqs'] = ssl.CERT_NONE
Dmytro Shteflyukacbcf102026-02-13 18:25:55 -0500362 if 'certfile' not in kwargs:
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900363 kwargs['certfile'] = 'cert.pem'
Bryan Duxbury69720412012-01-03 17:32:30 +0000364
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900365 unix_socket = kwargs.pop('unix_socket', None)
Nobuaki Sukegawaf39f7db2016-02-04 15:09:41 +0900366 self._validate_callback = \
Nobuaki Sukegawaf32bae72016-02-20 08:51:33 +0900367 kwargs.pop('validate_callback', _match_hostname)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900368 TSSLBase.__init__(self, True, None, kwargs)
369 TSocket.TServerSocket.__init__(self, host, port, unix_socket)
Nobuaki Sukegawaf32bae72016-02-20 08:51:33 +0900370 if self._should_verify and not _match_has_ipaddress:
Nobuaki Sukegawabf9fa902016-09-04 18:49:21 +0900371 raise ValueError('Need ipaddress and backports.ssl_match_hostname '
Nobuaki Sukegawaf32bae72016-02-20 08:51:33 +0900372 'module to verify client certificate')
Bryan Duxbury50409112011-03-21 17:59:49 +0000373
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900374 def setCertfile(self, certfile):
Nobuaki Sukegawa25536ad2016-02-04 15:08:55 +0900375 """Set or change the server certificate file used to wrap new
376 connections.
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900377
378 @param certfile: The filename of the server certificate,
379 i.e. '/etc/certs/server.pem'
380 @type certfile: str
381
382 Raises an IOError exception if the certfile is not present or unreadable.
383 """
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900384 warnings.warn(
385 'setCertfile is deprecated. please use certfile property instead.',
386 DeprecationWarning, stacklevel=2)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900387 self.certfile = certfile
388
389 def accept(self):
390 plain_client, addr = self.handle.accept()
391 try:
392 client = self._wrap_socket(plain_client)
James E. King IIIf5f430d2018-06-08 03:37:55 +0000393 except (ssl.SSLError, socket.error, OSError):
Nobuaki Sukegawace1c8ab2016-02-11 18:21:39 +0900394 logger.exception('Error while accepting from %s', addr)
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900395 # failed handshake/ssl wrap, close socket to client
396 plain_client.close()
397 # raise
398 # We can't raise the exception, because it kills most TServer derived
399 # serve() methods.
400 # Instead, return None, and let the TServer instance deal with it in
401 # other exception handling. (but TSimpleServer dies anyway)
402 return None
Nobuaki Sukegawaf39f7db2016-02-04 15:09:41 +0900403
404 if self._should_verify:
405 client.peercert = client.getpeercert()
406 try:
407 self._validate_callback(client.peercert, addr[0])
408 client.is_valid = True
409 except Exception:
Alexander Shadchin0bc2cb92024-07-21 23:27:26 +0300410 logger.warning('Failed to validate client certificate address: %s',
411 addr[0], exc_info=True)
Nobuaki Sukegawaf39f7db2016-02-04 15:09:41 +0900412 client.close()
413 plain_client.close()
414 return None
415
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900416 result = TSocket.TSocket()
Nobuaki Sukegawa6a0ca7f2016-02-13 03:11:16 +0900417 result.handle = client
Nobuaki Sukegawa10308cb2016-02-03 01:57:03 +0900418 return result