Luca
Luca

Reputation: 125

BOTO3 - generate_presigned_url for `put_object` return `The request signature we calculated does not match the signature you provided`

I'm trying to create a presigned url that will help some customers to upload files . Here my test script that is currently working

# Get the service client.
s3 = boto3.client('s3')
boto3.set_stream_logger(name='botocore')

# Generate the URL to get 'key-name' from 'bucket-name'
url = s3.generate_presigned_url(
    ClientMethod='put_object',
    Params={
        'Bucket': s3_bucket_name,
        'Key': test_key,
    }    
)

files = StringIO("asdfasdfasdf")
response = requests.put(url, data=files)

print(str(response.content))

But if I'm adding:

`ACL': 'public-read' 

to Params (or add some metadata following the information in the put_object documentation I receive back from the server:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

I've open also a issue on BOTO3: https://github.com/boto/boto3/issues/1722

Upvotes: 9

Views: 18237

Answers (3)

Me Sa
Me Sa

Reputation: 1094

I had same issue finally found a great video on youtube, you can watch this video

https://www.youtube.com/watch?v=MfDZKmL_PNo

or do this:

def download_generate_pre_signed_url(self, key, expires_sec: int = 3600):
    client = boto3.client('s3')
    res = client.generate_presigned_url(
        ClientMethod='get_object',
        Params={'Bucket': self.__bucket_name, 'Key': key},
        ExpiresIn=expires_sec)
    return res

def upload_generate_pre_signed_url_post(self, key, expires_sec: int = 3600):
    client = boto3.client('s3')
    res = client.generate_presigned_post(
        Bucket=self.__bucket_name,
        Key=key,
        ExpiresIn=expires_sec)
    return res

Upvotes: 0

Cio bu
Cio bu

Reputation: 91

Got the same problem using S3 on Dell ECS object storage. The S3 protocol is implemented partially so there's no support for POST method with ECS. The workaround is to use correct headers in PUT methtod, then the ACL for the object are set correctly on the server.

    # Get the service client.
    s3 = boto3.client('s3')
    boto3.set_stream_logger(name='botocore')

    # Generate the URL to get 'key-name' from 'bucket-name'
    url = s3.generate_presigned_url(
        ClientMethod='put_object',
        Params={
            'Bucket': s3_bucket_name,
            'Key': test_key,
            'ACL': 'public-read'
        }    
    )

    files = StringIO("asdfasdfasdf")
    headers = {'x-amz-acl': 'public-read'}
    response = requests.put(url, data=files, headers=headers)

    print(str(response.content))

Upvotes: 9

Jason
Jason

Reputation: 11363

This is covered in the github issue https://github.com/boto/boto3/issues/934

For uploading an object, you should use generate_presigned_post. There are several parameters that cannot be embedded within the url, and those are returned to you by that method.

Upvotes: 7

Related Questions