How to implement URLSessionDelegate to allow self signed certificate? (iOS/Swift) - ios

I'm trying to use SocketIO to connect to a server running on my workstation from an iOS/Swift app. The certificate I'm using on the server is self-signed and I'm using the following code to connect:
import UIKit
import SocketIO
class ViewController: UIViewController, URLSessionDelegate {
let socketManager = SocketManager(socketURL: URL(string:"https://my_server_url")!,
config: [SocketIOClientOption.log(true),
SocketIOClientOption.forcePolling(true),
SocketIOClientOption.selfSigned(true),
SocketIOClientOption.sessionDelegate(self)])
func URLSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?)
-> Void) {
print("didReceive challenge")
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
Unfortunately I get the following error: Argument type '(ViewController) -> () -> (ViewController)' does not conform to expected type 'URLSessionDelegate' where I set the sessionDelegate to self.
I'm not sure why that is the case since all funcs in URLSessionDelegate are optional and I thought that my implementation of URLSession conformed to the protocol. I apologise if I'm doing something dumb but I'm new to iOS and Swift and I've been looking for an answer for hours with no success!

func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// Pass test server with self signed certificate
if challenge.protectionSpace.host == "self-signed-certificate.server.com" {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
} else {
completionHandler(.performDefaultHandling, nil)
}
}

Related

URLSession delegate is not working on swift 4.2

This code is working fine on Swift version 3, I'm not able to make it work on Swift 4
func rest() {
let path = "https://localhost:8443/someservice"
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json:JSON = JSON(data: data!)
if let c = json["content"].string {
print(c)
}
})
task.resume()
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}
You may need latest syntax
func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
Your Delegate method is right for below swift 4.0 version but it's wrong for swift 4.0 and higher.
Here is working code, You need to use like this.
class ViewController: UIViewController,URLSessionDelegate {
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
}

URLSession dataTask -- Could not connect to the server

I'm trying to load data from the following url:: https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4
Function
func download() {
let configuration = URLSessionConfiguration.default
self.session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
self.downloadTask = self.session.dataTask(with: self.url)
self.downloadTask.resume()
}
Delegates
// NOT GETTING CALLED
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
// NOT GETTING CALLED
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
self.completion(self, data)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print(error)
// THIS IS GETTING CALLED WITH ERROR: Could not connect to the server. FULL ERROR BELOW.
}
func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
print(error)
}
Full Error
(Error Domain=NSURLErrorDomain Code=-1004 \"Could not connect to the
server.\" UserInfo={NSUnderlyingError=0x1c0658cc0 {Error
Domain=kCFErrorDomainCFNetwork Code=-1004 \"(null)\"
UserInfo={_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}},
NSErrorFailingURLStringKey=https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4,
NSErrorFailingURLKey=https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4,
_kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=61, NSLocalizedDescription=Could not connect to the server.})
Below is the ATS configuration
Any help would be really appreciated!
Note The above URL works in Chrome but fails to load in Safari

ios download file with data chunks delegate

I want to download a file from a certain url .
what I need is the data delegate ( the delegate which gives me the downloaded data) .
I implemented the :
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
delegate but it doesn't get called .
my code is :
func download(url: URL)
{
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
let task = session.downloadTask(with: url)
task.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
print("apending ")
self.dataaa.append(data)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: #escaping (URLSession.ResponseDisposition) -> Void) {
print("here")
}
the two delegate functions don't get called !
You're using the delegate methods for a data task, but you're creating a download task. Those two task types work differently and use completely different delegate methods.

Swift 3 URLSession with URLCredential not working

I am doing a URLSession, but the URL requires credentials.
I have this whole method here that is trying to do a URLSession with URLCredentials:
func loginUser(_ username: String, password: String, completion: #escaping (_ result: Bool) -> Void)
{
//Create request URL as String
let requestString = String(format:"%#", webservice) as String
//Covert URL request string to URL
guard let url = URL(string: requestString) else {
print("Error: cannot create URL")
return
}
//Convert URL to URLRequest
let urlRequest = URLRequest(url: url)
print(urlRequest)
//Add the username and password to URLCredential
credential = URLCredential(user:username, password:password, persistence: .forSession)
//Setup the URLSessionConfiguration
let config = URLSessionConfiguration.default
//Setup the URLSession
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
//Prepare the task to get data.
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
DispatchQueue.main.async(execute: {
if(error == nil)
{
completion(true)
}
else
{
completion(false)
}
})
})
//Run the task to get data.
task.resume()
}
and here are my URLSessionDelegate Methods:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
/**
Requests credentials from the delegate in response to an authentication request from the remote server.
*/
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential,credential)
}
I notice when I debug this in this 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)
}
else
{
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
}
}
That this method gets called twice and when it hits this line for the second time:
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:challenge.protectionSpace.serverTrust!))
I get this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
and then my app crashes! How do I fix this error?
the crash is due to challenge.protectionSpace.serverTrust being nil when you attempt to force unwrap it.
you should unwrap serverTrust and handle it being nil. my guess is that when serverTrust is nil challenge.error has a value.
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount > 0 {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
} else if let serverTrust = challenge.protectionSpace.serverTrust {
completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: serverTrust))
} else {
print("unknown state. error: \(challenge.error)")
// do something w/ completionHandler here
}
}
Here is syntax as per swift 3.
Just verify firstly in which part of the delegate method it entered
open func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void){
var disposition: URLSession.AuthChallengeDisposition = URLSession.AuthChallengeDisposition.performDefaultHandling
var credential:URLCredential?
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
if (credential != nil) {
disposition = URLSession.AuthChallengeDisposition.useCredential
}
else{
disposition = URLSession.AuthChallengeDisposition.performDefaultHandling
}
}
else{
disposition = URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
}
if (completionHandler != nil) {
completionHandler(disposition, credential);
}
}
Here is a slightly refactored from the above answers, a delegate class checks the number of failures, uses default unless the challenge is of type server trust it then calls the completion with trust credential:
class AuthSessionDelegate: NSObject, URLSessionDelegate {
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let authMethod = challenge.protectionSpace.authenticationMethod
guard challenge.previousFailureCount < 1, authMethod == NSURLAuthenticationMethodServerTrust,
let trust = challenge.protectionSpace.serverTrust else {
completionHandler(.performDefaultHandling, nil)
return
}
completionHandler(.useCredential, URLCredential(trust: trust))
}
}

Debugging URLSession (in iOS 10)

I am having trouble with a URLSession that creates and resumes a URLSessionDataTask in the sense that I expect subsequent calls to certain methods in the session's (and task`s) delegate but apparently no such calls occur.
How can I debug URLSession in a situation like this? For instance, can I request log output from it e.g. to find out when it sends or receives HTTP traffic or when it attempts to call a method in the delegate but cannot find the relevant implementation (e.g. because the method signature in the implementation may be slightly off).
Delegate methods are now (starting to be) called as expected. The solution consisted in copying method signatures from the very code base of URLSessionDataDelegate and URLSessionTaskDelegate (not their documentation) to ensure exact matches. Looking at device log output (lines with marked libsystem_network.dylib and <Debug>) was also helpful. The employed methods signatures are now as follows:
public func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {
// ...
}
public func urlSession(_ session: URLSession,
dataTask: URLSessionDataTask,
didReceive data: Data) {
// ...
}
public func urlSession(_ session: URLSession,
task: URLSessionTask,
didCompleteWithError error: Error?) {
// ...
}

Resources