First task for my Amazon move is getting data assets (non-code-managed files) over to S3. I have a variety of types of data assets that need to move and have references updated, most of which require authentication. To make that easier, I wrote a little UDF to take care of building urls with authentication credentials in there.
<cffunction name="s3Url" output="false" returntype="string">
<cfargument name="awsKey" type="string" required="true" />
<cfargument name="awsSecret" type="string" required="true" />
<cfargument name="bucket" type="string" required="true" />
<cfargument name="objectKey" type="string" required="true" />
<cfargument name="requestType" type="string" default="vhost"
hint="Must be one of 'regular', 'ssl', 'vhost', or 'cname'. 'Vhost' and 'cname' are only valid if your bucket name conforms to the S3 virtual host conventions, and cname requires a CNAME record configured in your DNS." />
<cfargument name="timeout" type="numeric" default="900"
hint="The number of seconds the URL is good for. Defaults to 900 (15 minutes)." />
<cfscript>
var expires = "";
var stringToSign = "";
var algo = "HmacSHA1";
var signingKey = "";
var mac = "";
var signature = "";
var destUrl = "";
expires = int(getTickCount() / 1000) + timeout;
stringToSign = "GET" & chr(10)
& chr(10)
& chr(10)
& expires & chr(10)
& "/#bucket#/#objectKey#";
signingKey = createObject("java", "javax.crypto.spec.SecretKeySpec").init(awsSecret.getBytes(), algo);
mac = createObject("java", "javax.crypto.Mac").getInstance(algo);
mac.init(signingKey);
signature = toBase64(mac.doFinal(stringToSign.getBytes()));
if (requestType EQ "ssl" OR requestType EQ "regular") {
destUrl = "http" & iif(requestType EQ "ssl", de("s"), de("")) & "://s3.amazonaws.com/#bucket#/#objectKey#?AWSAccessKeyId=#awsKey#&Signature=#urlEncodedFormat(signature)#&Expires=#expires#";
} else if (requestType EQ "cname") {
destUrl = "http://#bucket#/#objectKey#?AWSAccessKeyId=#awsKey#&Signature=#urlEncodedFormat(signature)#&Expires=#expires#";
} else { // vhost
destUrl = "http://#bucket#.s3.amazonaws.com/#objectKey#?AWSAccessKeyId=#awsKey#&Signature=#urlEncodedFormat(signature)#&Expires=#expires#";
}
return destUrl;
</cfscript>
</cffunction>
To use it, do something like this:
s3Url(aws_key, aws_secret, "s3.barneyb.com", "test.txt", 'cname');
That will generate a request to the file "test.txt" in the "s3.barneyb.com" bucket, using a CNAME-style URL. Obviously you'll have to know my AWS key and secret for it to work, and I'm not telling, but substitute your own values. You can use regular (bucket name in the request), vhost (bucket name in an S3 subdomain), cname (a vanity CNAME pointing at S3), or ssl (regular over HTTPS) for the 5th type parameter to control the style of URL generated.
Edit: here's a link to the project page.
OK, that's so sweet. Worked first try.
R.,
Glad it worked for you.