Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / ssl_client_certificate_selector.cc
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/ui/views/ssl_client_certificate_selector.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/i18n/time_formatting.h"
9 #include "base/logging.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/certificate_viewer.h"
12 #include "components/web_modal/web_contents_modal_dialog_host.h"
13 #include "components/web_modal/web_contents_modal_dialog_manager.h"
14 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/web_contents.h"
17 #include "grit/generated_resources.h"
18 #include "net/cert/x509_certificate.h"
19 #include "net/ssl/ssl_cert_request_info.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/models/table_model.h"
22 #include "ui/base/models/table_model_observer.h"
23 #include "ui/gfx/native_widget_types.h"
24 #include "ui/views/controls/button/label_button.h"
25 #include "ui/views/controls/label.h"
26 #include "ui/views/controls/table/table_view.h"
27 #include "ui/views/layout/grid_layout.h"
28 #include "ui/views/layout/layout_constants.h"
29 #include "ui/views/widget/widget.h"
30 #include "ui/views/window/dialog_client_view.h"
31
32 #if defined(USE_NSS)
33 #include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
34 #endif
35
36 using content::BrowserThread;
37 using content::WebContents;
38 using web_modal::WebContentsModalDialogManager;
39 using web_modal::WebContentsModalDialogManagerDelegate;
40
41 namespace {
42
43 // The dimensions of the certificate selector table view, in pixels.
44 static const int kTableViewWidth = 400;
45 static const int kTableViewHeight = 100;
46
47 }  // namespace
48
49 ///////////////////////////////////////////////////////////////////////////////
50 // CertificateSelectorTableModel:
51
52 class CertificateSelectorTableModel : public ui::TableModel {
53  public:
54   explicit CertificateSelectorTableModel(
55       net::SSLCertRequestInfo* cert_request_info);
56
57   // ui::TableModel implementation:
58   virtual int RowCount() OVERRIDE;
59   virtual base::string16 GetText(int index, int column_id) OVERRIDE;
60   virtual void SetObserver(ui::TableModelObserver* observer) OVERRIDE;
61
62  private:
63   std::vector<base::string16> items_;
64
65   DISALLOW_COPY_AND_ASSIGN(CertificateSelectorTableModel);
66 };
67
68 CertificateSelectorTableModel::CertificateSelectorTableModel(
69     net::SSLCertRequestInfo* cert_request_info) {
70   for (size_t i = 0; i < cert_request_info->client_certs.size(); ++i) {
71     net::X509Certificate* cert = cert_request_info->client_certs[i].get();
72     base::string16 text = l10n_util::GetStringFUTF16(
73         IDS_CERT_SELECTOR_TABLE_CERT_FORMAT,
74         base::UTF8ToUTF16(cert->subject().GetDisplayName()),
75         base::UTF8ToUTF16(cert->issuer().GetDisplayName()));
76     items_.push_back(text);
77   }
78 }
79
80 int CertificateSelectorTableModel::RowCount() {
81   return items_.size();
82 }
83
84 base::string16 CertificateSelectorTableModel::GetText(int index,
85                                                       int column_id) {
86   DCHECK_EQ(column_id, 0);
87   DCHECK_GE(index, 0);
88   DCHECK_LT(index, static_cast<int>(items_.size()));
89
90   return items_[index];
91 }
92
93 void CertificateSelectorTableModel::SetObserver(
94     ui::TableModelObserver* observer) {
95 }
96
97 ///////////////////////////////////////////////////////////////////////////////
98 // SSLClientCertificateSelector:
99
100 SSLClientCertificateSelector::SSLClientCertificateSelector(
101     WebContents* web_contents,
102     const net::HttpNetworkSession* network_session,
103     net::SSLCertRequestInfo* cert_request_info,
104     const chrome::SelectCertificateCallback& callback)
105     : SSLClientAuthObserver(network_session, cert_request_info, callback),
106       model_(new CertificateSelectorTableModel(cert_request_info)),
107       web_contents_(web_contents),
108       window_(NULL),
109       table_(NULL),
110       view_cert_button_(NULL) {
111   DVLOG(1) << __FUNCTION__;
112 }
113
114 SSLClientCertificateSelector::~SSLClientCertificateSelector() {
115   table_->SetModel(NULL);
116 }
117
118 void SSLClientCertificateSelector::Init() {
119   views::GridLayout* layout = views::GridLayout::CreatePanel(this);
120   SetLayoutManager(layout);
121
122   const int column_set_id = 0;
123   views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
124   column_set->AddColumn(
125       views::GridLayout::FILL, views::GridLayout::FILL,
126       1, views::GridLayout::USE_PREF, 0, 0);
127
128   layout->StartRow(0, column_set_id);
129   base::string16 text = l10n_util::GetStringFUTF16(
130       IDS_CLIENT_CERT_DIALOG_TEXT,
131       base::ASCIIToUTF16(cert_request_info()->host_and_port.ToString()));
132   views::Label* label = new views::Label(text);
133   label->SetMultiLine(true);
134   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
135   label->SetAllowCharacterBreak(true);
136   layout->AddView(label);
137
138   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
139
140   CreateCertTable();
141   layout->StartRow(1, column_set_id);
142   layout->AddView(table_->CreateParentIfNecessary(), 1, 1,
143                   views::GridLayout::FILL,
144                   views::GridLayout::FILL, kTableViewWidth, kTableViewHeight);
145
146   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
147
148   StartObserving();
149
150   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
151       WebContentsModalDialogManager::FromWebContents(web_contents_);
152   WebContentsModalDialogManagerDelegate* modal_delegate =
153       web_contents_modal_dialog_manager->delegate();
154   DCHECK(modal_delegate);
155   window_ = views::Widget::CreateWindowAsFramelessChild(
156       this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
157   web_contents_modal_dialog_manager->ShowModalDialog(
158       window_->GetNativeView());
159
160   // Select the first row automatically.  This must be done after the dialog has
161   // been created.
162   table_->Select(0);
163 }
164
165 net::X509Certificate* SSLClientCertificateSelector::GetSelectedCert() const {
166   int selected = table_->FirstSelectedRow();
167   if (selected >= 0 &&
168       selected < static_cast<int>(
169           cert_request_info()->client_certs.size()))
170     return cert_request_info()->client_certs[selected].get();
171   return NULL;
172 }
173
174 ///////////////////////////////////////////////////////////////////////////////
175 // SSLClientAuthObserver implementation:
176
177 void SSLClientCertificateSelector::OnCertSelectedByNotification() {
178   DVLOG(1) << __FUNCTION__;
179   DCHECK(window_);
180   window_->Close();
181 }
182
183 ///////////////////////////////////////////////////////////////////////////////
184 // DialogDelegateView implementation:
185
186 bool SSLClientCertificateSelector::CanResize() const {
187   return true;
188 }
189
190 base::string16 SSLClientCertificateSelector::GetWindowTitle() const {
191   return l10n_util::GetStringUTF16(IDS_CLIENT_CERT_DIALOG_TITLE);
192 }
193
194 void SSLClientCertificateSelector::DeleteDelegate() {
195   DVLOG(1) << __FUNCTION__;
196   delete this;
197 }
198
199 bool SSLClientCertificateSelector::IsDialogButtonEnabled(
200     ui::DialogButton button) const {
201   if (button == ui::DIALOG_BUTTON_OK)
202     return !!GetSelectedCert();
203   return true;
204 }
205
206 bool SSLClientCertificateSelector::Cancel() {
207   DVLOG(1) << __FUNCTION__;
208   StopObserving();
209   CertificateSelected(NULL);
210
211   return true;
212 }
213
214 bool SSLClientCertificateSelector::Accept() {
215   DVLOG(1) << __FUNCTION__;
216   scoped_refptr<net::X509Certificate> cert = GetSelectedCert();
217   if (cert) {
218     // Remove the observer before we try unlocking, otherwise we might act on a
219     // notification while waiting for the unlock dialog, causing us to delete
220     // ourself before the Unlocked callback gets called.
221     StopObserving();
222 #if defined(USE_NSS)
223     chrome::UnlockCertSlotIfNecessary(
224         cert,
225         chrome::kCryptoModulePasswordClientAuth,
226         cert_request_info()->host_and_port,
227         window_->GetNativeView(),
228         base::Bind(&SSLClientCertificateSelector::Unlocked,
229                    base::Unretained(this),
230                    cert));
231 #else
232     Unlocked(cert);
233 #endif
234     return false;  // Unlocked() will close the dialog.
235   }
236
237   return false;
238 }
239
240 views::View* SSLClientCertificateSelector::GetInitiallyFocusedView() {
241   return table_;
242 }
243
244 views::View* SSLClientCertificateSelector::CreateExtraView() {
245   DCHECK(!view_cert_button_);
246   view_cert_button_ = new views::LabelButton(this,
247       l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON));
248   view_cert_button_->SetStyle(views::Button::STYLE_BUTTON);
249   return view_cert_button_;
250 }
251
252 ui::ModalType SSLClientCertificateSelector::GetModalType() const {
253 #if defined(USE_ASH)
254   return ui::MODAL_TYPE_CHILD;
255 #else
256   return views::WidgetDelegate::GetModalType();
257 #endif
258 }
259
260 ///////////////////////////////////////////////////////////////////////////////
261 // views::ButtonListener implementation:
262
263 void SSLClientCertificateSelector::ButtonPressed(
264     views::Button* sender, const ui::Event& event) {
265   if (sender == view_cert_button_) {
266     net::X509Certificate* cert = GetSelectedCert();
267     if (cert)
268       ShowCertificateViewer(web_contents_,
269                             web_contents_->GetTopLevelNativeWindow(),
270                             cert);
271   }
272 }
273
274 ///////////////////////////////////////////////////////////////////////////////
275 // views::TableViewObserver implementation:
276 void SSLClientCertificateSelector::OnSelectionChanged() {
277   GetDialogClientView()->ok_button()->SetEnabled(!!GetSelectedCert());
278 }
279
280 void SSLClientCertificateSelector::OnDoubleClick() {
281   if (Accept())
282     window_->Close();
283 }
284
285 ///////////////////////////////////////////////////////////////////////////////
286 // SSLClientCertificateSelector private methods:
287
288 void SSLClientCertificateSelector::CreateCertTable() {
289   std::vector<ui::TableColumn> columns;
290   columns.push_back(ui::TableColumn());
291   table_ = new views::TableView(model_.get(),
292                                 columns,
293                                 views::TEXT_ONLY,
294                                 true /* single_selection */);
295   table_->SetObserver(this);
296 }
297
298 void SSLClientCertificateSelector::Unlocked(net::X509Certificate* cert) {
299   DVLOG(1) << __FUNCTION__;
300   CertificateSelected(cert);
301   window_->Close();
302 }
303
304 namespace chrome {
305
306 void ShowSSLClientCertificateSelector(
307     content::WebContents* contents,
308     const net::HttpNetworkSession* network_session,
309     net::SSLCertRequestInfo* cert_request_info,
310     const chrome::SelectCertificateCallback& callback) {
311   DVLOG(1) << __FUNCTION__ << " " << contents;
312   DCHECK_CURRENTLY_ON(BrowserThread::UI);
313   (new SSLClientCertificateSelector(
314        contents, network_session, cert_request_info, callback))->Init();
315 }
316
317 }  // namespace chrome