Übersicht:
Sie das Client-SSL-Zertifikat auf dem Gerät Schlüsselbund installiert hat.
Safari.app und Mail.app können auf diesen Schlüsselbund zugreifen, die iOS-App dagegen nicht.
Der Grund ist, dass die Apps, die wir entwickeln, Sandboxed sind und keine Zugriffsrechte außerhalb davon im nicht-jailbroken Gerät haben.
Da Safari Zugriff darauf hat, hatte es keine Probleme, sich mit der Serverherausforderung zu verbinden und zu authentifizieren.
Lösung:
Fügen Sie die exportierte P12-Datei mit dem App-Bundle und beziehen sich auf das richtige Client-Zertifikat finden der Server war auf der Suche for.It ist eigentlich eine Abhilfe. Die Hardcoding ist der zuverlässige Weg, um die P12-Datei zu greifen.
Implementation:
betreffende Verfahren ist in willSendRequestForAuthenticationChallenge
NSURLConenction delegate
. Sie müssen den Challenge-Typ NSURLAuthenticationMethodClientCertificate
berücksichtigen, um die Serverherausforderung zu bewältigen. Hier haben wir die Magie implementiert, um die korrekte Zertifikatsidentität aus der eingebetteten P12-Datei zu extrahieren. Code ist unter
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] > 0) {
//this will cause an authentication failure
[[challenge sender] cancelAuthenticationChallenge:challenge];
NSLog(@"Bad Username Or Password");
return;
}
//this is checking the server certificate
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
SecTrustResultType result;
//This takes the serverTrust object and checkes it against your keychain
SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result);
//if we want to ignore invalid server for certificates, we just accept the server
if (kSPAllowInvalidServerCertificates) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge];
return;
} else if(result == kSecTrustResultProceed || result == kSecTrustResultConfirm || result == kSecTrustResultUnspecified) {
//When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server
[challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge];
return;
}
} else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
//this handles authenticating the client certificate
/*
What we need to do here is get the certificate and an an identity so we can do this:
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:myCerts persistence:NSURLCredentialPersistencePermanent];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
It's easy to load the certificate using the code in -installCertificate
It's more difficult to get the identity.
We can get it from a .p12 file, but you need a passphrase:
*/
NSString *p12Path = [[BundleManager bundleForCurrentSkin] pathForResource:kP12FileName ofType:@"p12"];
NSData *p12Data = [[NSData alloc] initWithContentsOfFile:p12Path];
CFStringRef password = CFSTR("PASSWORD");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef p12Items;
OSStatus result = SecPKCS12Import((CFDataRef)p12Data, optionsDictionary, &p12Items);
if(result == noErr) {
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(p12Items, 0);
SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);
SecCertificateRef certRef;
SecIdentityCopyCertificate(identityApp, &certRef);
SecCertificateRef certArray[1] = { certRef };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
CFRelease(certRef);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identityApp certificates:(NSArray *)myCerts persistence:NSURLCredentialPersistencePermanent];
CFRelease(myCerts);
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
} else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault || [[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodNTLM) {
// For normal authentication based on username and password. This could be NTLM or Default.
DAVCredentials *cred = _parentSession.credentials;
NSURLCredential *credential = [NSURLCredential credentialWithUser:cred.username password:cred.password persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
//If everything fails, we cancel the challenge.
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
Referenz: Ref1, Ref2, Ref3
hoffte, das hilft
Erhalten Sie Ihre Websites und Dienste mit selbst signierten Zertifikat für https Sicherung? Oder versuchen Sie, das Zertifikat als Mittel zur Authentifizierung zu verwenden, anstatt Benutzernamen und Passwort zu verwenden? –
Wir möchten das Zertifikat verwenden, um den Benutzer zu authentifizieren (anstelle von Benutzername/Passwort). –
Welche Lösung verwenden Sie für Ihre Webanwendungen NTLM oder Kerberos-Authentifizierung? –