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

Commit

Permalink
Basic-auth improvements
Browse files Browse the repository at this point in the history
* If a TDRemoteRequest gets an auth challenge and finds a new credential based on the Realm string,
  it now remembers that in its authorizer, and the replicator will pick it up and use that as its
  authorizer from then on. This should help pick up credentials registered with non-empty realms.
* TDRemoteRequest now tries the 'proposed' credential, if there is one, on its first pass through
  the auth challenge handler.
* Added more logging about the auth flow, for future debugging needs.

I am not sure if these will fix issue #242 but they should help.
  • Loading branch information
snej committed Apr 5, 2013
1 parent 9c9c730 commit f3788a0
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 10 deletions.
13 changes: 8 additions & 5 deletions Listener/TouchServ.m
Expand Up @@ -55,7 +55,7 @@

static bool doReplicate( TD_Server* server, const char* replArg,
BOOL pull, BOOL createTarget, BOOL continuous,
const char *user, const char *password)
const char *user, const char *password, const char *realm)
{
NSURL* remote = CFBridgingRelease(CFURLCreateWithBytes(NULL, (const UInt8*)replArg,
strlen(replArg),
Expand All @@ -73,7 +73,8 @@ static bool doReplicate( TD_Server* server, const char* replArg,
if (user && password) {
NSString* userStr = @(user);
NSString* passStr = @(password);
Log(@"Setting credentials for user '%@'", userStr);
NSString* realmStr = realm ? @(realm) : nil;
Log(@"Setting session credentials for user '%@' in realm %@", userStr, realmStr);
NSURLCredential* cred;
cred = [NSURLCredential credentialWithUser: userStr
password: passStr
Expand All @@ -85,7 +86,7 @@ static bool doReplicate( TD_Server* server, const char* replArg,
space = [[NSURLProtectionSpace alloc] initWithHost: remote.host
port: port
protocol: remote.scheme
realm: nil
realm: realmStr
authenticationMethod: NSURLAuthenticationMethodDefault];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential: cred
forProtectionSpace: space];
Expand Down Expand Up @@ -135,7 +136,7 @@ int main (int argc, const char * argv[])
#endif

TD_DatabaseManagerOptions options = kTD_DatabaseManagerDefaultOptions;
const char* replArg = NULL, *user = NULL, *password = NULL;
const char* replArg = NULL, *user = NULL, *password = NULL, *realm = NULL;
BOOL auth = NO, pull = NO, createTarget = NO, continuous = NO;

for (int i = 1; i < argc; ++i) {
Expand All @@ -156,6 +157,8 @@ int main (int argc, const char * argv[])
user = argv[++i];
} else if (strcmp(argv[i], "--password") == 0) {
password = argv[++i];
} else if (strcmp(argv[i], "--realm") == 0) {
realm = argv[++i];
}
}

Expand Down Expand Up @@ -188,7 +191,7 @@ int main (int argc, const char * argv[])
[listener start];

if (replArg) {
if (!doReplicate(server, replArg, pull, createTarget, continuous, user, password))
if (!doReplicate(server, replArg, pull, createTarget, continuous, user, password, realm))
return 1;
} else {
Log(@"TouchServ %@ is listening%@ on port %d ... relax!",
Expand Down
21 changes: 17 additions & 4 deletions Source/TDRemoteRequest.m
Expand Up @@ -210,27 +210,40 @@ - (void)connection:(NSURLConnection *)connection
id<NSURLAuthenticationChallengeSender> sender = challenge.sender;
NSURLProtectionSpace* space = challenge.protectionSpace;
NSString* authMethod = space.authenticationMethod;
LogTo(RemoteRequest, @"Got challenge: %@ (%@)", challenge, authMethod);
LogTo(RemoteRequest, @"Got challenge for %@: method=%@, proposed=%@, err=%@", self, authMethod, challenge.proposedCredential, challenge.error);
if ($equal(authMethod, NSURLAuthenticationMethodHTTPBasic)) {
_challenged = true;
if (!_authorizer && challenge.previousFailureCount == 0) {
NSURLCredential* cred = [_request.URL my_credentialForRealm: space.realm
authenticationMethod: authMethod];
_authorizer = nil;
if (challenge.previousFailureCount <= 1) {
// On basic auth challenge, use proposed credential on first attempt. On second attempt
// or if there's no proposed credential, look one up. After that, give up.
NSURLCredential* cred = challenge.proposedCredential;
if (cred == nil || challenge.previousFailureCount > 0) {
cred = [_request.URL my_credentialForRealm: space.realm
authenticationMethod: authMethod];
}
if (cred) {
LogTo(RemoteRequest, @" challenge: useCredential: %@", cred);
[sender useCredential: cred forAuthenticationChallenge:challenge];
// Update my authorizer so my owner (the replicator) can pick it up when I'm done
_authorizer = [[TDBasicAuthorizer alloc] initWithCredential: cred];
return;
}
}
LogTo(RemoteRequest, @" challenge: continueWithoutCredential");
[sender continueWithoutCredentialForAuthenticationChallenge: challenge];
} else if ($equal(authMethod, NSURLAuthenticationMethodServerTrust)) {
SecTrustRef trust = space.serverTrust;
if ([[self class] checkTrust: trust forHost: space.host]) {
LogTo(RemoteRequest, @" useCredential for trust: %@", trust);
[sender useCredential: [NSURLCredential credentialForTrust: trust]
forAuthenticationChallenge: challenge];
} else {
LogTo(RemoteRequest, @" challenge: cancel");
[sender cancelAuthenticationChallenge: challenge];
}
} else {
LogTo(RemoteRequest, @" challenge: performDefaultHandling");
[sender performDefaultHandlingForAuthenticationChallenge: challenge];
}
}
Expand Down
10 changes: 9 additions & 1 deletion Source/TDReplicator.m
Expand Up @@ -227,8 +227,11 @@ - (void) start {
];

// If client didn't set an authorizer, use basic auth if credential is available:
if (!_authorizer)
if (!_authorizer) {
_authorizer = [[TDBasicAuthorizer alloc] initWithURL: _remote];
if (_authorizer)
LogTo(SyncVerbose, @"%@: Found credential, using %@", self, _authorizer);
}

self.running = YES;
_startTime = CFAbsoluteTimeGetCurrent();
Expand Down Expand Up @@ -521,6 +524,11 @@ - (TDRemoteJSONRequest*) sendAsyncRequest: (NSString*)method
onCompletion: ^(id result, NSError* error) {
TDReplicator *strongSelf = weakSelf;
[strongSelf removeRemoteRequest: req];
id<TDAuthorizer> auth = req.authorizer;
if (auth && auth != _authorizer && error.code != 401) {
LogTo(SyncVerbose, @"%@: Updated to %@", self, auth);
_authorizer = auth;
}
onCompletion(result, error);
}];
req.authorizer = _authorizer;
Expand Down

0 comments on commit f3788a0

Please sign in to comment.