From 39df713492714f55e9d5bf578bece4cd9fc98fef Mon Sep 17 00:00:00 2001 From: Marek 'marx' Grac Date: Mon, 1 Sep 2014 15:05:20 +0200 Subject: [PATCH 07/11] fencing: Add new options --ssl-secure and --ssl-insecure These new options extends current --ssl (same as --ssl-secure). Until now certificate of the fence device was not validated what can possibly lead to attack on infrastructe. With this patch, user can decide if certificate should (--ssl-secure) or should not (--ssl-insecure) be verified. The default option is to validate certificate. Resolves: rhbz#1072564 --- fence/agents/cisco_ucs/fence_cisco_ucs.py | 9 ++++++-- fence/agents/lib/fencing.py.py | 28 ++++++++++++++++++++--- fence/agents/rhevm/fence_rhevm.py | 9 ++++++-- fence/agents/vmware_soap/fence_vmware_soap.py | 33 +++++++++++++++++++++++---- 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/fence/agents/cisco_ucs/fence_cisco_ucs.py b/fence/agents/cisco_ucs/fence_cisco_ucs.py index f72e696..888d689 100644 --- a/fence/agents/cisco_ucs/fence_cisco_ucs.py +++ b/fence/agents/cisco_ucs/fence_cisco_ucs.py @@ -90,8 +90,13 @@ def send_command(opt, command, timeout): conn.setopt(pycurl.POSTFIELDS, command) conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) conn.setopt(pycurl.TIMEOUT, timeout) - conn.setopt(pycurl.SSL_VERIFYPEER, 0) - conn.setopt(pycurl.SSL_VERIFYHOST, 0) + if opt.has_key("--ssl") or opt.has_key("--ssl-secure"): + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + + if opt.has_key("--ssl-insecure"): + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) conn.perform() result = web_buffer.getvalue() diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index 4520ea8..7d1d28e 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -179,6 +179,21 @@ all_opt = { "required" : "0", "shortdesc" : "SSL connection", "order" : 1}, + "ssl_insecure" : { + "getopt" : "9", + "longopt" : "ssl-insecure", + "help" : "--ssl-insecure Use ssl connection without verifying certificate", + "required" : "0", + "shortdesc" : "SSL connection without verifying fence device's certificate", + "order" : 1}, + "ssl_secure" : { + "getopt" : "9", + "longopt" : "ssl-secure", + "help" : "--ssl-secure Use ssl connection with verifying certificate", + "required" : "0", + "shortdesc" : "SSL connection with verifying fence device's certificate", + "order" : 1}, + "notls" : { "getopt" : "t", "longopt" : "notls", @@ -385,6 +400,7 @@ DEPENDENCY_OPT = { "secure" : ["identity_file", "ssh_options"], "ipaddr" : ["ipport", "inet4_only", "inet6_only"], "port" : ["separator"], + "ssl" : ["ssl_secure", "ssl_insecure"], "community" : ["snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \ "snmp_priv_passwd", "snmp_priv_passwd_script"] } @@ -663,7 +679,7 @@ def check_input(device_opt, opt): elif options.has_key("--ssh") or (all_opt["secure"].has_key("default") and all_opt["secure"]["default"] == '1'): all_opt["ipport"]["default"] = 22 all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 22)" - elif options.has_key("--ssl") or (all_opt["ssl"].has_key("default") and all_opt["ssl"]["default"] == '1'): + elif options.has_key("--ssl") or options.has_key("--ssl-secure") or options.has_key("--ssl-insecure") or (all_opt["ssl"].has_key("default") and all_opt["ssl"]["default"] == '1'): all_opt["ipport"]["default"] = 443 all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 443)" elif device_opt.count("web"): @@ -970,11 +986,17 @@ def fence_login(options, re_login_string=r"(login\s*: )|(Login Name: )|(usernam if options.has_key("--ssl"): gnutls_opts = "" + ssl_opts = "" + if options.has_key("--notls"): gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:-VERS-TLS1.0:+VERS-SSL3.0\"" - command = '%s %s --insecure --crlf -p %s %s' % \ - (SSL_PATH, gnutls_opts, options["--ipport"], options["--ip"]) + # --ssl is same as the --ssl-secure + if options.has_key("--ssl-insecure"): + ssl_opts = "--insecure" + + command = '%s %s %s --insecure --crlf -p %s %s' % \ + (SSL_PATH, gnutls_opts, ssl_opts, options["--ipport"], options["--ip"]) try: conn = fspawn(options, command) except pexpect.ExceptionPexpect, ex: diff --git a/fence/agents/rhevm/fence_rhevm.py b/fence/agents/rhevm/fence_rhevm.py index a0d8d59..444fb56 100644 --- a/fence/agents/rhevm/fence_rhevm.py +++ b/fence/agents/rhevm/fence_rhevm.py @@ -91,8 +91,13 @@ def send_command(opt, command, method="GET"): conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC) conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"]) conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) - conn.setopt(pycurl.SSL_VERIFYPEER, 0) - conn.setopt(pycurl.SSL_VERIFYHOST, 0) + if opt.has_key("--ssl") or opt.has_key("--ssl-secure"): + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + + if opt.has_key("--ssl-insecure"): + conn.setopt(pycurl.SSL_VERIFYPEER, 0) + conn.setopt(pycurl.SSL_VERIFYHOST, 0) if method == "POST": conn.setopt(pycurl.POSTFIELDS, "") diff --git a/fence/agents/vmware_soap/fence_vmware_soap.py b/fence/agents/vmware_soap/fence_vmware_soap.py index 53fd9ea..3217c6b 100644 --- a/fence/agents/vmware_soap/fence_vmware_soap.py +++ b/fence/agents/vmware_soap/fence_vmware_soap.py @@ -2,12 +2,14 @@ import sys import shutil, tempfile, suds -import logging +import logging, requests import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from suds.client import Client from suds.sudsobject import Property +from suds.transport.http import HttpAuthenticated +from suds.transport import Reply, TransportError from fencing import * from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, EC_WAITING_ON, EC_WAITING_OFF from fencing import run_delay @@ -18,12 +20,31 @@ REDHAT_COPYRIGHT="" BUILD_DATE="April, 2011" #END_VERSION_GENERATION +class RequestsTransport(HttpAuthenticated): + def __init__(self, **kwargs): + self.cert = kwargs.pop('cert', None) + self.verify = kwargs.pop('verify', True) + self.session = requests.Session() + # super won't work because not using new style class + HttpAuthenticated.__init__(self, **kwargs) + + def send(self, request): + self.addcredentials(request) + resp = self.session.post(request.url, data = request.message, headers = request.headers, cert = self.cert, verify = self.verify) + result = Reply(resp.status_code, resp.headers, resp.content) + return result + def soap_login(options): run_delay(options) - if options.has_key("--ssl"): + if options.has_key("--ssl") or options.has_key("--ssl-secure") or options.has_key("--ssl-insecure"): + if options.has_key("--ssl-insecure"): + verify = False + else: + verify = True url = "https://" else: + verify = False url = "http://" url += options["--ip"] + ":" + str(options["--ipport"]) + "/sdk" @@ -33,8 +54,8 @@ def soap_login(options): atexit.register(remove_tmp_dir, tmp_dir) try: - conn = Client(url + "/vimService.wsdl") - conn.set_options(location=url) + headers = {"Content-Type" : "text/xml;charset=UTF-8", "SOAPAction" : ""} + conn = Client(url + "/vimService.wsdl", location = url, transport = RequestsTransport(verify = verify), headers = headers) mo_ServiceInstance = Property('ServiceInstance') mo_ServiceInstance._type = 'ServiceInstance' @@ -43,6 +64,8 @@ def soap_login(options): mo_SessionManager._type = 'SessionManager' conn.service.Login(mo_SessionManager, options["--username"], options["--password"]) + except requests.exceptions.SSLError, ex: + fail_usage("Server side certificate verification failed") except Exception: fail(EC_LOGIN_DENIED) @@ -205,6 +228,8 @@ Alternatively you can always use UUID to access virtual machine." logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.CRITICAL) + logging.getLogger("requests").setLevel(logging.CRITICAL) + logging.getLogger("urllib3").setLevel(logging.CRITICAL) ## ## Operate the fencing device -- 1.8.4.5