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