diff --git a/botocore/auth.py b/botocore/auth.py index bc04e82f2b..5066614b94 100644 --- a/botocore/auth.py +++ b/botocore/auth.py @@ -535,7 +535,7 @@ def canonical_string(self, method, split, headers, expires=None, def get_signature(self, method, split, headers, expires=None, auth_path=None): - if self.credentials.token: + if self.credentials.token and 'x-amz-security-token' not in headers: headers['x-amz-security-token'] = self.credentials.token string_to_sign = self.canonical_string(method, split, @@ -553,6 +553,14 @@ def add_auth(self, request): signature = self.get_signature(request.method, split, request.headers, auth_path=request.auth_path) + if 'Authorization' in request.headers: + # We have to do this because request.headers is not + # normal dictionary. It has the (unintuitive) behavior + # of aggregating repeated setattr calls for the same + # key value. For example: + # headers['foo'] = 'a'; headers['foo'] = 'b' + # list(headers) will print ['foo', 'foo']. + del request.headers['Authorization'] request.headers['Authorization'] = ( "AWS %s:%s" % (self.credentials.access_key, signature)) diff --git a/tests/unit/auth/test_signers.py b/tests/unit/auth/test_signers.py index 53ba839d2a..4aa5203781 100644 --- a/tests/unit/auth/test_signers.py +++ b/tests/unit/auth/test_signers.py @@ -85,6 +85,39 @@ def test_bucket_operations(self): cr = self.hmacv1.canonical_resource(split) self.assertEqual(cr, '/quotes?%s' % operation) + def test_sign_with_token(self): + credentials = botocore.credentials.Credentials( + access_key='foo', secret_key='bar', token='baz') + auth = botocore.auth.HmacV1Auth(credentials) + request = AWSRequest() + request.headers['Date'] = 'Thu, 17 Nov 2005 18:49:58 GMT' + request.headers['Content-Type'] = 'text/html' + request.method = 'PUT' + request.url = 'https://s3.amazonaws.com/bucket/key' + auth.add_auth(request) + self.assertIn('Authorization', request.headers) + # We're not actually checking the signature here, we're + # just making sure the auth header has the right format. + self.assertTrue(request.headers['Authorization'].startswith('AWS ')) + + def test_resign_with_token(self): + credentials = botocore.credentials.Credentials( + access_key='foo', secret_key='bar', token='baz') + auth = botocore.auth.HmacV1Auth(credentials) + request = AWSRequest() + request.headers['Date'] = 'Thu, 17 Nov 2005 18:49:58 GMT' + request.headers['Content-Type'] = 'text/html' + request.method = 'PUT' + request.url = 'https://s3.amazonaws.com/bucket/key' + + auth.add_auth(request) + original_auth = request.headers['Authorization'] + # Resigning the request shouldn't change the authorization + # header. + auth.add_auth(request) + self.assertEqual(request.headers.get_all('Authorization'), + [original_auth]) + class TestSigV2(unittest.TestCase):