VMAX Driver - Incorrect SSL cert verification

SSL certificates are not being applied to the REST session as desired.
If a user sets SSL verification to True but does not specify a path
to the SSL cert, SSL is disabled instead of looking in the system
certificate bundle.

Closes-Bug #1772924

Change-Id: I20cb64c11e43c22558939e27708ec678c5723ca2
This commit is contained in:
michael-mcaleer 2018-05-24 13:54:59 +01:00 committed by Helen Walsh
parent 6ac8051314
commit 512fd07124
6 changed files with 93 additions and 19 deletions

View File

@ -1170,6 +1170,10 @@ class FakeConfiguration(object):
self.chap_username = value
elif key == 'chap_password':
self.chap_password = value
elif key == 'driver_ssl_cert_verify':
self.driver_ssl_cert_verify = value
elif key == 'driver_ssl_cert_path':
self.driver_ssl_cert_path = value
def safe_get(self, key):
try:
@ -3083,6 +3087,21 @@ class VMAXRestTest(test.TestCase):
iterator_id, result_count, start_position, end_position)
self.assertEqual(expected_response, actual_response)
def test_set_rest_credentials(self):
array_info = {
'RestServerIp': '10.10.10.10',
'RestServerPort': '8443',
'RestUserName': 'user_test',
'RestPassword': 'pass_test',
'SSLVerify': True,
}
self.rest.set_rest_credentials(array_info)
self.assertEqual('user_test', self.rest.user)
self.assertEqual('pass_test', self.rest.passwd)
self.assertTrue(self.rest.verify)
self.assertEqual('https://10.10.10.10:8443/univmax/restapi',
self.rest.base_uri)
class VMAXProvisionTest(test.TestCase):
def setUp(self):
@ -5186,7 +5205,6 @@ class VMAXCommonTest(test.TestCase):
'RestServerPort': 8443,
'RestUserName': 'smc',
'RestPassword': 'smc',
'SSLCert': None,
'SSLVerify': False,
'SerialNumber': self.data.array,
'srpName': 'SRP_1',
@ -5209,7 +5227,6 @@ class VMAXCommonTest(test.TestCase):
'RestServerPort': 3448,
'RestUserName': 'smc',
'RestPassword': 'smc',
'SSLCert': None,
'SSLVerify': False,
'SerialNumber': self.data.array,
'srpName': 'SRP_1',
@ -5228,7 +5245,6 @@ class VMAXCommonTest(test.TestCase):
'RestServerPort': 3448,
'RestUserName': 'smc',
'RestPassword': 'smc',
'SSLCert': None,
'SSLVerify': False,
'SerialNumber': self.data.array,
'srpName': 'SRP_1',
@ -5247,7 +5263,6 @@ class VMAXCommonTest(test.TestCase):
'RestServerPort': 8443,
'RestUserName': 'smc',
'RestPassword': 'smc',
'SSLCert': None,
'SSLVerify': False,
'SerialNumber': self.data.array,
'srpName': 'SRP_1',
@ -5260,6 +5275,28 @@ class VMAXCommonTest(test.TestCase):
kwargs_returned = self.common.get_attributes_from_cinder_config()
self.assertEqual(kwargs_expected, kwargs_returned)
def test_get_ssl_attributes_from_cinder_config(self):
conf = FakeConfiguration(
None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
vmax_port_groups=[self.data.port_group_name_i],
driver_ssl_cert_verify=True,
driver_ssl_cert_path='/path/to/cert')
self.common.configuration = conf
conf_returned = self.common.get_attributes_from_cinder_config()
self.assertEqual('/path/to/cert', conf_returned['SSLVerify'])
conf.driver_ssl_cert_verify = True
conf.driver_ssl_cert_path = None
conf_returned = self.common.get_attributes_from_cinder_config()
self.assertTrue(conf_returned['SSLVerify'])
conf.driver_ssl_cert_verify = False
conf.driver_ssl_cert_path = None
conf_returned = self.common.get_attributes_from_cinder_config()
self.assertFalse(conf_returned['SSLVerify'])
@mock.patch.object(rest.VMAXRest,
'get_size_of_device_on_array',
return_value=2.0)
@ -5479,6 +5516,40 @@ class VMAXCommonTest(test.TestCase):
marker, limit, offset, sort_keys, sort_dirs)
self.assertEqual(vols_lists, expected_response)
def test_get_slo_workload_combo_from_cinder_conf(self):
self.common.configuration.vmax_service_level = 'Diamond'
self.common.configuration.vmax_workload = 'DSS'
response1 = self.common.get_attributes_from_cinder_config()
self.assertEqual('Diamond', response1['ServiceLevel'])
self.assertEqual('DSS', response1['Workload'])
self.common.configuration.vmax_service_level = 'Diamond'
self.common.configuration.vmax_workload = None
response2 = self.common.get_attributes_from_cinder_config()
self.assertEqual(self.common.configuration.vmax_service_level,
response2['ServiceLevel'])
self.assertIsNone(response2['Workload'])
expected_response = {
'RestServerIp': '1.1.1.1',
'RestServerPort': 8443,
'RestUserName': 'smc',
'RestPassword': 'smc',
'SSLVerify': False,
'SerialNumber': '000197800123',
'srpName': 'SRP_1',
'PortGroup': 'OS-fibre-PG'}
self.common.configuration.vmax_service_level = None
self.common.configuration.vmax_workload = 'DSS'
response3 = self.common.get_attributes_from_cinder_config()
self.assertEqual(expected_response, response3)
self.common.configuration.vmax_service_level = None
self.common.configuration.vmax_workload = None
response4 = self.common.get_attributes_from_cinder_config()
self.assertEqual(expected_response, response4)
class VMAXFCTest(test.TestCase):
def setUp(self):

View File

@ -4227,7 +4227,6 @@ class VMAXCommon(object):
:returns: kwargs
"""
LOG.debug("Using cinder.conf file")
kwargs = None
username = self.configuration.safe_get(utils.VMAX_USER_NAME)
password = self.configuration.safe_get(utils.VMAX_PASSWORD)
@ -4239,7 +4238,7 @@ class VMAXCommon(object):
if srp_name is None:
LOG.error("SRP Name must be set in cinder.conf")
slo = self.configuration.safe_get(utils.VMAX_SERVICE_LEVEL)
workload = self.configuration.safe_get(utils.WORKLOAD)
workload = self.configuration.safe_get(utils.VMAX_WORKLOAD)
port_groups = self.configuration.safe_get(utils.VMAX_PORT_GROUPS)
random_portgroup = None
if port_groups:
@ -4252,18 +4251,22 @@ class VMAXCommon(object):
'RestServerPort': self._get_unisphere_port(),
'RestUserName': username,
'RestPassword': password,
'SSLCert': self.configuration.safe_get('driver_client_cert'),
'SerialNumber': serial_number,
'srpName': srp_name,
'PortGroup': random_portgroup})
if self.configuration.safe_get('driver_ssl_cert_verify'):
kwargs.update({'SSLVerify': self.configuration.safe_get(
'driver_ssl_cert_path')})
if self.configuration.safe_get('driver_ssl_cert_path'):
kwargs.update({'SSLVerify': self.configuration.safe_get(
'driver_ssl_cert_path')})
else:
kwargs.update({'SSLVerify': True})
else:
kwargs.update({'SSLVerify': False})
if slo is not None:
if slo:
kwargs.update({'ServiceLevel': slo, 'Workload': workload})
return kwargs
def _get_unisphere_port(self):

View File

@ -95,6 +95,7 @@ class VMAXFCDriver(san.SanDriver, driver.FibreChannelDriver):
- Support for multiattach volumes (bp vmax-allow-multi-attach)
- Support for list manageable volumes and snapshots
(bp/vmax-list-manage-existing)
- Fix for SSL verification/cert application (bug #1772924)
"""
VERSION = "3.2.0"

View File

@ -100,6 +100,7 @@ class VMAXISCSIDriver(san.SanISCSIDriver):
- Support for multiattach volumes (bp vmax-allow-multi-attach)
- Support for list manageable volumes and snapshots
(bp/vmax-list-manage-existing)
- Fix for SSL verification/cert application (bug #1772924)
"""
VERSION = "3.2.0"

View File

@ -75,14 +75,10 @@ class VMAXRest(object):
port = array_info['RestServerPort']
self.user = array_info['RestUserName']
self.passwd = array_info['RestPassword']
self.cert = array_info['SSLCert']
verify = array_info['SSLVerify']
if verify and verify.lower() == 'false':
verify = False
self.verify = verify
self.verify = array_info['SSLVerify']
ip_port = "%(ip)s:%(port)s" % {'ip': ip, 'port': port}
self.base_uri = ("https://%(ip_port)s/univmax/restapi"
% {'ip_port': ip_port})
self.base_uri = ("https://%(ip_port)s/univmax/restapi" % {
'ip_port': ip_port})
self.session = self._establish_rest_session()
def _establish_rest_session(self):
@ -97,8 +93,6 @@ class VMAXRest(object):
session.auth = requests.auth.HTTPBasicAuth(self.user, self.passwd)
if self.verify is not None:
session.verify = self.verify
if self.cert:
session.cert = self.cert
return session

View File

@ -0,0 +1,4 @@
---
fixes:
- |
VMAX driver - fixes SSL certificate verification error.