From f6122f1bbfa6e79f3e014a4ba65ffef7e1c113c1 Mon Sep 17 00:00:00 2001 From: Gris Ge Date: Thu, 30 Mar 2017 21:03:26 +0800 Subject: [PATCH] ONTAP plugin: SSL fix. Issue: lsmcli -u "ontap+ssl://root@na3170b.lab.bos.redhat.com" ls NETWORK_ERROR(142): --- doc/man/ontap_lsmplugin.1.in | 11 +++++++++-- plugin/ontap/na.py | 44 +++++++++++++++++++++++++++++++++----------- plugin/ontap/ontap.py | 21 +++++++++++---------- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/doc/man/ontap_lsmplugin.1.in b/doc/man/ontap_lsmplugin.1.in index ef0cd12..3d6cc70 100644 --- a/doc/man/ontap_lsmplugin.1.in +++ b/doc/man/ontap_lsmplugin.1.in @@ -12,9 +12,10 @@ This plugin requires NetApp ONTAP storage array to enable these options: \fBoptions httpd.enable on\fR \fBoptions httpd.admin.enable on\fR -This options is required for HTTPS connection: +These options are required for HTTPS connection: \fBoptions httpd.admin.ssl.enable on\fR + \fBoptions tls.enable on\fR .SH URI To use this plugin, users should set their URI to this format: @@ -40,7 +41,13 @@ The \fBontap_filer_ip\fR is the NetApp ONTAP filer IP address or DNS name. .TP \fBURI parameters\fR -No additional URI parameters are supported by this plugin. +This URI parameter is supported by this plugin: + +.RS 7 +.TP +\fBssl_verify=yes\fR +By default, SSL connection does not verify hostname and certification. +If this URI parameter is defined, all SSL verifications will be performed. .SH Supported Hardware NetApp ONTAP 8.x is supported. diff --git a/plugin/ontap/na.py b/plugin/ontap/na.py index a16e884..26c0ff6 100644 --- a/plugin/ontap/na.py +++ b/plugin/ontap/na.py @@ -20,10 +20,9 @@ from xml.etree import ElementTree import time from binascii import hexlify -from ssl import SSLError +import ssl from lsm.external.xmltodict import convert_xml_to_dict -from lsm import (ErrorNumber) - +from lsm import (LsmError, ErrorNumber) if six.PY3: long = int @@ -33,6 +32,7 @@ urlopen, HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, + HTTPSHandler, build_opener, install_opener) from urllib.error import (URLError, HTTPError) @@ -42,6 +42,7 @@ urlopen, HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, + HTTPSHandler, build_opener, install_opener, URLError, @@ -79,13 +80,13 @@ def param_value(val): def netapp_filer(host, username, password, timeout, command, parameters=None, - ssl=False): + use_ssl=False, ssl_verify=False): """ Issue a command to the NetApp filer. - Note: Change to default ssl on before we ship a release version. + Note: Change to default use_ssl on before we ship a release version. """ proto = 'http' - if ssl: + if use_ssl: proto = 'https' url = "%s://%s/servlets/netapp.servlets.admin.XMLrequest_filer" % \ @@ -98,7 +99,15 @@ def netapp_filer(host, username, password, timeout, command, parameters=None, password_manager.add_password(None, url, username, password) auth_manager = HTTPBasicAuthHandler(password_manager) - opener = build_opener(auth_manager) + if use_ssl: + ssl._DEFAULT_CIPHERS += ':RC4-SHA' + ssl_ctx = ssl.create_default_context() + if ssl_verify == False: + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE + opener = build_opener(HTTPSHandler(context=ssl_ctx), auth_manager) + else: + opener = build_opener(auth_manager) install_opener(opener) # build the command and the arguments for it @@ -127,13 +136,23 @@ def netapp_filer(host, username, password, timeout, command, parameters=None, except HTTPError: raise except URLError as ue: + err_msg = str(ue) if isinstance(ue.reason, socket.timeout): raise FilerError(Filer.ETIMEOUT, "Connection timeout") + elif "UNSUPPORTED_PROTOCOL" in err_msg or \ + "EOF occurred in violation of protocol" in err_msg : + raise LsmError(ErrorNumber.NO_SUPPORT, + "ONTAP SSL version is not supported, " + "please enable TLS on ONTAP filer, " + "check 'man 1 ontap_lsmplugin'") + elif "CERTIFICATE_VERIFY_FAILED" in err_msg: + raise LsmError(ErrorNumber.NETWORK_CONNREFUSED, + "SSL certification verification failed") else: raise except socket.timeout: raise FilerError(Filer.ETIMEOUT, "Connection timeout") - except SSLError as sse: + except ssl.SSLError as sse: # The ssl library doesn't give a good way to find specific reason. # We are doing a string contains which is not ideal, but other than # throwing a generic error in this case there isn't much we can do @@ -262,7 +281,8 @@ class Filer(object): def _invoke(self, command, parameters=None): rc = netapp_filer(self.host, self.username, self.password, - self.timeout, command, parameters, self.ssl) + self.timeout, command, parameters, self.use_ssl, + self.ssl_verify) t = rc['netapp']['results']['attrib'] @@ -271,12 +291,14 @@ def _invoke(self, command, parameters=None): return rc['netapp']['results'] - def __init__(self, host, username, password, timeout, ssl=True): + def __init__(self, host, username, password, timeout, use_ssl=True, + ssl_verify=False): self.host = host self.username = username self.password = password self.timeout = timeout - self.ssl = ssl + self.use_ssl = use_ssl + self.ssl_verify = ssl_verify def system_info(self): rc = self._invoke('system-get-info') diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py index 7fd5dc3..186a57a 100644 --- a/plugin/ontap/ontap.py +++ b/plugin/ontap/ontap.py @@ -22,15 +22,10 @@ AccessGroup, System, Capabilities, Disk, Pool, IStorageAreaNetwork, INfs, LsmError, ErrorNumber, JobStatus, md5, VERSION, common_urllib2_error_handler, - search_property, TargetPort, int_div) + search_property, TargetPort, int_div, uri_parse) import lsm.plugin.ontap.na as na -try: - from urllib.parse import urlparse -except ImportError: - from urlparse import urlparse - # Maps na to lsm, this is expected to expand over time. e_map = { na.Filer.ENOSPC: ErrorNumber.NOT_ENOUGH_SPACE, @@ -135,13 +130,19 @@ def __init__(self): @handle_ontap_errors def plugin_register(self, uri, password, timeout, flags=0): ssl = False - u = urlparse(uri) + u = uri_parse(uri) - if u.scheme.lower() == 'ontap+ssl': + if u['scheme'].lower() == 'ontap+ssl': ssl = True + if 'parameters' in u and 'ssl_verify' in u['parameters'] and \ + u['parameters']['ssl_verify'] == 'yes': + ssl_verify = True + else: + ssl_verify = False - self.f = na.Filer(u.hostname, u.username, password, - int_div(timeout, Ontap.TMO_CONV), ssl) + self.f = na.Filer(u['host'], u['username'], password, + int_div(timeout, Ontap.TMO_CONV), ssl, + ssl_verify) # Smoke test i = self.f.system_info() # TODO Get real filer status -- 2.12.1