Skip to content

Commit 8d6ec4b

Browse files
authored
fix: set minimum TLS version to v1.2 (#139)
This commit introduces a custom HTTP adapter that wraps the original one and adds an SSL context that sets the minimum TLS version required to v1.2.
1 parent 20cc41f commit 8d6ec4b

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

ibm_cloud_sdk_core/base_service.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@
2424
from urllib3.util.retry import Retry
2525

2626
import requests
27-
from requests.adapters import HTTPAdapter
2827
from requests.structures import CaseInsensitiveDict
2928

3029
from ibm_cloud_sdk_core.authenticators import Authenticator
3130
from .api_exception import ApiException
3231
from .detailed_response import DetailedResponse
3332
from .token_managers.token_manager import TokenManager
3433
from .utils import (has_bad_first_or_last_char, remove_null_values,
35-
cleanup_values, read_external_sources, strip_extra_slashes)
34+
cleanup_values, read_external_sources, strip_extra_slashes,
35+
SSLHTTPAdapter)
3636
from .version import __version__
3737

3838
# Uncomment this to enable http debugging
@@ -94,12 +94,15 @@ def __init__(self,
9494
self.enable_gzip_compression = enable_gzip_compression
9595
self._set_user_agent_header(self._build_user_agent())
9696
self.retry_config = None
97-
self.http_adapter = HTTPAdapter()
97+
self.http_adapter = SSLHTTPAdapter()
9898
if not self.authenticator:
9999
raise ValueError('authenticator must be provided')
100100
if not isinstance(self.authenticator, Authenticator):
101101
raise ValueError('authenticator should be of type Authenticator')
102102

103+
self.http_client.mount('http://', self.http_adapter)
104+
self.http_client.mount('https://', self.http_adapter)
105+
103106
def enable_retries(self, max_retries: int = 4, retry_interval: float = 1.0) -> None:
104107
"""Enable automatic retries on the underlying http client used by the BaseService instance.
105108
@@ -121,14 +124,14 @@ def enable_retries(self, max_retries: int = 4, retry_interval: float = 1.0) -> N
121124
allowed_methods=['HEAD', 'GET', 'PUT',
122125
'DELETE', 'OPTIONS', 'TRACE', 'POST']
123126
)
124-
self.http_adapter = HTTPAdapter(max_retries=self.retry_config)
127+
self.http_adapter = SSLHTTPAdapter(max_retries=self.retry_config)
125128
self.http_client.mount('http://', self.http_adapter)
126129
self.http_client.mount('https://', self.http_adapter)
127130

128131
def disable_retries(self):
129132
"""Remove retry config from http_adapter"""
130133
self.retry_config = None
131-
self.http_adapter = HTTPAdapter()
134+
self.http_adapter = SSLHTTPAdapter()
132135
self.http_client.mount('http://', self.http_adapter)
133136
self.http_client.mount('https://', self.http_adapter)
134137

ibm_cloud_sdk_core/utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,33 @@
1616
# from ibm_cloud_sdk_core.authenticators import Authenticator
1717
import datetime
1818
import json as json_import
19+
import ssl
1920
from os import getenv, environ, getcwd
2021
from os.path import isfile, join, expanduser
2122
from typing import List, Union
2223
from urllib.parse import urlparse, parse_qs
2324

25+
from requests.adapters import HTTPAdapter
26+
from urllib3.util.ssl_ import create_urllib3_context
27+
2428
import dateutil.parser as date_parser
2529

2630

31+
class SSLHTTPAdapter(HTTPAdapter):
32+
"""Wraps the original HTTP adapter and adds additional SSL context.
33+
"""
34+
def __init__(self, *args, **kwargs):
35+
super().__init__(*args, **kwargs)
36+
37+
#pylint: disable=arguments-differ
38+
def init_poolmanager(self, connections, maxsize, block):
39+
"""Extends the parent's method by adding minimum SSL version to the args.
40+
"""
41+
ssl_context = create_urllib3_context()
42+
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
43+
super().init_poolmanager(connections, maxsize, block, ssl_context=ssl_context)
44+
45+
2746
def has_bad_first_or_last_char(val: str) -> bool:
2847
"""Returns true if a string starts with any of: {," ; or ends with any of: },".
2948

test/test_base_service.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import gzip
44
import json
55
import os
6+
import ssl
67
import tempfile
78
import time
89
from shutil import copyfile
@@ -923,3 +924,11 @@ def test_configure_service_error():
923924
with pytest.raises(ValueError) as err:
924925
service.configure_service(None)
925926
assert str(err.value) == 'Service_name must be of type string.'
927+
928+
929+
def test_min_ssl_version():
930+
service = AnyServiceV1('2022-03-08', authenticator=NoAuthAuthenticator())
931+
adapter = service.http_client.get_adapter('https://')
932+
ssl_context = adapter.poolmanager.connection_pool_kw.get('ssl_context', None)
933+
assert ssl_context is not None
934+
assert ssl_context.minimum_version == ssl.TLSVersion.TLSv1_2

0 commit comments

Comments
 (0)