NSURLCredentialStorage default credential not used automatically

826 views Asked by At

I'm switching from NSURLConnection to NSURLSession for my app communications and, while I'm at it, trying to move from delegated authentication to utilising NSURLCredentialStorage. I've moved over the code however I'm getting -URLSession:task:didReceiveChallenge being called on the delegate despite having set defaultCredentials on the sharedCredentialStorage when the app launches.

The protection spaces are identical (the one I created when setting up the credentials and the ones passed by the NSURLAuthenticationChallenge) as per the below logged messages:

Register credentials for: <NSURLProtectionSpace: 0x162227c0>: Host:192.168.1.99, Server:https, Auth-Scheme:NSURLAuthenticationMethodDefault, Realm:192.168.1.99, Port:23650, Proxy:NO, Proxy-Type:(null)
Unexpected authentication challenge: <NSURLProtectionSpace: 0x1680ee40>: Host:192.168.1.99, Server:https, Auth-Scheme:NSURLAuthenticationMethodDefault, Realm:192.168.1.99, Port:23650, Proxy:NO, Proxy-Type:(null)

and during the didReceiveChallenge:(NSURLAuthenticationChallenge*)challenge delegate method:

po [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:[challenge protectionSpace]]

results in

<NSURLCredential: 0x1680ff00>: thecorrectusername

https://stackoverflow.com/a/501869/563905 indicates that, when the server responds with a 401 challenge, the NSURLConnection (is this a NSURLSession problem?) first checks the headers for Authorization (there aren't any set) and then consults NSURLCredentialStorage for credentials for the protection space.

I just don't understand why I'm getting the didReceiveChallenge delegate being called? When I don't have the delegate method set the NSURLSession simply resends the request without any credentials... I'm stumped...

Edit: I've added manual credential handling to the didReceiveChallenge: method and it's being triggered for every request despite only a single NSURLSession being used.

2

There are 2 answers

3
angryCutlet On BEST ANSWER

i was just having the same problem where my URLSession would not use the stored credentials. Then i read the reference docs for NSURLSession. Basically what it says is that if you're implementing a custom delegate then you have to handle all the stuff yourself when the delegate methods get called. In other words saving the credentials is half the battle. You will be receiving the challenge every time the server requires authentication so in the didReceiveChallenge method you now have to manually extract the credentials to use and pass them to the completion handler. Let me know if that makes sense.

0
jordiz On

You need use NSURLSessionTaskDelegate or NSURLSessionDelegate.

//That is for Basic credentials https://developer.apple.com/documentation/foundation/nsurlsessiontaskdelegate/1411595-urlsession

or

//That is for session-level challenges—NSURLAuthenticationMethodNTLM, NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate, or NSURLAuthenticationMethodServerTrust https://developer.apple.com/documentation/foundation/nsurlsessiondelegate/1409308-urlsession

For example:

@interface MySessionClass : URLSession <URLSessionTaskDelegate>

@end

@implementation MySessionClass

#pragma mark - Delegate

//That method will call one time if you use NSURLCredentialPersistencePermanent but if you use other type that method it will call all the time.
- (void) URLSession:(NSURLSession *)session 
               task:(NSURLSessionTask *)task 
 didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
  completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {

if (challenge.previousFailureCount == 0) {
        NSURLCredential *credential = [NSURLCredential credentialWithUser:self.user password:self.password persistence:NSURLCredentialPersistencePermanent];
        completionHandler(NSURLSessionAuthChallengeUseCredential, credentials);
    } else {
        completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
    }
}

@end