Permalink
Browse files

Added OAuth 1 authorizer. Wired it up to replication 'oauth' object.

  • Loading branch information...
1 parent c716eba commit 8f48fe873b453847afc5ce4df50a5a1f10816a3c @snej snej committed May 21, 2012
View
@@ -7,3 +7,6 @@
[submodule "vendor/MYUtilities"]
path = vendor/MYUtilities
url = git://github.com/snej/MYUtilities.git
+[submodule "vendor/oauthconsumer"]
+ path = vendor/oauthconsumer
+ url = git://github.com/couchbaselabs/ios-oauthconsumer.git
View
@@ -0,0 +1,54 @@
+//
+// TDAuthorizer.h
+// TouchDB
+//
+// Created by Jens Alfke on 5/21/12.
+// Copyright (c) 2012 Couchbase, Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+/** Protocol for adding authorization to HTTP requests. */
+@protocol TDAuthorizer <NSObject>
+
+/** Should generate and return an authorization string for the given request.
+ The string, if non-nil, will be set as the value of the "Authorization:" HTTP header. */
+- (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request
+ forRealm: (NSString*)realm;
+
+@end
+
+
+
+/** Simple implementation of TDAuthorizer that does HTTP Basic Auth. */
+@interface TDBasicAuthorizer : NSObject <TDAuthorizer>
+{
+ @private
+ NSURLCredential* _credential;
+}
+
+/** Initialize given a credential object that contains a username and password. */
+- (id) initWithCredential: (NSURLCredential*)credential;
+
+@end
+
+
+
+/** Implementation of TDAuthorizer that supports MAC authorization as used in OAuth 2. */
+@interface TDMACAuthorizer : NSObject <TDAuthorizer>
+{
+@private
+ NSString *_key, *_identifier;
+ NSDate* _issueTime;
+ NSData* (*_hmacFunction)(NSData*, NSData*);
+
+}
+
+/** Initialize given MAC credentials */
+- (id) initWithKey: (NSString*)key
+ identifier: (NSString*)identifier
+ algorithm: (NSString*)algorithm
+ issueTime: (NSDate*)issueTime;
+
+@end
View
@@ -0,0 +1,113 @@
+//
+// TDAuthorizer.m
+// TouchDB
+//
+// Created by Jens Alfke on 5/21/12.
+// Copyright (c) 2012 Couchbase, Inc. All rights reserved.
+//
+
+#import "TDAuthorizer.h"
+#import "TDMisc.h"
+#import "TDBase64.h"
+#import "MYURLUtils.h"
+
+
+@implementation TDBasicAuthorizer
+
+- (id) initWithCredential: (NSURLCredential*)credential {
+ Assert(credential);
+ self = [super init];
+ if (self) {
+ _credential = [credential retain];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [_credential release];
+ [super dealloc];
+}
+
+- (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request
+ forRealm: (NSString*)realm
+{
+ NSString* username = _credential.user;
+ NSString* password = _credential.password;
+ if (username && password) {
+ NSString* seekrit = $sprintf(@"%@:%@", username, password);
+ seekrit = [TDBase64 encode: [seekrit dataUsingEncoding: NSUTF8StringEncoding]];
+ return [@"Basic " stringByAppendingString: seekrit];
+ }
+ return nil;
+}
+
+@end
+
+
+@implementation TDMACAuthorizer
+
+- (id) initWithKey: (NSString*)key
+ identifier: (NSString*)identifier
+ algorithm: (NSString*)algorithm
+ issueTime: (NSDate*)issueTime
+{
+ self = [super init];
+ if (self) {
+ _key = [key copy];
+ _identifier = [identifier copy];
+ _issueTime = [issueTime copy];
+ if ([algorithm isEqualToString: @"hmac-sha-1"])
+ _hmacFunction = &TDHMACSHA1;
+ else if ([algorithm isEqualToString: @"hmac-sha-256"])
+ _hmacFunction = &TDHMACSHA256;
+ else {
+ [self release];
+ return nil;
+ }
+ }
+ return self;
+}
+
+
+- (void)dealloc
+{
+ [_key release];
+ [_identifier release];
+ [_issueTime release];
+ [super dealloc];
+}
+
+
+- (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request
+ forRealm: (NSString*)realm
+{
+ // <http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-00>
+ NSString* nonce = $sprintf(@"%.0f:%@", -[_issueTime timeIntervalSinceNow], TDCreateUUID());
+ NSURL* url = request.URL;
+ NSString* ext = @""; // not implemented yet
+
+ NSString* bodyHash = @"";
+ NSData* body = request.HTTPBody;
+ if (body.length > 0) {
+ NSData* digest = (_hmacFunction == &TDHMACSHA1) ? TDSHA1Digest(body) : TDSHA256Digest(body);
+ bodyHash = [TDBase64 encode: digest];
+ }
+
+ NSString* normalized = $sprintf(@"%@\n%@%@\n%@\n%d\n%@\n%@\n",
+ nonce,
+ request.HTTPMethod,
+ url.my_pathAndQuery,
+ [url.host lowercaseString],
+ url.my_effectivePort,
+ bodyHash,
+ ext);
+ NSString* mac;
+ mac = [TDBase64 encode: _hmacFunction([_key dataUsingEncoding: NSUTF8StringEncoding],
+ [normalized dataUsingEncoding: NSUTF8StringEncoding])];
+ return $sprintf(@"MAC id=\"%@\", nonce=\"%@\", bodyhash=\"%@\", mac=\"%@\"",
+ _identifier, nonce, bodyHash, mac);
+}
+
+
+@end
@@ -0,0 +1,28 @@
+//
+// TDOAuth1Authorizer.h
+// TouchDB
+//
+// Created by Jens Alfke on 5/21/12.
+// Copyright (c) 2012 Couchbase, Inc. All rights reserved.
+//
+
+#import "TDAuthorizer.h"
+@class OAConsumer, OAToken;
+@protocol OASignatureProviding;
+
+
+/** Implementation of TAuthorizer for OAuth 1 requests. */
+@interface TDOAuth1Authorizer : NSObject <TDAuthorizer>
+{
+ OAConsumer* _consumer;
+ OAToken* _token;
+ id<OASignatureProviding> _signatureProvider;
+}
+
+- (id) initWithConsumerKey: (NSString*)consumerKey
+ consumerSecret: (NSString*)consumerSecret
+ token: (NSString*)token
+ tokenSecret: (NSString*)tokenSecret
+ signatureMethod: (NSString*)signatureMethod;
+
+@end
@@ -0,0 +1,91 @@
+//
+// TDOAuth1Authorizer.m
+// TouchDB
+//
+// Created by Jens Alfke on 5/21/12.
+// Copyright (c) 2012 Couchbase, Inc. All rights reserved.
+//
+
+#import "TDOAuth1Authorizer.h"
+#import "TDMisc.h"
+#import "TDBase64.h"
+#import "OAMutableURLRequest.h"
+#import "OAConsumer.h"
+#import "OAToken.h"
+#import "OAPlaintextSignatureProvider.h"
+
+
+@implementation TDOAuth1Authorizer
+
+
+- (id) initWithConsumerKey: (NSString*)consumerKey
+ consumerSecret: (NSString*)consumerSecret
+ token: (NSString*)token
+ tokenSecret: (NSString*)tokenSecret
+ signatureMethod: (NSString*)signatureMethod
+{
+ self = [super init];
+ if (self) {
+ if (!consumerKey || !consumerSecret || !token || !tokenSecret) {
+ [self release];
+ return nil;
+ }
+ _consumer = [[OAConsumer alloc] initWithKey: consumerKey secret: consumerSecret];
+ _token = [[OAToken alloc] initWithKey: token secret: tokenSecret];
+ if ([signatureMethod isEqualToString: @"HMAC-SHA1"] || signatureMethod == nil)
+ _signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init];
+ else if ([signatureMethod isEqualToString: @"PLAINTEXT"])
+ _signatureProvider = [[OAPlaintextSignatureProvider alloc] init];
+ else {
+ Warn(@"Unsupported signature method '%@'", signatureMethod);
+ [self release];
+ return nil;
+ }
+ }
+ return self;
+}
+
+
+- (void)dealloc
+{
+ [_consumer release];
+ [_token release];
+ [_signatureProvider release];
+ [super dealloc];
+}
+
+
+// TDAuthorizer API:
+- (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request
+ forRealm: (NSString*)realm
+{
+ OAMutableURLRequest* oarq = [[OAMutableURLRequest alloc] initWithURL: request.URL
+ consumer: _consumer
+ token: _token
+ realm: realm
+ signatureProvider: _signatureProvider];
+ oarq.HTTPMethod = request.HTTPMethod;
+ oarq.HTTPBody = request.HTTPBody;
+ [oarq prepare];
+ NSString* authorization = [oarq valueForHTTPHeaderField: @"Authorization"];
+ [oarq release];
+ return authorization;
+}
+
+@end
+
+
+// Include our own implementation of this instead of the OAuth library's, because it drags in
+// a bunch of other stuff including its own SHA1 and Base64 implementations.
+@implementation OAHMAC_SHA1SignatureProvider
+
+- (NSString *)name {
+ return @"HMAC-SHA1";
+}
+
+- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret {
+ return [TDBase64 encode: TDHMACSHA1([secret dataUsingEncoding: NSUTF8StringEncoding],
+ [text dataUsingEncoding: NSUTF8StringEncoding])];
+}
+
+@end
View
@@ -18,6 +18,7 @@
#import "TDDatabase+Replication.h"
#import <TouchDB/TDRevision.h>
#import "TDChangeTracker.h"
+#import "TDAuthorizer.h"
#import "TDBatcher.h"
#import "TDMultipartDownloader.h"
#import "TDSequenceMap.h"
@@ -105,7 +106,8 @@ - (void) beginReplicating {
if (_authorizer) {
NSURL* url = _changeTracker.changesFeedURL;
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL: url];
- NSString* authorization = [_authorizer authorizeURLRequest: request];
+ NSString* authorization = [_authorizer authorizeURLRequest: request
+ forRealm: nil];
if (authorization)
[headers setObject: authorization forKey: @"Authorization"];
}
View
@@ -14,6 +14,7 @@
// and limitations under the License.
#import "TDRemoteRequest.h"
+#import "TDAuthorizer.h"
#import "TDMisc.h"
#import "TDBlobStore.h"
#import <TouchDB/TDDatabase.h>
@@ -59,7 +60,8 @@ - (id) initWithMethod: (NSString*)method
LogTo(RemoteRequest, @"%@: Starting...", self);
[self setupRequest: _request withBody: body];
- NSString* authHeader = [authorizer authorizeURLRequest: _request];
+ NSString* authHeader = [authorizer authorizeURLRequest: _request
+ forRealm: nil];
if (authHeader)
[_request setValue: authHeader forHTTPHeaderField: @"Authorization"];
View
@@ -98,48 +98,3 @@ extern NSString* TDReplicatorStoppedNotification;
@property (readonly, nonatomic) NSUInteger changesTotal;
@end
-
-
-
-/** Protocol for adding authorization to HTTP requests sent by a TDReplicator. */
-@protocol TDAuthorizer <NSObject>
-
-/** Should generate and return an authorization string for the given request.
- The string, if non-nil, will be set as the value of the "Authorization:" HTTP header. */
-- (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request;
-
-@end
-
-
-
-/** Simple implementation of TDAuthorizer that does HTTP Basic Auth. */
-@interface TDBasicAuthorizer : NSObject <TDAuthorizer>
-{
- @private
- NSURLCredential* _credential;
-}
-
-/** Initialize given a credential object that contains a username and password. */
-- (id) initWithCredential: (NSURLCredential*)credential;
-
-@end
-
-
-
-/** Implementation of TDAuthorizer that supports MAC authorization as used in OAuth 2. */
-@interface TDMACAuthorizer : NSObject <TDAuthorizer>
-{
-@private
- NSString *_key, *_identifier;
- NSDate* _issueTime;
- NSData* (*_hmacFunction)(NSData*, NSData*);
-
-}
-
-/** Initialize given MAC credentials */
-- (id) initWithKey: (NSString*)key
- identifier: (NSString*)identifier
- algorithm: (NSString*)algorithm
- issueTime: (NSDate*)issueTime;
-
-@end
Oops, something went wrong.

0 comments on commit 8f48fe8

Please sign in to comment.