Permalink
Browse files

Better logging if change tracker fails HTTP auth

If TDSocketChangeTracker gets a 401 or 407 and can't find a credential, or the credential is rejected,
it now logs a message of the form
    TDSocketChangeTracker[...]: HTTP auth failed; sent Authorization: %@  ;  got WWW-Authenticate: %@
showing the Authorization header it sent (if any, else null) and the WWW-Authenticate response header.
These headers are also returned in the NSError as keys "HTTPAuthorization" and "HTTPAuthenticateHeader"
(although this is of limited use since this info won't make it all the way up to the public replication API, yet.)
This should help in diagnosing issue #242.
  • Loading branch information...
1 parent ec50437 commit 9296c47cc822f4d8a7f4b513603b4f623c4a3b8f @snej snej committed Mar 28, 2013
Showing with 38 additions and 17 deletions.
  1. +27 −14 Source/ChangeTracker/TDSocketChangeTracker.m
  2. +1 −0 Source/TDStatus.h
  3. +10 −3 Source/TDStatus.m
@@ -68,7 +68,8 @@ - (BOOL) start {
// .hasPassword when setting _credential earlier. (See #195.) Keychain bug??
// If this happens, try looking up the credential again:
LogTo(ChangeTracker, @"Huh, couldn't get password of %@; trying again", _credential);
- _credential = [self credentialForResponse: _unauthResponse];
+ _credential = [self credentialForAuthHeader:
+ [self authHeaderForResponse: _unauthResponse]];
password = _credential.password;
}
if (password) {
@@ -171,13 +172,17 @@ - (BOOL) checkSSLCert {
}
-- (NSURLCredential*) credentialForResponse: (CFHTTPMessageRef)response {
+- (NSString*) authHeaderForResponse: (CFHTTPMessageRef)response {
+ return CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(response,
+ CFSTR("WWW-Authenticate")));
+}
+
+
+- (NSURLCredential*) credentialForAuthHeader: (NSString*)authHeader {
NSString* realm;
NSString* authenticationMethod;
// Basic & digest auth: http://www.ietf.org/rfc/rfc2617.txt
- NSString* authHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(response,
- CFSTR("WWW-Authenticate")));
if (!authHeader)
return nil;
@@ -214,25 +219,33 @@ - (BOOL) readResponseHeader {
kCFStreamPropertyHTTPResponseHeader);
Assert(response);
_gotResponseHeaders = true;
+ NSDictionary* errorInfo = nil;
// Handle authentication failure (401 or 407 status):
CFIndex status = CFHTTPMessageGetResponseStatusCode(response);
LogTo(ChangeTracker, @"%@ got status %ld", self, status);
- if ((status == 401 || status == 407) && !_credential
- && ![_requestHeaders objectForKey: @"Authorization"]) {
- _credential = [self credentialForResponse: response];
- LogTo(ChangeTracker, @"%@: Auth challenge; credential = %@", self, _credential);
- if (_credential) {
- // Recoverable auth failure -- try again with _credential:
- _unauthResponse = response;
- [self errorOccurred: TDStatusToNSError((TDStatus)status, self.changesFeedURL)];
- return NO;
+ if (status == 401 || status == 407) {
+ NSString* authorization = [_requestHeaders objectForKey: @"Authorization"];
+ NSString* authResponse = [self authHeaderForResponse: response];
+ if (!_credential && !authorization) {
+ _credential = [self credentialForAuthHeader: authResponse];
+ LogTo(ChangeTracker, @"%@: Auth challenge; credential = %@", self, _credential);
+ if (_credential) {
+ // Recoverable auth failure -- close socket but try again with _credential:
+ _unauthResponse = response;
+ [self errorOccurred: TDStatusToNSError((TDStatus)status, self.changesFeedURL)];
+ return NO;
+ }
}
+ Log(@"%@: HTTP auth failed; sent Authorization: %@ ; got WWW-Authenticate: %@",
+ self, authorization, authResponse);
+ errorInfo = $dict({@"HTTPAuthorization", authorization},
+ {@"HTTPAuthenticateHeader", authResponse});
}
CFRelease(response);
if (status >= 300) {
- self.error = TDStatusToNSError(status, self.changesFeedURL);
+ self.error = TDStatusToNSErrorWithInfo(status, self.changesFeedURL, errorInfo);
[self stop];
return NO;
}
View
@@ -49,3 +49,4 @@ static inline bool TDStatusIsError(TDStatus status) {return status >= 300;}
int TDStatusToHTTPStatus( TDStatus status, NSString** outMessage );
NSError* TDStatusToNSError( TDStatus status, NSURL* url );
+NSError* TDStatusToNSErrorWithInfo( TDStatus status, NSURL* url, NSDictionary* extraInfo );
View
@@ -61,11 +61,18 @@ int TDStatusToHTTPStatus( TDStatus status, NSString** outMessage ) {
}
-NSError* TDStatusToNSError( TDStatus status, NSURL* url ) {
+NSError* TDStatusToNSErrorWithInfo( TDStatus status, NSURL* url, NSDictionary* extraInfo ) {
NSString* reason;
status = TDStatusToHTTPStatus(status, &reason);
- NSDictionary* info = $dict({NSURLErrorKey, url},
+ NSMutableDictionary* info = $mdict({NSURLErrorKey, url},
{NSLocalizedFailureReasonErrorKey, reason},
{NSLocalizedDescriptionKey, $sprintf(@"%i %@", status, reason)});
- return [NSError errorWithDomain: TDHTTPErrorDomain code: status userInfo: info];
+ if (extraInfo)
+ [info addEntriesFromDictionary: extraInfo];
+ return [NSError errorWithDomain: TDHTTPErrorDomain code: status userInfo: [info copy]];
+}
+
+
+NSError* TDStatusToNSError( TDStatus status, NSURL* url ) {
+ return TDStatusToNSErrorWithInfo(status, url, nil);
}

0 comments on commit 9296c47

Please sign in to comment.