Reputation: 41
I am trying to use the put Object copy functionality of s3 (s3 replaces the file) with user defined metadata in ColdFusion. I am using Joe Danziger's functions (https://gist.github.com/CFJSGeek/3f6f14ba86049af75361) to create the signature. However I keep getting the error that my signature does not match. Any ideas? Here's my code:
public function setMetaDataForObject(string bucket, string objectKey, struct metadata){
var dateTimeString = GetHTTPTimeString(now());
writedump(metadata);
var cs = "PUT\n\nimg/png\n#dateTimeString#\nx-amz-copy-source:/#arguments.bucket#/#arguments.objectKey#\nx-amz-metadata-directive:REPLACE\n";
for(key in arguments.metadata){
cs &= "#key#:#metadata[key]#\n";
}
cs &= "/#arguments.bucket#/#arguments.objectKey#";
writeoutput(cs);
var signature = createSignature(cs);
var httpReq = new http();
httpReq.setMethod("PUT");
httpReq.setUrl("http://#arguments.bucket#.s3.amazonaws.com/#arguments.objectKey#" );
//httpReq.setTimeout(timeout="300");
httpReq.addParam(type="header", name="Date", value="#dateTimeString#");
httpReq.addParam(type="header", name="Content-Type", value="img/png");
httpReq.addParam(type="header", name="x-amz-copy-source", value="/#arguments.bucket#/#arguments.objectKey#");
httpReq.addParam(type="header", name="x-amz-metadata-directive", value="REPLACE");
httpReq.addParam(type="header", name="Authorization", value="AWS #variables.accessKeyId#:#signature#");
for(var i in arguments.metadata){
httpReq.addParam(type="header", name="#i#", value="#arguments.metadata[i]#");
}
//httpReq.addParam(type="body", value="#fileS3#");
var result = httpReq.send().getPrefix(); writedump(result);
}
Joe Danziger's code (that i rewrote in script):
private binary function HMAC_SHA1(required string signKey, required string signMessage){
var jMsg = JavaCast("string",arguments.signMessage).getBytes("iso-8859-1");
var jKey = JavaCast("string",arguments.signKey).getBytes("iso-8859-1");
var key = createObject("java","javax.crypto.spec.SecretKeySpec");
var mac = createObject("java","javax.crypto.Mac");
key = key.init(jKey,"HmacSHA1");
mac = mac.getInstance(key.getAlgorithm());
mac.init(key);
mac.update(jMsg);
return mac.doFinal();
}
private string function createSignature(required string stringIn){
var fixedData = replace(arguments.stringIn,"\n","#chr(10)#","all");
var digest = HMAC_SHA1(variables.awsSecretKey, fixedData);
var signature = ToBase64("#digest#");
return signature;
}
Upvotes: 2
Views: 502
Reputation: 41
I solved this problem: the headers need to be sorted alphabetically! (when being passed in to the createSignature function.. it doesn't seem to be giving a problem with the actual http headers) here's my updated code:
public function setMetaDataForObject(required string bucket, required string objectKey, struct metadata, string contentType){
if(!isdefined("argumetns.contentType")){
var meta = getMetaDataForObject(arguments.bucket, arguments.objectKey);
arguments.contentType = meta['Content-type'];
}
var dateTimeString = GetHTTPTimeString(now());
var cs = "PUT\n\n#arguments.contentType#\n#dateTimeString#\nx-amz-copy-source:/#arguments.bucket#/#arguments.objectKey#\n";
if(isdefined("arguments.metadata")){
for(key in structSort(arguments.metadata)){
cs &= "#key#:#metadata[key]#\n";
}
}
cs &= "x-amz-metadata-directive:REPLACE\n/#arguments.bucket#/#arguments.objectKey#";
var signature = createSignature(cs);
var httpReq = new http();
httpReq.setMethod("PUT");
httpReq.setUrl("http://#arguments.bucket#.s3.amazonaws.com/#arguments.objectKey#" );
httpReq.addParam(type="header", name="Date", value="#dateTimeString#");
httpReq.addParam(type="header", name="Content-Type", value="img/png");
httpReq.addParam(type="header", name="x-amz-copy-source", value="/#arguments.bucket#/#arguments.objectKey#");
httpReq.addParam(type="header", name="x-amz-metadata-directive", value="REPLACE");
httpReq.addParam(type="header", name="Authorization", value="AWS #variables.accessKeyId#:#signature#");
if(isdefined("arguments.metadata")){
for(var i in arguments.metadata){
httpReq.addParam(type="header", name="#i#", value="#arguments.metadata[i]#");
}
}
var result = httpReq.send().getPrefix(); writedump(result);
}
Upvotes: 2