• Save
July 11 Weekly Code Drop Part 1 of 3 Creating an S3 library
Upcoming SlideShare
Loading in...5

July 11 Weekly Code Drop Part 1 of 3 Creating an S3 library



This is part one of a three part series on creating an S3 LIbrary for CoCoa touch. There will be a follow on slide as well that covers using the library to store audio files gathered from the ...

This is part one of a three part series on creating an S3 LIbrary for CoCoa touch. There will be a follow on slide as well that covers using the library to store audio files gathered from the iPhone/iPod touch.



Total Views
Views on SlideShare
Embed Views



1 Embed 4

http://www.slideshare.net 4



Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • Guys,

    This is working fine now! A very special thanks to Amit at Slideshare, more to come this weekend! The slideshare response was great, parts 2 and 3 will be posted this weekend.

    Hope all is well,
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

July 11 Weekly Code Drop Part 1 of 3 Creating an S3 library July 11 Weekly Code Drop Part 1 of 3 Creating an S3 library Presentation Transcript

  • Weekly Code Drop: Connecting to Amazon S3 Part 1 of 3 Formulating the S3 Request Jason Hayes Christensen jasonc411.com July 11 Weekly Code Drop
  • ● Amazon S3 is a cloud-storage technology from Amazon Web Services, LLC. ● Cloud storage can help overcome the storage limitations of mobile architectures. ● There is a cost to using S3, so the applications that use S3 to augment storage should have a business model that accounts for these costs. ● Pricing Information: http://aws.amazon.com/s3/#pricing July 11 Weekly Code Drop
  • ● Detailed S3 documentation can be accessed at: http://developer.amazonwebservices.com/connect/entry.jspaexternalID=123&categoryID=48 ● We are not using any of the existing S3 libs. ● This is a 4-part set of presentations that show how to develop for S3 from the ground up. ● The focus of this particular presentation is how to augment the headers of the HTTP REST request for authentication in virtual hosted mode. – Using NSURL and NSMutableURLRequest. July 11 Weekly Code Drop
  • ● First, we will be using the ehmacauth functionality from the July 4 code drop. – Note that a memory leak was fixed and the download site is updated. ● We create the “StringToSign” in this example. ● The “StringToSign” is defined on page 13 of the S3 Developers Guide 20060301 as: StringToSign = HTTP-Verb + "n" + Content-MD5 + "n" + Content-Type + "n" + Date + "n" + CanonicalizedAmzHeaders + CanonicalizedResource; July 11 Weekly Code Drop
  • ● Remember, we are using virtual hosted mode, this means that we address a bucket as: <bucketName>.s3.amazonaws.com ● The “resource” is the file name, it is specified as the path on the server when using virtual hosted mode: mybucket.s3.amazonaws.com/myresource.wav ● This model is nice because we do not have to determine what part of the file path is the bucket vs. the resource. July 11 Weekly Code Drop
  • ● Let's define a new class that will modify the headers of the outbound URL Request. ● This class adds S3 headers to an existing NSMutableURLRequest. ● This class is named S3HTTPRequestHeaders. ● The one initializer for this class is: - (id)initForBucket:(NSString*) bucket andResource:(NSString*) resource; ● To avoid any specific coupling, the bucket and resource names are broken out. July 11 Weekly Code Drop
  • ● This initializer simply sets up the member variables, including the start of the auth token: - (id) initForBucket:(NSString*) bucket andResource:(NSString*) resource { _bucket = bucket; _resource = resource; _authToken = [NSString stringWithFormat:@"AWS %@:", kPublicKey]; _amzDate = NO; return self; } July 11 Weekly Code Drop
  • ● Dates are key to the request process. ● First of all, a request's date can differ by no more than 15 minutes from the time it is received by the Amazon servers. ● Second, if the date in the StringToSign is different than the date Amazon receives in the request header it will not authenticate. ● Watch for issues that affect the date header; for instance some proxies can modify Date header slightly. – In this case use X-Amz-Date header. July 11 Weekly Code Drop
  • ● Date header formatting must meet the RFC 1123 standard( http://ietf.org/rfc/rfc1123.txt ) ● To do this we use NSDateFormatter. – This allows us to both read and stream string representations of the Date header. - (NSString*)currentRFC1123DateTime:(NSDate*) date { NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [dateFormatter setFormatterBehavior: NSDateFormatterBehavior10_4]; [dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss ZZ"]; [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; return [dateFormatter stringFromDate:date]; } July 11 Weekly Code Drop
  • ● Modifying a header is simple, here we update the HTTP Date header by calling: – NSMutableURLRequest setValue: forHTTPHeaderField:. - (void) appendDateHeader:(NSMutableURLRequest*) request date:(NSDate*) date useAmzDate:(Boolean) amzDate; { [request setValue:[self currentRFC1123DateTime:date] forHTTPHeaderField:@"Date"]; if(amzDate){ [request setValue:[self currentRFC1123DateTime:date] forHTTPHeaderField:@"X-Amz-Date"]; _amzDate = amzDate;} } July 11 Weekly Code Drop
  • ● Since we are using virtualized host mode, we have to modify the host header, this again is very simple using the NSHttpURLRequest setValue:forHTTPHeaderField:. - (void) appendHostHeader:(NSMutableURLRequest*) request { [request setValue:[NSString stringWithFormat:@"%@.%@", _bucket, kHost] forHTTPHeaderField:@"Host"]; } July 11 Weekly Code Drop
  • ● Next we will add the canonicalizedResource. ● Directly from page 14 of the developers guide: 1 Start with the empty string (""). 2 If the request specif es a bucket using the HTTP Host header (virtual hosted- i style), append the bucket name preceded by a "/" (e.g., "/bucketname"). For path-style requests and requests that don't address a bucket, do nothing. For more information on virtual hosted-style requests, see Virtual Hosting of Buckets (p. 25). 3 Append the path part of the un-decoded HTTP Request-URI, up-to but not including the query string. 4 If the request addresses a sub-resource, like ?location, ?acl, or ? torrent, append the sub-resource including question mark. July 11 Weekly Code Drop
  • ● Because we break out the resource and bucket separately in the initializer for S3HTTPRequestHeaders, this ends up being very simple. - (NSString*)canonicalizedResource:(NSURLRequest*) request { NSMutableString* canonResource = [[[NSMutableString alloc] initWithString:@"/"] autorelease]; if(_bucket != nil) [canonResource appendFormat:@"%@", _bucket]; if(_resource != nil) [canonResource appendFormat:@"%@", _resource]; return canonResource; } July 11 Weekly Code Drop
  • ● The most obscure part of the “StringToSign” for new devs are the canonicalizedAmzHeaders. ● These headers all have the prefix X-Amz- ● They are used to communicate application specific information in the REST request. ● One caveat: multiple headers of the same name are not supported by NSHTTPUrlRequest. ● Therefore our demo code just concatenates the headers after sorting them. July 11 Weekly Code Drop
  • ● Directly from pp 14-15 of the Developers Guide: 1 Convert each HTTP header name to lower-case. For example, 'X-Amz-Date' becomes 'x- amz-date'. 2 Sort the collection of headers lexicographically by header name. 3 Combine header f elds with the same name into one "header-name:comma- i separated-value-list" pair as prescribed by RFC 2616, section 4.2, without any white-space between values. For example, the two metadata headers 'x-amz-meta-username: fred' and 'x- amz-meta-username: barney' would be combined into the single header 'x-amz-meta- username: fred,barney'. 4 "Un-fold" long headers that span multiple lines (as allowed by RFC 2616, section 4.2) by replacing the folding white-space (including new-line) by a single space. July 11 Weekly Code Drop
  • ● CanonicalizedAmzHeaders Process Cont. 5 Trim any white-space around the colon in the header. For example, the header 'x-amz- meta-username: fred,barney' would become 'x- amz-meta-username:fred,barney' 6 Finally, append a new-line (U+000A) to each canonicalized header in the resulting list. Construct the CanonicalizedResource element by concatenating all headers in this list into a single string ● Since our utility class NSHTTPUrlRequest does not support multiple entries of the same header, and removes whitespace, we have simplified the code for the demo. July 11 Weekly Code Drop
  • ● First, we have to sort the headers – to do this we grab the array of keys and sort them using NSString's caseInsensitiveCompare. - (NSString*)canonicalizedAmzHeaders:(NSURLRequest*) request { NSMutableString* ret = [[[NSMutableString alloc] init] autorelease]; NSDictionary* dict = [request allHTTPHeaderFields]; NSArray* keys = [[dict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:) ]; July 11 Weekly Code Drop
  • ● Next we iterate over the array of keys looking for keys with the header X-Amz ● When we find one we append it and its value to the return string. for(id header in keys) { NSString* str = [(NSString*)header lowercaseString]; if([str hasPrefix:@"x-amz"]) [ret appendFormat:@"%@:%@n", str, (NSString*)[dict objectForKey:header]]; } return ret; } July 11 Weekly Code Drop
  • ● Finally we have all the information we need for the StringToSign so we add the authorization header. ● We sign the string with our private key, then pass the public key, and the signature to S3 in the Authorization header. ● The string has the format: “AWS <PublicKey>:<Signature>” July 11 Weekly Code Drop
  • ● OK, a final look at setting up the StringToSign ● Let's setup a mutable string and grab the standard headers that make up the string. NSMutableString* s2s = [[[NSMutableString alloc] initWithFormat:@"%@n", [request HTTPMethod]] autorelease]; NSString* contentMD5 = [request valueForHTTPHeaderField:@"content-md5"]; NSString* contentType = [request valueForHTTPHeaderField:@"content-type"]; NSString* date = [request valueForHTTPHeaderField:@"date"]; //We can't append null strings, so we do the following check on each header if(contentMD5 != nil) [s2s appendFormat:@"%@n", contentMD5]; else [s2s appendString:@"n"]; July 11 Weekly Code Drop
  • ● Next we append the canonicalized headers, push out a debug string, and return the string. [s2s appendString:[self canonicalizedAmzHeaders:request]]; [s2s appendString:[self canonicalizedResource:request]]; NSLog(@"************ String to Sign follows *******************"); NSLog(s2s); NSLog(@"************ End String To Sign ***********************"); return s2s; } July 11 Weekly Code Drop
  • ● Finally we sign the string, this should look familiar from last weeks code drop. - (void) appendAuthorizationHeader:(NSMutableURLRequest*) request { NSString* stringToSign = [self createStringToSign:request]; NSString* authToken = [NSString stringWithFormat:@"%@:%@", _authToken, [EncodedHMACToken createEncodedHMACToken:kPrivateKey message:stringToSign signatureType:kSHA1 forURI:NO]]; [request setValue:authToken forHTTPHeaderField:@"Authorization"]; } July 11 Weekly Code Drop
  • ● At this point, we should be good to go. The NSMutableURLRequest has the appropriate headers to make the invocation. ● From this point, to make a request, you will have to setup your own S3 Account. ● See page 9 of the Getting Started Guide for S3 accessible at: http://developer.amazonwebservices.com/connect/entry.jspaexternalID=123&categoryID=48 July 11 Weekly Code Drop
  • ● In summary – Unit test are included – To this point, we are able to use the outlined tests in the developers guide on pp. 14-19 – The first three lines of each test are just staged for right now, in the actual requests they will be more formalized. – As always, code is accessible at jasonc411.com's downloads pages. – July 18 WCD should go out mid-week. July 11 Weekly Code Drop
  • ● Upcoming Code Drops: – Part 2 Processing a Response – Part 3 Creating the libS3 Functional interface – Part 4 Using S3 with the iAudioNotebook. Hope all is well, jason h christensen (on Twitter: jasonc411) founder jasonc411.com software architecture technical research technical thought leadership July 11 Weekly Code Drop
  • ● Signatures Slide 1 EHMACAUTH files SHA1(Base64Encoder.h)= 848aa02c301987ab116e5228e8437816191c68f8 ● SHA1(Base64Encoder.m)= b494db4979f5e001a954d9559e73175b3adfd426 ● SHA1(EncodedHMACToken.h)= a9709162247ded70311e69d5233dc8994cb511f1 ● SHA1(EncodedHMACToken.m)= 3bd9b592455920476eff5bb931dc4ac7cbf1e18f ● SHA1(base64HMACTests-Info.plist)= 6b31f761a5a58d61c06282778fa005410bdbbe37 ● SHA1(base64HMACTests.h)= be22db6b5528ed65856568ce0e1658b3b12997dd ● SHA1(base64HMACTests.m)= fd4b7dce4519ff11cd0942d8bb9075b8d96229c4 ● SHA1(ehmacauth_Prefix.pch)= 7c43d1c65c49c85da9a73643fe6032f2bbf95c2a ● SHA1(ehmacauth.xcodeproj/project.pbxproj)= cd287838fcd106a55dddfa1477719acc0a798898 July 11 Weekly Code Drop
  • ● Signatures Slide 2 S3HTTPRequestHeaders and Tests SHA1(S3HTTPRequestHeaders.h)= baaabcf47147758ef9b9bc51de9fef650a5c5767 ● SHA1(S3HTTPRequestHeaders.m)= ce5e49cac2d19e430cc9b49373aa6129c121c093 ● SHA1(S3Tests-Info.plist)= 6b31f761a5a58d61c06282778fa005410bdbbe37 ● SHA1(S3_Prefix.pch)= 7c43d1c65c49c85da9a73643fe6032f2bbf95c2a ● SHA1(libS3RequestTests.h)= f52cd50b70cca323549f1f0f148d94b3934a3849 ● SHA1(libS3RequestTests.m)= aa2e08ce3e7f1d700360bad587e612e17b6e890d ● SHA1(S3.xcodeproj/project.pbxproj)= ff7f3b41e08ddd5dd3405e74887112ce5c072616 July 11 Weekly Code Drop