diff options
-rw-r--r-- | boto/auth.py | 26 | ||||
-rw-r--r-- | boto/connection.py | 5 | ||||
-rw-r--r-- | boto/provider.py | 9 | ||||
-rw-r--r-- | boto/s3/connection.py | 25 | ||||
-rw-r--r-- | tests/unit/s3/test_connection.py | 35 |
5 files changed, 81 insertions, 19 deletions
diff --git a/boto/auth.py b/boto/auth.py index b479d126..4374f73b 100644 --- a/boto/auth.py +++ b/boto/auth.py @@ -98,21 +98,26 @@ SIGV4_DETECT = [ class HmacKeys(object): """Key based Auth handler helper.""" - def __init__(self, host, config, provider): + def __init__(self, host, config, provider, anon=False): if provider.access_key is None or provider.secret_key is None: - raise boto.auth_handler.NotReadyToAuthenticate() + if not anon: + raise boto.auth_handler.NotReadyToAuthenticate() + else: + self._hmac = None + self._hmac_256 = None self.host = host self.update_provider(provider) def update_provider(self, provider): self._provider = provider - self._hmac = hmac.new(self._provider.secret_key.encode('utf-8'), - digestmod=sha) - if sha256: - self._hmac_256 = hmac.new(self._provider.secret_key.encode('utf-8'), - digestmod=sha256) - else: - self._hmac_256 = None + if self._provider.secret_key: # Anonymous handler has no key. + self._hmac = hmac.new(self._provider.secret_key.encode('utf-8'), + digestmod=sha) + if sha256: + self._hmac_256 = hmac.new( + self._provider.secret_key.encode('utf-8'), digestmod=sha256) + else: + self._hmac_256 = None def algorithm(self): if self._hmac_256: @@ -152,7 +157,8 @@ class AnonAuthHandler(AuthHandler, HmacKeys): capability = ['anon'] def __init__(self, host, config, provider): - super(AnonAuthHandler, self).__init__(host, config, provider) + AuthHandler.__init__(self, host, config, provider) + HmacKeys.__init__(self, host, config, provider, anon=True) def add_auth(self, http_request, **kwargs): pass diff --git a/boto/connection.py b/boto/connection.py index 2fef4487..34b428f1 100644 --- a/boto/connection.py +++ b/boto/connection.py @@ -543,6 +543,8 @@ class AWSAuthConnection(object): self.http_connection_kwargs['timeout'] = config.getint( 'Boto', 'http_socket_timeout', 70) + is_anonymous_connection = getattr(self, 'anon', False) + if isinstance(provider, Provider): # Allow overriding Provider self.provider = provider @@ -552,7 +554,8 @@ class AWSAuthConnection(object): aws_access_key_id, aws_secret_access_key, security_token, - profile_name) + profile_name, + anon=is_anonymous_connection) # Allow config file to override default host, port, and host header. if self.provider.host: diff --git a/boto/provider.py b/boto/provider.py index e08afa30..494f3f7d 100644 --- a/boto/provider.py +++ b/boto/provider.py @@ -179,7 +179,7 @@ class Provider(object): } def __init__(self, name, access_key=None, secret_key=None, - security_token=None, profile_name=None): + security_token=None, profile_name=None, anon=False): self.host = None self.port = None self.host_header = None @@ -187,6 +187,7 @@ class Provider(object): self.secret_key = secret_key self.security_token = security_token self.profile_name = profile_name + self.anon = anon self.name = name self.acl_class = self.AclClassMap[self.name] self.canned_acls = self.CannedAclsMap[self.name] @@ -244,6 +245,9 @@ class Provider(object): security_token = property(get_security_token, set_security_token) def _credentials_need_refresh(self): + if self.anon: + return False + if self._credential_expiry_time is None: return False else: @@ -264,6 +268,9 @@ class Provider(object): def get_credentials(self, access_key=None, secret_key=None, security_token=None, profile_name=None): + if self.anon: + return + access_key_name, secret_key_name, security_token_name, \ profile_name_name = self.CredentialMap[self.name] diff --git a/boto/s3/connection.py b/boto/s3/connection.py index fa3fbd72..f364a6b0 100644 --- a/boto/s3/connection.py +++ b/boto/s3/connection.py @@ -171,20 +171,31 @@ class S3Connection(AWSAuthConnection): host=NoHostProvided, debug=0, https_connection_factory=None, calling_format=DefaultCallingFormat, path='/', provider='aws', bucket_class=Bucket, security_token=None, - suppress_consec_slashes=True, anon=False, + suppress_consec_slashes=True, anon=None, validate_certs=None, profile_name=None): + self.bucket_class = bucket_class + + if isinstance(calling_format, six.string_types): + calling_format=boto.utils.find_class(calling_format)() + self.calling_format = calling_format + + # Fetching config options at init time, instead of using a class-level + # default (set at class declaration time) as the default arg value, + # allows our tests to ensure that the config file options are + # respected. + if anon is None: + # Only fetch from the config option if a non-default arg value was + # provided. + anon = boto.config.getbool('s3', 'no_sign_request', False) + self.anon = anon + no_host_provided = False - # Try falling back to the boto config file's value, if present. if host is NoHostProvided: host = boto.config.get('s3', 'host') if host is None: host = self.DefaultHost no_host_provided = True - if isinstance(calling_format, six.string_types): - calling_format=boto.utils.find_class(calling_format)() - self.calling_format = calling_format - self.bucket_class = bucket_class - self.anon = anon + super(S3Connection, self).__init__(host, aws_access_key_id, aws_secret_access_key, is_secure, port, proxy, proxy_port, proxy_user, proxy_pass, diff --git a/tests/unit/s3/test_connection.py b/tests/unit/s3/test_connection.py index 05c561b4..8fd33a0a 100644 --- a/tests/unit/s3/test_connection.py +++ b/tests/unit/s3/test_connection.py @@ -59,6 +59,41 @@ class TestAnon(MockServiceWithConfigTestCase): url = conn.generate_url(0, 'GET', bucket='examplebucket', key='test.txt') self.assertNotIn('Signature=', url) + def test_anon_default_taken_from_config_opt(self): + self.config = { + 's3': { + # Value must be a string for `config.getbool` to not crash. + 'no_sign_request': 'True', + } + } + + conn = self.connection_class( + aws_access_key_id='less', + aws_secret_access_key='more', + host='s3.amazonaws.com', + ) + url = conn.generate_url( + 0, 'GET', bucket='examplebucket', key='test.txt') + self.assertNotIn('Signature=', url) + + def test_explicit_anon_arg_overrides_config_value(self): + self.config = { + 's3': { + # Value must be a string for `config.getbool` to not crash. + 'no_sign_request': 'True', + } + } + + conn = self.connection_class( + aws_access_key_id='less', + aws_secret_access_key='more', + host='s3.amazonaws.com', + anon=False + ) + url = conn.generate_url( + 0, 'GET', bucket='examplebucket', key='test.txt') + self.assertIn('Signature=', url) + class TestPresigned(MockServiceWithConfigTestCase): connection_class = S3Connection |