Basic support for client cert authentication

Add client_cert_file to nsxlib initialization.
If specified, nsxlib will authenticate with client certificate.
If unspecified (default), basic user/pwd authentication is used.

Change-Id: If36841e9fd9701fa173ffa294732415dc07d49e7
This commit is contained in:
Anna Khmelnitsky 2017-01-05 11:24:28 -08:00
parent fc115e4605
commit c9063831c3
4 changed files with 72 additions and 4 deletions

View File

@ -30,6 +30,7 @@ NSX_PASSWORD = 'default'
NSX_MANAGER = '1.2.3.4'
NSX_INSECURE = False
NSX_CERT = '/opt/stack/certs/nsx.pem'
CLIENT_CERT = '/opt/stack/certs/client.pem'
NSX_HTTP_RETRIES = 10
NSX_HTTP_TIMEOUT = 10
NSX_HTTP_READ_TIMEOUT = 180
@ -108,13 +109,37 @@ def get_default_nsxlib_config():
plugin_ver=PLUGIN_VER)
def get_nsxlib_config_with_client_cert():
return config.NsxLibConfig(
client_cert_file=CLIENT_CERT,
retries=NSX_HTTP_RETRIES,
insecure=NSX_INSECURE,
ca_file=NSX_CERT,
concurrent_connections=NSX_CONCURENT_CONN,
http_timeout=NSX_HTTP_TIMEOUT,
http_read_timeout=NSX_HTTP_READ_TIMEOUT,
conn_idle_timeout=NSX_CONN_IDLE_TIME,
http_provider=None,
nsx_api_managers=[],
plugin_scope=PLUGIN_SCOPE,
plugin_tag=PLUGIN_TAG,
plugin_ver=PLUGIN_VER)
class NsxLibTestCase(unittest.TestCase):
def use_client_cert_auth(self):
return False
def setUp(self, *args, **kwargs):
super(NsxLibTestCase, self).setUp()
_mock_nsxlib()
nsxlib_config = get_default_nsxlib_config()
if self.use_client_cert_auth():
nsxlib_config = get_nsxlib_config_with_client_cert()
else:
nsxlib_config = get_default_nsxlib_config()
self.nsxlib = v3.NsxLib(nsxlib_config)
# print diffs when assert comparisons fail

View File

@ -58,6 +58,25 @@ class RequestsHTTPProviderTestCase(unittest.TestCase):
self.assertEqual(session.adapters['https://'].max_retries.total, 100)
self.assertEqual(session.timeout, 99)
def test_new_connection_with_client_auth(self):
mock_api = mock.Mock()
mock_api.nsxlib_config = mock.Mock()
mock_api.nsxlib_config.retries = 100
mock_api.nsxlib_config.insecure = True
mock_api.nsxlib_config.ca_file = None
mock_api.nsxlib_config.http_timeout = 99
mock_api.nsxlib_config.conn_idle_timeout = 39
provider = cluster.NSXRequestsHTTPProvider()
session = provider.new_connection(
mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6',
None, None, None,
'/etc/cert.pem'))
self.assertEqual(session.auth, None)
self.assertEqual(session.verify, False)
self.assertEqual(session.cert, '/etc/cert.pem')
self.assertEqual(session.timeout, 99)
def test_validate_connection(self):
self.skipTest("Revist")
mock_conn = mocks.MockRequestSessionApi()
@ -125,6 +144,14 @@ class NsxV3ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase):
self.assertEqual(kwargs['timeout'], (7, 37))
# Repeat the above tests with client cert present
# in NsxLib initialization
class NsxV3ClusteredAPIWithClientCertTestCase(NsxV3ClusteredAPITestCase):
def use_client_cert_auth(self):
return True
class ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase):
def _test_health(self, validate_fn, expected_health):

View File

@ -121,7 +121,11 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider):
config = cluster_api.nsxlib_config
session = TimeoutSession(config.http_timeout,
config.http_read_timeout)
session.auth = (provider.username, provider.password)
if provider.client_cert_file:
session.cert = provider.client_cert_file
else:
session.auth = (provider.username, provider.password)
# NSX v3 doesn't use redirects
session.max_redirects = 0
@ -172,11 +176,13 @@ class Provider(object):
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, client_cert_file=None):
self.id = provider_id
self.url = provider_url
self.username = username
self.password = password
self.client_cert_file = client_cert_file
self.ca_file = ca_file
def __str__(self):
@ -489,5 +495,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.client_cert_file(provider_index)))
return providers

View File

@ -25,6 +25,10 @@ class NsxLibConfig(object):
and port 443 for https.
:param username: User name for the NSX manager
:param password: Password for the NSX manager
:param client_cert_file: Specify a file containing client certificate and
private key. If specified, nsxlib will use client
cert authentication 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 unsest the default system root CAs
@ -67,6 +71,7 @@ class NsxLibConfig(object):
nsx_api_managers=None,
username=None,
password=None,
client_cert_file=None,
insecure=True,
ca_file=None,
concurrent_connections=10,
@ -86,6 +91,7 @@ class NsxLibConfig(object):
self.nsx_api_managers = nsx_api_managers
self._username = username
self._password = password
self._client_cert_file = client_cert_file
self._ca_file = ca_file
self.insecure = insecure
self.concurrent_connections = concurrent_connections
@ -119,5 +125,8 @@ class NsxLibConfig(object):
def password(self, index):
return self._attribute_by_index(self._password, index)
def client_cert_file(self, index):
return self._attribute_by_index(self._client_cert_file, index)
def ca_file(self, index):
return self._attribute_by_index(self._ca_file, index)