如何使用Cocoa中的WebView连接客户端证书?

时间:2011-04-15 13:54:54

标签: cocoa macos webkit client-certificates

我正在尝试连接到需要客户端证书的服务器。 因此,浏览此服务器时发生的正常事件流是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.
但是,如何显示对话框以便用户可以从钥匙串中选择证书?

2 个答案:

答案 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”。