• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ssl/ssl_tab_helper.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/basictypes.h"
11 #include "base/command_line.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/certificate_viewer.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/content_settings/host_content_settings_map.h"
18 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
19 #include "chrome/browser/infobars/infobar.h"
20 #include "chrome/browser/infobars/infobar_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ssl/ssl_add_cert_handler.h"
23 #include "chrome/browser/ssl/ssl_client_certificate_selector.h"
24 #include "chrome/browser/ui/browser_finder.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_observer.h"
28 #include "content/public/browser/notification_registrar.h"
29 #include "content/public/browser/notification_source.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/browser/web_contents_view.h"
32 #include "grit/generated_resources.h"
33 #include "grit/theme_resources.h"
34 #include "net/base/net_errors.h"
35 #include "net/cert/x509_certificate.h"
36 #include "ui/base/l10n/l10n_util.h"
37 
38 
39 // SSLCertResultInfoBarDelegate -----------------------------------------------
40 
41 namespace {
42 
43 class SSLCertResultInfoBarDelegate : public ConfirmInfoBarDelegate {
44  public:
45   // Creates an SSL cert result infobar and delegate.  If |previous_infobar| is
46   // NULL, adds the infobar to |infobar_service|; otherwise, replaces
47   // |previous_infobar|.  Returns the new infobar if it was successfully added.
48   // |cert| is valid iff cert addition was successful.
49   static InfoBar* Create(InfoBarService* infobar_service,
50                          InfoBar* previous_infobar,
51                          const base::string16& message,
52                          net::X509Certificate* cert);
53 
54  private:
55   SSLCertResultInfoBarDelegate(const base::string16& message,
56                                net::X509Certificate* cert);
57   virtual ~SSLCertResultInfoBarDelegate();
58 
59   // ConfirmInfoBarDelegate:
60   virtual int GetIconID() const OVERRIDE;
61   virtual Type GetInfoBarType() const OVERRIDE;
62   virtual base::string16 GetMessageText() const OVERRIDE;
63   virtual int GetButtons() const OVERRIDE;
64   virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
65   virtual bool Accept() OVERRIDE;
66 
67   base::string16 message_;
68   scoped_refptr<net::X509Certificate> cert_;  // The cert we added, if any.
69 
70   DISALLOW_COPY_AND_ASSIGN(SSLCertResultInfoBarDelegate);
71 };
72 
73 // static
Create(InfoBarService * infobar_service,InfoBar * previous_infobar,const base::string16 & message,net::X509Certificate * cert)74 InfoBar* SSLCertResultInfoBarDelegate::Create(InfoBarService* infobar_service,
75                                               InfoBar* previous_infobar,
76                                               const base::string16& message,
77                                               net::X509Certificate* cert) {
78   scoped_ptr<InfoBar> infobar(ConfirmInfoBarDelegate::CreateInfoBar(
79       scoped_ptr<ConfirmInfoBarDelegate>(
80           new SSLCertResultInfoBarDelegate(message, cert))));
81   return previous_infobar ?
82       infobar_service->ReplaceInfoBar(previous_infobar, infobar.Pass()) :
83       infobar_service->AddInfoBar(infobar.Pass());
84 }
85 
SSLCertResultInfoBarDelegate(const base::string16 & message,net::X509Certificate * cert)86 SSLCertResultInfoBarDelegate::SSLCertResultInfoBarDelegate(
87     const base::string16& message,
88     net::X509Certificate* cert)
89     : ConfirmInfoBarDelegate(),
90       message_(message),
91       cert_(cert) {
92 }
93 
~SSLCertResultInfoBarDelegate()94 SSLCertResultInfoBarDelegate::~SSLCertResultInfoBarDelegate() {
95 }
96 
GetIconID() const97 int SSLCertResultInfoBarDelegate::GetIconID() const {
98   // TODO(davidben): use a more appropriate icon.
99   return IDR_INFOBAR_SAVE_PASSWORD;
100 }
101 
GetInfoBarType() const102 InfoBarDelegate::Type SSLCertResultInfoBarDelegate::GetInfoBarType() const {
103   return cert_.get() ? PAGE_ACTION_TYPE : WARNING_TYPE;
104 }
105 
GetMessageText() const106 base::string16 SSLCertResultInfoBarDelegate::GetMessageText() const {
107   return message_;
108 }
109 
GetButtons() const110 int SSLCertResultInfoBarDelegate::GetButtons() const {
111   return cert_.get() ? BUTTON_OK : BUTTON_NONE;
112 }
113 
GetButtonLabel(InfoBarButton button) const114 base::string16 SSLCertResultInfoBarDelegate::GetButtonLabel(
115     InfoBarButton button) const {
116   DCHECK_EQ(BUTTON_OK, button);
117   return l10n_util::GetStringUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_BUTTON);
118 }
119 
Accept()120 bool SSLCertResultInfoBarDelegate::Accept() {
121   ShowCertificateViewer(web_contents(),
122                         web_contents()->GetView()->GetTopLevelNativeWindow(),
123                         cert_.get());
124   return false;  // Hiding the infobar just as the dialog opens looks weird.
125 }
126 
127 }  // namespace
128 
129 
130 // SSLTabHelper::SSLAddCertData ------------------------------------------------
131 
132 class SSLTabHelper::SSLAddCertData
133     : public content::NotificationObserver {
134  public:
135   explicit SSLAddCertData(InfoBarService* infobar_service);
136   virtual ~SSLAddCertData();
137 
138   // Displays an infobar, replacing |infobar_| if it exists.
139   void ShowInfoBar(const base::string16& message, net::X509Certificate* cert);
140 
141  private:
142   // content::NotificationObserver:
143   virtual void Observe(int type,
144                        const content::NotificationSource& source,
145                        const content::NotificationDetails& details) OVERRIDE;
146 
147   InfoBarService* infobar_service_;
148   InfoBar* infobar_;
149   content::NotificationRegistrar registrar_;
150 
151   DISALLOW_COPY_AND_ASSIGN(SSLAddCertData);
152 };
153 
SSLAddCertData(InfoBarService * infobar_service)154 SSLTabHelper::SSLAddCertData::SSLAddCertData(InfoBarService* infobar_service)
155     : infobar_service_(infobar_service),
156       infobar_(NULL) {
157   content::Source<InfoBarService> source(infobar_service_);
158   registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
159                  source);
160   registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED,
161                  source);
162 }
163 
~SSLAddCertData()164 SSLTabHelper::SSLAddCertData::~SSLAddCertData() {
165 }
166 
ShowInfoBar(const base::string16 & message,net::X509Certificate * cert)167 void SSLTabHelper::SSLAddCertData::ShowInfoBar(const base::string16& message,
168                                                net::X509Certificate* cert) {
169   infobar_ = SSLCertResultInfoBarDelegate::Create(infobar_service_, infobar_,
170                                                   message, cert);
171 }
172 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)173 void SSLTabHelper::SSLAddCertData::Observe(
174     int type,
175     const content::NotificationSource& source,
176     const content::NotificationDetails& details) {
177   DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED ||
178          type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED);
179   if (infobar_ ==
180       ((type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED) ?
181           content::Details<InfoBar::RemovedDetails>(details)->first :
182           content::Details<InfoBar::ReplacedDetails>(details)->first))
183     infobar_ = NULL;
184 }
185 
186 
187 // SSLTabHelper ----------------------------------------------------------------
188 
189 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLTabHelper);
190 
SSLTabHelper(content::WebContents * contents)191 SSLTabHelper::SSLTabHelper(content::WebContents* contents)
192     : WebContentsObserver(contents),
193       web_contents_(contents) {
194 }
195 
~SSLTabHelper()196 SSLTabHelper::~SSLTabHelper() {
197 }
198 
DidChangeVisibleSSLState()199 void SSLTabHelper::DidChangeVisibleSSLState() {
200 #if !defined(OS_ANDROID)
201   Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
202   if (browser)
203     browser->VisibleSSLStateChanged(web_contents_);
204 #endif  // !defined(OS_ANDROID)
205 }
206 
ShowClientCertificateRequestDialog(const net::HttpNetworkSession * network_session,net::SSLCertRequestInfo * cert_request_info,const base::Callback<void (net::X509Certificate *)> & callback)207 void SSLTabHelper::ShowClientCertificateRequestDialog(
208     const net::HttpNetworkSession* network_session,
209     net::SSLCertRequestInfo* cert_request_info,
210     const base::Callback<void(net::X509Certificate*)>& callback) {
211   chrome::ShowSSLClientCertificateSelector(web_contents_, network_session,
212                                            cert_request_info, callback);
213 }
214 
OnVerifyClientCertificateError(scoped_refptr<SSLAddCertHandler> handler,int error_code)215 void SSLTabHelper::OnVerifyClientCertificateError(
216     scoped_refptr<SSLAddCertHandler> handler, int error_code) {
217   // Display an infobar with the error message.
218   // TODO(davidben): Display a more user-friendly error string.
219   GetAddCertData(handler.get())->ShowInfoBar(
220       l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_INVALID_CERT,
221                                  base::IntToString16(-error_code),
222                                  ASCIIToUTF16(net::ErrorToString(error_code))),
223       NULL);
224 }
225 
AskToAddClientCertificate(scoped_refptr<SSLAddCertHandler> handler)226 void SSLTabHelper::AskToAddClientCertificate(
227     scoped_refptr<SSLAddCertHandler> handler) {
228   NOTREACHED();  // Not implemented yet.
229 }
230 
OnAddClientCertificateSuccess(scoped_refptr<SSLAddCertHandler> handler)231 void SSLTabHelper::OnAddClientCertificateSuccess(
232     scoped_refptr<SSLAddCertHandler> handler) {
233   net::X509Certificate* cert = handler->cert();
234   // TODO(evanm): GetDisplayName should return UTF-16.
235   GetAddCertData(handler.get())->ShowInfoBar(
236       l10n_util::GetStringFUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_LABEL,
237                                  UTF8ToUTF16(cert->issuer().GetDisplayName())),
238       cert);
239 }
240 
OnAddClientCertificateError(scoped_refptr<SSLAddCertHandler> handler,int error_code)241 void SSLTabHelper::OnAddClientCertificateError(
242     scoped_refptr<SSLAddCertHandler> handler,
243     int error_code) {
244   // TODO(davidben): Display a more user-friendly error string.
245   GetAddCertData(handler.get())->ShowInfoBar(
246       l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_FAILED,
247                                  base::IntToString16(-error_code),
248                                  ASCIIToUTF16(net::ErrorToString(error_code))),
249       NULL);
250 }
251 
OnAddClientCertificateFinished(scoped_refptr<SSLAddCertHandler> handler)252 void SSLTabHelper::OnAddClientCertificateFinished(
253     scoped_refptr<SSLAddCertHandler> handler) {
254   // Clean up.
255   request_id_to_add_cert_data_.erase(handler->network_request_id());
256 }
257 
258 SSLTabHelper::SSLAddCertData*
GetAddCertData(SSLAddCertHandler * handler)259     SSLTabHelper::GetAddCertData(SSLAddCertHandler* handler) {
260   // Find/create the slot.
261   linked_ptr<SSLAddCertData>& ptr_ref =
262       request_id_to_add_cert_data_[handler->network_request_id()];
263   // Fill it if necessary.
264   if (!ptr_ref.get()) {
265     ptr_ref.reset(
266         new SSLAddCertData(InfoBarService::FromWebContents(web_contents_)));
267   }
268   return ptr_ref.get();
269 }
270