Saturday, November 17, 2018

Handle ios NSURLSession authentication request

Some notes about ios NSURLSession authentication

1. Session and task delegate
Although NSURLSessionTaskDelegate can be used to handle task specific event, there is no api to allow setting a task delegate for each individual data task when it is created.
Both NSURLSessionDelegate and NSURLSessionTaskDelegate is set when calling NSURLSession
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id<NSURLSessionDelegate>)delegate
method. That means the NSURLSessionDelegate and NSURLSessionTaskDelegate must be implemented in the same object if you need to handle both them in your app.

Note, both NSURLSessionDelegate and NSURLSessionTaskDelegate defines the didReceiveChallenge method for application to handle the authentication challenge.

For NSURLAuthenticationMethodServerTrust and NSURLAuthenticationMethodClientCertificate authentication methods, if didReceiveChallenge is implemented in NSURLSessionDelegate, then the session delegate will be called. Otherwise, the didReceiveChallenge method implemented in NSURLSessionTaskDelegate will be called.

For NSURLAuthenticationMethodDefault and NSURLAuthenticationMethodHTTPBasic authentication method, they will only be called on NSURLSessionTaskDelegate's didReceivedChallenge method, and if not implemented there, the request will fail and will not invoke the NSURLSessionDelegate's implementation.


2. Handle NSURLAuthenticationMethodServerTrust authentication
For NSURLAuthenticationMethodServerTrust, if you just want the same bebaviour of how Mobile Safari handles the server trust authentication, then it is better to just let ios default handler to handle it by calling the completionHandler with below parameter

completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil)
You only need to implement your customization logic if you want to trust all server cert or implement server certificate pin function.

3. Timeout for user interaction during authentication handling
When handling authentication challenge, you may want to show some UI to allow user interaction, such as trusting self sign server cert for server trust, or picking a client certificate for client certification challenge. 

However, this does not work for NSURLAuthenticationMethodServerTrust and NSURLAuthenticationMethodClientCertificate authentication methods. As for most server, if the authentication challenge's completion block is not called in few seconds, the server will abort the TCP connection, and then the client will get the same challenge again (the previousFailureCount is still 0 for the new challenge). At this moment, even if the app handles the second challenge properly, the original datatask request cannot finish, and the datatask's didCompleteWithError method is never called. So in order to handle the case, if the application gets the second pending request before the first one's completion block is called, the app should cancel the current data request, so the datatask's didCompleteWithError will be called to finish the data request.

As a result, in order to properly handle NSURLAuthenticationMethodServerTrust and NSURLAuthenticationMethodClientCertificate challenge, the application should avoid any user interaction, so that the app can finish the authentication and call the completion block in 1 or 2 seconds.

Note this behavior is different from NSURLAuthenticationMethodHTTPBasic (or NSURLAuthenticationMethodDefault) authentication methods. As for NSURLAuthenticationMethodHTTPBasic challenge, usually user needs to input the username and password, the test shows if the completion block is not called, the server will just wait without automatically aborting the connection, until it is called later.

This issue for not calling the completion block for NSURLAuthenticationMethodServerTrust and NSURLAuthenticationMethodClientCertificate challenge is even more serious for WKWebView's didReceiveAuthenticationChallenge method
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;
If the completionHandler is not called in few seconds, then the app will just crash.

By the way, client certificate mutual authentication for wkwebview is supported in iOS 12.

No comments:

Post a Comment