summaryrefslogtreecommitdiffstats
path: root/src/jaegertracing/thrift/lib/py/src/transport/sslcompat.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/jaegertracing/thrift/lib/py/src/transport/sslcompat.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/py/src/transport/sslcompat.py b/src/jaegertracing/thrift/lib/py/src/transport/sslcompat.py
new file mode 100644
index 000000000..ab00cb2a8
--- /dev/null
+++ b/src/jaegertracing/thrift/lib/py/src/transport/sslcompat.py
@@ -0,0 +1,100 @@
+#
+# 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 logging
+import sys
+
+from thrift.transport.TTransport import TTransportException
+
+logger = logging.getLogger(__name__)
+
+
+def legacy_validate_callback(cert, hostname):
+ """legacy method to validate the peer's SSL certificate, and to check
+ the commonName of the certificate to ensure it matches the hostname we
+ used to make this connection. Does not support subjectAltName records
+ in certificates.
+
+ raises TTransportException if the certificate fails validation.
+ """
+ if 'subject' not in cert:
+ raise TTransportException(
+ TTransportException.NOT_OPEN,
+ 'No SSL certificate found from %s' % hostname)
+ fields = cert['subject']
+ for field in fields:
+ # ensure structure we get back is what we expect
+ if not isinstance(field, tuple):
+ continue
+ cert_pair = field[0]
+ if len(cert_pair) < 2:
+ continue
+ cert_key, cert_value = cert_pair[0:2]
+ if cert_key != 'commonName':
+ continue
+ certhost = cert_value
+ # this check should be performed by some sort of Access Manager
+ if certhost == hostname:
+ # success, cert commonName matches desired hostname
+ return
+ else:
+ raise TTransportException(
+ TTransportException.UNKNOWN,
+ 'Hostname we connected to "%s" doesn\'t match certificate '
+ 'provided commonName "%s"' % (hostname, certhost))
+ raise TTransportException(
+ TTransportException.UNKNOWN,
+ 'Could not validate SSL certificate from host "%s". Cert=%s'
+ % (hostname, cert))
+
+
+def _optional_dependencies():
+ try:
+ import ipaddress # noqa
+ logger.debug('ipaddress module is available')
+ ipaddr = True
+ except ImportError:
+ logger.warn('ipaddress module is unavailable')
+ ipaddr = False
+
+ if sys.hexversion < 0x030500F0:
+ try:
+ from backports.ssl_match_hostname import match_hostname, __version__ as ver
+ ver = list(map(int, ver.split('.')))
+ logger.debug('backports.ssl_match_hostname module is available')
+ match = match_hostname
+ if ver[0] * 10 + ver[1] >= 35:
+ return ipaddr, match
+ else:
+ logger.warn('backports.ssl_match_hostname module is too old')
+ ipaddr = False
+ except ImportError:
+ logger.warn('backports.ssl_match_hostname is unavailable')
+ ipaddr = False
+ try:
+ from ssl import match_hostname
+ logger.debug('ssl.match_hostname is available')
+ match = match_hostname
+ except ImportError:
+ logger.warn('using legacy validation callback')
+ match = legacy_validate_callback
+ return ipaddr, match
+
+
+_match_has_ipaddress, _match_hostname = _optional_dependencies()