1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Merge pull request #13573 from ansible/ssl-context-with-proxy

Fix a few problems with url handling.
This commit is contained in:
Toshio Kuratomi 2015-12-16 08:00:59 -08:00
commit 7d519127fe

View file

@ -310,36 +310,45 @@ class NoSSLError(SSLValidationError):
"""Needed to connect to an HTTPS url but no ssl library available to verify the certificate""" """Needed to connect to an HTTPS url but no ssl library available to verify the certificate"""
pass pass
# Some environments (Google Compute Engine's CoreOS deploys) do not compile
# against openssl and thus do not have any HTTPS support.
CustomHTTPSConnection = CustomHTTPSHandler = None
if hasattr(httplib, 'HTTPSConnection') and hasattr(urllib2, 'HTTPSHandler'):
class CustomHTTPSConnection(httplib.HTTPSConnection):
def __init__(self, *args, **kwargs):
httplib.HTTPSConnection.__init__(self, *args, **kwargs)
if HAS_SSLCONTEXT:
self.context = create_default_context()
if self.cert_file:
self.context.load_cert_chain(self.cert_file, self.key_file)
class CustomHTTPSConnection(httplib.HTTPSConnection): def connect(self):
def __init__(self, *args, **kwargs): "Connect to a host on a given (SSL) port."
httplib.HTTPSConnection.__init__(self, *args, **kwargs)
if HAS_SSLCONTEXT:
self.context = create_default_context()
if self.cert_file:
self.context.load_cert_chain(self.cert_file, self.key_file)
def connect(self): if hasattr(self, 'source_address'):
"Connect to a host on a given (SSL) port." sock = socket.create_connection((self.host, self.port), self.timeout, self.source_address)
else:
sock = socket.create_connection((self.host, self.port), self.timeout)
if hasattr(self, 'source_address'): server_hostname = self.host
sock = socket.create_connection((self.host, self.port), self.timeout, self.source_address) # Note: self._tunnel_host is not available on py < 2.6 but this code
else: # isn't used on py < 2.6 (lack of create_connection)
sock = socket.create_connection((self.host, self.port), self.timeout) if self._tunnel_host:
if self._tunnel_host: self.sock = sock
self.sock = sock self._tunnel()
self._tunnel() server_hostname = self._tunnel_host
if HAS_SSLCONTEXT:
self.sock = self.context.wrap_socket(sock, server_hostname=self.host)
else:
self.sock = ssl.wrap_socket(sock, keyfile=self.key_file, certfile=self.cert_file, ssl_version=PROTOCOL)
class CustomHTTPSHandler(urllib2.HTTPSHandler): if HAS_SSLCONTEXT:
self.sock = self.context.wrap_socket(sock, server_hostname=server_hostname)
else:
self.sock = ssl.wrap_socket(sock, keyfile=self.key_file, certfile=self.cert_file, ssl_version=PROTOCOL)
def https_open(self, req): class CustomHTTPSHandler(urllib2.HTTPSHandler):
return self.do_open(CustomHTTPSConnection, req)
https_request = urllib2.AbstractHTTPHandler.do_request_ def https_open(self, req):
return self.do_open(CustomHTTPSConnection, req)
https_request = urllib2.AbstractHTTPHandler.do_request_
def generic_urlparse(parts): def generic_urlparse(parts):
''' '''
@ -373,7 +382,10 @@ def generic_urlparse(parts):
# get the username, password, etc. # get the username, password, etc.
try: try:
netloc_re = re.compile(r'^((?:\w)+(?::(?:\w)+)?@)?([A-Za-z0-9.-]+)(:\d+)?$') netloc_re = re.compile(r'^((?:\w)+(?::(?:\w)+)?@)?([A-Za-z0-9.-]+)(:\d+)?$')
(auth, hostname, port) = netloc_re.match(parts[1]) match = netloc_re.match(parts[1])
auth = match.group(1)
hostname = match.group(2)
port = match.group(3)
if port: if port:
# the capture group for the port will include the ':', # the capture group for the port will include the ':',
# so remove it and convert the port to an integer # so remove it and convert the port to an integer
@ -383,6 +395,8 @@ def generic_urlparse(parts):
# and then split it up based on the first ':' found # and then split it up based on the first ':' found
auth = auth[:-1] auth = auth[:-1]
username, password = auth.split(':', 1) username, password = auth.split(':', 1)
else:
username = password = None
generic_parts['username'] = username generic_parts['username'] = username
generic_parts['password'] = password generic_parts['password'] = password
generic_parts['hostname'] = hostname generic_parts['hostname'] = hostname
@ -390,7 +404,7 @@ def generic_urlparse(parts):
except: except:
generic_parts['username'] = None generic_parts['username'] = None
generic_parts['password'] = None generic_parts['password'] = None
generic_parts['hostname'] = None generic_parts['hostname'] = parts[1]
generic_parts['port'] = None generic_parts['port'] = None
return generic_parts return generic_parts
@ -532,7 +546,8 @@ class SSLValidationHandler(urllib2.BaseHandler):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if https_proxy: if https_proxy:
proxy_parts = generic_urlparse(urlparse.urlparse(https_proxy)) proxy_parts = generic_urlparse(urlparse.urlparse(https_proxy))
s.connect((proxy_parts.get('hostname'), proxy_parts.get('port'))) port = proxy_parts.get('port') or 443
s.connect((proxy_parts.get('hostname'), port))
if proxy_parts.get('scheme') == 'http': if proxy_parts.get('scheme') == 'http':
s.sendall(self.CONNECT_COMMAND % (self.hostname, self.port)) s.sendall(self.CONNECT_COMMAND % (self.hostname, self.port))
if proxy_parts.get('username'): if proxy_parts.get('username'):
@ -542,7 +557,7 @@ class SSLValidationHandler(urllib2.BaseHandler):
connect_result = s.recv(4096) connect_result = s.recv(4096)
self.validate_proxy_response(connect_result) self.validate_proxy_response(connect_result)
if context: if context:
ssl_s = context.wrap_socket(s, server_hostname=proxy_parts.get('hostname')) ssl_s = context.wrap_socket(s, server_hostname=self.hostname)
else: else:
ssl_s = ssl.wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=PROTOCOL) ssl_s = ssl.wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=PROTOCOL)
match_hostname(ssl_s.getpeercert(), self.hostname) match_hostname(ssl_s.getpeercert(), self.hostname)
@ -661,8 +676,9 @@ def open_url(url, data=None, headers=None, method=None, use_proxy=True,
handlers.append(proxyhandler) handlers.append(proxyhandler)
# pre-2.6 versions of python cannot use the custom https # pre-2.6 versions of python cannot use the custom https
# handler, since the socket class is lacking this method # handler, since the socket class is lacking create_connection.
if hasattr(socket, 'create_connection'): # Some python builds lack HTTPS support.
if hasattr(socket, 'create_connection') and CustomHTTPSHandler:
handlers.append(CustomHTTPSHandler) handlers.append(CustomHTTPSHandler)
opener = urllib2.build_opener(*handlers) opener = urllib2.build_opener(*handlers)