Reputation: 2494
I'm trying to realise basic-authentication using URLSessionDelegate
and URLCredentials
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void)
Apple recommends not to write manually Authorization
header. So I'm trying to use URLCredentials
.
I'm doing very simple example in Swift Playground:
class Callback: NSObject {}
extension Callback: URLSessionDelegate {
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {
print("received challenge")
print(challenge.protectionSpace.authenticationMethod)
completionHandler(.performDefaultHandling, nil)
}
}
let callback = Callback()
var configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: callback, delegateQueue: nil)
let string = "http://demo0230490.mockable.io/test"
var request = URLRequest(url: URL(string: string)!)
session.dataTask(with: request) { (data, response, error) in
print("response")
print(response)
}.resume()
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
The problem is – I don't receive auth challenge.
If you go to http://demo0230490.mockable.io/test
in browser you will see the browser showing alert for basic auth.
From my mock http I return header like:
"Www-Authenticate" = (
"Basic realm=\"Access to MRM\""
);
Also I tried switching to https
(I mean https://demo0230490.mockable.io/test
) to check whether I'll receive auth challenge of type NSURLAuthenticationMethodServerTrust
.
And that works. That means that my delegate
is properly set and works in some circumstances.
So the question is:
Can anybody point the problem or provide the working example for basic auth using URLCredentials
(for example using https://www.mockable.io)?
Upvotes: 0
Views: 882
Reputation: 469
According to the documentation urlSession(_:didReceive:completionHandler:)
is called only in two situations:
- When a remote server asks for client certificates or Windows NT LAN Manager (NTLM) authentication, to allow your app to provide appropriate credentials
- When a session first establishes a connection to a remote server that uses SSL or TLS, to allow your app to verify the server’s certificate chain
When you are switching to https the second condition is met and therefore method is called.
There is two types of authentication challenges: session-level and non-session-level.
For non-session-level challenges URLSession calls urlSession(_:task:didReceive:completionHandler:)
. For session-level challenges URLSession calls urlSession(_:didReceive:completionHandler:)
.
Difference between session-level challenges and non-session-level challenges is described in the discussion section of urlSession(_:task:didReceive:completionHandler:)
documentation:
For session-level challenges—NSURLAuthenticationMethodNTLM, NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate, or NSURLAuthenticationMethodServerTrust—the NSURLSession object calls the session delegate’s urlSession(:didReceive:completionHandler:) method. If your app does not provide a session delegate method, the NSURLSession object calls the task delegate’s urlSession(:task:didReceive:completionHandler:) method to handle the challenge.
For non-session-level challenges (all others), the URLSession object calls the session delegate’s urlSession(:task:didReceive:completionHandler:) method to handle the challenge. If your app provides a session delegate and you need to handle authentication, then you must either handle the authentication at the task level or provide a task-level handler that calls the per-session handler explicitly. The session delegate’s urlSession(:didReceive:completionHandler:) method is not called for non-session-level challenges.
In your case you should implement non-session-level challenge handler:
extension Callback: URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
print("received task challenge")
}
}
Also there is working example on Apple-forum.
Upvotes: 2
Reputation: 171
You should use urlSession(_:task:didReceive:completionHandler:)
of URLSessionTaskDelegate
. Method you use is for connection-level challenge, not for app-level.
Upvotes: 2