Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Honor REQUESTS_CA_BUNDLE env var in Endpoint class #203

Merged
merged 2 commits into from
Jan 9, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions botocore/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# IN THE SOFTWARE.
#

import os
import logging
import time
import threading
Expand Down Expand Up @@ -51,12 +52,13 @@ class Endpoint(object):
:ivar session: The session object.
"""

def __init__(self, service, region_name, host, auth, proxies=None):
def __init__(self, service, region_name, host, auth, proxies=None,
verify=True):
self.service = service
self.session = self.service.session
self.region_name = region_name
self.host = host
self.verify = True
self.verify = verify
self.auth = auth
if proxies is None:
proxies = {}
Expand Down Expand Up @@ -242,7 +244,7 @@ def _get_proxies(url):
return get_environ_proxies(url)


def get_endpoint(service, region_name, endpoint_url):
def get_endpoint(service, region_name, endpoint_url, verify=None):
cls = SERVICE_TO_ENDPOINT.get(service.type)
if cls is None:
raise botocore.exceptions.UnknownServiceStyle(
Expand All @@ -256,7 +258,23 @@ def get_endpoint(service, region_name, endpoint_url):
region_name=region_name,
service_object=service)
proxies = _get_proxies(endpoint_url)
return cls(service, region_name, endpoint_url, auth=auth, proxies=proxies)
verify = _get_verify_value(verify)
return cls(service, region_name, endpoint_url, auth=auth, proxies=proxies,
verify=verify)


def _get_verify_value(verify):
# This is to account for:
# https://github.com/kennethreitz/requests/issues/1436
# where we need to honor REQUESTS_CA_BUNDLE because we're creating our
# own request objects.
# First, if verify is not None, then the user explicitly specified
# a value so this automatically wins.
if verify is not None:
return verify
# Otherwise use the value from REQUESTS_CA_BUNDLE, or default to
# True if the env var does not exist.
return os.environ.get('REQUESTS_CA_BUNDLE', True)


def _get_auth(signature_version, credentials, service_name, region_name,
Expand Down
10 changes: 5 additions & 5 deletions botocore/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _build_endpoint_url(self, host, is_secure):
return endpoint_url

def get_endpoint(self, region_name=None, is_secure=True,
endpoint_url=None):
endpoint_url=None, verify=None):
"""
Return the Endpoint object for this service in a particular
region.
Expand Down Expand Up @@ -127,7 +127,7 @@ def get_endpoint(self, region_name=None, is_secure=True,
# Before getting into any of the region/endpoint
# logic, if an endpoint_url is explicitly
# provided, just use what's been explicitly passed in.
return self._get_endpoint(region_name, endpoint_url)
return self._get_endpoint(region_name, endpoint_url, verify)
if region_name is None and not self.global_endpoint:
# The only time it's ok to *not* provide a region is
# if the service is a global_endpoint (e.g. IAM).
Expand Down Expand Up @@ -163,14 +163,14 @@ def get_endpoint(self, region_name=None, is_secure=True,
# endpoint_prefix.region.amazonaws.com.
host = '%s.%s.amazonaws.com' % (self.endpoint_prefix, region_name)
endpoint_url = self._build_endpoint_url(host, is_secure)
return self._get_endpoint(region_name, endpoint_url)
return self._get_endpoint(region_name, endpoint_url, verify)

def _get_endpoint(self, region_name, endpoint_url):
def _get_endpoint(self, region_name, endpoint_url, verify):
event = self.session.create_event('creating-endpoint',
self.endpoint_prefix)
self.session.emit(event, service=self, region_name=region_name,
endpoint_url=endpoint_url)
return get_endpoint(self, region_name, endpoint_url)
return get_endpoint(self, region_name, endpoint_url, verify)

def get_operation(self, operation_name):
"""
Expand Down
44 changes: 44 additions & 0 deletions tests/unit/test_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ def seek(self, where):


class TestGetEndpoint(unittest.TestCase):
def setUp(self):
self.environ = {}
self.environ_patch = patch('os.environ', self.environ)
self.environ_patch.start()

def tearDown(self):
self.environ_patch.stop()

def create_mock_service(self, service_type, signature_version='v2'):
service = Mock()
service.type = service_type
Expand Down Expand Up @@ -101,6 +109,42 @@ def test_omitted_auth_handler(self):
'https://service.region.amazonaws.com')
self.assertIsNone(endpoint.auth)

def test_get_endpoint_default_verify_ssl(self):
service = self.create_mock_service('query')
endpoint = get_endpoint(service, 'us-west-2',
'https://service.region.amazonaws.com')
self.assertTrue(endpoint.verify)

def test_verify_ssl_can_be_disabled(self):
service = self.create_mock_service('query')
endpoint = get_endpoint(service, 'us-west-2',
'https://service.region.amazonaws.com',
verify=False)
self.assertFalse(endpoint.verify)

def test_verify_ssl_can_specify_cert_bundle(self):
service = self.create_mock_service('query')
endpoint = get_endpoint(service, 'us-west-2',
'https://service.region.amazonaws.com',
verify='/path/cacerts.pem')
self.assertEqual(endpoint.verify, '/path/cacerts.pem')

def test_honor_cert_bundle_env_var(self):
self.environ['REQUESTS_CA_BUNDLE'] = '/env/cacerts.pem'
service = self.create_mock_service('query')
endpoint = get_endpoint(service, 'us-west-2',
'https://service.region.amazonaws.com')
self.assertEqual(endpoint.verify, '/env/cacerts.pem')

def test_env_ignored_if_explicitly_passed(self):
self.environ['REQUESTS_CA_BUNDLE'] = '/env/cacerts.pem'
service = self.create_mock_service('query')
endpoint = get_endpoint(service, 'us-west-2',
'https://service.region.amazonaws.com',
verify='/path/cacerts.pem')
# /path/cacerts.pem wins over the value from the env var.
self.assertEqual(endpoint.verify, '/path/cacerts.pem')


class TestEndpointBase(unittest.TestCase):

Expand Down
5 changes: 5 additions & 0 deletions tests/unit/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ def test_get_endpoint_with_no_region(self):
endpoint = service.get_endpoint()
self.assertEqual(endpoint.host, 'https://iam.amazonaws.com/')

def test_get_endpoint_forwards_verify_args(self):
service = self.session.get_service('iam')
endpoint = service.get_endpoint(verify='/path/cacerts.pem')
self.assertEqual(endpoint.verify, '/path/cacerts.pem')

def test_endpoint_arg_overrides_everything(self):
service = self.session.get_service('iam')
endpoint = service.get_endpoint(
Expand Down