11

My server provide several authentication methods: NTLM and digest.
My iOS client won't handle the NTLM authentication, so I implement the connection:willSendRequestForAuthenticationChallenge: delegate to reject the NTLM, then use correct credential only for the digest authentication challenge.
Everything works fine on iOS 7 so far.

But on iOS 8, I found a weird behavior:
the connection:willSendRequestForAuthenticationChallenge: delegate won't be called at most time (95%)!!

I got this error instead:

Error: Error Domain=NSPOSIXErrorDomain Code=54 "The operation couldn’t be completed. Connection reset by peer" 
UserInfo=0x16520fb0 {_kCFStreamErrorCodeKey=54, 
NSErrorPeerAddressKey=<CFData 0x16682e40 [0x2f752440]>{length = 16, capacity = 16, bytes = 0x10020d7eac12780b0000000000000000}, 
NSErrorFailingURLKey=http://SERVER_IP:SERVER_PORT/Tunnel/Message.aspx, 
NSErrorFailingURLStringKey=http://SERVER_IP:SERVER_PORT/Tunnel/Message.aspx, 
_kCFStreamErrorDomainKey=1}

Only 5% time the delegate is correctly called and work as usual.

Below shows how I send my request to server and handle the authentication challenge:

- (void)postRequest
{
    NSString *IP = SERVER_IP;
    int port = SERVER_PORT;

    NSString *url = [NSString stringWithFormat:@"http://%@:%d/Tunnel/Message.aspx", IP, port];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"];

    NSString *xml = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?><GetServerInfo></GetServerInfo>"];
    [request setHTTPBody: [xml dataUsingEncoding:NSUTF8StringEncoding]];

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    NSLog(@"%@", challenge.protectionSpace);

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPDigest])
    {
        if ([challenge previousFailureCount] == 0)
        {
            [[challenge sender] useCredential:[NSURLCredential credentialWithUser:USERNAME
                                                                         password:PASSWORD
                                                                      persistence:NSURLCredentialPersistenceNone]
                   forAuthenticationChallenge:challenge];
        }
        else
        {
            [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
        }
    }
    else
    {
        [[challenge sender] rejectProtectionSpaceAndContinueWithChallenge:challenge];
    }
}

Those code work on iOS 7, willSendRequestForAuthenticationChallenge get called several times during the authentication challenge, but not even called any once on iOS 8!

Could this be a bug of iOS 8 or something changed since iOS 8?

Davis Cho
  • 340
  • 4
  • 12
  • Updated. Thanks for remind. – Davis Cho Aug 29 '14 at 13:53
  • Incidentally, I used your code on iOS 8 against my basic auth server and it worked fine (though I obviously replaced your digest ref with basic). I'd suggest watching this in [Charles](http://charlesproxy.com) (or similar tool) and see how your server is responding. Repeat the process in iOS 7.1 and compare. The port and server name look suspicious to me, but you say it used to work, so I guess that's not it. – Rob Aug 29 '14 at 14:29
  • 1
    Sadly I recall ios7 breaking NTLM in release. Comparing the traffic exchange as previously recommended will be useful in any bug raised with Apple. If you have a developer account check out #17832727, as well as the following forum threads https://devforums.apple.com/message/1042503#1042503, https://devforums.apple.com/message/1042505#1042505 – garthoid Sep 15 '14 at 14:14
  • Any progress on this? I'm seeing the exact same issue with iOS 8.0.2 using Digest. – Etienne Sep 30 '14 at 21:36
  • iOS 8.1 beta 2 still fail, what a shame. – Davis Cho Oct 15 '14 at 08:51

1 Answers1

2

This happened to me when I was updating my iOS 7 app to iOS 8. We were using Oracle SOA as the middle ware and sunddenly it stopped calling the delegate methods. Below worked for me in both iOS8 and iOS7. (With Xcode 6.1)

  - (void) addBasicHTTPAuthenticationHeaders
    {
        NSString * wsUserName = @"userNameForWebService";
        NSString * wsPassword = @"passwordForWebService";

        NSString *authStr = [NSString stringWithFormat:@"%@:%@", wsUserName, wsPassword];
        NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
        NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]];
        [urlRequest setValue:authValue forHTTPHeaderField:@"Authorization"];
    }
Charith Nidarsha
  • 4,195
  • 3
  • 28
  • 32