Home | History | Annotate | Download | only in views
      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 "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 
     33 using content::BrowserThread;
     34 using content::WebContents;
     35 using web_modal::WebContentsModalDialogManager;
     36 
     37 namespace {
     38 
     39 // The dimensions of the certificate selector table view, in pixels.
     40 static const int kTableViewWidth = 400;
     41 static const int kTableViewHeight = 100;
     42 
     43 }  // namespace
     44 
     45 ///////////////////////////////////////////////////////////////////////////////
     46 // CertificateSelectorTableModel:
     47 
     48 class 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 
     64 CertificateSelectorTableModel::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].get();
     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 
     76 int CertificateSelectorTableModel::RowCount() {
     77   return items_.size();
     78 }
     79 
     80 string16 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 
     88 void CertificateSelectorTableModel::SetObserver(
     89     ui::TableModelObserver* observer) {
     90 }
     91 
     92 ///////////////////////////////////////////////////////////////////////////////
     93 // SSLClientCertificateSelector:
     94 
     95 SSLClientCertificateSelector::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 
    109 SSLClientCertificateSelector::~SSLClientCertificateSelector() {
    110   table_->SetModel(NULL);
    111 }
    112 
    113 void 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 
    159 net::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].get();
    165   return NULL;
    166 }
    167 
    168 ///////////////////////////////////////////////////////////////////////////////
    169 // SSLClientAuthObserver implementation:
    170 
    171 void SSLClientCertificateSelector::OnCertSelectedByNotification() {
    172   DVLOG(1) << __FUNCTION__;
    173   DCHECK(window_);
    174   window_->Close();
    175 }
    176 
    177 ///////////////////////////////////////////////////////////////////////////////
    178 // DialogDelegateView implementation:
    179 
    180 bool SSLClientCertificateSelector::CanResize() const {
    181   return true;
    182 }
    183 
    184 string16 SSLClientCertificateSelector::GetWindowTitle() const {
    185   return l10n_util::GetStringUTF16(IDS_CLIENT_CERT_DIALOG_TITLE);
    186 }
    187 
    188 void SSLClientCertificateSelector::DeleteDelegate() {
    189   DVLOG(1) << __FUNCTION__;
    190   delete this;
    191 }
    192 
    193 bool SSLClientCertificateSelector::IsDialogButtonEnabled(
    194     ui::DialogButton button) const {
    195   if (button == ui::DIALOG_BUTTON_OK)
    196     return !!GetSelectedCert();
    197   return true;
    198 }
    199 
    200 bool SSLClientCertificateSelector::Cancel() {
    201   DVLOG(1) << __FUNCTION__;
    202   StopObserving();
    203   CertificateSelected(NULL);
    204 
    205   return true;
    206 }
    207 
    208 bool 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.
    222 views::NonClientFrameView*
    223     SSLClientCertificateSelector::CreateNonClientFrameView(
    224         views::Widget* widget) {
    225   return CreateConstrainedStyleNonClientFrameView(
    226       widget,
    227       web_contents_->GetBrowserContext());
    228 }
    229 
    230 views::View* SSLClientCertificateSelector::GetInitiallyFocusedView() {
    231   return table_;
    232 }
    233 
    234 views::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 
    242 ui::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 
    253 void 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:
    266 void SSLClientCertificateSelector::OnSelectionChanged() {
    267   GetDialogClientView()->ok_button()->SetEnabled(!!GetSelectedCert());
    268 }
    269 
    270 void SSLClientCertificateSelector::OnDoubleClick() {
    271   if (Accept())
    272     window_->Close();
    273 }
    274 
    275 ///////////////////////////////////////////////////////////////////////////////
    276 // SSLClientCertificateSelector private methods:
    277 
    278 void 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 
    288 namespace chrome {
    289 
    290 void 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