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.
5 #include "chrome/browser/ui/views/ssl_client_certificate_selector.h"
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/grit/generated_resources.h"
12 #include "components/constrained_window/constrained_window_views.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"
29 #include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
32 ///////////////////////////////////////////////////////////////////////////////
33 // CertificateSelectorTableModel:
35 class CertificateSelectorTableModel
: public ui::TableModel
{
37 explicit CertificateSelectorTableModel(
38 net::SSLCertRequestInfo
* cert_request_info
);
40 // ui::TableModel implementation:
41 int RowCount() override
;
42 base::string16
GetText(int index
, int column_id
) override
;
43 void SetObserver(ui::TableModelObserver
* observer
) override
;
46 std::vector
<base::string16
> items_
;
48 DISALLOW_COPY_AND_ASSIGN(CertificateSelectorTableModel
);
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
);
63 int CertificateSelectorTableModel::RowCount() {
67 base::string16
CertificateSelectorTableModel::GetText(int index
,
69 DCHECK_EQ(column_id
, 0);
71 DCHECK_LT(index
, static_cast<int>(items_
.size()));
76 void CertificateSelectorTableModel::SetObserver(
77 ui::TableModelObserver
* observer
) {
80 ///////////////////////////////////////////////////////////////////////////////
81 // SSLClientCertificateSelector:
83 SSLClientCertificateSelector::SSLClientCertificateSelector(
84 content::WebContents
* web_contents
,
85 const scoped_refptr
<net::SSLCertRequestInfo
>& cert_request_info
,
86 const chrome::SelectCertificateCallback
& callback
)
87 : SSLClientAuthObserver(web_contents
->GetBrowserContext(),
88 cert_request_info
, callback
),
89 model_(new CertificateSelectorTableModel(cert_request_info
.get())),
90 web_contents_(web_contents
),
92 view_cert_button_(NULL
) {
93 DVLOG(1) << __FUNCTION__
;
96 SSLClientCertificateSelector::~SSLClientCertificateSelector() {
97 table_
->SetModel(NULL
);
100 void SSLClientCertificateSelector::Init() {
101 views::GridLayout
* layout
= views::GridLayout::CreatePanel(this);
102 SetLayoutManager(layout
);
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);
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
);
120 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
122 // The dimensions of the certificate selector table view, in pixels.
123 static const int kTableViewWidth
= 400;
124 static const int kTableViewHeight
= 100;
127 layout
->StartRow(1, column_set_id
);
128 layout
->AddView(table_
->CreateParentIfNecessary(), 1, 1,
129 views::GridLayout::FILL
,
130 views::GridLayout::FILL
, kTableViewWidth
, kTableViewHeight
);
132 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
136 constrained_window::ShowWebModalDialogViews(this, web_contents_
);
138 // Select the first row automatically. This must be done after the dialog has
143 net::X509Certificate
* SSLClientCertificateSelector::GetSelectedCert() const {
144 int selected
= table_
->FirstSelectedRow();
146 selected
< static_cast<int>(cert_request_info()->client_certs
.size()))
147 return cert_request_info()->client_certs
[selected
].get();
151 ///////////////////////////////////////////////////////////////////////////////
152 // SSLClientAuthObserver implementation:
154 void SSLClientCertificateSelector::OnCertSelectedByNotification() {
155 DVLOG(1) << __FUNCTION__
;
156 GetWidget()->Close();
159 ///////////////////////////////////////////////////////////////////////////////
160 // DialogDelegateView implementation:
162 bool SSLClientCertificateSelector::CanResize() const {
166 base::string16
SSLClientCertificateSelector::GetWindowTitle() const {
167 return l10n_util::GetStringUTF16(IDS_CLIENT_CERT_DIALOG_TITLE
);
170 void SSLClientCertificateSelector::DeleteDelegate() {
171 DVLOG(1) << __FUNCTION__
;
175 bool SSLClientCertificateSelector::IsDialogButtonEnabled(
176 ui::DialogButton button
) const {
177 if (button
== ui::DIALOG_BUTTON_OK
)
178 return !!GetSelectedCert();
182 bool SSLClientCertificateSelector::Cancel() {
183 DVLOG(1) << __FUNCTION__
;
185 CertificateSelected(NULL
);
189 bool SSLClientCertificateSelector::Accept() {
190 DVLOG(1) << __FUNCTION__
;
191 scoped_refptr
<net::X509Certificate
> cert
= GetSelectedCert();
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.
198 chrome::UnlockCertSlotIfNecessary(
200 chrome::kCryptoModulePasswordClientAuth
,
201 cert_request_info()->host_and_port
,
202 GetWidget()->GetNativeView(),
203 base::Bind(&SSLClientCertificateSelector::Unlocked
,
204 base::Unretained(this),
207 Unlocked(cert
.get());
209 return false; // Unlocked() will close the dialog.
215 views::View
* SSLClientCertificateSelector::GetInitiallyFocusedView() {
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_
;
227 ui::ModalType
SSLClientCertificateSelector::GetModalType() const {
228 return ui::MODAL_TYPE_CHILD
;
231 ///////////////////////////////////////////////////////////////////////////////
232 // views::ButtonListener implementation:
234 void SSLClientCertificateSelector::ButtonPressed(
235 views::Button
* sender
, const ui::Event
& event
) {
236 if (sender
== view_cert_button_
) {
237 net::X509Certificate
* cert
= GetSelectedCert();
239 ShowCertificateViewer(web_contents_
,
240 web_contents_
->GetTopLevelNativeWindow(),
245 ///////////////////////////////////////////////////////////////////////////////
246 // views::TableViewObserver implementation:
247 void SSLClientCertificateSelector::OnSelectionChanged() {
248 GetDialogClientView()->ok_button()->SetEnabled(!!GetSelectedCert());
251 void SSLClientCertificateSelector::OnDoubleClick() {
253 GetWidget()->Close();
256 ///////////////////////////////////////////////////////////////////////////////
257 // SSLClientCertificateSelector private methods:
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);
267 void SSLClientCertificateSelector::Unlocked(net::X509Certificate
* cert
) {
268 DVLOG(1) << __FUNCTION__
;
269 CertificateSelected(cert
);
270 GetWidget()->Close();
275 void ShowSSLClientCertificateSelector(
276 content::WebContents
* contents
,
277 net::SSLCertRequestInfo
* cert_request_info
,
278 const chrome::SelectCertificateCallback
& callback
) {
279 DVLOG(1) << __FUNCTION__
<< " " << contents
;
280 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
281 (new SSLClientCertificateSelector(
282 contents
, cert_request_info
, callback
))->Init();
285 } // namespace chrome