Add support for using thumbprint to verify Manager certificate
This patch adds a new config option "thumbprint". It will be used to verify Manager server certificate when "insecure" is false and "ca_file" is unset. Change-Id: Idfb654c5b502cd6df12275e0a88cf10c546d819d
This commit is contained in:
parent
20996b400d
commit
56ae89a6fc
|
@ -125,6 +125,44 @@ class RequestsHTTPProviderTestCase(unittest.TestCase):
|
|||
mock_get_def_headers.assert_called_once_with(
|
||||
mock.ANY, cluster_provider, False, token_provider_inst)
|
||||
|
||||
@mock.patch("vmware_nsxlib.v3.cluster.NSXHTTPAdapter.__init__")
|
||||
def test_new_connection_with_ca_file(self, mock_adaptor_init):
|
||||
mock_api = mock.Mock()
|
||||
mock_api.nsxlib_config = mock.Mock()
|
||||
mock_api.nsxlib_config.retries = 100
|
||||
mock_api.nsxlib_config.insecure = False
|
||||
mock_adaptor_init.return_value = None
|
||||
provider = cluster.NSXRequestsHTTPProvider()
|
||||
with mock.patch.object(cluster.TimeoutSession, 'request',
|
||||
return_value=get_sess_create_resp()):
|
||||
session = provider.new_connection(
|
||||
mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6',
|
||||
None, None, "ca_file"))
|
||||
|
||||
self.assertEqual("ca_file", session.verify)
|
||||
mock_adaptor_init.assert_called_once_with(
|
||||
pool_connections=1, pool_maxsize=1,
|
||||
max_retries=100, pool_block=False, thumbprint=None)
|
||||
|
||||
@mock.patch("vmware_nsxlib.v3.cluster.NSXHTTPAdapter.__init__")
|
||||
def test_new_connection_with_thumbprint(self, mock_adaptor_init):
|
||||
mock_api = mock.Mock()
|
||||
mock_api.nsxlib_config = mock.Mock()
|
||||
mock_api.nsxlib_config.retries = 100
|
||||
mock_api.nsxlib_config.insecure = False
|
||||
mock_adaptor_init.return_value = None
|
||||
provider = cluster.NSXRequestsHTTPProvider()
|
||||
with mock.patch.object(cluster.TimeoutSession, 'request',
|
||||
return_value=get_sess_create_resp()):
|
||||
session = provider.new_connection(
|
||||
mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6',
|
||||
None, None, None, "thumbprint"))
|
||||
|
||||
self.assertIsNone(session.verify)
|
||||
mock_adaptor_init.assert_called_once_with(
|
||||
pool_connections=1, pool_maxsize=1,
|
||||
max_retries=100, pool_block=False, thumbprint="thumbprint")
|
||||
|
||||
def test_validate_connection_keep_alive(self):
|
||||
mock_conn = mocks.MockRequestSessionApi()
|
||||
mock_conn.default_headers = {}
|
||||
|
@ -189,6 +227,16 @@ class RequestsHTTPProviderTestCase(unittest.TestCase):
|
|||
provider.validate_connection(mock_cluster, mock_ep, mock_conn)
|
||||
|
||||
|
||||
class NSXHTTPAdapterTestCase(nsxlib_testcase.NsxClientTestCase):
|
||||
|
||||
@mock.patch("requests.adapters.HTTPAdapter.init_poolmanager")
|
||||
def test_init_poolmanager(self, mock_init_poolmanager):
|
||||
cluster.NSXHTTPAdapter(thumbprint="thumbprint")
|
||||
mock_init_poolmanager.assert_called_once_with(
|
||||
mock.ANY, mock.ANY, block=mock.ANY,
|
||||
assert_fingerprint="thumbprint")
|
||||
|
||||
|
||||
class NsxV3ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase):
|
||||
|
||||
def _assert_providers(self, cluster_api, provider_tuples):
|
||||
|
|
|
@ -221,16 +221,28 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider):
|
|||
# NSX v3 doesn't use redirects
|
||||
session.max_redirects = 0
|
||||
|
||||
session.verify = not config.insecure
|
||||
if session.verify and provider.ca_file:
|
||||
if config.insecure:
|
||||
# no verification on server certificate
|
||||
session.verify = False
|
||||
thumbprint = None
|
||||
elif provider.ca_file:
|
||||
# verify using the said ca bundle path
|
||||
session.verify = provider.ca_file
|
||||
thumbprint = None
|
||||
elif provider.thumbprint:
|
||||
# verify using the thumbprint
|
||||
session.verify = None
|
||||
thumbprint = provider.thumbprint
|
||||
else:
|
||||
# verify using the default system root CAs
|
||||
session.verify = True
|
||||
thumbprint = None
|
||||
|
||||
# we are pooling with eventlet in the cluster class
|
||||
adapter = adapters.HTTPAdapter(
|
||||
adapter = NSXHTTPAdapter(
|
||||
pool_connections=1, pool_maxsize=1,
|
||||
max_retries=config.retries,
|
||||
pool_block=False)
|
||||
pool_block=False, thumbprint=thumbprint)
|
||||
session.mount('http://', adapter)
|
||||
session.mount('https://', adapter)
|
||||
|
||||
|
@ -314,6 +326,17 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider):
|
|||
{'url': provider.url, 'hdr': session.default_headers})
|
||||
|
||||
|
||||
class NSXHTTPAdapter(adapters.HTTPAdapter):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.thumbprint = kwargs.pop("thumbprint", None)
|
||||
super(NSXHTTPAdapter, self).__init__(*args, **kwargs)
|
||||
|
||||
def init_poolmanager(self, *args, **kwargs):
|
||||
if self.thumbprint:
|
||||
kwargs["assert_fingerprint"] = self.thumbprint
|
||||
super(NSXHTTPAdapter, self).init_poolmanager(*args, **kwargs)
|
||||
|
||||
|
||||
class ClusterHealth(object):
|
||||
"""Indicator of overall cluster health.
|
||||
|
||||
|
@ -343,12 +366,14 @@ class Provider(object):
|
|||
Which has a unique id a connection URL, and the credential details.
|
||||
"""
|
||||
|
||||
def __init__(self, provider_id, provider_url, username, password, ca_file):
|
||||
def __init__(self, provider_id, provider_url, username, password, ca_file,
|
||||
thumbprint=None):
|
||||
self.id = provider_id
|
||||
self.url = provider_url
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.ca_file = ca_file
|
||||
self.thumbprint = thumbprint
|
||||
|
||||
def __str__(self):
|
||||
return str(self.url)
|
||||
|
@ -717,5 +742,6 @@ class NSXClusteredAPI(ClusteredAPI):
|
|||
urlparse.urlunparse(conf_url),
|
||||
self.nsxlib_config.username(provider_index),
|
||||
self.nsxlib_config.password(provider_index),
|
||||
self.nsxlib_config.ca_file(provider_index)))
|
||||
self.nsxlib_config.ca_file(provider_index),
|
||||
self.nsxlib_config.thumbprint(provider_index)))
|
||||
return providers
|
||||
|
|
|
@ -35,13 +35,18 @@ class NsxLibConfig(object):
|
|||
instead of basic authentication.
|
||||
:param insecure: If true, the NSX Manager server certificate is not
|
||||
verified. If false the CA bundle specified via "ca_file"
|
||||
will be used or if unset the default system root CAs
|
||||
will be used or if unset the "thumbprint" will be used.
|
||||
If "thumbprint" is unset, the default system root CAs
|
||||
will be used.
|
||||
:param ca_file: Specify a CA bundle file to use in verifying the NSX
|
||||
Manager server certificate. This option is ignored if
|
||||
"insecure" is set to True. If "insecure" is set to
|
||||
False and ca_file is unset, the system root CAs will
|
||||
be used to verify the server certificate.
|
||||
"insecure" is set to True. If "insecure" is set to False
|
||||
and "ca_file" is unset, the "thumbprint" will be used.
|
||||
If "thumbprint" is unset, the system root CAs will be
|
||||
used to verify the server certificate.
|
||||
:param thumbprint: Specify a thumbprint string to use in verifying the
|
||||
NSX Manager server certificate. This option is ignored
|
||||
if "insecure" is set to True or "ca_file" is defined.
|
||||
:param token_provider: None, or instance of implemented AbstractJWTProvider
|
||||
which will return the JSON Web Token used in the
|
||||
requests in NSX for authorization.
|
||||
|
@ -98,6 +103,7 @@ class NsxLibConfig(object):
|
|||
client_cert_provider=None,
|
||||
insecure=True,
|
||||
ca_file=None,
|
||||
thumbprint=None,
|
||||
token_provider=None,
|
||||
concurrent_connections=10,
|
||||
retries=3,
|
||||
|
@ -123,6 +129,7 @@ class NsxLibConfig(object):
|
|||
self._username = username
|
||||
self._password = password
|
||||
self._ca_file = ca_file
|
||||
self._thumbprint = thumbprint
|
||||
self.insecure = insecure
|
||||
self.concurrent_connections = concurrent_connections
|
||||
self.retries = retries
|
||||
|
@ -178,3 +185,6 @@ class NsxLibConfig(object):
|
|||
|
||||
def ca_file(self, index):
|
||||
return self._attribute_by_index(self._ca_file, index)
|
||||
|
||||
def thumbprint(self, index):
|
||||
return self._attribute_by_index(self._thumbprint, index)
|
||||
|
|
Loading…
Reference in New Issue