views:

623

answers:

1

Morning Everyone,

I've been attempting to write an application that does some GETs from a remote Web Service that requires authentication. My main problem is that the majority of these remote servers (and there are a lot of them) don't have valid certificates. I've got code to accept the invalid certificate and code to respond to the challenge with the correct uname & pass (below). The problem I'm having is getting the two to play together. I can't seem to find a way to send the challenge both NSURLCredentials or a way to chain the callbacks correctly. When I try to chain them I can't get my NSURLRequest to call didReceiveAuthenticationChallenge twice.

Any thoughts would be appreciated!

Code for Authentication...

-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{   
    if(!hasCanceled){
        if ([challenge previousFailureCount] == 0) {
            NSURLCredential *newCredential;
            newCredential=[NSURLCredential credentialWithUser:_username password:_password persistence:NSURLCredentialPersistenceNone];
            [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
        } 
        else {
            [[challenge sender] cancelAuthenticationChallenge:challenge];
            NSLog(@"Bad Username Or Password");
            badUsernameAndPassword = YES;
            finished = YES;
        }
    }
}
+3  A: 

You can only reply to an NSURLAuthenticationChallenge with a credential for that challenge. You can determine what type of challenge you've received using:

[[challenge protectionSpace] authenticationMethod]

The possible values are documented here. In the case of an invalid server certificate, the authentication method will be NSURLAuthenticationMethodServerTrust. In your code, you should check the authentication method and respond appropriately.

if ([challenge previousFailureCount] > 0) {
    // handle bad credentials here
    [[challenge sender] cancelAuthenticationChallenge:challenge];
    return;
}

if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
    // check if the user has previously accepted the certificate, otherwise prompt
} else if ([[challenge protectionSpace] authenticationMethod] == /* your supported authentication method here */) {
    [[challenge sender] useCredential:/* your user's credential */ forAuthenticationChallenge:challenge];
}

It's not an error if you don't get both authentication challenges each time. You can cache credentials when you create them. If you do, you won't necessarily be prompted again.

Alex
Worked like a charm. Needed to implement the "canAuthenticateAgainstProtectionSpace" method correctly to get my app to call this method. But after that all is well. Thanks!
Staros