Repository: libcloud
Updated Branches:
  refs/heads/use_sslv23_constant_in_newer_versions_of_python [created] 67b513122


Update SSL related code to use ssl.PROTOCOL_v23 constant on Python >= 2.7.9 and
Python >= 3.4 by default.

In those versions SSL v3.0 is disabled by default so it's safe to use this
constant and it results in the best compatibility since it will use TLS v1.0 /
v1.1 / v1.2 based on the versions supported by the server.

Also refactor exception wrapping functionality into a separate function.


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/4b218afd
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/4b218afd
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/4b218afd

Branch: refs/heads/use_sslv23_constant_in_newer_versions_of_python
Commit: 4b218afdac4d6bbde00d4a0089dfa914ef5bd575
Parents: 9c4d15c
Author: Tomaz Muraus <to...@tomaz.me>
Authored: Sat Jan 16 14:13:14 2016 +0100
Committer: Tomaz Muraus <to...@tomaz.me>
Committed: Sat Jan 16 14:26:12 2016 +0100

----------------------------------------------------------------------
 libcloud/httplib_ssl.py | 61 +++++++++++++++++++++++++++-----------------
 libcloud/security.py    | 44 +++++++++++++++++++++++++++++---
 libcloud/utils/py3.py   |  2 ++
 3 files changed, 81 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/4b218afd/libcloud/httplib_ssl.py
----------------------------------------------------------------------
diff --git a/libcloud/httplib_ssl.py b/libcloud/httplib_ssl.py
index 5f11d05..c2d14ee 100644
--- a/libcloud/httplib_ssl.py
+++ b/libcloud/httplib_ssl.py
@@ -12,10 +12,12 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
 """
 Subclass for httplib.HTTPSConnection with optional certificate name
 verification, depending on libcloud.security settings.
 """
+
 import os
 import sys
 import socket
@@ -24,6 +26,7 @@ import base64
 import warnings
 
 import libcloud.security
+from libcloud.security import get_ssl_version
 from libcloud.utils.py3 import b
 from libcloud.utils.py3 import httplib
 from libcloud.utils.py3 import urlparse
@@ -290,6 +293,9 @@ class LibcloudHTTPSConnection(httplib.HTTPSConnection, 
LibcloudBaseConnection):
         if self.http_proxy_used:
             self._activate_http_proxy(sock=sock)
 
+        # Dynamically retrieve SSL version which is to be used
+        ssl_version = get_ssl_version()
+
         try:
             self.sock = ssl.wrap_socket(
                 sock,
@@ -297,31 +303,10 @@ class LibcloudHTTPSConnection(httplib.HTTPSConnection, 
LibcloudBaseConnection):
                 self.cert_file,
                 cert_reqs=ssl.CERT_REQUIRED,
                 ca_certs=self.ca_cert,
-                ssl_version=libcloud.security.SSL_VERSION)
+                ssl_version=ssl_version)
         except socket.error:
             exc = sys.exc_info()[1]
-            exc_msg = str(exc)
-
-            # Re-throw an exception with a more friendly error message
-            if 'connection reset by peer' in exc_msg.lower():
-                ssl_version = libcloud.security.SSL_VERSION
-                ssl_version = SSL_CONSTANT_TO_TLS_VERSION_MAP[ssl_version]
-                msg = (UNSUPPORTED_TLS_VERSION_ERROR_MSG %
-                       (exc_msg, ssl_version))
-
-                # Note: In some cases arguments are (errno, message) and in
-                # other it's just (message,)
-                exc_args = getattr(exc, 'args', [])
-
-                if len(exc_args) == 2:
-                    new_exc_args = [exc.args[0], msg]
-                else:
-                    new_exc_args = [msg]
-
-                new_exc = socket.error(*new_exc_args)
-                new_exc.original_exc = exc
-                raise new_exc
-
+            exc = get_socket_error_exception(ssl_version=ssl_version, exc=exc)
             raise exc
 
         cert = self.sock.getpeercert()
@@ -330,3 +315,33 @@ class LibcloudHTTPSConnection(httplib.HTTPSConnection, 
LibcloudBaseConnection):
         except CertificateError:
             e = sys.exc_info()[1]
             raise ssl.SSLError('Failed to verify hostname: %s' % (str(e)))
+
+
+def get_socket_error_exception(ssl_version, exc):
+    """
+    Function which intercepts socket.error exceptions and re-throws an
+    exception with a more user-friendly message in case server doesn't support
+    requested SSL version.
+    """
+    exc_msg = str(exc)
+
+    # Re-throw an exception with a more friendly error message
+    if 'connection reset by peer' in exc_msg.lower():
+        ssl_version_name = SSL_CONSTANT_TO_TLS_VERSION_MAP[ssl_version]
+        msg = (UNSUPPORTED_TLS_VERSION_ERROR_MSG %
+               (exc_msg, ssl_version_name))
+
+        # Note: In some cases arguments are (errno, message) and in
+        # other it's just (message,)
+        exc_args = getattr(exc, 'args', [])
+
+        if len(exc_args) == 2:
+            new_exc_args = [exc.args[0], msg]
+        else:
+            new_exc_args = [msg]
+
+        new_exc = socket.error(*new_exc_args)
+        new_exc.original_exc = exc
+        return new_exc
+
+    return exc

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4b218afd/libcloud/security.py
----------------------------------------------------------------------
diff --git a/libcloud/security.py b/libcloud/security.py
index 4d024db..3659b8d 100644
--- a/libcloud/security.py
+++ b/libcloud/security.py
@@ -19,22 +19,35 @@ Usage:
     import libcloud.security
     libcloud.security.VERIFY_SSL_CERT = True
 
-    # Optional.
+    # Optional
     libcloud.security.CA_CERTS_PATH.append('/path/to/cacert.txt')
+
+    # Use a custom SSL / TLS version
+    libcloud.security.SSL_VERSION = ssl.PROTOCOL_TLSv1_2
 """
 
 import os
 import ssl
 
+from libcloud.utils.py3 import PY2_post_279
+from libcloud.utils.py3 import PY3_post_34
+
 __all__ = [
     'VERIFY_SSL_CERT',
     'SSL_VERSION',
-    'CA_CERTS_PATH'
+    'CA_CERTS_PATH',
+
+    'get_ssl_version'
 ]
 
 VERIFY_SSL_CERT = True
 
-SSL_VERSION = ssl.PROTOCOL_TLSv1
+# Default SSL version which is used if one is not explicitli specified
+DEFAULT_SSL_VERSION = ssl.PROTOCOL_TLSv1
+
+# SSL version to be used as specified by the user
+SSL_VERSION = None
+
 
 # File containing one or more PEM-encoded CA certificates
 # concatenated together.
@@ -87,3 +100,28 @@ VERIFY_SSL_DISABLED_MSG = (
     'certificate verification, please visit the libcloud '
     'documentation.'
 )
+
+
+def get_ssl_version():
+    """
+    Return SSL / TLS version which is to be used when establishing SSL / TLS
+    connection.
+
+    The return value depends on the Python version and
+    libcloud.security.SSL_VERSION setting value.
+
+    :rtype: ``int``
+    """
+    ssl_version = DEFAULT_SSL_VERSION
+
+    # In Python >= 2.7.9 and >= 3.4 unsecure SSL v3.0 is disabled by default
+    # so it's safe to use PROTOCOL_SSLv23.
+    if PY2_post_279 or PY3_post_34:
+        ssl_version = ssl.PROTOCOL_SSLv23
+
+    # libcloud.security.SSL_VERSION has precedence over dynamicaly obtained
+    # values
+    if SSL_VERSION:
+        ssl_version = SSL_VERSION
+
+    return ssl_version

http://git-wip-us.apache.org/repos/asf/libcloud/blob/4b218afd/libcloud/utils/py3.py
----------------------------------------------------------------------
diff --git a/libcloud/utils/py3.py b/libcloud/utils/py3.py
index f7a66c0..3f4f736 100644
--- a/libcloud/utils/py3.py
+++ b/libcloud/utils/py3.py
@@ -30,11 +30,13 @@ except ImportError:
 
 PY2 = sys.version_info[0] == 2
 PY3 = sys.version_info[0] == 3
+PY2_post_279 = PY2 and sys.version_info >= (2, 7, 0)
 PY2_pre_25 = PY2 and sys.version_info < (2, 5)
 PY2_pre_26 = PY2 and sys.version_info < (2, 6)
 PY2_pre_27 = PY2 and sys.version_info < (2, 7)
 PY2_pre_279 = PY2 and sys.version_info < (2, 7, 9)
 PY3_pre_32 = PY3 and sys.version_info < (3, 2)
+PY3_post_34 = PY3 and sys.version_info >= (3, 4, 0)
 
 PY2 = False
 PY25 = False

Reply via email to