0

Je suis perplexe: mon application doit se connecter à un serveur qui utilise des certificats auto-signés pour HTTPS et requiert une authentification côté client. Pire encore, j'ai réellement besoin le lecteur multimédia iOS pour se connecter à ce serveur, donc j'ai suivi Apple instruction pour cela à la lettre:NSURLCredentialStorage setDefaultCredential: ne fonctionne pas pour [NSURLSession sharedSession]

credential = [NSURLCredential credentialWithIdentity:identity certificates:certs persistence:NSURLCredentialPersistenceForSession]; 
NSURLProtectionSpace *space = [[NSURLProtectionSpace alloc] initWithHost:@"server.com" 
                    port:0 
                   protocol:NSURLProtectionSpaceHTTPS 
                    realm:nil 
                authenticationMethod:NSURLAuthenticationMethodClientCertificate]; 
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:space]; 

Mais il ne va pas fonctionner. J'ai donc essayé de faire une demande au serveur manuellement:

NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://server.com"] 
             completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
              NSLog(@"Done : %@", error ? error : @"OK"); 
             }]; 

tout ce que je reçois est cette erreur:

2016-06-13 08:22:37.767 TestiOSSSL[3172:870700] CFNetwork SSLHandshake failed (-9824 -> -9829) 
2016-06-13 08:22:37.793 TestiOSSSL[3172:870700] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9829) 
2016-06-13 08:22:37.815 TestiOSSSL[3172:870685] Done : Error Domain=NSURLErrorDomain Code=-1206 "The server “ server.com” requires a client certificate." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x13de519b0>, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9829, NSUnderlyingError=0x13de4f280 {Error Domain=kCFErrorDomainCFNetwork Code=-1206 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=1, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x13de519b0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9829, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9829, kCFStreamPropertySSLPeerCertificates=<CFArray 0x13dda0a70 [0x1a0dc2150]>{type = immutable, count = 2, values = (
    0 : <cert(0x13dda4970) s: Server.com i: Localhost CA> 
    1 : <cert(0x13dda50d0) s: Localhost CA i: Localhost CA> 
)}}}, NSErrorPeerCertificateChainKey=<CFArray 0x13dda0a70 [0x1a0dc2150]>{type = immutable, count = 2, values = (
    0 : <cert(0x13dda4970) s: Server.com i: Localhost CA> 
    1 : <cert(0x13dda50d0) s: Localhost CA i: Localhost CA> 
)}, NSLocalizedDescription=The server “server.com” requires a client certificate., NSErrorFailingURLKey=https://server.com/, NSErrorFailingURLStringKey=https://server.com/, NSErrorClientCertificateStateKey=1} 

Maintenant, si je mets mon propre NSURLSession et utilise le URLSession: didReceiveChallenge: completionHandler: rappel:

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; 
theSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; 
NSURLSessionDataTask *task = [theSession dataTaskWithURL:[NSURL URLWithString:@"https://server.com"] 
             completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
              NSLog(@"Done : %@", error ? error : @"OK"); 
             }]; 

puis:

- (void)URLSession:(NSURLSession *)session 
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, 
          NSURLCredential *credential))completionHandler 
{ 
    NSLog(@"Asking for credential"); 
    NSURLCredential *conf = [session.configuration.URLCredentialStorage defaultCredentialForProtectionSpace:challenge.protectionSpace]; 
    completionHandler(NSURLSessionAuthChallengeUseCredential, conf); 
} 

Notez que j'utilise [session.configuration.URLCredentialStorage defaultCredentialForProtectionSpace: challenge.protectionSpace], ce qui est ce que je suppose que l'implémentation par défaut de NSURLSession fait quand il obtient un défi d'authentification.

Cela fonctionne, pour cette connexion particulière! Ce qui prouve que les informations d'identification sont correctes et qu'elles sont correctement enregistrées en tant que données d'identification par défaut dans le NSURLCredentialStorage par défaut. Mais toute solution tournant autour du didReceiveChallenge: callback n'est pas bonne parce que je ne peux pas contrôler quelle NSURLSession le lecteur multimédia utilise.

J'ai essayé le hack CustomHTTPProtocol et cela ne fonctionne pas non plus.

Une suggestion? Je suis passé par tous les messages similaires sur SO, je ne trouve pas de solution pour cela. Ce post est vraiment proche, mais la réponse acceptée n'a pas de sens pour moi et contredit clairement la documentation d'Apple.

Répondre

0

Bien que de nombreuses fonctionnalités soient partagées entre la session par défaut et NSURLConnection, il semble que ce bit ne l'est pas. Avez-vous essayé d'appeler cette méthode sur [NSURLSession sharedSession].configuration.URLCredentialStorage?

L'autre possibilité est que les demandes se déroulent dans une tâche distincte, auquel cas il ne sera peut-être pas possible de le faire de la manière que vous essayez, car cela impliquera une session partagée différente. Si c'est le cas, vous devrez probablement stocker vous-même les informations d'identification dans le trousseau et espérer que l'autre processus partagera le trousseau et récupérera les informations d'identification correctement.

+0

Merci pour la suggestion, oui, j'ai essayé de l'appeler sur le sharedSession, pas de joie. Dans tous les cas, l'utilisation du stockage des informations d'identification partagées ne fonctionnera jamais dans mon cas, car iOS MediaPlayer ne fonctionne pas du tout dans mon processus, il est complètement isolé dans un processus séparé et partage uniquement l'écran avec mon application. La seule solution que j'ai pu trouver qui a réellement fonctionné était d'installer un proxy HTTP dans mon application qui se posait en serveur pour le lecteur multimédia et renvoyait les requêtes reçues au serveur réel, en gérant les informations d'identification sur sa propre connexion. Clunky :-( –

+0

Ouais, c'est un problème pour les gens qui font des choses avec des vues web, si vous n'avez pas déjà, déposer un bug avec Apple et demander un moyen de fournir des informations d'identification au lecteur multimédia. ont été un problème récurrent pendant de nombreuses années.Il y a toujours des hacks dans un de mes sites Web pour contourner le fait que la lecture vidéo intégrée de Safari ne pouvait pas passer les références d'authentification de base ou de digest il y a quelques années. J'ai déposé un bogue, et ils l'ont finalement corrigé, mais il est clair que ce n'est pas un modèle d'utilisation auquel ils pensent beaucoup. Déposer un bug pour leur rappeler que l'authentification est importante. – dgatwood