10
10
import shutil
11
11
import tempfile
12
12
import time
13
+ from importlib .util import find_spec
13
14
from io import BytesIO
14
15
from operator import itemgetter
15
16
from typing import TYPE_CHECKING
@@ -6546,7 +6547,7 @@ def test_pre_signed_url_forward_slash_bucket(
6546
6547
"signature_version" ,
6547
6548
["s3" , "s3v4" ],
6548
6549
)
6549
- @markers .aws .unknown
6550
+ @markers .aws .validated
6550
6551
def test_s3_presign_url_encoding (
6551
6552
self , aws_client , s3_bucket , signature_version , patch_s3_skip_signature_validation_false
6552
6553
):
@@ -6568,6 +6569,86 @@ def test_s3_presign_url_encoding(
6568
6569
assert req .ok
6569
6570
assert req .content == b"123"
6570
6571
6572
+ @markers .aws .validated
6573
+ def test_s3_ignored_special_headers (
6574
+ self ,
6575
+ s3_bucket ,
6576
+ patch_s3_skip_signature_validation_false ,
6577
+ monkeypatch ,
6578
+ ):
6579
+ # if the crt.auth is not available, not need to patch as it will use it by default
6580
+ if find_spec ("botocore.crt.auth" ):
6581
+ # the CRT client does not allow us to pass a protected header, it will trigger an exception, so we need
6582
+ # to patch the Signer selection to the Python implementation which does not have this check
6583
+ from botocore .auth import AUTH_TYPE_MAPS , S3SigV4QueryAuth
6584
+
6585
+ monkeypatch .setitem (AUTH_TYPE_MAPS , "s3v4-query" , S3SigV4QueryAuth )
6586
+
6587
+ key = "my-key"
6588
+ presigned_client = _s3_client_custom_config (
6589
+ Config (signature_version = "s3v4" , s3 = {"payload_signing_enabled" : True }),
6590
+ endpoint_url = _endpoint_url (),
6591
+ )
6592
+
6593
+ def add_content_sha_header (request , ** kwargs ):
6594
+ request .headers ["x-amz-content-sha256" ] = "UNSIGNED-PAYLOAD"
6595
+
6596
+ presigned_client .meta .events .register (
6597
+ "before-sign.s3.PutObject" ,
6598
+ handler = add_content_sha_header ,
6599
+ )
6600
+ try :
6601
+ url = presigned_client .generate_presigned_url (
6602
+ "put_object" , Params = {"Bucket" : s3_bucket , "Key" : key }
6603
+ )
6604
+ assert "x-amz-content-sha256" in url
6605
+ # somehow, it's possible to add "x-amz-content-sha256" to signed headers, the AWS Go SDK does it
6606
+ resp = requests .put (
6607
+ url ,
6608
+ data = "something" ,
6609
+ verify = False ,
6610
+ headers = {"x-amz-content-sha256" : "UNSIGNED-PAYLOAD" },
6611
+ )
6612
+ assert resp .ok
6613
+
6614
+ # if signed but not provided, AWS will raise an exception
6615
+ resp = requests .put (url , data = "something" , verify = False )
6616
+ assert resp .status_code == 403
6617
+
6618 + finally :
6619
+ presigned_client .meta .events .unregister (
6620
+ "before-sign.s3.PutObject" ,
6621
+ add_content_sha_header ,
6622
+ )
6623
+
6624
+ # recreate the request, without the signed header
6625
+ url = presigned_client .generate_presigned_url (
6626
+ "put_object" , Params = {"Bucket" : s3_bucket , "Key" : key }
6627
+ )
6628
+ assert "x-amz-content-sha256" not in url
6629
+
6630
+ # assert that if provided and not signed, AWS will ignore it even if it starts with `x-amz`
6631
+ resp = requests .put (
6632
+ url ,
6633
+ data = "something" ,
6634
+ verify = False ,
6635
+ headers = {"x-amz-content-sha256" : "UNSIGNED-PAYLOAD" },
6636
+ )
6637
+ assert resp .ok
6638
+
6639
+ # assert that x-amz-user-agent is not ignored, it must be set in SignedHeaders
6640
+ resp = requests .put (
6641
+ url , data = "something" , verify = False , headers = {"x-amz-user-agent" : "test" }
6642
+ )
6643
+ assert resp .status_code == 403
6644
+
6645
+ # X-Amz-Signature needs to be the last query string parameter: insert x-id before like the Go SDK
6646
+ index = url .find ("&X-Amz-Signature" )
6647
+ rewritten_url = url [:index ] + "&x-id=PutObject" + url [index :]
6648
+ # however, the x-id query string parameter is not ignored
6649
+ resp = requests .put (rewritten_url , data = "something" , verify = False )
6650
+ assert resp .status_code == 403
6651
+
6571
6652
6572
6653
class TestS3DeepArchive :
6573
6654
"""
0 commit comments