NSErrorClientCertificateStateKey depuis autre classe

NSErrorClientCertificateStateKey depuis autre classe - iOS - Programmation

Marsh Posté le 02-08-2020 à 17:03:08    

Bonjour tout le monde  :hello:  
 
Je débute en programmation swift après m'être enfin acheté un mac. Je suis donc un bébé dans le domaine :D  
 
Après avoir suivi plusieurs tuto, je me lance dans un projet factice donc le but est de récupérer des données via un webservice. L'URL en question est sous couvert d'un certificat autosigné, donc quand on s'y connecte depuis swift j'ai le message suivant :
 

Code :
  1. 2020-08-02 16:41:00.345244+0200 Meteo3D[40325:3674569] Connection 1: default TLS Trust evaluation failed(-9807)
  2. 2020-08-02 16:41:00.345431+0200 Meteo3D[40325:3674569] Connection 1: TLS Trust encountered error 3:-9807
  3. 2020-08-02 16:41:00.345528+0200 Meteo3D[40325:3674569] Connection 1: encountered error(3:-9807)
  4. 2020-08-02 16:41:00.349079+0200 Meteo3D[40325:3674569] Task <68502971-2F6B-4A13-A89C-EDB632C75B09>.<1> HTTP load failed, 0/0 bytes (error code: -1202 [3:-9807])
  5. 2020-08-02 16:41:00.352081+0200 Meteo3D[40325:3674569] Task <68502971-2F6B-4A13-A89C-EDB632C75B09>.<1> finished with error [-1202] Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “meteo.mondomaine.com” which could put your confidential information at risk." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x60000357ccf0>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9807, NSErrorPeerCertificateChainKey=(
  6.     "<cert(0x7ff0b880c800) s: synology.com i: Synology Inc. CA>"
  7. ), NSUnderlyingError=0x6000009756e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x60000357ccf0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9807, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9807, kCFStreamPropertySSLPeerCertificates=(
  8.     "<cert(0x7ff0b880c800) s: synology.com i: Synology Inc. CA>"
  9. )}}, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “meteo.mondomaine.com” which could put your confidential information at risk., NSErrorFailingURLKey=https://meteo.mondomaine.com:1234/request/, NSErrorFailingURLStringKey=https://meteo.mondomaine.com:1234/request/, NSErrorClientCertificateStateKey=0}
  10. Optional(Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “meteo.mondomaine.com” which could put your confidential information at risk." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x60000357ccf0>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9807, NSErrorPeerCertificateChainKey=(
  11.     "<cert(0x7ff0b880c800) s: synology.com i: Synology Inc. CA>"
  12. ), NSUnderlyingError=0x6000009756e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x60000357ccf0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9807, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9807, kCFStreamPropertySSLPeerCertificates=(
  13.     "<cert(0x7ff0b880c800) s: synology.com i: Synology Inc. CA>"
  14. )}}, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “meteo.mondomaine.com” which could put your confidential information at risk., NSErrorFailingURLKey=https://meteo.mondomaine.com:1234/request/, NSErrorFailingURLStringKey=https://meteo.mondomaine.com:1234/request/, NSErrorClientCertificateStateKey=0})
  15. server error


 
Après pas mal de recherches, j'ai pu contourner le problème en ajoutant le code suivant à mon fichier Info.plist :
 

Code :
  1. <key>NSAppTransportSecurity</key>
  2. <dict>
  3.     <key>NSAllowsArbitraryLoads</key>
  4.     <true/>
  5.     <key>NSExceptionDomains</key>
  6.     <dict>
  7.         <key>example.com</key>
  8.         <dict>
  9.             <key>NSExceptionAllowsInsecureHTTPLoads</key>
  10.             <true/>
  11.             <key>NSIncludesSubdomains</key>
  12.             <true/>
  13.         </dict>
  14.     </dict>
  15. </dict>


 
J'ai ensuite créé la classe suivante pour pouvoir lancer des requêtes facilement dans mon projet, en contournant au passage le problème de certificat (partie "extension" ) :
 

Code :
  1. import Foundation
  2. extension AppDelegate: URLSessionDelegate {
  3.     public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
  4.        //Trust the certificate even if not valid
  5.        let urlCredential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
  6.        completionHandler(.useCredential, urlCredential)
  7.     }
  8. }
  9. struct NetworkRequest {
  10.     static let url: URL = URL(string: "https://meteo.mondomaine.com:1234/request/" )!
  11.     static let login: String = "login"
  12.     static let password: String = "password"
  13.    
  14.     static func execute(delegate: URLSessionDelegate?, action: String, data: Data?, callback: @escaping (_ mime: String?, _ data: Data?) -> Void){
  15.         let parameters = [
  16.             "log_ACTION": "1",
  17.             "log_USER": login,
  18.             "log_PSWD": password,
  19.             "action": action
  20.         ]
  21.         let postData = try? JSONSerialization.data(withJSONObject: parameters, options: [])
  22.         var request = URLRequest(url: url)
  23.         request.httpMethod = "POST"
  24.         request.allHTTPHeaderFields = [
  25.             "Content-Type": "application/json",
  26.             "cache-control": "no-cache"
  27.         ]
  28.         request.httpBody = postData!
  29.         let session = URLSession(configuration: URLSessionConfiguration.default, delegate: delegate, delegateQueue: nil)
  30.         let dataTask = session.dataTask(with: request as URLRequest) { (data, response, error) in
  31.             if (error != nil) {
  32.                 print(error as Any)
  33.             }
  34.             guard let httpresponse = response as? HTTPURLResponse,
  35.                 (200...299).contains(httpresponse.statusCode) else {
  36.                     print("server error" )
  37.                     callback(nil,nil)
  38.                     return
  39.             }
  40.             callback(response?.mimeType,data)
  41.         }
  42.         dataTask.resume()
  43.     }
  44. }


 
Résultat, depuis mon fichier ViewController.swift, j'ajoute le code suivant et j'obtiens bien mes données :
 

Code :
  1. NetworkRequest.execute(delegate: self, action: "lastData", data: nil) { (mimeType: String?, data: Data?) in
  2.     var liste: [Temperature] = [Temperature]()
  3.     if mimeType == "application/json",
  4.         let data = data {
  5.             do {
  6.                 let json = try JSONDecoder().decode([String:String].self, from: data)
  7.                 for (key, value) in json {
  8.                     if let temperature = Float(value) {
  9.                         liste.append(Temperature(label: key, value: temperature))
  10.                     }
  11.                 }
  12.             } catch {
  13.                 print(error)
  14.             }
  15.         }
  16.     //suite du traitement
  17. }


 
Tout pourrait s'arrêter ici et je n'aurai pas eu à poster sur le forum :love: Mais voilà, j'aime me prendre la tête et j'ai créé une classe pour pouvoir gérer une CollectionView que j'ai ajouté sur mon storyboard :
 

Code :
  1. import UIKit
  2. class TemperatureController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, URLSessionDelegate {
  3.    
  4.     @IBOutlet weak var temperaturesCollection: TemperatureController!
  5.     let identifier = "temperatureCell"
  6.     var items = [Temperature]()
  7.    
  8.     override func viewDidLoad() {
  9.         super .viewDidLoad()
  10.         //Récupération des données
  11.     }
  12.     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  13.         return items.count
  14.     }
  15.    
  16.     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  17.         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath as IndexPath) as! TemperatureViewCell
  18.         //Mise en forme de ma ViewCell
  19.         return cell
  20.     }
  21.     func collectionView(_ collectionView: UICollectionView,
  22.                         layout collectionViewLayout: UICollectionViewLayout,
  23.                         sizeForItemAt indexPath: IndexPath) -> CGSize {
  24.         return CGSize(width: collectionView.bounds.size.width, height: 100)
  25.     }
  26.     func collectionView(_ collectionView: UICollectionView,
  27.                         layout collectionViewLayout: UICollectionViewLayout,
  28.                         minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
  29.         return 1.0
  30.     }
  31.     func collectionView(_ collectionView: UICollectionView, layout
  32.         collectionViewLayout: UICollectionViewLayout,
  33.                         minimumLineSpacingForSectionAt section: Int) -> CGFloat {
  34.         return 1.0
  35.     }
  36. }


 
Et j'ai affecté cette classe au ViewController de mon storyboard afin de ne plus passer par ViewController.swift mais par TemperatureController.swift.  
 
Mon problème le voici : si j'utilise ma commande de récupération de données dans cette nouvelle classe, j'obtiens alors l'erreur de certificat que j'avais à l'origine... Message que je n'obtiens pas quand j'exécute cette même commande dans ViewController.swift.
 
J'imagine qu'il doit y avoir une histoire de contexte ? Ou bien une subtilité que je ne comprend pas encore...
 
Quelqu'un a une idée ?  :sweat:


Message édité par matheo265 le 02-08-2020 à 17:04:35
Reply

Marsh Posté le 02-08-2020 à 17:03:08   

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed