I've read the Technical QA regarding TLS caching and I'm attempting to workaround the issue of TLS server trust caching using two NSURLSessions but I'm not having success.
My test project setup is fairly simple:
Two separate NSURLSessions using ephemeralSessionConfiguration:
self.session1 = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(), delegate: self, delegateQueue: self.delegateQueue)
self.session2 = NSURLSession(configuration: NSURLSessionConfiguration.ephemeralSessionConfiguration(), delegate: self, delegateQueue: self.delegateQueue)
Two NSURLSessionDataTasks (one for each session) to the same URL (https://www.apple.com). The second one starts after a 5 second delay.
let url = NSURL(string: "https://www.apple.com")
let task1 = session1.dataTaskWithURL(url)
task1.resume()
let task2 = self.session2.dataTaskWithURL(url)
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(5 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
task2.resume()
}
And the session:didReceiveChallenge: delegate method implementation
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void) {
let sessionName = session == self.session1 ? "session1" : "session2"
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
NSLog("didReceiveChallenge for \(sessionName) at \(challenge.protectionSpace.host) \(challenge.protectionSpace.port)")
let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)
} else {
NSLog("didReceiveChallenge \(challenge.protectionSpace.authenticationMethod)")
completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)
}
}
When I run the application both tasks complete successfully, however session:didReceiveChallenge: is only invoked once (for task1, session1). Based on the note in the QA1727, I was expecting it to be invoked twice (one time per session).
My questions:
1. Am I doing something wrong or am I misunderstanding the note in QA1727? I've tried different NSURLSessionConfiguration types but I see the same behaviour.
2. If this is the expected behaviour, is there any way to view the (cached) serverTrust object that is being used during the connection?
The platform is iOS and I'm targeting iOS 8.0+.
I recommend you testing with iOS 9 beta; this feature got broken at some point (I think with iOS 8) and wasn’t fixed until iOS 9 )-:
Often session:didReceiveChallenge: is invoked twice, sometimes just once, and sometimes not at all!
Make sure to disable caching on your requests, otherwise you might be getting answers from the cache.
Share and Enjoy
—
Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"