From 8b6868aaaec9058ef01f42cf4c3dc9825efa79b2 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Thu, 2 Mar 2017 16:39:26 +0800 Subject: [PATCH] Handle ssl for VNX manila driver From python 2.7.9 on, the ssl verification is enabled by default, This commit adds 2 options for Manila, so user is able to control the ssl verification. The 2 options are ported from cinder/driver.py, these can be used by any vendor driver which needs to handle ssl verification. Closes-bug: 1669202 Implements: blueprint add-ssl-verification-options Change-Id: Ia9a488cab9d4d2d25c5ab534dbf4d61e930cfd7f --- manila/share/driver.py | 8 ++++++ .../drivers/dell_emc/plugins/vnx/connector.py | 12 ++++++-- .../drivers/dell_emc/plugins/vnx/fakes.py | 3 ++ manila/tests/test_utils.py | 28 +++++++++++++++++++ manila/utils.py | 24 +++++++++++++++- ...d-ssl-verify-options-2287ae7b40e3ae83.yaml | 6 ++++ 6 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/add-ssl-verify-options-2287ae7b40e3ae83.yaml diff --git a/manila/share/driver.py b/manila/share/driver.py index bd0a52932b..c1dc0b2b54 100644 --- a/manila/share/driver.py +++ b/manila/share/driver.py @@ -132,6 +132,14 @@ share_opts = [ cfg.StrOpt('goodness_function', help='String representation for an equation that will be ' 'used to determine the goodness of a host.'), + cfg.BoolOpt('driver_ssl_cert_verify', + default=False, + help='If set to True the https client will validate the SSL ' + 'certificate of the backend endpoint.'), + cfg.StrOpt('driver_ssl_cert_path', + help='Can be used to specify a non default path to a ' + 'CA_BUNDLE file or directory with certificates of trusted ' + 'CAs, which will be used to validate the backend.'), ] ssh_opts = [ diff --git a/manila/share/drivers/dell_emc/plugins/vnx/connector.py b/manila/share/drivers/dell_emc/plugins/vnx/connector.py index ce6d3c8149..25a5a56916 100644 --- a/manila/share/drivers/dell_emc/plugins/vnx/connector.py +++ b/manila/share/drivers/dell_emc/plugins/vnx/connector.py @@ -38,11 +38,17 @@ class XMLAPIConnector(object): self.storage_ip = configuration.emc_nas_server self.username = configuration.emc_nas_login self.password = configuration.emc_nas_password + self.ssl_cert_verify = configuration.driver_ssl_cert_verify + self.ssl_cert_path = configuration.driver_ssl_cert_path self.debug = debug self.auth_url = 'https://' + self.storage_ip + '/Login' - self._url = ('https://' + self.storage_ip - + '/servlets/CelerraManagementServices') - https_handler = url_request.HTTPSHandler() + self._url = 'https://{}/servlets/CelerraManagementServices'.format( + self.storage_ip) + context = utils.create_ssl_context(configuration) + if context: + https_handler = url_request.HTTPSHandler(context=context) + else: + https_handler = url_request.HTTPSHandler() cookie_handler = url_request.HTTPCookieProcessor( http_cookiejar.CookieJar()) self.url_opener = url_request.build_opener(https_handler, diff --git a/manila/tests/share/drivers/dell_emc/plugins/vnx/fakes.py b/manila/tests/share/drivers/dell_emc/plugins/vnx/fakes.py index 738eeb304f..fabddc6937 100644 --- a/manila/tests/share/drivers/dell_emc/plugins/vnx/fakes.py +++ b/manila/tests/share/drivers/dell_emc/plugins/vnx/fakes.py @@ -1467,6 +1467,9 @@ class FakeEMCShareDriver(object): self.configuration.emc_nas_login = FakeData.emc_nas_login self.configuration.emc_nas_password = FakeData.emc_nas_password self.configuration.share_backend_name = FakeData.share_backend_name + self.configuration.driver_ssl_cert_verify = False + self.configuration.driver_ssl_cert_path = None + CIFS_SHARE = fake_share.fake_share( id=FakeData.share_id, diff --git a/manila/tests/test_utils.py b/manila/tests/test_utils.py index 9fdf051084..9131346a23 100644 --- a/manila/tests/test_utils.py +++ b/manila/tests/test_utils.py @@ -17,6 +17,7 @@ import datetime import errno import socket +import ssl import time import ddt @@ -744,3 +745,30 @@ class ShareMigrationHelperTestCase(test.TestCase): self.assertRaises(expected_exc, utils.wait_for_access_update, self.context, db, fake_instance, 1) + + +class SslContextTestCase(test.TestCase): + + def test_create_ssl_context(self): + configuration = mock.Mock() + configuration.driver_ssl_cert_verify = True + configuration.driver_ssl_cert_path = "./cert_path/" + self.mock_object(ssl, 'create_default_context') + context = utils.create_ssl_context(configuration) + self.assertIsNotNone(context) + + def test_create_ssl_context_no_verify(self): + configuration = mock.Mock() + configuration.driver_ssl_cert_verify = False + self.mock_object(ssl, 'create_default_context') + context = utils.create_ssl_context(configuration) + self.assertFalse(context.check_hostname) + + def test_no_create_default_context(self): + """Test scenario of running on python 2.7.8 or earlier.""" + configuration = mock.Mock() + configuration.driver_ssl_cert_verify = False + self.mock_object(ssl, 'create_default_context', + mock.Mock(side_effect=AttributeError)) + context = utils.create_ssl_context(configuration) + self.assertIsNone(context) diff --git a/manila/utils.py b/manila/utils.py index 16720502cd..8902399752 100644 --- a/manila/utils.py +++ b/manila/utils.py @@ -26,6 +26,7 @@ import random import re import shutil import socket +import ssl import sys import tempfile import time @@ -48,7 +49,7 @@ from webob import exc from manila.common import constants from manila.db import api as db_api from manila import exception -from manila.i18n import _ +from manila.i18n import _, _LW CONF = cfg.CONF LOG = log.getLogger(__name__) @@ -590,3 +591,24 @@ def wait_for_access_update(context, db, share_instance, raise exception.ShareMigrationFailed(reason=msg) else: time.sleep(tries ** 2) + + +def create_ssl_context(configuration): + """Create context for ssl verification. + + .. note:: starting from python 2.7.9 ssl adds create_default_context. + We need to keep compatibility with previous python as well. + """ + try: + if configuration.driver_ssl_cert_verify: + context = ssl.create_default_context( + capath=configuration.driver_ssl_cert_path) + else: + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + except AttributeError: + LOG.warning(_LW('Creating ssl context is not supported on this ' + 'version of Python, ssl verification is disabled.')) + context = None + return context diff --git a/releasenotes/notes/add-ssl-verify-options-2287ae7b40e3ae83.yaml b/releasenotes/notes/add-ssl-verify-options-2287ae7b40e3ae83.yaml new file mode 100644 index 0000000000..c80f132d15 --- /dev/null +++ b/releasenotes/notes/add-ssl-verify-options-2287ae7b40e3ae83.yaml @@ -0,0 +1,6 @@ +--- +features: + - Added following 2 options for SSL verification + ``driver_ssl_cert_verify`` + ``driver_ssl_cert_path`` + For more details, see OpenStack official documentation.