You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2013/01/30 08:14:35 UTC

svn commit: r1440296 - in /libcloud/branches/0.12.x: ./ CHANGES libcloud/httplib_ssl.py libcloud/security.py libcloud/test/test_httplib_ssl.py libcloud/utils/py3.py

Author: tomaz
Date: Wed Jan 30 07:14:35 2013
New Revision: 1440296

URL: http://svn.apache.org/viewvc?rev=1440296&view=rev
Log:
Backport commit r1440289 from trunk.

Modified:
    libcloud/branches/0.12.x/   (props changed)
    libcloud/branches/0.12.x/CHANGES
    libcloud/branches/0.12.x/libcloud/httplib_ssl.py
    libcloud/branches/0.12.x/libcloud/security.py
    libcloud/branches/0.12.x/libcloud/test/test_httplib_ssl.py
    libcloud/branches/0.12.x/libcloud/utils/py3.py

Propchange: libcloud/branches/0.12.x/
------------------------------------------------------------------------------
  Merged /libcloud/trunk:r1440289

Modified: libcloud/branches/0.12.x/CHANGES
URL: http://svn.apache.org/viewvc/libcloud/branches/0.12.x/CHANGES?rev=1440296&r1=1440295&r2=1440296&view=diff
==============================================================================
--- libcloud/branches/0.12.x/CHANGES (original)
+++ libcloud/branches/0.12.x/CHANGES Wed Jan 30 07:14:35 2013
@@ -20,6 +20,13 @@ Changes with Apache Libcloud 0.12.0:
       set_driver method. (LIBCLOUD-255)
       [Mahendra M]
 
+    - Allow user to explicitly specify which CA file is used for verifying
+      the server certificate by setting 'SSL_CERT_FILE' environment variable.
+
+      Note: When this variable is specified, the specified path is the only
+      CA file which is used to verifying the server certificate. (LIBCLOUD-283)
+      [Tomaz Muraus, Erinn Looney-Triggs]
+
   *) Compute
 
     - Fix string interpolation bug in __repr__ methods in the IBM SCE driver.

Modified: libcloud/branches/0.12.x/libcloud/httplib_ssl.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.12.x/libcloud/httplib_ssl.py?rev=1440296&r1=1440295&r2=1440296&view=diff
==============================================================================
--- libcloud/branches/0.12.x/libcloud/httplib_ssl.py (original)
+++ libcloud/branches/0.12.x/libcloud/httplib_ssl.py Wed Jan 30 07:14:35 2013
@@ -68,7 +68,7 @@ class LibcloudHTTPSConnection(httplib.HT
 
         ca_certs_available = [cert
                               for cert in libcloud.security.CA_CERTS_PATH
-                              if os.path.exists(cert)]
+                              if os.path.exists(cert) and os.path.isfile(cert)]
         if ca_certs_available:
             # use first available certificate
             self.ca_cert = ca_certs_available[0]

Modified: libcloud/branches/0.12.x/libcloud/security.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.12.x/libcloud/security.py?rev=1440296&r1=1440295&r2=1440296&view=diff
==============================================================================
--- libcloud/branches/0.12.x/libcloud/security.py (original)
+++ libcloud/branches/0.12.x/libcloud/security.py Wed Jan 30 07:14:35 2013
@@ -23,6 +23,8 @@ Usage:
     libcloud.security.CA_CERTS_PATH.append("/path/to/cacert.txt")
 """
 
+import os
+
 VERIFY_SSL_CERT = True
 VERIFY_SSL_CERT_STRICT = True
 
@@ -42,6 +44,22 @@ CA_CERTS_PATH = [
     '/opt/local/share/curl/curl-ca-bundle.crt',
 ]
 
+# Allow user to explicitly specify which CA bundle to use, using an environment
+# variable
+environment_cert_file = os.getenv('SSL_CERT_FILE', None)
+if environment_cert_file is not None:
+    # Make sure the file exists
+    if not os.path.exists(environment_cert_file):
+        raise ValueError('Certificate file %s doesn\'t exist' %
+                         (environment_cert_file))
+
+    if not os.path.isfile(environment_cert_file):
+        raise ValueError('Certificate file can\'t be a directory')
+
+    # If a provided file exists we ignore other common paths because we
+    # don't want to fall-back to a potentially less restrictive bundle
+    CA_CERTS_PATH = [environment_cert_file]
+
 CA_CERTS_UNAVAILABLE_WARNING_MSG = (
     'Warning: No CA Certificates were found in CA_CERTS_PATH. '
     'Toggling VERIFY_SSL_CERT to False.'

Modified: libcloud/branches/0.12.x/libcloud/test/test_httplib_ssl.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.12.x/libcloud/test/test_httplib_ssl.py?rev=1440296&r1=1440295&r2=1440296&view=diff
==============================================================================
--- libcloud/branches/0.12.x/libcloud/test/test_httplib_ssl.py (original)
+++ libcloud/branches/0.12.x/libcloud/test/test_httplib_ssl.py Wed Jan 30 07:14:35 2013
@@ -13,19 +13,64 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import os
 import sys
 import unittest
 import os.path
+import warnings
+
+from mock import patch
 
 import libcloud.security
+
+from libcloud.utils.py3 import reload
 from libcloud.httplib_ssl import LibcloudHTTPSConnection
 
+ORIGINAL_CA_CERS_PATH = libcloud.security.CA_CERTS_PATH
+
 class TestHttpLibSSLTests(unittest.TestCase):
 
     def setUp(self):
         libcloud.security.VERIFY_SSL_CERT = False
+        libcloud.security.CA_CERTS_PATH = ORIGINAL_CA_CERS_PATH
         self.httplib_object = LibcloudHTTPSConnection('foo.bar')
 
+    def test_custom_ca_path_using_env_var_doesnt_exist(self):
+        os.environ['SSL_CERT_FILE'] = '/foo/doesnt/exist'
+
+        try:
+            reload(libcloud.security)
+        except ValueError:
+            e = sys.exc_info()[1]
+            msg = 'Certificate file /foo/doesnt/exist doesn\'t exist'
+            self.assertEqual(str(e), msg)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_custom_ca_path_using_env_var_is_directory(self):
+        file_path  = os.path.dirname(os.path.abspath(__file__))
+        os.environ['SSL_CERT_FILE'] = file_path
+
+        try:
+            reload(libcloud.security)
+        except ValueError:
+            e = sys.exc_info()[1]
+            msg = 'Certificate file can\'t be a directory'
+            self.assertEqual(str(e), msg)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_custom_ca_path_using_env_var_exist(self):
+        # When setting a path we don't actually check that a valid CA file is
+        # provied.
+        # This happens later in the code in httplib_ssl.connect method
+        file_path  = os.path.abspath(__file__)
+        os.environ['SSL_CERT_FILE'] = file_path
+
+        reload(libcloud.security)
+
+        self.assertEqual(libcloud.security.CA_CERTS_PATH, [file_path])
+
     def test_verify_hostname(self):
         cert1 = {'notAfter': 'Feb 16 16:54:50 2013 GMT',
          'subject': ((('countryName', 'US'),),
@@ -142,19 +187,28 @@ class TestHttpLibSSLTests(unittest.TestC
         self.assertEqual(self.httplib_object._get_common_name({}),
                          None)
 
-    def test_setup_verify(self):
-        # @TODO: catch warnings
-        # non-strict mode,s hould just emit a warning
+    @patch('warnings.warn')
+    def test_setup_verify(self, _):
+        libcloud.security.CA_CERTS_PATH = []
+
+        # non-strict mode should just emit a warning
         libcloud.security.VERIFY_SSL_CERT = True
         libcloud.security.VERIFY_SSL_CERT_STRICT = False
         self.httplib_object._setup_verify()
 
+        warnings.warn.assert_called_once_with(
+            libcloud.security.CA_CERTS_UNAVAILABLE_WARNING_MSG)
+
         # strict mode, should throw a runtime error
         libcloud.security.VERIFY_SSL_CERT = True
         libcloud.security.VERIFY_SSL_CERT_STRICT = True
+
         try:
             self.httplib_object._setup_verify()
-        except:
+        except RuntimeError:
+            e = sys.exc_info()[1]
+            msg = libcloud.security.CA_CERTS_UNAVAILABLE_ERROR_MSG
+            self.assertEqual(str(e), msg)
             pass
         else:
             self.fail('Exception not thrown')
@@ -163,24 +217,34 @@ class TestHttpLibSSLTests(unittest.TestC
         libcloud.security.VERIFY_SSL_CERT_STRICT = False
         self.httplib_object._setup_verify()
 
-    def test_setup_ca_cert(self):
-        # @TODO: catch warnings
+    @patch('warnings.warn')
+    def test_setup_ca_cert(self, _):
+        # verify = False, _setup_ca_cert should be a no-op
         self.httplib_object.verify = False
         self.httplib_object.strict = False
         self.httplib_object._setup_ca_cert()
 
         self.assertEqual(self.httplib_object.ca_cert, None)
 
+        # verify = True, a valid path is provided, self.ca_cert should be set to
+        # a valid path
         self.httplib_object.verify = True
 
         libcloud.security.CA_CERTS_PATH = [os.path.abspath(__file__)]
         self.httplib_object._setup_ca_cert()
+
         self.assertTrue(self.httplib_object.ca_cert is not None)
 
+        # verify = True, no CA certs are available, warning should be emitted
         libcloud.security.CA_CERTS_PATH = []
         self.httplib_object._setup_ca_cert()
+
+        warnings.warn.assert_called_once_with(
+            libcloud.security.CA_CERTS_UNAVAILABLE_WARNING_MSG)
+
         self.assertFalse(self.httplib_object.ca_cert)
         self.assertFalse(self.httplib_object.verify)
 
+
 if __name__ == '__main__':
     sys.exit(unittest.main())

Modified: libcloud/branches/0.12.x/libcloud/utils/py3.py
URL: http://svn.apache.org/viewvc/libcloud/branches/0.12.x/libcloud/utils/py3.py?rev=1440296&r1=1440295&r2=1440296&view=diff
==============================================================================
--- libcloud/branches/0.12.x/libcloud/utils/py3.py (original)
+++ libcloud/branches/0.12.x/libcloud/utils/py3.py Wed Jan 30 07:14:35 2013
@@ -24,9 +24,10 @@ import sys
 import types
 from xml.etree import ElementTree as ET
 
-PY3 = False
 PY2 = False
 PY25 = False
+PY3 = False
+PY32 = False
 
 if sys.version_info >= (2, 0) and sys.version_info < (3, 0):
     PY2 = True
@@ -37,6 +38,9 @@ if sys.version_info >= (2, 5) and sys.ve
 if sys.version_info >= (3, 0):
     PY3 = True
 
+if sys.version_info >= (3, 2) and sys.version_info < (3, 3):
+    PY32 = True
+
 if PY3:
     import http.client as httplib
     from io import StringIO
@@ -118,3 +122,8 @@ if PY25:
         if not rel_list:
             return posixpath.curdir
         return posixpath.join(*rel_list)
+
+if PY32:
+    from imp import reload
+else:
+    from __builtin__ import reload