Skip to content

Instantly share code, notes, and snippets.

@dcinzona
Created May 1, 2018 18:38
Show Gist options
  • Save dcinzona/ad6d5aab61008694135dcf8255f1b873 to your computer and use it in GitHub Desktop.
Save dcinzona/ad6d5aab61008694135dcf8255f1b873 to your computer and use it in GitHub Desktop.
Salesforce Apex AWS S3 Signature Helper class
/**
* Created by gtandeciarz on 12/14/16.
*/
public class AWS_Helper {
public string secret { get; set; }
public string key { get; set; }
public string bucket {get;set;}
public String endpoint_x = 'https://s3.amazonaws.com/';
public Integer version = 2;
public static AWS_Setting__c settings;
static {
settings = AWS_Setting__c.getInstance('CaseAttachments');
}
public AWS_Helper() {
this.secret = AWS_Helper.settings.Access_Secret__c;
this.key = AWS_Helper.settings.Access_Key__c;
this.bucket = AWS_Helper.settings.Bucket__c;
}
public AWS_Helper(Integer versionInt) {
this.secret = AWS_Helper.settings.Access_Secret__c;
this.key = AWS_Helper.settings.Access_Key__c;
this.bucket = AWS_Helper.settings.Bucket__c;
this.version = versionInt;
}
public Blob createCanonicalRequest(String method, String queryString, Map<String, String> headers, String payload) {
String canonicalRequest = method + '\n';
canonicalRequest += '/' + '\n';
canonicalRequest += queryString + '\n';
List<String> headersList = new List<String>(headers.keySet());
headersList.sort();
for (String header : headersList) {
String headerContent = header.toLowerCase() + ':' + headers.get(header).trim();
canonicalRequest += headerContent + '\n';
}
for (String header : headersList) {
canonicalRequest += header.toLowerCase() + ';';
}
canonicalRequest = canonicalRequest.removeEnd(';');
canonicalRequest += '\n';
canonicalRequest += EncodingUtil.convertToHex(Crypto.generateDigest('SHA256', Blob.valueOf(payload))).toLowerCase();
return Crypto.generateDigest('SHA256', Blob.valueOf(canonicalRequest));
}
public String getStringToSignV4(Blob canonicalRequest, Datetime requestdate, String region, String service) {
String stringToSign = 'AWS4-HMAC-SHA256' + '\n';
String formatedDate = requestdate.formatGmt('yyyyMMdd') + 'T' + requestdate.formatGmt('hhmmss') + 'Z';
stringToSign += formatedDate + '\n';
stringToSign += requestdate.formatGmt('yyyyMMdd') + '/' + region + '/' + service + '/aws4_request\n';
//stringToSign += String.valueOf(canonicalRequest);
// stringToSign += EncodingUtil.base64Encode(canonicalRequest); COMMENTED OUT THIS LINE AND REPLACED WITH THE ONE BELOW
stringToSign += EncodingUtil.convertToHex(Crypto.generateDigest('SHA-256', canonicalRequest));
return stringToSign;
}
public String signatureV4(String secret, String today, String region, String service, String stringToSign) {
Blob privateKey = Crypto.generateMac('HmacSHA256', Crypto.generateMac('HmacSHA256', Crypto.generateMac('HmacSHA256', Crypto.generateMac('HmacSHA256',
Blob.valueOf(today), Blob.valueOf('AWS4' + secret)),
Blob.valueOf(region)),
Blob.valueOf(service)),
Blob.valueOf('aws4_request'));
return EncodingUtil.convertToHex(Crypto.generateMac('HmacSHA256', Blob.valueOf(stringToSign), privateKey));
}
public static string GetSigningSignatureV2(string stringToSign, string key){
Blob mac = Crypto.generateMac('HMACSHA1', blob.valueOf(stringToSign), blob.valueof(key));
String signed = EncodingUtil.base64Encode(mac);
return signed;
}
public String GetAuthHeaderStringV2(String stringToSign){
return 'AWS' + ' ' + this.key + ':' + AWS_Helper.GetSigningSignatureV2(stringToSign, this.secret);
}
public HttpRequest generateHttpRequest(Attachment a, String fileName){
return this.generateHttpRequest(a.Name, a.contentType,a.Body,fileName);
}
public HttpRequest generateHttpRequest(String attachmentName, string attachmentContentType, Blob body, String fileName){
string extension = '.' + attachmentName.substringAfterLast('.');
String contentType = attachmentContentType == null ? 'binary/octet-stream' : attachmentContentType;
System.debug('extension: ' + extension);
System.debug('Filename: ' + fileName);
String attachmentBody = EncodingUtil.base64Encode(body);
String formattedDateString = DateTime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');// + '+0000';
String bucketname = this.bucket;//you can write the bucket name where files should be uploaded
String host = 's3.amazonaws.com';//aws server base url'https://s3.amazonaws.com/'+bucketName+'/'+uploadedFilename
String method = 'PUT';
String endpointUrl = 'https://' + host + '/' + bucketname + '/' + filename;
//endpointUrl = 'https://' + bucketname + '.' + host + '/' + filename;
HttpRequest req = new HttpRequest();
req.setMethod(method);
req.setEndpoint(endpointUrl);
//host = bucketname + '.' + host;
//req.setHeader('Host', host);
req.setHeader('Content-Length', String.valueOf(attachmentBody.length()));
req.setHeader('Content-Type', contentType);
req.setHeader('Connection', 'keep-alive');
req.setHeader('Date', formattedDateString);
req.setHeader('x-amz-server-side-encryption', 'AES256');
req.setHeader('ACL', 'public-read');
Blob blobBody = EncodingUtil.base64Decode(attachmentBody);
req.setBodyAsBlob(blobBody);
String stringToSign = method+'\n\n'
+ contentType + '\n'
+ formattedDateString + '\n'
+ 'x-amz-server-side-encryption:AES256\n'
+ '/' + bucketname
+ '/'
+ filename;
System.debug(stringToSign);
System.debug('key: ' + this.key);
System.debug('secret: ' + this.secret);
req.setHeader('Authorization', GetAuthHeaderStringV2(stringToSign));
return req;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment