Permalink
Browse files

More BrowserID work (don't store assertion in database)

BrowserID assertions are extremely short-lived, so it doesn't make sense
to store them in a persistent replication's document. Instead, store the
email address only. The assertion is registered with the authorizer
before starting replication.

Conflicts:
	Source/API/TDReplication.h
	Source/API/TDReplication.m
	TouchDB.xcodeproj/project.pbxproj
  • Loading branch information...
snej committed Jan 15, 2013
1 parent 9917fe7 commit 91a6d34e5e89f36d11917d488e0dceee1fb84016
View
@@ -22,8 +22,8 @@
@optional
-@property (readonly) NSDictionary* loginParameters;
@property (readonly) NSString* loginPath;
+- (NSDictionary*) loginParametersForSite: (NSURL*)site;
@end
View
@@ -81,7 +81,7 @@ - (NSString*) loginPath {
return @"/_session";
}
-- (NSDictionary*) loginParameters {
+- (NSDictionary*) loginParametersForSite: (NSURL*)site {
NSString* username = _credential.user;
NSString* password = _credential.password;
if (username && password) {
@@ -10,8 +10,14 @@
@interface TDBrowserIDAuthorizer: NSObject <TDAuthorizer>
-- (id) initWithAssertion: (NSString*)assertion;
++ (NSURL*) originForSite: (NSURL*)url;
-@property (readonly) NSString* assertion;
++ (void) registerAssertion: (NSString*)assertion
+ forEmailAddress: (NSString*)email
+ toSite: (NSURL*)site;
+
+- (id) initWithEmailAddress: (NSString*)emailAddress;
+
+@property (readonly) NSString* emailAddress;
@end
@@ -8,19 +8,66 @@
#import "TDBrowserIDAuthorizer.h"
+
+static NSMutableDictionary* sAssertions;
+
+
@implementation TDBrowserIDAuthorizer
-- (id) initWithAssertion:(NSString *)assertion {
+
++ (NSURL*) originForSite: (NSURL*)url {
+ NSString* scheme = url.scheme.lowercaseString;
+ NSMutableString* str = [NSMutableString stringWithFormat: @"%@://%@",
+ scheme, url.host.lowercaseString];
+ NSNumber* port = url.port;
+ if (port) {
+ int defaultPort = [scheme isEqualToString: @"https"] ? 443 : 80;
+ if (port.intValue != defaultPort)
+ [str appendFormat: @":%@", port];
+ }
+ [str appendString: @"/"];
+ return [NSURL URLWithString: str];
+}
+
+
++ (void) registerAssertion: (NSString*)assertion
+ forEmailAddress: (NSString*)email
+ toSite: (NSURL*)site
+{
+ @synchronized(self) {
+ if (!sAssertions)
+ sAssertions = [NSMutableDictionary dictionary];
+ id key = @[email, [self originForSite: site]];
+ sAssertions[key] = assertion;
+ }
+}
+
+
++ (NSString*) takeAssertionForEmailAddress: (NSString*)email
+ site: (NSURL*)site
+{
+ @synchronized(self) {
+ id key = @[email, [self originForSite: site]];
+ NSString* assertion = sAssertions[key];
+ //[sAssertions removeObjectForKey: key];
+ return assertion;
+ }
+}
+
+
+@synthesize emailAddress=_emailAddress;
+
+
+- (id) initWithEmailAddress: (NSString*)emailAddress {
self = [super init];
if (self) {
- if (!assertion)
+ if (!emailAddress)
return nil;
- _assertion = [assertion copy];
+ _emailAddress = [emailAddress copy];
}
return self;
}
-@synthesize assertion=_assertion;
- (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request
forRealm: (NSString*)realm
@@ -29,19 +76,25 @@ - (NSString*) authorizeURLRequest: (NSMutableURLRequest*)request
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};
+
+- (NSDictionary*) loginParametersForSite: (NSURL*)site {
+ NSString* assertion = [[self class] takeAssertionForEmailAddress: _emailAddress site: site];
+ if (!assertion)
+ return nil;
+ return @{@"assertion": assertion};
}
@end
View
@@ -338,7 +338,7 @@ - (BOOL) goOnline {
_lastSequence = nil;
self.error = nil;
- [self login];
+ [self checkSession];
[self postProgressChanged];
}
return YES;
@@ -430,30 +430,60 @@ - (void) revisionFailed {
}
+// Before doing anything else, determine whether we have an active login session.
+- (void) checkSession {
+ if (![_authorizer respondsToSelector: @selector(loginParametersForSite:)])
+ [self fetchRemoteCheckpointDoc];
+
+ // First check whether a session exists
+ [self asyncTaskStarted];
+ [self sendAsyncRequest: @"GET"
+ path: @"/_session"
+ body: nil
+ onCompletion: ^(id result, NSError *error) {
+ if (error) {
+ LogTo(Sync, @"%@: Session check failed: %@", self, error);
+ self.error = error;
+ } else {
+ NSString* username = $castIf(NSString, [[result objectForKey: @"userCtx"] objectForKey: @"name"]);
+ if (username) {
+ LogTo(Sync, @"%@: Active session, logged in as '%@'", self, username);
+ [self fetchRemoteCheckpointDoc];
+ } else {
+ [self login];
+ }
+ }
+ [self asyncTasksFinished: 1];
+ }
+ ];
+}
+
+
+// If there is no login session, attempt to log in, if the authorizer knows the parameters.
- (void) login {
- if ([_authorizer respondsToSelector: @selector(loginParameters)]) {
- NSDictionary* loginParameters = _authorizer.loginParameters;
- if (loginParameters != nil) {
- LogTo(Sync, @"%@: Logging in with %@ at %@ ...", self, _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);
- self.error = error;
- } else {
- LogTo(Sync, @"%@: Successfully logged in!", self);
- [self fetchRemoteCheckpointDoc];
- }
- [self asyncTasksFinished: 1];
- }];
- return;
- }
+ NSDictionary* loginParameters = [_authorizer loginParametersForSite: _remote];
+ if (loginParameters == nil) {
+ LogTo(Sync, @"%@: Authorizer has no login parameters, so skipping login", self);
+ [self fetchRemoteCheckpointDoc];
+ return;
}
-
- [self fetchRemoteCheckpointDoc];
+
+ LogTo(Sync, @"%@: Logging in with %@ at %@ ...", self, _authorizer.class, _authorizer.loginPath);
+ [self asyncTaskStarted];
+ [self sendAsyncRequest: @"POST"
+ path: _authorizer.loginPath
+ body: loginParameters
+ onCompletion: ^(id result, NSError *error) {
+ if (error) {
+ LogTo(Sync, @"%@: Login failed!", self);
+ self.error = error;
+ } else {
+ LogTo(Sync, @"%@: Successfully logged in!", self);
+ [self fetchRemoteCheckpointDoc];
+ }
+ [self asyncTasksFinished: 1];
+ }
+ ];
}
@@ -272,12 +272,12 @@ - (TDStatus) parseReplicatorProperties: (NSDictionary*)properties
} else {
NSDictionary* browserid = $castIf(NSDictionary, auth[@"browserid"]);
if (browserid) {
- NSString* assertion = $castIf(NSString, browserid[@"assertion"]);
- *outAuthorizer = [[TDBrowserIDAuthorizer alloc] initWithAssertion: assertion];
+ NSString* email = $castIf(NSString, browserid[@"email"]);
+ *outAuthorizer = [[TDBrowserIDAuthorizer alloc] initWithEmailAddress: email];
}
}
if (!*outAuthorizer)
- return kTDStatusBadRequest;
+ Warn(@"Invalid authorizer settings: %@", auth);
}
}
@@ -167,8 +167,9 @@
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 */; };
+ 2776A5D516A61FD6006FF199 /* TDBrowserIDAuthorizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2776A5D316A61FD6006FF199 /* TDBrowserIDAuthorizer.h */; };
+ 2776A5D616A61FD6006FF199 /* TDBrowserIDAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2776A5D416A61FD6006FF199 /* TDBrowserIDAuthorizer.m */; };
+ 2776A5D716A61FD6006FF199 /* TDBrowserIDAuthorizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2776A5D416A61FD6006FF199 /* 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"; }; };
@@ -648,7 +649,8 @@
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>"; };
+ 2776A5D316A61FD6006FF199 /* TDBrowserIDAuthorizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDBrowserIDAuthorizer.h; sourceTree = "<group>"; };
+ 2776A5D416A61FD6006FF199 /* 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>"; };
@@ -976,6 +978,7 @@
279EB2D7149192C700E74185 /* Router */,
27821BB4148E7D590099B373 /* Replicator */,
27E2E62E159A26A1005B9234 /* Networking */,
+ 2776A5A316A48EEB006FF199 /* Auth */,
279EB2D8149192DF00E74185 /* Support */,
2713789014BCCA7B0058C5CD /* Tests */,
);
@@ -1174,6 +1177,19 @@
name = "Supporting Files";
sourceTree = "<group>";
};
+ 2776A5A316A48EEB006FF199 /* Auth */ = {
+ isa = PBXGroup;
+ children = (
+ 270F5703156AE0BF000FEB8F /* TDAuthorizer.h */,
+ 270F5704156AE0BF000FEB8F /* TDAuthorizer.m */,
+ 2776A5D316A61FD6006FF199 /* TDBrowserIDAuthorizer.h */,
+ 2776A5D416A61FD6006FF199 /* TDBrowserIDAuthorizer.m */,
+ 27F128AF156AC1C8008465C2 /* TDOAuth1Authorizer.h */,
+ 27F128B0156AC1C9008465C2 /* TDOAuth1Authorizer.m */,
+ );
+ name = Auth;
+ sourceTree = "<group>";
+ };
27821BB4148E7D590099B373 /* Replicator */ = {
isa = PBXGroup;
children = (
@@ -1224,12 +1240,6 @@
279EB2DA1491C34300E74185 /* TDCollateJSON.m */,
279906EC149ABFC1003D4338 /* TDBatcher.h */,
279906ED149ABFC2003D4338 /* TDBatcher.m */,
- 270F5703156AE0BF000FEB8F /* TDAuthorizer.h */,
- 270F5704156AE0BF000FEB8F /* TDAuthorizer.m */,
- 27F128AF156AC1C8008465C2 /* TDOAuth1Authorizer.h */,
- 27F128B0156AC1C9008465C2 /* TDOAuth1Authorizer.m */,
- 2776A536169F4C41006FF199 /* TDBrowserIDAuthorizer.h */,
- 2776A537169F4C41006FF199 /* TDBrowserIDAuthorizer.m */,
279C7E2C14F424090004A1E8 /* TDSequenceMap.h */,
279C7E2D14F424090004A1E8 /* TDSequenceMap.m */,
27A073EA14C0BB6200F52FE7 /* TDMisc.h */,
@@ -1530,6 +1540,7 @@
2781E3C915C31FDA00E970DC /* MYRegexUtils.h in Headers */,
27ED9AA1163B01D5000C844A /* TDSocketChangeTracker.h in Headers */,
2776A538169F4C41006FF199 /* TDBrowserIDAuthorizer.h in Headers */,
+ 2776A5D516A61FD6006FF199 /* TDBrowserIDAuthorizer.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2078,7 +2089,7 @@
27F128B8156AC8EC008465C2 /* OAConsumer.m in Sources */,
27F128B9156AC8F0008465C2 /* OAMutableURLRequest.m in Sources */,
270F5702156AD215000FEB8F /* OARequestParameter.m in Sources */,
- 2776A539169F4C41006FF199 /* TDBrowserIDAuthorizer.m in Sources */,
+ 2776A5D616A61FD6006FF199 /* TDBrowserIDAuthorizer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2197,7 +2208,7 @@
27F128A9156ABFE0008465C2 /* NSMutableURLRequest+Parameters.m in Sources */,
275F535215C04F7B00BAF578 /* MYStreamUtils.m in Sources */,
2781E3CB15C31FDA00E970DC /* MYRegexUtils.m in Sources */,
- 2776A53A169F4C41006FF199 /* TDBrowserIDAuthorizer.m in Sources */,
+ 2776A5D716A61FD6006FF199 /* TDBrowserIDAuthorizer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

0 comments on commit 91a6d34

Please sign in to comment.