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