@ -118,6 +118,15 @@ try:
except ImportError :
except ImportError :
HAS_SSLCONTEXT = False
HAS_SSLCONTEXT = 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_SNI_SUPPORT = True
except ImportError :
HAS_URLLIB3_SNI_SUPPORT = False
# Select a protocol that includes all secure tls protocols
# Select a protocol that includes all secure tls protocols
# Exclude insecure ssl protocols if possible
# Exclude insecure ssl protocols if possible
@ -340,6 +349,8 @@ if hasattr(httplib, 'HTTPSConnection') and hasattr(urllib2, 'HTTPSHandler'):
if HAS_SSLCONTEXT :
if HAS_SSLCONTEXT :
self . sock = self . context . wrap_socket ( sock , server_hostname = server_hostname )
self . sock = self . context . wrap_socket ( sock , server_hostname = server_hostname )
elif HAS_URLLIB3_SNI_SUPPORT :
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 :
else :
self . sock = ssl . wrap_socket ( sock , keyfile = self . key_file , certfile = self . cert_file , ssl_version = PROTOCOL )
self . sock = ssl . wrap_socket ( sock , keyfile = self . key_file , certfile = self . cert_file , ssl_version = PROTOCOL )
@ -476,6 +487,33 @@ def RedirectHandlerFactory(follow_redirects=None, validate_certs=True):
return RedirectHandler
return RedirectHandler
def build_ssl_validation_error ( hostname , port , paths ) :
''' Inteligently build out the SSLValidationError based on what support
you have installed
'''
msg = [
( ' Failed to validate the SSL certificate for %s : %s . '
' Make sure your managed systems have a valid CA '
' certificate installed. ' )
]
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_URLLIB3_SNI_SUPPORT :
msg . append ( ' or you can install the `urllib3`, `pyopenssl`, '
' `ndg-httpsclient`, and `pyasn1` python modules ' )
msg . append ( ' to perform SNI verification in python >= 2.6. ' )
msg . append ( ' You can use validate_certs=False if you do '
' not need to confirm the servers identity but this is '
' unsafe and not recommended. '
' Paths checked for this platform: %s ' )
raise SSLValidationError ( ' ' . join ( msg ) % ( hostname , port , " , " . join ( paths ) ) )
class SSLValidationHandler ( urllib2 . BaseHandler ) :
class SSLValidationHandler ( urllib2 . BaseHandler ) :
'''
'''
A custom handler class for SSL validation .
A custom handler class for SSL validation .
@ -607,6 +645,8 @@ class SSLValidationHandler(urllib2.BaseHandler):
self . validate_proxy_response ( connect_result )
self . validate_proxy_response ( connect_result )
if context :
if context :
ssl_s = context . wrap_socket ( s , server_hostname = self . hostname )
ssl_s = context . wrap_socket ( s , server_hostname = self . hostname )
elif HAS_URLLIB3_SNI_SUPPORT :
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 :
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 )
@ -616,6 +656,8 @@ class SSLValidationHandler(urllib2.BaseHandler):
s . connect ( ( self . hostname , self . port ) )
s . connect ( ( self . hostname , self . port ) )
if context :
if context :
ssl_s = context . wrap_socket ( s , server_hostname = self . hostname )
ssl_s = context . wrap_socket ( s , server_hostname = self . hostname )
elif HAS_URLLIB3_SNI_SUPPORT :
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 :
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 )
@ -627,17 +669,9 @@ class SSLValidationHandler(urllib2.BaseHandler):
if ' connection refused ' in str ( e ) . lower ( ) :
if ' connection refused ' in str ( e ) . lower ( ) :
raise ConnectionError ( ' Failed to connect to %s : %s . ' % ( self . hostname , self . port ) )
raise ConnectionError ( ' Failed to connect to %s : %s . ' % ( self . hostname , self . port ) )
else :
else :
raise SSLValidationError ( ' Failed to validate the SSL certificate for %s : %s . '
build_ssl_validation_error ( self . hostname , self . port , paths_checked )
' Make sure your managed systems have a valid CA '
' certificate installed. If the website serving the url '
' uses SNI you need python >= 2.7.9 on your managed '
' machine. You can use validate_certs=False if you do '
' not need to confirm the server \ s identity but this is '
' unsafe and not recommended '
' Paths checked for this platform: %s ' % ( self . hostname , self . port , " , " . join ( paths_checked ) )
)
except CertificateError :
except CertificateError :
raise SSLValidationError ( " SSL Certificate does not belong to %s . Make sure the url has a certificate that belongs to it or use validate_certs=False (insecure) " % self . hostname )
build_ssl_validation_error ( self . hostname , self . port , paths_checked )
try :
try :
# cleanup the temp file created, don't worry
# cleanup the temp file created, don't worry