Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Commit

Permalink
BrowserID support for replicator (untested)
Browse files Browse the repository at this point in the history
To use it with non persistent replications, set a TDBrowserIDAuthorizer.

With persistent replications, add a "auth" sub-object of the "source"
or "target" object (just as for OAuth) and in it put a "browserid"
object with an "assertion" property whose value is the BrowserID
assertion.

This obviously requires that the remote server have BrowserID support.
There is a CouchDB-BrowserID plugin, and IrisCouch's servers have it.
  • Loading branch information
snej committed Jan 11, 2013
1 parent efb7fb5 commit 649d14f
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 22 deletions.
5 changes: 5 additions & 0 deletions Source/TDAuthorizer.h
Expand Up @@ -20,6 +20,11 @@
- (NSString*) authorizeHTTPMessage: (CFHTTPMessageRef)message
forRealm: (NSString*)realm;

@optional

@property (readonly) NSDictionary* loginParameters;
@property (readonly) NSString* loginPath;

@end


Expand Down
19 changes: 19 additions & 0 deletions Source/TDAuthorizer.m
Expand Up @@ -72,6 +72,25 @@ - (NSString*) description {
return $sprintf(@"%@[%@/****]", self.class, _credential.user);
}

#if 0
// If enabled, these methods would make TouchDB use cookie-based login intstead of basic auth;
// but there's not really much point in doing so, as such logins expire, which would cause trouble
// with long-lived replications.

- (NSString*) loginPath {
return @"/_session";
}

- (NSDictionary*) loginParameters {
NSString* username = _credential.user;
NSString* password = _credential.password;
if (username && password) {
return @{@"name": username, @"password": password};
}
return nil;
}
#endif

@end


Expand Down
17 changes: 17 additions & 0 deletions Source/TDBrowserIDAuthorizer.h
@@ -0,0 +1,17 @@
//
// TDBrowserIDAuthorizer.h
// TouchDB
//
// Created by Jens Alfke on 1/9/13.
//
//

#import "TDAuthorizer.h"

@interface TDBrowserIDAuthorizer: NSObject <TDAuthorizer>

- (id) initWithAssertion: (NSString*)assertion;

@property (readonly) NSString* assertion;

@end
47 changes: 47 additions & 0 deletions Source/TDBrowserIDAuthorizer.m
@@ -0,0 +1,47 @@
//
// TDBrowserIDAuthorizer.m
// TouchDB
//
// Created by Jens Alfke on 1/9/13.
//
//

#import "TDBrowserIDAuthorizer.h"

@implementation TDBrowserIDAuthorizer

- (id) initWithAssertion:(NSString *)assertion {
self = [super init];
if (self) {
if (!_assertion)
return nil;
_assertion = [assertion copy];
}
return self;
}

@synthesize assertion=_assertion;

- (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request
forRealm: (NSString*)realm
{
// Auth is via cookie, which is automatically added by CFNetwork.
return nil;
}

- (NSString*) authorizeHTTPMessage: (CFHTTPMessageRef)message
forRealm: (NSString*)realm
{
// Auth is via cookie, which is automatically added by CFNetwork.
return nil;
}

- (NSString*) loginPath {
return @"/_browserid";
}

- (NSDictionary*) loginParameters {
return @{@"assertion": _assertion};
}

@end
2 changes: 1 addition & 1 deletion Source/TDPuller.m
Expand Up @@ -407,7 +407,7 @@ - (void) pullBulkRevisions: (NSArray*)bulkRevs {
NSMutableArray* remainingRevs = [bulkRevs mutableCopy];
NSArray* keys = [bulkRevs my_map: ^(TD_Revision* rev) { return rev.docID; }];
[self sendAsyncRequest: @"POST"
path: @"/_all_docs?include_docs=true"
path: @"_all_docs?include_docs=true"
body: $dict({@"keys", keys})
onCompletion:^(id result, NSError *error) {
if (error) {
Expand Down
6 changes: 3 additions & 3 deletions Source/TDPusher.m
Expand Up @@ -188,7 +188,7 @@ - (void) processInbox: (TD_RevisionList*)changes {

// Call _revs_diff on the target db:
[self asyncTaskStarted];
[self sendAsyncRequest: @"POST" path: @"/_revs_diff" body: diffs
[self sendAsyncRequest: @"POST" path: @"_revs_diff" body: diffs
onCompletion:^(NSDictionary* results, NSError* error) {
if (error) {
self.error = error;
Expand Down Expand Up @@ -264,7 +264,7 @@ - (void) uploadBulkDocs: (NSArray*)docsToSend
self.changesTotal += numDocsToSend;
[self asyncTaskStarted];
[self sendAsyncRequest: @"POST"
path: @"/_bulk_docs"
path: @"_bulk_docs"
body: $dict({@"docs", docsToSend},
{@"new_edits", $false})
onCompletion: ^(NSDictionary* response, NSError *error) {
Expand Down Expand Up @@ -384,7 +384,7 @@ - (void) uploadJSONRevision: (TD_Revision*)rev {
}

[self asyncTaskStarted];
NSString* path = $sprintf(@"/%@?new_edits=false", TDEscapeID(rev.docID));
NSString* path = $sprintf(@"%@?new_edits=false", TDEscapeID(rev.docID));
[self sendAsyncRequest: @"PUT"
path: path
body: rev.properties
Expand Down
2 changes: 1 addition & 1 deletion Source/TDRemoteRequest.m
Expand Up @@ -319,7 +319,7 @@ - (NSURLRequest *)connection:(NSURLConnection *)connection


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
LogTo(RemoteRequest, @"%@: Got %lu bytes", self, (unsigned long)data.length);
LogTo(RemoteRequestVerbose, @"%@: Got %lu bytes", self, (unsigned long)data.length);
}


Expand Down
41 changes: 36 additions & 5 deletions Source/TDReplicator.m
Expand Up @@ -338,7 +338,7 @@ - (BOOL) goOnline {
_lastSequence = nil;
self.error = nil;

[self fetchRemoteCheckpointDoc];
[self login];
[self postProgressChanged];
}
return YES;
Expand Down Expand Up @@ -430,6 +430,33 @@ - (void) revisionFailed {
}


- (void) login {
if ([_authorizer respondsToSelector: @selector(loginParameters)]) {
NSDictionary* loginParameters = _authorizer.loginParameters;
if (loginParameters != nil) {
LogTo(Sync, @"Logging in with %@ at %@ ...", _authorizer.class, _authorizer.loginPath);
[self asyncTaskStarted];
[self sendAsyncRequest: @"POST"
path: _authorizer.loginPath
body: _authorizer.loginParameters
onCompletion: ^(id result, NSError *error) {
if (error) {
LogTo(Sync, @"Login failed!");
self.error = error;
} else {
LogTo(Sync, @"Successfully logged in!");
[self fetchRemoteCheckpointDoc];
}
[self asyncTasksFinished: 1];
}];
return;
}
}

[self fetchRemoteCheckpointDoc];
}


#pragma mark - HTTP REQUESTS:


Expand All @@ -439,8 +466,12 @@ - (TDRemoteJSONRequest*) sendAsyncRequest: (NSString*)method
onCompletion: (TDRemoteRequestCompletionBlock)onCompletion
{
LogTo(SyncVerbose, @"%@: %@ .%@", self, method, relativePath);
NSString* urlStr = [_remote.absoluteString stringByAppendingString: relativePath];
NSURL* url = [NSURL URLWithString: urlStr];
NSURL* url;
if ([relativePath hasPrefix: @"/"]) {
url = [[NSURL URLWithString: relativePath relativeToURL: _remote] absoluteURL];
} else {
url = [_remote URLByAppendingPathComponent: relativePath];
}
onCompletion = [onCompletion copy];

// under ARC, using variable req used directly inside the block results in a compiler error (it could have undefined value).
Expand Down Expand Up @@ -522,7 +553,7 @@ - (void) fetchRemoteCheckpointDoc {
[self asyncTaskStarted];
TDRemoteJSONRequest* request =
[self sendAsyncRequest: @"GET"
path: [@"/_local/" stringByAppendingString: checkpointID]
path: [@"_local/" stringByAppendingString: checkpointID]
body: nil
onCompletion: ^(id response, NSError* error) {
// Got the response:
Expand Down Expand Up @@ -577,7 +608,7 @@ - (void) saveLastSequence {
_savingCheckpoint = YES;
NSString* checkpointID = self.remoteCheckpointDocID;
[self sendAsyncRequest: @"PUT"
path: [@"/_local/" stringByAppendingString: checkpointID]
path: [@"_local/" stringByAppendingString: checkpointID]
body: body
onCompletion: ^(id response, NSError* error) {
_savingCheckpoint = NO;
Expand Down
33 changes: 21 additions & 12 deletions Source/TDReplicatorManager.m
Expand Up @@ -25,6 +25,7 @@
#import "TDPuller.h"
#import "TD_View.h"
#import "TDOAuth1Authorizer.h"
#import "TDBrowserIDAuthorizer.h"
#import "TDInternal.h"
#import "TDMisc.h"
#import "MYBlockUtils.h"
Expand Down Expand Up @@ -168,18 +169,26 @@ - (TDStatus) parseReplicatorProperties: (NSDictionary*)properties
if (outAuthorizer) {
*outAuthorizer = nil;
NSDictionary* auth = $castIf(NSDictionary, remoteDict[@"auth"]);
NSDictionary* oauth = $castIf(NSDictionary, auth[@"oauth"]);
if (oauth) {
NSString* consumerKey = $castIf(NSString, oauth[@"consumer_key"]);
NSString* consumerSec = $castIf(NSString, oauth[@"consumer_secret"]);
NSString* token = $castIf(NSString, oauth[@"token"]);
NSString* tokenSec = $castIf(NSString, oauth[@"token_secret"]);
NSString* sigMethod = $castIf(NSString, oauth[@"signature_method"]);
*outAuthorizer = [[TDOAuth1Authorizer alloc] initWithConsumerKey: consumerKey
consumerSecret: consumerSec
token: token
tokenSecret: tokenSec
signatureMethod: sigMethod];
if (auth) {
NSDictionary* oauth = $castIf(NSDictionary, auth[@"oauth"]);
if (oauth) {
NSString* consumerKey = $castIf(NSString, oauth[@"consumer_key"]);
NSString* consumerSec = $castIf(NSString, oauth[@"consumer_secret"]);
NSString* token = $castIf(NSString, oauth[@"token"]);
NSString* tokenSec = $castIf(NSString, oauth[@"token_secret"]);
NSString* sigMethod = $castIf(NSString, oauth[@"signature_method"]);
*outAuthorizer = [[TDOAuth1Authorizer alloc] initWithConsumerKey: consumerKey
consumerSecret: consumerSec
token: token
tokenSecret: tokenSec
signatureMethod: sigMethod];
} else {
NSDictionary* browserid = $castIf(NSDictionary, auth[@"browserid"]);
if (browserid) {
NSString* assertion = $castIf(NSString, browserid[@"assertion"]);
*outAuthorizer = [[TDBrowserIDAuthorizer alloc] initWithAssertion: assertion];
}
}
if (!*outAuthorizer)
return kTDStatusBadRequest;
}
Expand Down
10 changes: 10 additions & 0 deletions TouchDB.xcodeproj/project.pbxproj
Expand Up @@ -166,6 +166,9 @@
2773ADC714BD1EB80027A292 /* TD_Database+LocalDocs.h in Headers */ = {isa = PBXBuildFile; fileRef = 2773ADC514BD1EB80027A292 /* TD_Database+LocalDocs.h */; settings = {ATTRIBUTES = (Public, ); }; };
2773ADC814BD1EB80027A292 /* TD_Database+LocalDocs.m in Sources */ = {isa = PBXBuildFile; fileRef = 2773ADC614BD1EB80027A292 /* TD_Database+LocalDocs.m */; };
2773ADC914BD1EB80027A292 /* TD_Database+LocalDocs.m in Sources */ = {isa = PBXBuildFile; fileRef = 2773ADC614BD1EB80027A292 /* TD_Database+LocalDocs.m */; };
2776A538169F4C41006FF199 /* TDBrowserIDAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2776A536169F4C41006FF199 /* TDBrowserIDAuthorizer.h */; };
2776A539169F4C41006FF199 /* TDBrowserIDAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2776A537169F4C41006FF199 /* TDBrowserIDAuthorizer.m */; };
2776A53A169F4C41006FF199 /* TDBrowserIDAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2776A537169F4C41006FF199 /* TDBrowserIDAuthorizer.m */; };
2781E3C915C31FDA00E970DC /* MYRegexUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2781E3C715C31FDA00E970DC /* MYRegexUtils.h */; };
2781E3CA15C31FDA00E970DC /* MYRegexUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2781E3C815C31FDA00E970DC /* MYRegexUtils.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
2781E3CB15C31FDA00E970DC /* MYRegexUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2781E3C815C31FDA00E970DC /* MYRegexUtils.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
Expand Down Expand Up @@ -644,6 +647,8 @@
27731F40149685A100815D67 /* list_area___checkbox___unchecked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "list_area___checkbox___unchecked.png"; sourceTree = "<group>"; };
2773ADC514BD1EB80027A292 /* TD_Database+LocalDocs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TD_Database+LocalDocs.h"; sourceTree = "<group>"; };
2773ADC614BD1EB80027A292 /* TD_Database+LocalDocs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TD_Database+LocalDocs.m"; sourceTree = "<group>"; };
2776A536169F4C41006FF199 /* TDBrowserIDAuthorizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDBrowserIDAuthorizer.h; sourceTree = "<group>"; };
2776A537169F4C41006FF199 /* TDBrowserIDAuthorizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDBrowserIDAuthorizer.m; sourceTree = "<group>"; };
2781E3C715C31FDA00E970DC /* MYRegexUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYRegexUtils.h; sourceTree = "<group>"; };
2781E3C815C31FDA00E970DC /* MYRegexUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYRegexUtils.m; sourceTree = "<group>"; };
27821BB5148E7D6F0099B373 /* TDReplicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDReplicator.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1223,6 +1228,8 @@
270F5704156AE0BF000FEB8F /* TDAuthorizer.m */,
27F128AF156AC1C8008465C2 /* TDOAuth1Authorizer.h */,
27F128B0156AC1C9008465C2 /* TDOAuth1Authorizer.m */,
2776A536169F4C41006FF199 /* TDBrowserIDAuthorizer.h */,
2776A537169F4C41006FF199 /* TDBrowserIDAuthorizer.m */,
279C7E2C14F424090004A1E8 /* TDSequenceMap.h */,
279C7E2D14F424090004A1E8 /* TDSequenceMap.m */,
27A073EA14C0BB6200F52FE7 /* TDMisc.h */,
Expand Down Expand Up @@ -1522,6 +1529,7 @@
275F535015C04F7B00BAF578 /* MYStreamUtils.h in Headers */,
2781E3C915C31FDA00E970DC /* MYRegexUtils.h in Headers */,
27ED9AA1163B01D5000C844A /* TDSocketChangeTracker.h in Headers */,
2776A538169F4C41006FF199 /* TDBrowserIDAuthorizer.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2070,6 +2078,7 @@
27F128B8156AC8EC008465C2 /* OAConsumer.m in Sources */,
27F128B9156AC8F0008465C2 /* OAMutableURLRequest.m in Sources */,
270F5702156AD215000FEB8F /* OARequestParameter.m in Sources */,
2776A539169F4C41006FF199 /* TDBrowserIDAuthorizer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2188,6 +2197,7 @@
27F128A9156ABFE0008465C2 /* NSMutableURLRequest+Parameters.m in Sources */,
275F535215C04F7B00BAF578 /* MYStreamUtils.m in Sources */,
2781E3CB15C31FDA00E970DC /* MYRegexUtils.m in Sources */,
2776A53A169F4C41006FF199 /* TDBrowserIDAuthorizer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

0 comments on commit 649d14f

Please sign in to comment.