Skip to content

Commit

Permalink
Fix generate_presigned_url for S3 operations where the modeled reques…
Browse files Browse the repository at this point in the history
…t URI contains a query component (#2971)
  • Loading branch information
jonemo authored Jul 10, 2023
1 parent c1cd648 commit 2f1f009
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changes/next-release/bugfix-s3-68869.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "bugfix",
"category": "s3",
"description": "Fix s3 presigned URLs for operations with query components (`#2962 <https://github.com/boto/botocore/issues/2962>`__)"
}
4 changes: 4 additions & 0 deletions botocore/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,10 @@ def remove_bucket_from_url_paths_from_model(params, model, context, **kwargs):
bucket_path = '/{Bucket}'
if req_uri.startswith(bucket_path):
model.http['requestUri'] = req_uri[len(bucket_path) :]
# Strip query off the requestUri before using as authPath. The
# HmacV1Auth signer will append query params to the authPath during
# signing.
req_uri = req_uri.split('?')[0]
# If the request URI is ONLY a bucket, the auth_path must be
# terminated with a '/' character to generate a signature that the
# server will accept.
Expand Down
47 changes: 47 additions & 0 deletions tests/unit/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1680,3 +1680,50 @@ def test_remove_arn_from_signing_path(auth_path_in, auth_path_expected):
request=request, some='other', kwarg='values'
)
assert request.auth_path == auth_path_expected


@pytest.mark.parametrize(
'request_uri_before, request_uri_after, auth_path',
[
('/{Bucket}', '', '/{Bucket}/'),
('/{Bucket}?query', '?query', '/{Bucket}/'),
('/{Bucket}/123', '/123', '/{Bucket}/123'),
('/{Bucket}/123?query', '/123?query', '/{Bucket}/123'),
],
)
def test_remove_bucket_from_url_paths_from_model(
request_uri_before, request_uri_after, auth_path
):
operation_def = {
'name': 'TestOp',
'http': {
'method': 'GET',
'requestUri': request_uri_before,
'responseCode': 200,
},
'input': {'shape': 'TestOpInput'},
}
service_def = {
'metadata': {},
'shapes': {
'TestOpInput': {
'type': 'structure',
'required': ['Bucket'],
'members': {
'Bucket': {
'shape': 'String',
'contextParam': {'name': 'Bucket'},
'location': 'uri',
'locationName': 'Bucket',
},
},
},
},
}
model = OperationModel(operation_def, ServiceModel(service_def))
# the handler modifies ``model`` in place
handlers.remove_bucket_from_url_paths_from_model(
params=None, model=model, context=None
)
assert model.http['requestUri'] == request_uri_after
assert model.http['authPath'] == auth_path

0 comments on commit 2f1f009

Please sign in to comment.