Your SlideShare is downloading. ×
July 11 Weekly Code Drop Part 1 of 3 Creating an S3 library
Upcoming SlideShare
Loading in...5

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

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


Published on

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.

Published in: Technology, Education

1 Comment
  • 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  Yes  No
    Your message goes here
  • Be the first to like this

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

No notes for slide


  • 1. Weekly Code Drop: Connecting to Amazon S3 Part 1 of 3 Formulating the S3 Request Jason Hayes Christensen July 11 Weekly Code Drop
  • 2. ● 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: July 11 Weekly Code Drop
  • 3. ● Detailed S3 documentation can be accessed at: ● 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
  • 4. ● 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
  • 5. ● Remember, we are using virtual hosted mode, this means that we address a bucket as: <bucketName> ● The “resource” is the file name, it is specified as the path on the server when using virtual hosted mode: ● 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
  • 6. ● 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
  • 7. ● 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
  • 8. ● 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
  • 9. ● Date header formatting must meet the RFC 1123 standard( ) ● 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
  • 10. ● 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
  • 11. ● 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
  • 12. ● 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
  • 13. ● 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
  • 14. ● 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
  • 15. ● 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
  • 16. ● 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
  • 17. ● 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
  • 18. ● 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
  • 19. ● 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
  • 20. ● 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
  • 21. ● 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
  • 22. ● 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
  • 23. ● 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: July 11 Weekly Code Drop
  • 24. ● 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's downloads pages. – July 18 WCD should go out mid-week. July 11 Weekly Code Drop
  • 25. ● 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 software architecture technical research technical thought leadership July 11 Weekly Code Drop
  • 26. ● 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
  • 27. ● 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