Support methods any other GET and POST in Signature V4 AWS S3 operations require HEAD / PUT / GET request
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/cde8824f Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/cde8824f Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/cde8824f Branch: refs/heads/trunk Commit: cde8824f07f4a4fb904fd393da28147eddd2197b Parents: 4bff0f0 Author: Geunwoo Shin <[email protected]> Authored: Wed Jan 27 19:52:39 2016 +0900 Committer: anthony-shaw <[email protected]> Committed: Tue Feb 9 15:12:48 2016 +1100 ---------------------------------------------------------------------- libcloud/common/aws.py | 15 ++++++++------- libcloud/test/common/test_aws.py | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/cde8824f/libcloud/common/aws.py ---------------------------------------------------------------------- diff --git a/libcloud/common/aws.py b/libcloud/common/aws.py index 2cc1d4b..7838ee1 100644 --- a/libcloud/common/aws.py +++ b/libcloud/common/aws.py @@ -50,6 +50,7 @@ __all__ = [ ] DEFAULT_SIGNATURE_VERSION = '2' +UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD' class AWSBaseResponse(XmlResponse): @@ -260,10 +261,6 @@ class AWSRequestSignerAlgorithmV4(AWSRequestSigner): def _get_authorization_v4_header(self, params, headers, dt, method='GET', path='/', data=None): - assert method in ['GET', 'POST'], 'AWS Signature V4 ' \ - 'not implemented for ' \ - 'other methods than GET and POST' - credentials_scope = self._get_credential_scope(dt=dt) signed_headers = self._get_signed_headers(headers=headers) signature = self._get_signature(params=params, headers=headers, @@ -322,10 +319,14 @@ class AWSRequestSignerAlgorithmV4(AWSRequestSigner): for k, v in sorted(headers.items())]) + '\n' def _get_payload_hash(self, method, data=None): - if method == 'GET': + if method in ('POST', 'PUT'): + if data: + return _hash(data) + else: + # When upload file, we can't know payload here even if given + return UNSIGNED_PAYLOAD + else: return _hash('') - elif method == 'POST': - return _hash(data) def _get_request_params(self, params): # For self.method == GET http://git-wip-us.apache.org/repos/asf/libcloud/blob/cde8824f/libcloud/test/common/test_aws.py ---------------------------------------------------------------------- diff --git a/libcloud/test/common/test_aws.py b/libcloud/test/common/test_aws.py index c855534..bfa81fe 100644 --- a/libcloud/test/common/test_aws.py +++ b/libcloud/test/common/test_aws.py @@ -5,6 +5,8 @@ from datetime import datetime import mock from libcloud.common.aws import SignedAWSConnection +from libcloud.common.aws import UNSIGNED_PAYLOAD +from libcloud.common.aws import AWSRequestSignerAlgorithmV2 from libcloud.common.aws import AWSRequestSignerAlgorithmV4 from libcloud.test import LibcloudTestCase @@ -53,11 +55,6 @@ class AWSRequestSignerAlgorithmV4TestCase(LibcloudTestCase): 'SignedHeaders=accept-encoding;host;user-agent;x-amz-date, ' 'Signature=f9868f8414b3c3f856c7955019cc1691265541f5162b9b772d26044280d39bd3') - def test_v4_signature_raises_error_if_request_method_not_GET_OR_POST(self): - with self.assertRaises(Exception): - self.signer._get_authorization_v4_header(params={}, headers={}, - dt=self.now, method='PUT') - def test_v4_signature_contains_user_id(self): sig = self.signer._get_authorization_v4_header(params={}, headers={}, dt=self.now) @@ -219,6 +216,16 @@ class AWSRequestSignerAlgorithmV4TestCase(LibcloudTestCase): self.assertEqual(self.signer._get_payload_hash(method='GET'), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855') + def test_get_payload_hash_with_data_for_PUT_requests(self): + SignedAWSConnection.method = 'PUT' + self.assertEqual(self.signer._get_payload_hash(method='POST', data='DUMMY'), + 'ceec12762e66397b56dad64fd270bb3d694c78fb9cd665354383c0626dbab013') + + def test_get_payload_hash_with_empty_data_for_POST_requests(self): + SignedAWSConnection.method = 'POST' + self.assertEqual(self.signer._get_payload_hash(method='POST'), + UNSIGNED_PAYLOAD) + def test_get_canonical_request(self): req = self.signer._get_canonical_request( {'Action': 'DescribeInstances', 'Version': '2013-10-15'},
