I have a play application that needs to upload files to S3. We are developing in scala and using the Java AWS SDK.
I'm having trouble trying to upload files, I keep getting 403 SignatureDoesNotMatch when using presigned urls. The url is being genereated using AWS Java SDK by the following code:
def generatePresignedPutRequest(filename: String) = { val expiration = new java.util.Date(); var msec = expiration.getTime() + 1000 * 60 * 60; // Add 1 hour. expiration.setTime(msec); s3 match { case Some(s3) => s3.generatePresignedUrl(bucketname, filename, expiration, HttpMethod.PUT).toString case None => { Logger.warn("S3 is not availiable. Cannot generate PUT request.") "URL not availiable" } } }
For the frontend code we followed ioncannon article.
The js function that uploads the file (the same as the one used in the article)
function uploadToS3(file, url) { var xhr = createCORSRequest('PUT', url); if (!xhr) { setProgress(0, 'CORS not supported'); } else { xhr.onload = function() { if(xhr.status == 200) { setProgress(100, 'Upload completed.'); } else { setProgress(0, 'Upload error: ' + xhr.status); } }; xhr.onerror = function() { setProgress(0, 'XHR error.'); }; xhr.upload.onprogress = function(e) { if (e.lengthComputable) { var percentLoaded = Math.round((e.loaded / e.total) * 100); setProgress(percentLoaded, percentLoaded == 100 ? 'Finalizing.' : 'Uploading.'); } }; xhr.setRequestHeader('Content-Type', 'image/png'); xhr.setRequestHeader('x-amz-acl', 'authenticated-read'); xhr.send(file); } }
The server's response is
<?xml version="1.0" encoding="UTF-8"?> <Error><Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> <StringToSignBytes>50 55 bla bla bla...</StringToSignBytes> <RequestId>F7A8F1659DE5909C</RequestId> <HostId>q+r+2T5K6mWHLKTZw0R9/jm22LyIfZFBTY8GEDznfmJwRxvaVJwPiu/hzUfuJWbW</HostId> <StringToSign>PUT image/png 1387565829 x-amz-acl:authenticated-read /mybucketname/icons/f5430c16-32da-4315-837f-39a6cf9f47a1</StringToSign> <AWSAccessKeyId>myaccesskey</AWSAccessKeyId></Error>
I have configured CORS, double checked aws credentials and tried changing request headers. I always get the same result. Why is Amazon telling me that signatures dont match?
Doubt the OP still has a problem with this, but for anyone else who runs into this, here is the answer:
When making a signed request to S3, AWS checks to make sure that the signature exactly matches the HTTP Header information the browser sent. This is unfortunately required reading: http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
However in the code above this is not actually the case, the Javascript is sending:
xhr.setRequestHeader('Content-Type', 'image/png'); xhr.setRequestHeader('x-amz-acl', 'authenticated-read');
But in the Java/Scala, s3.generatePresignedUrl is being called without passing in either of them. So the resulting signature is actually telling S3 to reject anything with a Content-Type or x-ams-acl header set. Oops (I fell for it too).
I've seen browsers send Content-Types automatically, so even if they're not explicitly added to the header they could still be coming into S3. So the question is, how do we add Content-Type and x-amz-acl headers into the signature?
There are several overloaded generatePresignedUrl functions in the AWS SDK, but only one of them allows us to pass in anything else besides the bucket-name, filename, expiration-date and http-method.
The solution is:
Here's the proper function definition of GeneratePresignedUrlRequest to use:
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html#generatePresignedUrl(com.amazonaws.services.s3.model.GeneratePresignedUrlRequest)
The function's code on the AWS GitHub repo was also helpful for me to see how to code up the solution. Hope this helps.
I faced a similar issue and setting the config signatureVersion: 'v4'
helped solve it in my case -
In JavaScript:
var s3 = new AWS.S3({ signatureVersion: 'v4' });
Adapted from https://github.com/aws/aws-sdk-js/issues/902#issuecomment-184872976
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With