I've read several tutorials about how to upload files to Amazon S3 from Salesforce using Apex (like this tutorial), but none of them are working for me. Also I've read many questions in this page but I haven't found a solution.
Every time I send a PUT request to upload a file in S3, I'm getting an error message saying 'The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256' so I investigated how to solve it, and I found that using named credentials in SF I could provide a valid credential, so I followed this documentation about how to create a Named Credential for AWS Signature Version 4.
However, my problem is that, even thought I configured correctly the named credential with my key and secret for S3 (I checked it twice) I'm always getting an error in the response saying Access Denied and I'm unable to upload the file to S3
Here is the code I'm using. I create first a dummy xml file and then I try to upload it to S3.
public static void uploadToAmazonS3() {
Xmlstreamwriter xmlW = new Xmlstreamwriter();
xmlW.writeStartDocument('utf-8','1.0');
xmlW.writeStartElement(null,'SERVICE', null);
xmlW.writeAttribute(null,null,'version','1.0');
xmlW.writeStartElement(null,'CLIENT',null);
xmlW.writeAttribute(null,null,'email','[email protected]');
xmlW.writeStartElement(null,'BASIC_FIELDS',null);
xmlW.writeAttribute(null,null,'id','1');
xmlW.writeStartElement(null,'ADRESS_LINE_1',null);
xmlW.writeAttribute(null,null,'id','2');
xmlW.writeCharacters('4 rue de rocher');
xmlW.writeEndElement(); //Close ADRESS_LINE_1
xmlW.writeStartElement(null,'CITY',null);
xmlW.writeAttribute(null,null,'id','3');
xmlW.writeCharacters('Paris');
xmlW.writeEndElement(); //Close CITY
xmlW.writeEndElement(); //Close BASIC_FIELDS
xmlW.writeEndElement(); //Close CLIENT
xmlW.writeEndElement(); //Close SERVICE
xmlW.writeEndDocument(); //Close XML document
String xmlStringxmlRes = xmlW.getXmlString();
xmlW.close();
Blob xmlContentBlob = Blob.valueOf(xmlStringxmlRes);
String attachmentBody = EncodingUtil.base64Encode(xmlContentBlob);
String formattedDateString = Datetime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');
String key = 'xxxxx'; //AWS key
String secret = 'xxxxxxx'; //AWS Secret key
String bucketname = 'emdev-test1'; //AWS bucket name
String host = 's3.us-east-2.amazonaws.com';
String method = 'PUT';
String filename = 'Upload-Test-1';
HttpRequest req = new HttpRequest();
req.setMethod(method);
req.setEndpoint('callout:Test1Amazons3' + '/' + filename); //virtual hosted-style request
//req.setEndpoint('https://' + bucketname + '.' + host + '/' + filename);
req.setHeader('Host', bucketname + '.' + host);
req.setHeader('Content-Length', String.valueOf(attachmentBody.length()));
req.setHeader('Content-Encoding', 'UTF-8');
req.setHeader('Content-type', 'application/xml');
req.setHeader('Connection', 'keep-alive');
req.setHeader('Date', formattedDateString);
req.setHeader('ACL', 'public-read-write');
Blob xmlBlob = EncodingUtil.base64Decode(attachmentBody);
req.setBodyAsBlob(xmlBlob);
String stringToSign = 'PUT\n\n' + 'application/xml' + '\n' + formattedDateString + '\n' + '/' + bucketname + '/' + filename;
Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign), blob.valueof(secret)); //HMACSHA256
String signedKey = EncodingUtil.base64Encode(mac);
String authHeader = 'AWS' + ' ' + key + ':' + signedKey;
req.setHeader('Authorization', authHeader);
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug('>>>> The response');
System.debug(res);
System.debug('>>>> The body');
System.debug(res.getBody());
System.debug('>>>> Status code');
System.debug(res.getStatusCode());
System.debug('>>>> Finished method');
}
And I always get "Access Denied". Any help would be really appreciated, as I've spent so many hours trying to find a solution. Thankyou very much for your time
PD: I've also read this other question here but this question is different from mine since the error is different than mine,my error is "Access denied" when I'm using naming credentials with Amazon S3. However I've tried this solution also and it didn't work. Thanks.