Index: chrome/browser/cocoa/ssl_client_certificate_selector.mm |
diff --git a/chrome/browser/cocoa/ssl_client_certificate_selector.mm b/chrome/browser/cocoa/ssl_client_certificate_selector.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3f057aff6485a16371c3d261e3feb95b2d324785 |
--- /dev/null |
+++ b/chrome/browser/cocoa/ssl_client_certificate_selector.mm |
@@ -0,0 +1,145 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/ssl_client_certificate_selector.h" |
+ |
+#import <SecurityInterface/SFChooseIdentityPanel.h> |
+ |
+#include <vector> |
+ |
+#import "app/l10n_util_mac.h" |
+#include "base/logging.h" |
+#include "base/ref_counted.h" |
+#include "base/scoped_cftyperef.h" |
+#import "base/scoped_nsobject.h" |
+#include "base/string_util.h" |
+#include "base/sys_string_conversions.h" |
+#include "chrome/browser/chrome_thread.h" |
+#include "chrome/browser/ssl/ssl_client_auth_handler.h" |
+#include "grit/generated_resources.h" |
+#include "net/base/x509_certificate.h" |
+ |
+@interface SSLClientCertificateSelectorCocoa : NSObject { |
+ @private |
+ // The handler to report back to. |
+ scoped_refptr<SSLClientAuthHandler> handler_; |
+ // The certificate request we serve. |
+ scoped_refptr<net::SSLCertRequestInfo> certRequestInfo_; |
+ // The list of identities offered to the user. |
+ scoped_nsobject<NSMutableArray> identities_; |
+ // The corresponding list of certificates. |
+ std::vector<scoped_refptr<net::X509Certificate> > certificates_; |
+ // The panel we display. |
+ scoped_nsobject<SFChooseIdentityPanel> panel_; |
+} |
+ |
+- (id)initWithHandler:(SSLClientAuthHandler*)handler |
+ certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo; |
+- (void)displayDialog:(gfx::NativeWindow)parent; |
+@end |
+ |
+namespace browser { |
+ |
+void ShowSSLClientCertificateSelector( |
+ gfx::NativeWindow parent, |
+ net::SSLCertRequestInfo* cert_request_info, |
+ SSLClientAuthHandler* delegate) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ SSLClientCertificateSelectorCocoa* selector = |
+ [[[SSLClientCertificateSelectorCocoa alloc] |
+ initWithHandler:delegate |
+ certRequestInfo:cert_request_info] autorelease]; |
+ [selector displayDialog:parent]; |
+} |
+ |
+} // namespace browser |
+ |
+@implementation SSLClientCertificateSelectorCocoa |
+ |
+- (id)initWithHandler:(SSLClientAuthHandler*)handler |
+ certRequestInfo:(net::SSLCertRequestInfo*)certRequestInfo { |
+ DCHECK(handler); |
+ DCHECK(certRequestInfo); |
+ if ((self = [super init])) { |
+ handler_ = handler; |
+ certRequestInfo_ = certRequestInfo; |
+ } |
+ return self; |
+} |
+ |
+- (void)sheetDidEnd:(NSWindow*)parent |
+ returnCode:(NSInteger)returnCode |
+ context:(void*)context { |
+ net::X509Certificate* cert = NULL; |
+ |
+ if (returnCode == NSFileHandlingPanelOKButton) { |
+ NSUInteger index = [identities_ indexOfObject:(id)[panel_ identity]]; |
+ DCHECK(index != NSNotFound); |
+ cert = certificates_[index]; |
+ } |
+ |
+ // Finally, tell the backend which identity (or none) the user selected. |
+ handler_->CertificateSelected(cert); |
+ // Clean up. The retain occurred just before the sheet opened. |
+ [self release]; |
+} |
+ |
+- (void)displayDialog:(gfx::NativeWindow)parent { |
+ DCHECK(!panel_.get()); |
+ // Create an array of CFIdentityRefs for the certificates: |
+ size_t numCerts = certRequestInfo_->client_certs.size(); |
+ identities_.reset([[NSMutableArray alloc] initWithCapacity:numCerts]); |
+ for (size_t i = 0; i < numCerts; ++i) { |
+ SecCertificateRef cert; |
+ cert = certRequestInfo_->client_certs[i]->os_cert_handle(); |
+ SecIdentityRef identity; |
+ if (SecIdentityCreateWithCertificate(NULL, cert, &identity) == noErr) { |
+ [identities_ addObject:(id)identity]; |
+ CFRelease(identity); |
+ certificates_.push_back(certRequestInfo_->client_certs[i]); |
+ } |
+ } |
+ |
+ // Get the message to display: |
+ NSString* title = l10n_util::GetNSString(IDS_CLIENT_CERT_DIALOG_TITLE); |
+ NSString* message = l10n_util::GetNSStringF( |
+ IDS_CLIENT_CERT_DIALOG_TEXT, |
+ ASCIIToUTF16(certRequestInfo_->host_and_port)); |
+ |
+ // Create and set up a system choose-identity panel. |
+ panel_.reset([[SFChooseIdentityPanel alloc] init]); |
+ NSString* domain = base::SysUTF8ToNSString( |
+ "https://" + certRequestInfo_->host_and_port); |
+ // Setting the domain causes the dialog to record the preferred |
+ // identity in the system keychain. |
+ [panel_ setDomain:domain]; |
+ [panel_ setInformativeText:message]; |
+ [panel_ setDefaultButtonTitle:l10n_util::GetNSString(IDS_OK)]; |
+ [panel_ setAlternateButtonTitle:l10n_util::GetNSString(IDS_CANCEL)]; |
+ SecPolicyRef sslPolicy; |
+ if (net::X509Certificate::CreateSSLClientPolicy(&sslPolicy) == noErr) { |
+ [panel_ setPolicies:(id)sslPolicy]; |
+ CFRelease(sslPolicy); |
+ } |
+ |
+ // Increase the retain count to keep |self| alive while the sheet |
+ // runs. -sheetDidEnd:returnCode:context: will release the |
+ // additional reference. |
+ [self retain]; |
+ if (parent) { |
+ // Open the cert panel as a sheet on the browser window. |
+ [panel_ beginSheetForWindow:parent |
+ modalDelegate:self |
+ didEndSelector:@selector(sheetDidEnd:returnCode:context:) |
+ contextInfo:nil |
+ identities:identities_ |
+ message:title]; |
+ } else { |
+ // No available browser window, so run independently as a (blocking) dialog. |
+ int returnCode = [panel_ runModalForIdentities:identities_ message:title]; |
+ [self sheetDidEnd:panel_ returnCode:returnCode context:nil]; |
+ } |
+} |
+ |
+@end |