function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
sakshi Gandhi 8sakshi Gandhi 8 

Amazon Salesforce Integration

Hello,

I need to create folder under bucket on amazon s3 through REST webservice in salesforce .I am getting 503 as status code .Below is my REST class.Please do help

global with sharing class SalesForceAmazonWebservices{

 public void s3RestPut() { 
  
  String Date1 =  Datetime.now().formatGMT('EEE,   dd MMM yyyy HH:mm:ss z');
  String filename = 'test3';
  String bucketname = 'Bucket1';
  String Method = 'PUT';
  HttpRequest req = new HttpRequest();
  req.setMethod(method);

 
  
  req.setEndpoint('http://aws-us-west-2.amazon.com/s3/'+  bucketname + '/' + filename);
  req.setHeader('HOST','aws-us-west-2.amazon.com/s3/'); 
  req.setHeader('content-type', filename);
  req.setHeader('content-Encoding', 'base64');
  req.setHeader('Date',Date1);
 
 
  String stringToSign = 'PUT\n\n\n'+Date1+'\n/'+bucketname+'/'+filename + '/' ;  

  Blob mac = Crypto.generateMac('HMacSHA1', blob.valueof(stringtosign),blob.valueof('*******************'));

      String signature = EncodingUtil.base64Encode(mac);
   
        String authHeader = 'AWS'  + '**************' + ':' + signature  ;
        req.setHeader('Authorization',authHeader);  
        req.setBody(filename);
        Http http = new Http()
        HTTPResponse res = http.send(req);
        
    }
}
Best Answer chosen by sakshi Gandhi 8
Jason FlammangJason Flammang

Here is some updated sample code that I'm currently using

You'll get the 403(Forbidden) status code when there is something wrong with your signature.  For me it was the dateTime and I using my local time zone.

Hope this helps
//method to use the S3 webservice and save pdf file
    public void saveToS3(String binaryPDF,String docName,String bucketname,String method,String contentType,String region,String key,String secret){
        /*  Input Variable Explanations
        binaryPDF -- this is a base64 Encoded binary string representation of a PDF I get from a different web service
        docName --  any name you want to use as the saved document name
        bucketname --  the Amazon S3 bucket you are saving to
        method --  I currently only use PUT
        contentType --  I leave this blank and it seems to work fine
        region --  !!!Important, this needs to be the region that the S3 bucket is set to, for example '-us-west-2'
        key --  this is the key you generate in the AWS console under Identity & Access Management for the user account setup to access the S3 bucket
        secret --  this is the secret you generate during the same process
        */

        //setup variables
        String formattedDateString = Datetime.now().format('EEE, dd MMM yyyy HH:mm:ss z','America/Denver');    //this is needed for the PUT operation and the generation of the signature.  I use my local time zone.
        String filename;
        HttpRequest req = new HttpRequest();
        Http http = new Http();
        filename = 'TEST_BUCKET_FOLDER_1/TEST_SUBFOLDER_1/' +    //Include any folders and subfolders you are using in your S3 Bucket
            docName.replace(' ', '+') + '.pdf';   //this replaces any spaces in the desired document name with a Plus symbol '+', as the filename needs to be URL friendly
        
        req.setHeader('Content-Type', contentType);
        req.setMethod(method);
        req.setHeader('Host','s3' + region + '.amazonaws.com');  //path style
        req.setEndpoint('https://s3' + region + '.amazonaws.com' + '/'+ bucketname + '/' + filename);   //path style
        req.setHeader('Date', formattedDateString);
        req.setHeader('Authorization',createAuthHeader(method,contentType,filename,formattedDateString,bucketname,key,secret));
        
        if(binaryPDF != null && binaryPDF != ''){
            Blob pdfBlob = EncodingUtil.base64Decode(binaryPDF);
            req.setBodyAsBlob(pdfBlob);
            req.setHeader('Content-Length', string.valueOf(binaryPDF.length()));
            
            //Execute web service call
            try {
                HTTPResponse res = http.send(req);
                System.debug('MYDEBUG: ' + docName + ' RESPONSE STRING: ' + res.toString());
                System.debug('MYDEBUG: ' + docName + ' RESPONSE STATUS: '+res.getStatus());
                System.debug('MYDEBUG: ' + docName + ' STATUS_CODE:'+res.getStatusCode());
                
            } catch(System.CalloutException e) {
                system.debug('MYDEBUG: AWS Service Callout Exception on ' + docName + 'ERROR: ' + e.getMessage());
            }
        }
    }
    
    //create authorization header for Amazon S3 REST API
    public string createAuthHeader(String method,String contentType,String filename,String formattedDateString,String bucket,String key,String secret){
        string auth;
        String stringToSign = method+'\n\n'+contentType+'\n'+formattedDateString+'\n/'+bucket+'/'+filename;
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
        String sig = EncodingUtil.base64Encode(mac);
        auth = 'AWS' + ' ' + key + ':' + sig;
        return auth;
    }

All Answers

Andy BoettcherAndy Boettcher
503 is an failed authorization response.  Check your "authHeader" variable and ensure that you are constructing that right.
sakshi Gandhi 8sakshi Gandhi 8
@andy boettcher  Thank you Andy for your response .After trying and debugging I am getting below error 403 (Forbidden) and after 


debugging it is saying  
"SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method."

Please do help me to resolve this error
Andy BoettcherAndy Boettcher
That's a pretty common error with Amazon services - it's not a Salesforce thing.  You need to run through the Amazon documentation and make sure that you are encrypting your header information correctly.
Jason FlammangJason Flammang

Here is some updated sample code that I'm currently using

You'll get the 403(Forbidden) status code when there is something wrong with your signature.  For me it was the dateTime and I using my local time zone.

Hope this helps
//method to use the S3 webservice and save pdf file
    public void saveToS3(String binaryPDF,String docName,String bucketname,String method,String contentType,String region,String key,String secret){
        /*  Input Variable Explanations
        binaryPDF -- this is a base64 Encoded binary string representation of a PDF I get from a different web service
        docName --  any name you want to use as the saved document name
        bucketname --  the Amazon S3 bucket you are saving to
        method --  I currently only use PUT
        contentType --  I leave this blank and it seems to work fine
        region --  !!!Important, this needs to be the region that the S3 bucket is set to, for example '-us-west-2'
        key --  this is the key you generate in the AWS console under Identity & Access Management for the user account setup to access the S3 bucket
        secret --  this is the secret you generate during the same process
        */

        //setup variables
        String formattedDateString = Datetime.now().format('EEE, dd MMM yyyy HH:mm:ss z','America/Denver');    //this is needed for the PUT operation and the generation of the signature.  I use my local time zone.
        String filename;
        HttpRequest req = new HttpRequest();
        Http http = new Http();
        filename = 'TEST_BUCKET_FOLDER_1/TEST_SUBFOLDER_1/' +    //Include any folders and subfolders you are using in your S3 Bucket
            docName.replace(' ', '+') + '.pdf';   //this replaces any spaces in the desired document name with a Plus symbol '+', as the filename needs to be URL friendly
        
        req.setHeader('Content-Type', contentType);
        req.setMethod(method);
        req.setHeader('Host','s3' + region + '.amazonaws.com');  //path style
        req.setEndpoint('https://s3' + region + '.amazonaws.com' + '/'+ bucketname + '/' + filename);   //path style
        req.setHeader('Date', formattedDateString);
        req.setHeader('Authorization',createAuthHeader(method,contentType,filename,formattedDateString,bucketname,key,secret));
        
        if(binaryPDF != null && binaryPDF != ''){
            Blob pdfBlob = EncodingUtil.base64Decode(binaryPDF);
            req.setBodyAsBlob(pdfBlob);
            req.setHeader('Content-Length', string.valueOf(binaryPDF.length()));
            
            //Execute web service call
            try {
                HTTPResponse res = http.send(req);
                System.debug('MYDEBUG: ' + docName + ' RESPONSE STRING: ' + res.toString());
                System.debug('MYDEBUG: ' + docName + ' RESPONSE STATUS: '+res.getStatus());
                System.debug('MYDEBUG: ' + docName + ' STATUS_CODE:'+res.getStatusCode());
                
            } catch(System.CalloutException e) {
                system.debug('MYDEBUG: AWS Service Callout Exception on ' + docName + 'ERROR: ' + e.getMessage());
            }
        }
    }
    
    //create authorization header for Amazon S3 REST API
    public string createAuthHeader(String method,String contentType,String filename,String formattedDateString,String bucket,String key,String secret){
        string auth;
        String stringToSign = method+'\n\n'+contentType+'\n'+formattedDateString+'\n/'+bucket+'/'+filename;
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
        String sig = EncodingUtil.base64Encode(mac);
        auth = 'AWS' + ' ' + key + ':' + sig;
        return auth;
    }
This was selected as the best answer