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