Kashish Goel Kashish Goel - 1 month ago 20
iOS Question

URLSession delegates not called after authentication challenge

I'm making a post call to a server and I kept getting the error that the server certificate was invalid, so after researching I found that i must trust the server using authentication challenge. This goes through perfectly fine (I print the authentication challenge to make sure it does) but the rest of the call does not go through and i cannot get information back from my server, nothing happens after the authentication challenge, normally I'd expect to be returned data. However nothing happens and none of my urlsessiondatadelegates are called (checked with breaks).

Can anyone spot why it may be? Code:

var request = URLRequest(url: URL(string: "https://45.56.105.97:7915/search-v2")!)
request.httpMethod = "POST"
request.addValue("Basic ***********", forHTTPHeaderField: "Authorization")

let task = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue.main)
task.dataTask(with: request) { (data, response, error) in
print(error)
print(data)
if let responseData = NSString(data: data!, encoding: String.Encoding.utf8.rawValue){
print("data: \(responseData)")
self.parseXML(data!)

}
}.resume()


delegate methods:

func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
print("did autherntcationchallenge = \(challenge.protectionSpace.authenticationMethod)")

if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
print("send credential Server Trust")
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
challenge.sender!.use(credential, for: challenge)

}else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic{
print("send credential HTTP Basic")
let defaultCredentials: URLCredential = URLCredential(user: "username", password: "password", persistence:URLCredential.Persistence.forSession)
challenge.sender!.use(defaultCredentials, for: challenge)

}else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM{
print("send credential NTLM")

} else{
challenge.sender!.performDefaultHandling!(for: challenge)
}

}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("Data received: \(data)")
}

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {

print("Response received: \(response)")
}

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("something went wrong: \(error)")
}

func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
print("rep: \(response)")
}


After running, all i get printed is:

did autherntcationchallenge = NSURLAuthenticationMethodServerTrust
send credential Server Trust

I've also seen conversations about how I can only use either a closure or delegate methods for retrieving data/not both. I've tried everything with no success.

**Also I know I shouldnt just be blindly trusting the server, but I am trying to figure out why I cannot receive data back, I am aware this has serious security flaws.

Answer

There are two problems:

  • As Rob already mentioned in a comment, you aren't calling the completion handlers in any of your delegate methods. This means that the connection will stop making progress at that point.
  • You're calling methods on the challenge sender to provide credentials. That would work with NSURLConnection, but NSURLSession requires you to do it by calling the completion handler. Otherwise, things will break very badly, IIRC, e.g.

        completionHandler(.PerformDefaultHandling, nil)