You need to sign in to do that
Don't have an account?
Upload binary stream to Amazon S3 using REST API PUT operation
I have a need to upload binary stream PDF files to Amazon S3. I've seen the sample code available to use the REST API with the POST operation on visualforce page, however, I need to upload the file via APEX without user involvment, as I'm retrieiving the files from another database via their SOAP API.
I'm trying to do this using the PUT operation, but I don't think I'm doing the authentication correctly as I'm getting a 403 Forbidden response.
Any ideas?
I'm trying to do this using the PUT operation, but I don't think I'm doing the authentication correctly as I'm getting a 403 Forbidden response.
Any ideas?
public void uploadPDF(String binaryPdfString, String key, String secret){ String Date = Datetime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z'); String bucketname = 'BucketName'; String method = 'PUT'; String filename = 'FileName'; HttpRequest req = new HttpRequest(); req.setMethod(method); req.setHeader('Host','s3-us-west-2.amazonaws.com'); req.setEndpoint('https://s3-us-west-2.amazonaws.com' + '/'+ bucketname + '/' + filename); req.setHeader('Content-Length', string.valueOf(binaryPdfString.length())); req.setHeader('Content-Encoding', 'base64'); req.setHeader('Content-Type', 'pdf'); req.setHeader('Date', Date); //get signature string String stringToSign = 'PUT\n\n\n'+formattedDateString+'\n\n/'+bucketname+'/'+filename; String encodedStringToSign = EncodingUtil.urlEncode(stringToSign,'UTF-8'); String signed = createSignature(encodedStringToSign,secret); String authHeader = 'AWS' + ' ' + key + ':' + signed; req.setHeader('Authorization',authHeader); req.setBody(binaryPdfString); Http http = new Http(); try { //Execute web service call HTTPResponse res = http.send(req); System.debug('RESPONSE STRING: ' + res.toString()); System.debug('RESPONSE STATUS: '+res.getStatus()); System.debug('STATUS_CODE: '+res.getStatusCode()); } catch(System.CalloutException e) { system.debug('AWS Service Callout Exception: ' + e.getMessage()); } } public string createSignature(string canonicalBuffer,String secret){ string sig; Blob mac = Crypto.generateMac('HMacSHA1', blob.valueof(canonicalBuffer),blob.valueof(secret)); sig = EncodingUtil.base64Encode(mac); return sig; }
turns out my signing string didn't need to be UTF-8 encoded (see old code "String encodedStringToSign = EncodingUtil.urlEncode(stringToSign,'UTF-8');" )
Amazon's doucmentation mentions "The string to sign (verb, headers, resource) must be UTF-8 encoded", however I removed this piece and just ran my createSignature class using stringToSign (not UTF-8 encoded) and it worked!!
Also, it turns out that you can decode the binary stream and use the decoded Blob as the body of the response. Otherwise, Amazon just displays the binary stream text on screen.
Here is my final code
Hope this helps someone else!
All Answers
turns out my signing string didn't need to be UTF-8 encoded (see old code "String encodedStringToSign = EncodingUtil.urlEncode(stringToSign,'UTF-8');" )
Amazon's doucmentation mentions "The string to sign (verb, headers, resource) must be UTF-8 encoded", however I removed this piece and just ran my createSignature class using stringToSign (not UTF-8 encoded) and it worked!!
Also, it turns out that you can decode the binary stream and use the decoded Blob as the body of the response. Otherwise, Amazon just displays the binary stream text on screen.
Here is my final code
Hope this helps someone else!
You'll get the 403(Forbidden) status code when there is something wrong with your signature. For me it was the dateTime and use my local time zone.
Hope this helps
i have done this successfully. i want to upload multiple attachments on s3 bucket almost at one time i need to transfer 25 to 30 attachments. how i can do this ? currently i hit on my apex through scheduler and soap connection with sales force and get attachments from sf and upload it on s3. in one time it upload only 4 or 5 attachments. how i can upload multiple attachments on s3 at a time ?
Your early response will be appreciated.
Thanks
umer
I know there are limits as to the number of callouts that can be made duing a batch process, so you'll want to make sure your batch size keeps you within those limits.
You'll also want to make sure you specify Database.AllowCallouts when setting up your batch APEX class otherwise you'll get an error.
I currently use a batch APEX class to make callouts to a 3rd party SOAP API that only allows for one record to be retrieved at a time. Using the Batch processing I can update thousands of records a day. Hope this helps.
Attach file related to any Salesforce object on Amazon.
5 GB free storage for one year.
Multiple file uplaod.
No file size limit for upload.
File access control capabiliy.
Track file downloads by users.
File exlorer capability.
https://appexchange.salesforce.com/listingDetail?listingId=a0N3000000CW1OXEA1
Here is our email address. Let us know if you have any query.
support@neiloncloud.com
Thanks.
I think you just have to re-arrange the stringToSign so that the "x-amz-acl" is AFTER the formattedDateString.
Yours: Corrected:
And just for anyone who cares. If you want your files to be stored in the cheaper S3 storage (Infrequent Access) and with public read-only access you would do this...
Change this To this:
And in the createAuthHeader method, change this:
to this:
(Refactor as desired)
Hi Jason,
Hey Jason,
Hi have to do a get request. I copied your code and made some changes. I need to get all the files from a buket.
I am getting Status=Bad Request, StatusCode=400. Please help me with this. I am posting my code below.
Thanks,
Manohar
I have tried to uploade a file to s3 bucket using your code but I face 403 error. I tried with my local time as well but no luck. Can you please help me out in this?
Thanks,
Raji M
Greetings. This is a massive help!! to anyone attempting S3 integration first hand. I wish I had this URL when I needed to create the integration!! :)
Some key points worth highlighting:
- Prefer NamedCredential with AWS Signature v4.0 as one need not then expose the keys in the code. Also, authentication gets taken care from the NamedCredential (less code)
- The FileName needs to be compatible to be sent over HTTPS. Prefer to remove any extra spaces (optional) and URLEncode it. This sometimes can cause issues in the signature check
@Raj - [2] may be of use for you as well.If there is anything amiss or incorrect; please be happy to correct me.
Cheers!
Prashant Menon
Here is a PUT request using Signature Version 4 If anyone need it:
I am trying to authenticate using the iam role.
Here i dont have accesskey and secretkey. So Please post me with your code snippet as to how to use the iam role to dynamically generate the key and secret using assume role.
Also please provide the preconditions .
Thanks
sahana
Hi All,
How to upload large files like morethan 2MB file, If I am uploading large files(morethan 1MB or 2MB), I am getting heap size memory is exceded error.
If anyone has any work around, please help me on this issue.
Thanks,
Venkat.