We are trying to access S3 resources via Cloudfront inside a VF page in Salesforce.
The S3 bucket, folder & files are all marked private and the access is granted only via Cloudfront.
We already tried generating the Signed url using the approach discussed in this thread in SFSE and also this option in SF Dev Forum
With both the options, we are getting 403 AccessDenied errors.
here's the current code we have in place.
public static String GetCFsignedURL() {
//Private Key in RSA
String cloudfrontPrivateKey1 = '.....';
//Private Key in PKCS8
String cloudfrontPrivateKey2 = '....';
String keyPairId = '...';
String secret = '...';
Datetime dt = Datetime.now();
Long longTime = dt.getTime();
Long expiryLong = (longTime / 1000) + 3600;
String expiry = String.valueOf(expiryLong);
String strpolicy = '{"Statement": [{"Resource": "https://prefix.cloudfront.net/s3folder/s3File","Condition": {"DateLessThan": {"AWS:EpochTime": ' + expiry + '}}}]}';
String policyEnc = EncodingUtil.base64Encode(Blob.valueOf(strpolicy));
policyEnc = policyEnc.replace('+', '-').replace('=', '_').replace('/', '~');
//Blob mac = Crypto.Sign('RSA',Blob.valueOf(policyEnc), EncodingUtil.base64Decode(cloudfrontPrivateKey1));
Blob mac = Crypto.generateMac('hmacSHA1', Blob.valueOf(rPolicy), Blob.valueOf(cloudfrontPrivateKey1));
String policySign = EncodingUtil.base64Encode(mac);
String finalURL = 'https://prefix.cloudfront.net/s3folder/s3File?Expires=' + expiry + '&Signature=' + policySign + '&Key-Pair-Id=' + keyPairId;
return finalURL;
}
Note – When I generate the cloudfront signed url from a .NET or Java client using the same private keys & access key pair id, it perfectly works fine. Its failing only with the signed url generated in Salesforce.
if anyone got any luck with generating cloudfront signed url within apex, please share your expertise..
Best Answer
You may want to implement the string replacement code found in both of those answers you referenced. I've run into similar issues generating presigned URLs for S3 and learned the (very) hard way about URL escaping reserved characters in the policy. In your code, you may want to try something like this:
Other languages (eg., Python in my case or .NET/Java in your case) seem to do a better job with this type of URL generation, but I've spent countless hours trying to debug this stuff in Apex in the past. Hope that helps!
Edit: just to be clear, the reason this should help (if not solve the issue) is because you're generating a presigned URL in the end, and that URL has to be properly formatted. If your base64-encoded policy includes characters normally found in URIs/URLs (eg.,
+
,=
, or/
) it will fail.