I am attempting to download a PDF from a URL.
private func downloadSessionWithFileURL(_ url: URL){
var request = URLRequest(url: url)
request.addValue("gzip, deflate", forHTTPHeaderField: "Accept-Encoding")
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
session.downloadTask(with: request).resume()
}
This calls its delegate method
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0 {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
if let serverTrust = challenge.protectionSpace.serverTrust {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
} else {
print("unknown state. error: \(String(describing: challenge.error))")
}
}
The URLAuthenticationChallenges protectionSpace is always serverTrust. When the URL of the PDF is attempted to be accessed it redirects user to a login screen. I would have thought there would be another call to
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
requiring user to enter their credentials but there isn't. So the download task attempts to download the contents of the redirected URL which is a login screen.
My Questions are.
What triggers a URLAuthenticationChallenge for a username and password. is it a specific header value in the HTML?
Which URLAuthenticationChallenge protectionSpace should I be expecting for a username password request from a server.
There are two different delegate protocols: for the URLSession itself, and its tasks.
URLSessionDelegate has: public func urlSession(_:didReceive:completionHandler:)
URLSessionTaskDelegate has: public func urlSession(_:task:didReceive:completionHandler:)
The URLSessionDelegate is used for server trust issues (e.g. allowing SSL trust when running through Charles or other proxy). The URLSessionTaskDelegate is used for authentication of an individual task.
So to get your authentication challenge, add this to your class:
extension MyClass: URLSessionTaskDelegate {
public func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodDefault ||
challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
let credential = URLCredential(user: self.basicAuthUserName,
password: self.basicAuthPassword,
persistence: .forSession)
completionHandler(.useCredential, credential)
}
else {
completionHandler(.performDefaultHandling, nil)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With