AWS S3 delete multiple files: signature does not match the signature you provided

0

I'm trying to use an Apex Class in Salesforce to remove multiple files from any specified S3 bucket, but at the moment of sending the request, I recieve the following response:

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

I tried testing a multiple file delete in Postman using the same information (access key and secret key) that I'm using on my class and it works. I'm creating the canonical request based on another class that uploads files, but I'm not sure how the '?delete' instruction should be included on it, if either on the URL for the request or in the Query string for the canonical. And since the request needs the body to be an XML with the file names, I'm alsonot sure if I'm doing the right thing creating a DOM.Document variable and then converting it into a string to finally add it as a blob to be used as a payload.

I've been using the documentation provided by Amazon as a reference too.

String accessKey = 'redacted';
String secretKey = 'redacted';

final String ALGORITHM = 'AWS4-HMAC-SHA256';
final String SERVICE = 's3';
final String AWS_DOMAIN = 's3.amazonaws.com';
final String DEFAULT_REGION = 'us-east-1';

String s3BucketName = 'redacted';

Datetime dt = Datetime.now();
String currentDate = dt.formatGMT('yyyyMMdd');
String isoTimeStamp = dt.formatGMT('yyyyMMdd\'T\'HHmmss\'Z\'');

String scope = currentDate + '/' + DEFAULT_REGION + '/' + SERVICE + '/aws4_request';

//DOM.Document requestBody = xmlBody(filesToRemove);
//String xmlToString = requestBody.toXmlString();
//Blob decodedContent = Blob.valueOf(xmlToString);

String url = 'https://' + s3BucketName + '.' + AWS_DOMAIN + '/?delete';

Blob payload = Blob.valueOf('');
String payloadHash = EncodingUtil.convertToHex(Crypto.generateDigest('SHA-256', payload));

String canonicalRequest = 'POST\n' +
            + '/' + '\n'
            + '?delete' + '\n'  
            + 'host:'+s3BucketName +'.' + AWS_DOMAIN + '\n'
            + 'x-amz-date:' + isoTimeStamp + '\n' + '\n' 
            + 'host;x-amz-date' + '\n' 
            + payloadHash;

String stringToSign = ALGORITHM + '\n' +  isoTimeStamp + '\n' +  scope + '\n' + 
            EncodingUtil.convertToHex(Crypto.generateDigest('SHA-256', Blob.valueOf(canonicalRequest)));

Blob dateKey =  Crypto.generateMac('hmacSHA256',Blob.valueOf(currentDate),Blob.valueOf('AWS4'+secretKey));
Blob dateRegionKey = Crypto.generateMac('hmacSHA256',Blob.valueOf(DEFAULT_REGION),dateKey);
Blob dateRegionServiceKey = Crypto.generateMac('hmacSHA256',Blob.valueOf(SERVICE),dateRegionKey);
Blob signingKey = Crypto.generateMac('hmacSHA256',Blob.valueOf('aws4_request'),dateRegionServiceKey);
 
string calculatedSignature = EncodingUtil.convertToHex(Crypto.generateMac('HMACSHA256', blob.valueof(stringToSign), signingKey));
        
String authorizationHeader = ALGORITHM + ' ' 
                + 'Credential=' + accessKey + '/' + scope + ', '
                + 'SignedHeaders=content-md5;host;x-amz-content-sha256;x-amz-date' + ', '
                + 'Signature=' + calculatedSignature;

Http http = new Http();
HttpRequest req = new HttpRequest();
req.setMethod('POST');
        
req.setHeader('Authorization', authorizationHeader);
req.setHeader('x-amz-date', isoTimeStamp);
req.setHeader('X-Amz-Content-SHA256', payloadHash);
req.setHeader('Content-Type','application/xml');
req.setEndpoint(url);

HttpResponse resp = http.send(req);
System.debug('Response: '+resp.getBody());
asked a year ago160 views
No Answers

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions