Fallback to old ssl_wrap_socket

This commit is contained in:
Matt Martz 2017-01-06 11:03:10 -06:00 committed by Toshio Kuratomi
parent b4b76bab14
commit 13ac993d25
3 changed files with 81 additions and 18 deletions

View file

@ -145,14 +145,26 @@ try:
except ImportError:
HAS_SSLCONTEXT = False
# SNI Handling for python < 2.7.9 with urllib3 support
try:
# urllib3>=1.15
HAS_URLLIB3_SSL_WRAP_SOCKET = False
try:
from urllib3.contrib.pyopenssl import PyOpenSSLContext
except ImportError:
from requests.packages.urllib3.contrib.pyopenssl import PyOpenSSLContext
HAS_PYOPENSSL_CONTEXT = True
HAS_URLLIB3_PYOPENSSLCONTEXT = True
except ImportError:
HAS_PYOPENSSL_CONTEXT = False
# urllib3<1.15,>=1.6
HAS_URLLIB3_PYOPENSSLCONTEXT = False
try:
try:
from urllib3.contrib.pyopenssl import ssl_wrap_socket
except ImportError:
from requests.packages.urllib3.contrib.pyopenssl import ssl_wrap_socket
HAS_URLLIB3_SSL_WRAP_SOCKET = True
except ImportError:
pass
# Select a protocol that includes all secure tls protocols
# Exclude insecure ssl protocols if possible
@ -362,7 +374,7 @@ if hasattr(httplib, 'HTTPSConnection') and hasattr(urllib_request, 'HTTPSHandler
self.context = None
if HAS_SSLCONTEXT:
self.context = create_default_context()
elif HAS_PYOPENSSL_CONTEXT:
elif HAS_URLLIB3_PYOPENSSLCONTEXT:
self.context = PyOpenSSLContext(PROTOCOL)
if self.context and self.cert_file:
self.context.load_cert_chain(self.cert_file, self.key_file)
@ -383,8 +395,11 @@ if hasattr(httplib, 'HTTPSConnection') and hasattr(urllib_request, 'HTTPSHandler
self._tunnel()
server_hostname = self._tunnel_host
if HAS_SSLCONTEXT or HAS_PYOPENSSL_CONTEXT:
if HAS_SSLCONTEXT or HAS_URLLIB3_PYOPENSSLCONTEXT:
self.sock = self.context.wrap_socket(sock, server_hostname=server_hostname)
elif HAS_URLLIB3_SSL_WRAP_SOCKET:
self.sock = ssl_wrap_socket(sock, keyfile=self.key_file, cert_reqs=ssl.CERT_NONE, certfile=self.cert_file, ssl_version=PROTOCOL,
server_hostname=server_hostname)
else:
self.sock = ssl.wrap_socket(sock, keyfile=self.key_file, certfile=self.cert_file, ssl_version=PROTOCOL)
@ -541,7 +556,7 @@ def build_ssl_validation_error(hostname, port, paths, exc=None):
if not HAS_SSLCONTEXT:
msg.append('If the website serving the url uses SNI you need'
' python >= 2.7.9 on your managed machine')
if not HAS_PYOPENSSL_CONTEXT:
if not HAS_URLLIB3_PYOPENSSLCONTEXT or not HAS_URLLIB3_SSL_WRAP_SOCKET:
msg.append('or you can install the `urllib3`, `pyOpenSSL`,'
' `ndg-httpsclient`, and `pyasn1` python modules')
@ -665,7 +680,7 @@ class SSLValidationHandler(urllib_request.BaseHandler):
return True
def _make_context(self, to_add_ca_cert_path):
if HAS_PYOPENSSL_CONTEXT:
if HAS_URLLIB3_PYOPENSSLCONTEXT:
context = PyOpenSSLContext(PROTOCOL)
else:
context = create_default_context()
@ -677,7 +692,7 @@ class SSLValidationHandler(urllib_request.BaseHandler):
tmp_ca_cert_path, to_add_ca_cert_path, paths_checked = self.get_ca_certs()
https_proxy = os.environ.get('https_proxy')
context = None
if HAS_SSLCONTEXT or HAS_PYOPENSSL_CONTEXT:
if HAS_SSLCONTEXT or HAS_URLLIB3_PYOPENSSLCONTEXT:
context = self._make_context(to_add_ca_cert_path)
# Detect if 'no_proxy' environment variable is set and if our URL is included
@ -708,6 +723,8 @@ class SSLValidationHandler(urllib_request.BaseHandler):
self.validate_proxy_response(connect_result)
if context:
ssl_s = context.wrap_socket(s, server_hostname=self.hostname)
elif HAS_URLLIB3_SSL_WRAP_SOCKET:
ssl_s = ssl_wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=PROTOCOL, server_hostname=self.hostname)
else:
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)
@ -717,6 +734,8 @@ class SSLValidationHandler(urllib_request.BaseHandler):
s.connect((self.hostname, self.port))
if context:
ssl_s = context.wrap_socket(s, server_hostname=self.hostname)
elif HAS_URLLIB3_SSL_WRAP_SOCKET:
ssl_s = ssl_wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=PROTOCOL, server_hostname=self.hostname)
else:
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)

View file

@ -236,15 +236,13 @@
- name: install OS packages that are needed for SNI on old python
package:
name: "{{ item }}"
with_items: "{{ uri_os_packages[ansible_os_family] | default([]) }}"
with_items: "{{ uri_os_packages[ansible_os_family].step1 | default([]) }}"
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
- name: install python modules for Older Python SNI verification
pip:
name: "{{ item }}"
with_items:
- urllib3
- PyOpenSSL
- ndg-httpsclient
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
@ -262,7 +260,7 @@
- 'sni_host in result.content'
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
- name: Uninstall ndg-httpsclient and urllib3
- name: Uninstall ndg-httpsclient
pip:
name: "{{ item }}"
state: absent
@ -274,7 +272,45 @@
package:
name: "{{ item }}"
state: absent
with_items: "{{ uri_os_packages[ansible_os_family] | default([]) }}"
with_items: "{{ uri_os_packages[ansible_os_family].step1 | default([]) }}"
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
- name: install OS packages that are needed for building cryptography
package:
name: "{{ item }}"
with_items: "{{ uri_os_packages[ansible_os_family].step2 | default([]) }}"
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
- name: install urllib3 and pyopenssl via pip
pip:
name: "{{ item }}"
state: latest
with_items:
- urllib3
- PyOpenSSL
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
- name: Verify SNI verification succeeds on old python with pip urllib3 contrib
uri:
url: 'https://{{ sni_host }}'
return_content: true
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
register: result
- name: Assert SNI verification succeeds on old python with pip urllib3 contrib
assert:
that:
- result|success
- 'sni_host in result.content'
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
- name: Uninstall urllib3 and PyOpenSSL
pip:
name: "{{ item }}"
state: absent
with_items:
- urllib3
- PyOpenSSL
when: not ansible_python.has_sslcontext and not is_ubuntu_precise|bool
- name: validate the status_codes are correct

View file

@ -1,9 +1,17 @@
uri_os_packages:
RedHat:
- python-pyasn1
- libffi-devel
- openssl-devel
step1:
- python-pyasn1
- pyOpenSSL
- python-urllib3
step2:
- libffi-devel
- openssl-devel
Debian:
- python-pyasn1
- libffi-dev
- libssl-dev
step1:
- python-pyasn1
- python-openssl
- python-urllib3
step2:
- libffi-dev
- libssl-dev