Hellow, I was using one iPhone with version 12.4 to run application for development. Suddely when I updated from version 12.4 to 13.1, one of my http rest api just stopped working and it returns me error:
"
019-09-25 16:56:56.578750+0200 SmaforetagarnasAPP[487:44045] task challenge NSURLAuthenticationMethodServerTrust
FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://appapi2.bankid.com/rp/v5/auth, NSErrorFailingURLKey=https://appapi2.bankid.com/rp/v5/auth, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <1FDB0948-469A-4333-BA23-9CAB3452F59B>.<1>"
), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <1FDB0948-469A-4333-BA23-9CAB3452F59B>.<1>, NSLocalizedDescription=cancelled}
2019-09-25 16:56:56.590973+0200 SmaforetagarnasAPP[487:44045] Task <1FDB0948-469A-4333-BA23-9CAB3452F59B>.<1> HTTP load failed, 0/0 bytes (error code: -999 [1:89])
2019-09-25 16:56:56.592230+0200 SmaforetagarnasAPP[487:44045] Connection 3: unable to determine interface type without an established connection
2019-09-25 16:56:56.592313+0200 SmaforetagarnasAPP[487:44045] Connection 3: unable to determine fallback status without a connection
"
Im using Alamofire SessionManager to make the http call
The http call requires certificate and here is my code:
Calling function:
func authenticate(completion: @escaping ModelCompletion<Bool>) {
let configuration = URLSessionConfiguration.default
// configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
let sessionManager = Alamofire.SessionManager(
configuration: configuration)
let endUserIp: String = self.getIPAddress() ?? "192.168.8.103"
let parameters: Parameters = ["endUserIp": endUserIp]
//set condition
// certificatePolicies to “1.2.752.78.1.5” to restrict the order to Mobile BankID only.
var header = HTTPHeaders()
header["Content-Type"] = "application/json"
sessionManager.request("https://appapi2.bankid.com/rp/v5/auth", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: header)
.validate()
.responseJSON { [weak self] data in
print(data)
guard let strongSelf = self else { return }
switch data.result {
case .success(let value):
let bankIDJson = JSON(value)
strongSelf.autoStartToken = bankIDJson[RequestJsonTag.autoStartToken.rawValue].string
strongSelf.orderRef = bankIDJson[RequestJsonTag.orderRef.rawValue].string
SessionManager.sharedInstance.orderRef = strongSelf.orderRef!
completion(ModelResult.success(true))
case .failure(let error):
completion(ModelResult.failure(error: error.localizedDescription))
}
}.session.finishTasksAndInvalidate()
// Seeion delegate
let delegate = sessionManager.delegate
self.didReceiveSessionManagerChallenge(delegate: delegate)
}
Once I receive Challenge this function will get called:
private func didReceiveSessionManagerChallenge(delegate: SessionDelegate) {
// Did Receive Challenge
delegate.sessionDidReceiveChallenge = { urlSession, challenge in
let protectionSpace = challenge.protectionSpace
NSLog("task challenge %@", protectionSpace.authenticationMethod)
switch (protectionSpace.authenticationMethod, protectionSpace.host) {
case (NSURLAuthenticationMethodServerTrust, "appapi2.bankid.com"):
if self.shouldTrustBankID(protectionSpace: protectionSpace) {
let credential = URLCredential(trust: protectionSpace.serverTrust!)
return (.useCredential, credential)
} else {
return (.cancelAuthenticationChallenge, nil)
}
case (NSURLAuthenticationMethodClientCertificate, "appapi2.bankid.com"):
let identity = Bundle.main.identityForBankIDPayment(named: "smaforetagarnasrpca", password: "Helsingborg#1977")
let credential = URLCredential(identity: identity, certificates: nil, persistence: .forSession)
return (.useCredential, credential)
default:
return (.performDefaultHandling, nil)
}
}
}
Here is extension once it requires the certificate:
extension Bundle {
func certificateForBankIDPayment(named: String) -> SecCertificate {
let cerURL = self.url(forResource: named, withExtension: "der")!
let cerData = try! Data(contentsOf: cerURL)
return SecCertificateCreateWithData(nil, cerData as NSData)!
}
func identityForBankIDPayment(named: String, password: String) -> SecIdentity {
let p12URL = Bundle.main.url(forResource: named, withExtension: "p12")!
let p12Data = try! Data(contentsOf: p12URL)
var importResult: CFArray? = nil
let err = SecPKCS12Import(
p12Data as NSData,
[kSecImportExportPassphrase: password] as NSDictionary,
&importResult)
assert(err == errSecSuccess)
let identityDicts = importResult! as! [[String:Any]]
return identityDicts.first![kSecImportItemIdentity as String]! as! SecIdentity
}
}
My Info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Småföretagarnas</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.curamet.SmaforetagarnasAPP</string>
<key>CFBundleURLSchemes</key>
<array>
<string>sfrapp</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>appapi2.bankid.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>MainTapBarView</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
P.s. I updated my Xcode till support the latest iOS 13.1 version as well.