我正在尝试连接到需要客户端证书的服务器。 因此,浏览此服务器时发生的正常事件流是Web浏览器(Safari和Chrome)提示用户选择证书并重试该操作。
那么如何在Cocoa项目中的嵌入式WebView中实现这一目标呢?
到目前为止,我已确定在didFailProvisionalLoadWithError
方法中引发了错误:
- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
NSLog(@"webView:didFailProvisionalLoadWithError:forFrame:");
NSLog(@" error = %@", error);
}
错误确实是error = Error Domain=NSURLErrorDomain Code=-1206 UserInfo=0x1006a8030 "The server “myserver.xxx” requires a client certificate.
但是,如何显示对话框以便用户可以从钥匙串中选择证书?
答案 0 :(得分:3)
问题解决了。
WebView组件的(已知)问题是罪魁祸首。 与Apple一起开通了DTS支持票,并获得了解决方法。
编辑: 这是DTS的解决方法(我不知道这是否仍然有效,因为它是3年前):
<马格努斯好吧,我有机会看到这一点,我知道会发生什么 上。在我们开始谈论WebView之前,我需要为您提供帮助 NSURLConnection使用的委托方法的速度,即 用于实际从'net上加载数据的底层API。 NSURLConnection开始支持单一身份验证 委托回调,-connection:didReceiveAuthenticationChallenge:,to 它通过了各种身份验证挑战 当时支持(用户名/密码样式的挑战)。在Mac中 OS X 10.6(和iOS 3.0)NSURLConnection已得到增强,可支持两个 TLS连接的其他类型的身份验证挑战:o 客户身份挑战 (NSURLAuthenticationMethodClientCertificate),给代表 为给定的TLS连接选择客户端身份的机会o 服务器信任挑战(NSURLAuthenticationMethodServerTrust),给予 委托有机会覆盖服务器信任评估 对于给定的TLS连接出于兼容性原因,它不是 可以将这些挑战传递给所有代表 环境,所以NSURLConnection引入了一个新的委托回调, -connection:canAuthenticateAgainstProtectionSpace :,允许代表选择接受这些挑战。 * * *现在,让我们把它带回你的应用程序。正如我所提到的,WebView使用 NSURLConnection和每个连接充当连接 代表。它拦截身份验证挑战并将其传递给 它的资源加载委托。这适用于老学校 身份验证的挑战,因为WebView没有获得挑战 必须做任何特别的事;但它无法进行TLS连接 身份验证的挑战,因为代表必须选择那些 挑战。你真正需要的是WebView版本 'canAuthenticateAgainstProtectionSpace'认证挑战。 好吧,事实证明这实际上是实现的。在寻找 通过WebView的开源,我发现有私有 代表回调, -webView:资源:canAuthenticateAgainstProtectionSpace:forDataSource :, 这正是你想要的。 http://www.opensource.apple.com/source/WebKit/WebKit-7533.20.25/mac/WebView/WebResourceLoadDelegatePrivate.h 如果您实现该方法,则可以选择加入客户端标识 身份验证挑战,并基于该挑战,呈现用户 允许用户选择身份的界面。我做了原型 这在您的测试应用程序中,它的工作魅力。这是我以前的代码 获得客户身份挑战: - (BOOL)webView:(WebView *)发送者资源:(id)标识符canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace forDataSource:(WebDataSource *)dataSource { NSLog(@“%@”,[protectionSpace authenticationMethod]); return [[protectionSpace authenticationMethod] isEqual:NSURLAuthenticationMethodClientCertificate];这是 我曾经回复过的代码: - (void)webView:(WebView *)发送者资源:(id)标识符didReceiveAuthenticationChallenge :( NSURLAuthenticationChallenge *)来自DataSource的挑战:(WebDataSource *)dataSource { 的NSLog(@ “didReceiveAuthenticationChallenge”); NSString * authenticationMethod = [[challenge protectionSpace] authenticationMethod]; NSLog(@“authenticationMethod =%@”,authenticationMethod);[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; }
显然,在真正的应用程序中,您需要显示一些UI,然后才能显示一次 用户已选择客户端标识,为其创建凭据 (+ [NSURLCredential credentialWithIdentity:certificates:persistence:]) 然后将该凭证应用于chalenge (-useCredential:forAuthenticationChallenge :)。 * * *那你从哪里开始呢?不管你做了什么,你都应该这样做 提交一个针对WebView的错误来获取 -webView:resource:canAuthenticateAgainstProtectionSpace:forDataSource:委托在公共头文件中发布的回调。这很明显, 最烦人的,遗漏。 http://developer.apple.com/bugreporter/ 一旦您提交了错误,请将错误号发给我,以便我可以 将此与此事件联系起来。除此之外,前进的道路更少 明确。如果您正在创建非Mac App Store应用程序,我的建议 就是你只是实施了 'canAuthenticateAgainstProtectionSpace'代表回调,就像我一样 如上所示,继续你的生活。 OTOH,如果你正在创造一个 Mac App Store应用程序,其中使用私有API,包括委托 回调,严格禁止,生活变得更加棘手。让我来 知道那种情况,我们可以讨论你的选择。分享和享受
答案 1 :(得分:1)
设置WebResourceLoadDelegate
并实现与身份验证 - 质询相关的委托方法。收到身份验证质询时会提示您,此时您可以提供要使用的证书。
ETA: 以下是如何根据NSURLCredential
中存储的证书创建clientSide.p12
:
NSString *thePath = [[NSBundle mainBundle]
pathForResource:@"clientside" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;
SecIdentityRef identity;
SecTrustRef trust;
extractIdentityAndTrust(inPKCS12Data, &identity, &trust);
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);
const void *certs[] = {certificate};
CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
NSURLCredential *credential = [NSURLCredential
credentialWithIdentity:identity
certificates:(NSArray*)certArray
persistence:NSURLCredentialPersistencePermanent];
这来自another question。您可能还会发现this question有帮助。我通过谷歌搜索了“nsurlcredential certificate”。