From 0fbd908fb6557b4bb3388cc876af0c2a96fc0e43 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Thu, 11 Jun 2015 20:52:07 +0530 Subject: [PATCH] app: event to pass client certificate data --- atom/browser/api/atom_api_app.cc | 62 +++++++++++++++++++++++++++++ atom/browser/api/atom_api_app.h | 4 ++ atom/browser/atom_browser_client.cc | 13 +++--- atom/browser/browser.cc | 13 ++++++ atom/browser/browser.h | 6 +++ atom/browser/browser_observer.h | 17 ++++++++ docs/api/app.md | 24 +++++++++++ 7 files changed, 132 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 473111dbc7e..036c61b407f 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -16,15 +16,18 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/browser.h" +#include "atom/browser/api/atom_api_web_contents.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "base/command_line.h" #include "base/environment.h" #include "base/files/file_path.h" #include "base/path_service.h" #include "brightray/browser/brightray_paths.h" +#include "content/public/browser/client_certificate_delegate.h" #include "native_mate/callback.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" +#include "net/ssl/ssl_cert_request_info.h" #if defined(OS_WIN) #include "base/strings/utf_string_conversions.h" @@ -57,6 +60,21 @@ struct Converter { }; #endif +template<> +struct Converter> { + static v8::Local ToV8( + v8::Isolate* isolate, + const scoped_refptr& val) { + mate::Dictionary dict(isolate, v8::Object::New(isolate)); + std::string encoded_data; + net::X509Certificate::GetPEMEncoded( + val->os_cert_handle(), &encoded_data); + dict.Set("data", encoded_data); + dict.Set("issuerName", val->issuer().GetDisplayName()); + return dict.GetHandle(); + } +}; + } // namespace mate @@ -90,6 +108,29 @@ int GetPathConstant(const std::string& name) { return -1; } +void OnClientCertificateSelected( + v8::Isolate* isolate, + std::shared_ptr delegate, + mate::Arguments* args) { + v8::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); + mate::Dictionary cert_data; + if (!(args->Length() == 1 && args->GetNext(&cert_data))) { + args->ThrowError(); + return; + } + + std::string encoded_data; + cert_data.Get("data", &encoded_data); + + auto certs = + net::X509Certificate::CreateCertificateListFromBytes( + encoded_data.data(), encoded_data.size(), + net::X509Certificate::FORMAT_AUTO); + + delegate->ContinueWithCertificate(certs[0].get()); +} + } // namespace App::App() { @@ -144,6 +185,27 @@ void App::OnFinishLaunching() { Emit("ready"); } +void App::OnSelectCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate) { + std::shared_ptr + shared_delegate(delegate.release()); + bool prevent_default = + Emit("select-certificate", + api::WebContents::CreateFrom(isolate(), web_contents), + cert_request_info->host_and_port.ToString(), + cert_request_info->client_certs, + base::Bind(&OnClientCertificateSelected, + isolate(), + shared_delegate)); + + // Default to first certificate from the platform store. + if (!prevent_default) + shared_delegate->ContinueWithCertificate( + cert_request_info->client_certs[0].get()); +} + base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) { bool succeed = false; base::FilePath path; diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index f3041757669..97489917dc2 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -42,6 +42,10 @@ class App : public mate::EventEmitter, void OnActivateWithNoOpenWindows() override; void OnWillFinishLaunching() override; void OnFinishLaunching() override; + void OnSelectCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate) override; // mate::Wrappable: mate::ObjectTemplateBuilder GetObjectTemplateBuilder( diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 6c29c162e4e..85e19cf234e 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -9,6 +9,7 @@ #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_quota_permission_context.h" #include "atom/browser/atom_speech_recognition_manager_delegate.h" +#include "atom/browser/browser.h" #include "atom/browser/native_window.h" #include "atom/browser/web_view_manager.h" #include "atom/browser/window_list.h" @@ -231,15 +232,13 @@ void AtomBrowserClient::SelectClientCertificate( auto cert_path = command_line->GetSwitchValueNative( switches::kClientCertificate); - // TODO(zcbenz): allow users to select certificate from - // client_cert list. Right now defaults to first certificate - // in the list. scoped_refptr certificate; - if (cert_path.empty()) { - if (!cert_request_info->client_certs.empty()) - certificate = cert_request_info->client_certs[0]; - } else { + if (!cert_path.empty()) { certificate = ImportCertFromFile(base::FilePath(cert_path)); + } else if (!cert_request_info->client_certs.empty()) { + Browser::Get()->ClientCertificateSelector(web_contents, + cert_request_info, + delegate.Pass()); } if (certificate.get()) diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index 123cfc4f984..1ca682de15b 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -9,6 +9,8 @@ #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/window_list.h" #include "base/message_loop/message_loop.h" +#include "content/public/browser/client_certificate_delegate.h" +#include "net/ssl/ssl_cert_request_info.h" namespace atom { @@ -104,6 +106,17 @@ void Browser::DidFinishLaunching() { FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching()); } +void Browser::ClientCertificateSelector( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate) { + FOR_EACH_OBSERVER(BrowserObserver, + observers_, + OnSelectCertificate(web_contents, + cert_request_info, + delegate.Pass())); +} + void Browser::NotifyAndShutdown() { bool prevent_default = false; FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default)); diff --git a/atom/browser/browser.h b/atom/browser/browser.h index 8648d885338..3e93c84b077 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -115,6 +115,12 @@ class Browser : public WindowListObserver { void WillFinishLaunching(); void DidFinishLaunching(); + // Called when client certificate is required. + void ClientCertificateSelector( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate); + void AddObserver(BrowserObserver* obs) { observers_.AddObserver(obs); } diff --git a/atom/browser/browser_observer.h b/atom/browser/browser_observer.h index 4f9f436712d..19f4bd85c1d 100644 --- a/atom/browser/browser_observer.h +++ b/atom/browser/browser_observer.h @@ -7,6 +7,17 @@ #include +#include "base/memory/scoped_ptr.h" + +namespace content { +class ClientCertificateDelegate; +class WebContents; +} + +namespace net { +class SSLCertRequestInfo; +} + namespace atom { class BrowserObserver { @@ -40,6 +51,12 @@ class BrowserObserver { virtual void OnWillFinishLaunching() {} virtual void OnFinishLaunching() {} + // The browser requires client certificate. + virtual void OnSelectCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate) {} + protected: virtual ~BrowserObserver() {} }; diff --git a/docs/api/app.md b/docs/api/app.md index 1564196ce81..d1b219cc15b 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -101,6 +101,30 @@ Emitted when a [browserWindow](browser-window.md) gets blurred. Emitted when a [browserWindow](browser-window.md) gets focused. +### Event: 'select-certificate' + +Emitted when client certificate is requested. + +* `event` Event +* `webContents` [WebContents](browser-window.md#class-webcontents) +* `url` String +* `certificateList` [Objects] + * `data` PEM encoded data + * `issuerName` Issuer's Common Name +* `callback` Function + +``` +app.on('select-certificate', function(event, host, url, list, callback) { + event.preventDefault(); + callback(list[0]); +}) +``` + +`url` corresponds to the navigation entry requesting the client certificate, +`callback` needs to be called with an entry filtered from the list. +`event.preventDefault()` prevents from using the first certificate from +the store. + ## app.quit() Try to close all windows. The `before-quit` event will first be emitted. If all