The pre-signed url is not working with md5 hash.
Normally when put
params = {'Bucket': bucket_name, 'Key': key}
url = s3_client.generate_presigned_url('put_object',
Params=params,
ExpiresIn=3600)
it works.
But when put any other put_object parameter like ACL md5 etc it throws
params = {'Bucket': bucket_name, 'Key': key,
'ACL': 'public-read', 'ContentMD5': '1cx12....'}
url = s3_client.generate_presigned_url('put_object',
Params=params,
ExpiresIn=3600)
Error><Code>SignatureDoesNotMatch</Code><Message>
The request signature we calculated does not match the
signature you provided. Check your key and signing method
If trying put header like Content-MD5 in put request it throws Headers not signed.
My S3 client is like
s3 = boto3.client('s3',
region_name=app.config['AWS_REGION'],
aws_access_key_id=app.config['AWS_ACCESS_KEY_ID'],
config=Config(signature_version='s3v4'),
aws_secret_access_key=app.config['AWS_SECRET_ACCESS_KEY']
)
I am using boto3==1.4.1
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.
Hi thanks for your reply. Today i was trying with generate_presigned_post
s3_client = boto3.client('s3',
region_name=app.config['AWS_REGION'],
aws_access_key_id=app.config['AWS_ACCESS_KEY_ID'],
config=Config(signature_version='s3v4'),
aws_secret_access_key=app.config['AWS_SECRET_ACCESS_KEY']
)
p = s3_client.generate_presigned_post(Bucket=bucket_name,
Key=key,
Fields={
'acl': 'public-read'
}
)
url = p['url']
data = p['fields']
files = {'path': "YOYO"}
response = requests.post(url, json=data, data=open(file))
I am getting 412 response
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>PreconditionFailed</Code>
<Message>At least one of the pre-conditions you specified did not hold</Message>
<Condition>Bucket POST must be of the enclosure-type multipart/form-data</Condition>
<RequestId>E5D751C1E8E3A187</RequestId>
<HostId>LWL4KO3n7Xotvef4x+1bvAk6XeHWa0sSMWluHkUP1zyNPBbFyzFnCIWANmSshuYnlkbDL+AXir4=</HostId>
</Error>
When i was doing, what is written in boto3 doc
p = s3_client.generate_presigned_post(Bucket=bucket_name,
Key=key,
Fields={
'acl': 'public-read'
}
)
url = p['url']
data = p['fields']
files = {local_path: "YOYO"}
response = requests.post(url, data=data, files=files)
I am getting 400
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidArgument</Code>
<Message>POST requires exactly one file upload per request.</Message>
<ArgumentName>file</ArgumentName>
<ArgumentValue>0</ArgumentValue>
<RequestId>4122DAA6E127CC6E</RequestId>
<HostId>SRRp+j+298weagOqsfIEAzMpVoNKKh4u5tPJmf5DAa9WeDak3bs8Ne+Nq1NMX8hkOyLENFxrSVU=</HostId>
</Error>
Maybe that's not the correct way to use files (the requests docs isn't super clear on this point). See below for a working sample.
import boto3
import requests
s3 = boto3.client('s3')
parts = s3.generate_presigned_post(Bucket='foo', Key='bar')
response = requests.post(parts['url'], data=parts['fields'],
files={'file': open('some_filename.txt', 'rb')})
@JordonPhillips thanks a lot, it is working. I am posting the working example for future reference.
import boto3
import requests
parts = s3_client.generate_presigned_post(Bucket=bucket_name,
Key=key,
Fields={
'acl': 'public-read',
'Content-MD5': str(md5),
'Content-Type': 'binary/octet-stream'
},
Conditions=[
{"acl": "public-read"},
["starts-with", "$Content-Type", ""],
["starts-with", "$Content-MD5", ""]
]
)
url = parts['url']
data = parts['fields']
files = {'file': open(local_path, 'rb')} # the key supposed to be file may be
response = requests.post(url, data=data, files=files)
Closing the issue
It appears that the key used in the files argument dict must be 'file'.
Most helpful comment
@JordonPhillips thanks a lot, it is working. I am posting the working example for future reference.
Closing the issue