Ok, this is driving me nuts.
I'm trying to create a simple AWS S3 client that would allow for basic interaction with S3, but it seems I'm doing something wrong and can't figure out what it is. It might be blatently obvious, but I'm not seeing it.
My keys are correct and have been tested - no trailing whitespace etc.
The issue seems to be with the signature, it keeps getting the 'the request signature we calculated does not match the signature you provided. Check your key and signing method' error from Amazon's REST API. I've create various categories that add the base64, HMAC SHA1 generation functionality and I've also looked through various online examples, but no success so far.
The reason for not using the library provided by Amazon is because it's aimed at Cocoa Touch and I don't want to hack around to make it work on Cocoa.
You can grab a copy of all the files/code here: https://www.dropbox.com/s/8ts9q71dz3uopxp/S3Lite.zip
I am however following Amazon's documentation around authentication and to my simple mind, everything is being done correctly.
Here's how I'm generating the signature:
-(NSString *)signRequest:(NSURLRequest *)request {
NSMutableString *sig = [[NSMutableString alloc] init];
// Request Method
[sig appendFormat:@"%@\n", [request HTTPMethod]];
// Content MD5
[sig appendFormat:@"%@\n", [[request HTTPBody] MD5String]];
// Content Type
[sig appendFormat:@"%@\n", [request valueForHTTPHeaderField:@"Content-Type"]];
// Date
[sig appendFormat:@"%@\n", [request valueForHTTPHeaderField:@"Date"]];
// Canonicalized Headers
[sig appendFormat:@"%@\n", @""]; // Empty for now
// Canonicalized Resource
[sig appendFormat:@"%@", [NSString stringWithFormat:@"/%@%@", _bucket, request.URL.path]];
NSString *encodedString = [[[sig dataUsingEncoding:NSUTF8StringEncoding] hmacSHA1SignatureWithKey:_secretKey] base64String];
return [[NSString alloc] initWithFormat:@"AWS %@:%@", _accessKey, encodedString];
}
Here's how you go about working with it to attempt to perform a simple PUT request.
#import "S3Lite.h"
S3Lite *aws = [[S3Lite alloc] initWithAccessKey:@"<access key>"
secretKey:@"<secret key>"
bucketName:@"<bucket name>"
region:kAmazonS3EUWest1Region
useSSL:NO];
NSData *file = [[NSData alloc] initWithContentsOfFile:@"<path to a file>"];
[aws putObjectWithData:file inPath:@"aRandomFile.png" withContentType:nil];
Any help in the right direction would be greatly appreciated.
S
Even if you aren't able to use the AWS SDK for iOS directly, it is open source, and you might get some ideas from examining the request signing code here:
https://github.com/aws/aws-sdk-ios/blob/master/AWSCore/Authentication/AWSSignature.m
You need to make sure you include empty values in that string when the corresponding header is missing from the request (e.g. Content-MD5
is optional for PUT requests and meaningless for GET requests - you should only include its value in the string you're signing if your request includes that header in the API call to S3).
At the moment I am developing a S3 Client Framework based on AFNetworking 1.0 (due to compatibility with older operating systems). The framework itself is still in development but all the request signing methods for AWS4-HMAC-SHA256 are already implemented and working. You can find the framework on github: https://github.com/StudioIstanbul/SIAFAWSClient
Feel free to fork it and implement your functions so we can work on it together. Currently all basic S3 requests are implemented.
Of course you can also just copy my -(NSString*)AuthorizationHeaderStringForRequest:(NSMutableURLRequest*)request function to your own code. The AWS documentation on this is not very good at the moment as it lacks some steps in creating the signing keys.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With