Repository: boto/botocore
Pull request #798 (2016-02-17 21:33:48)

Fix issue where AWS_CA_BUNDLE was not being used
Was not using the session's configuration and instead relied on the scoped config.

@jamesls @rayluo @JordonPhillips 


Patch:
diff --git a/botocore/client.py b/botocore/client.py
index 96119cb9c..d5174ed92 100644
--- a/botocore/client.py
+++ b/botocore/client.py
@@ -191,14 +191,6 @@ class ClientCreator(object):
 
         config_kwargs['s3'] = s3_configuration
 
-    def _resolve_verify_value(self, provided_verify_value, scoped_config):
-        # If a user provides a value for "verify" then we don't do anything.
-        # We always use explicit values provided.
-        if provided_verify_value is not None:
-            return provided_verify_value
-        elif scoped_config is not None:
-            return scoped_config.get('ca_bundle')
-
     def _get_client_args(self, service_model, region_name, is_secure,
                          endpoint_url, verify, credentials,
                          scoped_config, client_config):
@@ -211,7 +203,6 @@ class ClientCreator(object):
 
         response_parser = botocore.parsers.create_parser(protocol)
 
-        verify = self._resolve_verify_value(verify, scoped_config)
         # Determine what region the user provided either via the
         # region_name argument or the client_config.
         if region_name is None:
diff --git a/botocore/session.py b/botocore/session.py
index 6f91652ec..b254d7376 100644
--- a/botocore/session.py
+++ b/botocore/session.py
@@ -770,11 +770,19 @@ class Session(object):
         elif default_client_config is not None:
             config = default_client_config
 
+        # Figure out the user-provided region based on the various
+        # configuration options.
         if region_name is None:
             if config and config.region_name is not None:
                 region_name = config.region_name
             else:
                 region_name = self.get_config_variable('region')
+
+        # Figure out the verify value base on the various
+        # configuration options.
+        if verify is None:
+            verify = self.get_config_variable('ca_bundle')
+
         loader = self.get_component('data_loader')
         event_emitter = self.get_component('event_emitter')
         response_parser_factory = self.get_component(
@@ -791,8 +799,9 @@ class Session(object):
             loader, endpoint_resolver, self.user_agent(), event_emitter,
             retryhandler, translate, response_parser_factory)
         client = client_creator.create_client(
-            service_name, region_name, use_ssl, endpoint_url, verify,
-            credentials, scoped_config=self.get_scoped_config(),
+            service_name=service_name, region_name=region_name,
+            is_secure=use_ssl, endpoint_url=endpoint_url, verify=verify,
+            credentials=credentials, scoped_config=self.get_scoped_config(),
             client_config=config, api_version=api_version)
         return client
 


Test patch:
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
index a26b43b41..a192670a9 100644
--- a/tests/unit/test_client.py
+++ b/tests/unit/test_client.py
@@ -1094,21 +1094,6 @@ class TestAutoGeneratedClient(unittest.TestCase):
             client.meta.events.register.call_args_list
         )
 
-    def test_create_with_ca_bundle_from_scoped_config(self):
-        creator = self.create_client_creator()
-        creator.create_client('myservice', 'us-west-2',
-                              scoped_config={'ca_bundle': 'mycerts.pem'})
-        call_kwargs = self.endpoint_creator.create_endpoint.call_args[1]
-        self.assertEqual(call_kwargs['verify'], 'mycerts.pem')
-
-    def test_verify_takes_precedence_over_scoped_config(self):
-        creator = self.create_client_creator()
-        creator.create_client('myservice', 'us-west-2',
-                              verify='verify.pem',
-                              scoped_config={'ca_bundle': 'mycerts.pem'})
-        call_kwargs = self.endpoint_creator.create_endpoint.call_args[1]
-        self.assertEqual(call_kwargs['verify'], 'verify.pem')
-
     def test_before_call_short_circuits_request(self):
         def return_mock_tuple(**kwargs):
             http_mock = mock.Mock()
diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py
index ee82b6af1..78ddd9672 100644
--- a/tests/unit/test_session.py
+++ b/tests/unit/test_session.py
@@ -40,6 +40,7 @@ class BaseSessionTest(unittest.TestCase):
             'data_path': ('data_path', 'FOO_DATA_PATH', None, None),
             'config_file': (None, 'FOO_CONFIG_FILE', None, None),
             'credentials_file': (None, None, '/tmp/nowhere', None),
+            'ca_bundle': ('foo_ca_bundle', 'FOO_AWS_CA_BUNDLE', None, None),
         }
         self.environ = {}
         self.environ_patch = mock.patch('os.environ', self.environ)
@@ -422,7 +423,8 @@ class TestCreateClient(BaseSessionTest):
         config = client.Config(region_name='us-west-2')
         self.session.create_client('sts', config=config)
         client_creator.return_value.create_client.assert_called_with(
-            mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
+            service_name=mock.ANY, region_name=mock.ANY, is_secure=mock.ANY,
+            endpoint_url=mock.ANY, verify=mock.ANY, credentials=mock.ANY,
             scoped_config=mock.ANY, client_config=config,
             api_version=mock.ANY)
 
@@ -433,7 +435,8 @@ class TestCreateClient(BaseSessionTest):
         self.session.create_client('sts')
 
         client_creator.return_value.create_client.assert_called_with(
-            mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY, mock.ANY,
+            service_name=mock.ANY, region_name=mock.ANY, is_secure=mock.ANY,
+            endpoint_url=mock.ANY, verify=mock.ANY, credentials=mock.ANY,
             scoped_config=mock.ANY, client_config=config,
             api_version=mock.ANY)
 
@@ -481,6 +484,58 @@ class TestCreateClient(BaseSessionTest):
         ec2_client = self.session.create_client('ec2')
         self.assertEqual(ec2_client.meta.region_name, 'moon-west-1')
 
+    @mock.patch('botocore.client.ClientCreator')
+    def test_create_client_with_ca_bundle_from_config(self, client_creator):
+        with temporary_file('w') as f:
+            del self.environ['FOO_PROFILE']
+            self.environ['FOO_CONFIG_FILE'] = f.name
+            self.session = create_session(session_vars=self.env_vars)
+            f.write('[default]\n')
+            f.write('foo_ca_bundle=config-certs.pem\n')
+            f.flush()
+
+            self.session.create_client('ec2', 'us-west-2')
+            call_kwargs = client_creator.return_value.\
+                create_client.call_args[1]
+            self.assertEqual(call_kwargs['verify'], 'config-certs.pem')
+
+    @mock.patch('botocore.client.ClientCreator')
+    def test_create_client_with_ca_bundle_from_env_var(self, client_creator):
+        self.environ['FOO_AWS_CA_BUNDLE'] = 'env-certs.pem'
+        self.session.create_client('ec2', 'us-west-2')
+        call_kwargs = client_creator.return_value.create_client.call_args[1]
+        self.assertEqual(call_kwargs['verify'], 'env-certs.pem')
+
+    @mock.patch('botocore.client.ClientCreator')
+    def test_create_client_with_verify_param(self, client_creator):
+        self.session.create_client(
+            'ec2', 'us-west-2', verify='verify-certs.pem')
+        call_kwargs = client_creator.return_value.create_client.call_args[1]
+        self.assertEqual(call_kwargs['verify'], 'verify-certs.pem')
+
+    @mock.patch('botocore.client.ClientCreator')
+    def test_create_client_verify_param_overrides_all(self, client_creator):
+        with temporary_file('w') as f:
+            # Set the ca cert using the config file
+            del self.environ['FOO_PROFILE']
+            self.environ['FOO_CONFIG_FILE'] = f.name
+            self.session = create_session(session_vars=self.env_vars)
+            f.write('[default]\n')
+            f.write('foo_ca_bundle=config-certs.pem\n')
+            f.flush()
+
+            # Set the ca cert with an environment variable
+            self.environ['FOO_AWS_CA_BUNDLE'] = 'env-certs.pem'
+
+            # Set the ca cert using the verify parameter
+            self.session.create_client(
+                'ec2', 'us-west-2', verify='verify-certs.pem')
+            call_kwargs = client_creator.return_value.\
+                create_client.call_args[1]
+            # The verify parameter should override all the other
+            # configurations
+            self.assertEqual(call_kwargs['verify'], 'verify-certs.pem')
+
 
 class TestComponentLocator(unittest.TestCase):
     def setUp(self):