Skip to main content
Jason Flammang ha fatto una domanda in #Integration
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?

 

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;

}

 
15 risposte
  1. 12 giu 2015, 22:13
    well I guess I should have waited a bit longer to post this question...haha

    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!

    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 signed = createSignature(stringToSign,secret);

    String authHeader = 'AWS' + ' ' + key + ':' + signed;

    req.setHeader('Authorization',authHeader);

    Blob PDF = EncodingUtil.base64Decode(binaryPdfString);

    req.setBodyAsBlob(PDF);

    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;

    }

     
0/9000