Skip to content

Commit

Permalink
Merge pull request boto#1090 from JordonPhillips/presign-rest-json
Browse files Browse the repository at this point in the history
JSON load request data when presigning
  • Loading branch information
JordonPhillips authored Nov 28, 2016
2 parents 5ec04e8 + 3353623 commit 7a316e7
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changes/next-release/bugfix-Presigner-33378.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "Support presigning rest-json services.",
"type": "bugfix",
"category": "Presigner"
}
21 changes: 16 additions & 5 deletions botocore/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import functools
import time
import calendar
import json

from botocore.exceptions import NoCredentialsError
from botocore.utils import normalize_url_path, percent_encode_sequence
Expand Down Expand Up @@ -452,11 +453,9 @@ def _modify_request_before_signing(self, request):
# percent_encode_sequence(new_query_params)
operation_params = ''
if request.data:
# We also need to move the body params into the query string.
# request.data will be populated, for example, with query services
# which normally form encode the params into the body.
# This means that request.data is a dict() of the operation params.
query_dict.update(request.data)
# We also need to move the body params into the query string. To
# do this, we first have to convert it to a dict.
query_dict.update(self._get_body_as_dict(request))
request.data = ''
if query_dict:
operation_params = percent_encode_sequence(query_dict) + '&'
Expand All @@ -474,6 +473,18 @@ def _modify_request_before_signing(self, request):
new_url_parts = (p[0], p[1], p[2], new_query_string, p[4])
request.url = urlunsplit(new_url_parts)

def _get_body_as_dict(self, request):
# For query services, request.data is form-encoded and is already a
# dict, but for other services such as rest-json it could be a json
# string or bytes. In those cases we attempt to load the data as a
# dict.
data = request.data
if isinstance(data, six.binary_type):
data = json.loads(data.decode('utf-8'))
elif isinstance(data, six.string_types):
data = json.loads(data)
return data

def _inject_signature_to_request(self, request, signature):
# Rather than calculating an "Authorization" header, for the query
# param quth, we just append an 'X-Amz-Signature' param to the end
Expand Down
42 changes: 42 additions & 0 deletions tests/unit/auth/test_signers.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,48 @@ def test_presign_with_security_token(self):
self.assertEqual(
query_string['X-Amz-Security-Token'], 'security-token')

def test_presign_where_body_is_json_bytes(self):
request = AWSRequest()
request.method = 'GET'
request.url = 'https://myservice.us-east-1.amazonaws.com/'
request.data = b'{"Param": "value"}'
self.auth.add_auth(request)
query_string = self.get_parsed_query_string(request)
expected_query_string = {
'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
'X-Amz-Credential': (
'access_key/20140101/myregion/myservice/aws4_request'),
'X-Amz-Expires': '60',
'X-Amz-Date': '20140101T000000Z',
'X-Amz-Signature': (
'8e1d372d168d532313ce6df8f64a7dc51d'
'e6f312a9cfba6e5b345d8a771e839c'),
'X-Amz-SignedHeaders': 'host',
'Param': 'value'
}
self.assertEqual(query_string, expected_query_string)

def test_presign_where_body_is_json_string(self):
request = AWSRequest()
request.method = 'GET'
request.url = 'https://myservice.us-east-1.amazonaws.com/'
request.data = '{"Param": "value"}'
self.auth.add_auth(request)
query_string = self.get_parsed_query_string(request)
expected_query_string = {
'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
'X-Amz-Credential': (
'access_key/20140101/myregion/myservice/aws4_request'),
'X-Amz-Expires': '60',
'X-Amz-Date': '20140101T000000Z',
'X-Amz-Signature': (
'8e1d372d168d532313ce6df8f64a7dc51d'
'e6f312a9cfba6e5b345d8a771e839c'),
'X-Amz-SignedHeaders': 'host',
'Param': 'value'
}
self.assertEqual(query_string, expected_query_string)


class BaseS3PresignPostTest(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit 7a316e7

Please sign in to comment.