Home | History | Annotate | Download | only in options
      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/chromeos/options/vpn_config_view.h"
      6 
      7 #include "ash/system/chromeos/network/network_connect.h"
      8 #include "base/strings/string_util.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
     12 #include "chrome/browser/chromeos/options/network_connect.h"
     13 #include "chrome/browser/profiles/profile_manager.h"
     14 #include "chrome/common/net/x509_certificate_model.h"
     15 #include "chromeos/network/network_configuration_handler.h"
     16 #include "chromeos/network/network_event_log.h"
     17 #include "chromeos/network/network_state.h"
     18 #include "chromeos/network/network_state_handler.h"
     19 #include "chromeos/network/network_ui_data.h"
     20 #include "chromeos/network/onc/onc_constants.h"
     21 #include "grit/chromium_strings.h"
     22 #include "grit/generated_resources.h"
     23 #include "grit/locale_settings.h"
     24 #include "grit/theme_resources.h"
     25 #include "third_party/cros_system_api/dbus/service_constants.h"
     26 #include "ui/base/events/event.h"
     27 #include "ui/base/l10n/l10n_util.h"
     28 #include "ui/base/models/combobox_model.h"
     29 #include "ui/base/resource/resource_bundle.h"
     30 #include "ui/views/controls/button/checkbox.h"
     31 #include "ui/views/controls/combobox/combobox.h"
     32 #include "ui/views/controls/label.h"
     33 #include "ui/views/controls/textfield/textfield.h"
     34 #include "ui/views/layout/grid_layout.h"
     35 #include "ui/views/layout/layout_constants.h"
     36 #include "ui/views/widget/widget.h"
     37 #include "ui/views/window/dialog_client_view.h"
     38 
     39 namespace {
     40 
     41 // Root CA certificates that are built into Chrome use this token name.
     42 const char* const kRootCertificateTokenName = "Builtin Object Token";
     43 
     44 enum ProviderTypeIndex {
     45   PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK = 0,
     46   PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT = 1,
     47   PROVIDER_TYPE_INDEX_OPEN_VPN = 2,
     48   PROVIDER_TYPE_INDEX_MAX = 3,
     49 };
     50 
     51 string16 ProviderTypeIndexToString(int index) {
     52   switch (index) {
     53     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
     54       return l10n_util::GetStringUTF16(
     55           IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK);
     56     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
     57       return l10n_util::GetStringUTF16(
     58           IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT);
     59     case PROVIDER_TYPE_INDEX_OPEN_VPN:
     60       return l10n_util::GetStringUTF16(
     61           IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN);
     62   }
     63   NOTREACHED();
     64   return string16();
     65 }
     66 
     67 int ProviderTypeToIndex(const std::string& provider_type,
     68                         const std::string& client_cert_id) {
     69   if (provider_type == flimflam::kProviderL2tpIpsec) {
     70     if (!client_cert_id.empty())
     71       return PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
     72     else
     73       return PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK;
     74   } else {
     75     DCHECK(provider_type == flimflam::kProviderOpenVpn);
     76     return PROVIDER_TYPE_INDEX_OPEN_VPN;
     77   }
     78 }
     79 
     80 // Translates the provider type to the name of the respective ONC dictionary
     81 // containing configuration data for the type.
     82 std::string ProviderTypeIndexToONCDictKey(int provider_type_index) {
     83   switch (provider_type_index) {
     84     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
     85     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
     86       return chromeos::onc::vpn::kIPsec;
     87     case PROVIDER_TYPE_INDEX_OPEN_VPN:
     88       return chromeos::onc::vpn::kOpenVPN;
     89   }
     90   NOTREACHED() << "Unhandled provider type index " << provider_type_index;
     91   return std::string();
     92 }
     93 
     94 std::string GetPemFromDictionary(
     95     const base::DictionaryValue* provider_properties,
     96     const std::string& key) {
     97   const base::ListValue* pems = NULL;
     98   if (!provider_properties->GetListWithoutPathExpansion(key, &pems))
     99     return std::string();
    100   std::string pem;
    101   pems->GetString(0, &pem);
    102   return pem;
    103 }
    104 
    105 void ShillError(const std::string& function,
    106                 const std::string& error_name,
    107                 scoped_ptr<base::DictionaryValue> error_data) {
    108   NET_LOG_ERROR("Shill Error from VpnConfigView: " + error_name, function);
    109 }
    110 
    111 }  // namespace
    112 
    113 namespace chromeos {
    114 
    115 namespace internal {
    116 
    117 class ProviderTypeComboboxModel : public ui::ComboboxModel {
    118  public:
    119   ProviderTypeComboboxModel();
    120   virtual ~ProviderTypeComboboxModel();
    121 
    122   // Overridden from ui::ComboboxModel:
    123   virtual int GetItemCount() const OVERRIDE;
    124   virtual string16 GetItemAt(int index) OVERRIDE;
    125 
    126  private:
    127   DISALLOW_COPY_AND_ASSIGN(ProviderTypeComboboxModel);
    128 };
    129 
    130 class VpnServerCACertComboboxModel : public ui::ComboboxModel {
    131  public:
    132   VpnServerCACertComboboxModel();
    133   virtual ~VpnServerCACertComboboxModel();
    134 
    135   // Overridden from ui::ComboboxModel:
    136   virtual int GetItemCount() const OVERRIDE;
    137   virtual string16 GetItemAt(int index) OVERRIDE;
    138 
    139  private:
    140   DISALLOW_COPY_AND_ASSIGN(VpnServerCACertComboboxModel);
    141 };
    142 
    143 class VpnUserCertComboboxModel : public ui::ComboboxModel {
    144  public:
    145   VpnUserCertComboboxModel();
    146   virtual ~VpnUserCertComboboxModel();
    147 
    148   // Overridden from ui::ComboboxModel:
    149   virtual int GetItemCount() const OVERRIDE;
    150   virtual string16 GetItemAt(int index) OVERRIDE;
    151 
    152  private:
    153   DISALLOW_COPY_AND_ASSIGN(VpnUserCertComboboxModel);
    154 };
    155 
    156 // ProviderTypeComboboxModel ---------------------------------------------------
    157 
    158 ProviderTypeComboboxModel::ProviderTypeComboboxModel() {
    159 }
    160 
    161 ProviderTypeComboboxModel::~ProviderTypeComboboxModel() {
    162 }
    163 
    164 int ProviderTypeComboboxModel::GetItemCount() const {
    165   return PROVIDER_TYPE_INDEX_MAX;
    166 }
    167 
    168 string16 ProviderTypeComboboxModel::GetItemAt(int index) {
    169   return ProviderTypeIndexToString(index);
    170 }
    171 
    172 // VpnServerCACertComboboxModel ------------------------------------------------
    173 
    174 VpnServerCACertComboboxModel::VpnServerCACertComboboxModel() {
    175 }
    176 
    177 VpnServerCACertComboboxModel::~VpnServerCACertComboboxModel() {
    178 }
    179 
    180 int VpnServerCACertComboboxModel::GetItemCount() const {
    181   if (CertLibrary::Get()->CertificatesLoading())
    182     return 1;  // "Loading"
    183   // "Default" + certs.
    184   return CertLibrary::Get()->NumCertificates(
    185       CertLibrary::CERT_TYPE_SERVER_CA) + 1;
    186 }
    187 
    188 string16 VpnServerCACertComboboxModel::GetItemAt(int index) {
    189   if (CertLibrary::Get()->CertificatesLoading())
    190     return l10n_util::GetStringUTF16(
    191         IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING);
    192   if (index == 0)
    193     return l10n_util::GetStringUTF16(
    194         IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA_DEFAULT);
    195   int cert_index = index - 1;
    196   return CertLibrary::Get()->GetCertDisplayStringAt(
    197       CertLibrary::CERT_TYPE_SERVER_CA, cert_index);
    198 }
    199 
    200 // VpnUserCertComboboxModel ----------------------------------------------------
    201 
    202 VpnUserCertComboboxModel::VpnUserCertComboboxModel() {
    203 }
    204 
    205 VpnUserCertComboboxModel::~VpnUserCertComboboxModel() {
    206 }
    207 
    208 int VpnUserCertComboboxModel::GetItemCount() const {
    209   if (CertLibrary::Get()->CertificatesLoading())
    210     return 1;  // "Loading"
    211   int num_certs =
    212       CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER);
    213   if (num_certs == 0)
    214     return 1;  // "None installed"
    215   return num_certs;
    216 }
    217 
    218 string16 VpnUserCertComboboxModel::GetItemAt(int index) {
    219   if (CertLibrary::Get()->CertificatesLoading()) {
    220     return l10n_util::GetStringUTF16(
    221         IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING);
    222   }
    223   if (CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) == 0) {
    224     return l10n_util::GetStringUTF16(
    225         IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USER_CERT_NONE_INSTALLED);
    226   }
    227   return CertLibrary::Get()->GetCertDisplayStringAt(
    228       CertLibrary::CERT_TYPE_USER, index);
    229 }
    230 
    231 }  // namespace internal
    232 
    233 VPNConfigView::VPNConfigView(NetworkConfigView* parent,
    234                              const std::string& service_path)
    235     : ChildNetworkConfigView(parent, service_path),
    236       service_text_modified_(false),
    237       enable_psk_passphrase_(false),
    238       enable_user_cert_(false),
    239       enable_server_ca_cert_(false),
    240       enable_otp_(false),
    241       enable_group_name_(false),
    242       title_(0),
    243       layout_(NULL),
    244       server_textfield_(NULL),
    245       service_text_(NULL),
    246       service_textfield_(NULL),
    247       provider_type_combobox_(NULL),
    248       provider_type_text_label_(NULL),
    249       psk_passphrase_label_(NULL),
    250       psk_passphrase_textfield_(NULL),
    251       user_cert_label_(NULL),
    252       user_cert_combobox_(NULL),
    253       server_ca_cert_label_(NULL),
    254       server_ca_cert_combobox_(NULL),
    255       username_textfield_(NULL),
    256       user_passphrase_textfield_(NULL),
    257       otp_label_(NULL),
    258       otp_textfield_(NULL),
    259       group_name_label_(NULL),
    260       group_name_textfield_(NULL),
    261       save_credentials_checkbox_(NULL),
    262       error_label_(NULL),
    263       provider_type_index_(PROVIDER_TYPE_INDEX_MAX),
    264       weak_ptr_factory_(this) {
    265   Init();
    266 }
    267 
    268 VPNConfigView::~VPNConfigView() {
    269   CertLibrary::Get()->RemoveObserver(this);
    270 }
    271 
    272 string16 VPNConfigView::GetTitle() const {
    273   DCHECK_NE(title_, 0);
    274   return l10n_util::GetStringUTF16(title_);
    275 }
    276 
    277 views::View* VPNConfigView::GetInitiallyFocusedView() {
    278   // Put focus in the first editable field.
    279   if (server_textfield_)
    280     return server_textfield_;
    281   else if (service_textfield_)
    282     return service_textfield_;
    283   else if (provider_type_combobox_)
    284     return provider_type_combobox_;
    285   else if (psk_passphrase_textfield_ && psk_passphrase_textfield_->enabled())
    286     return psk_passphrase_textfield_;
    287   else if (user_cert_combobox_ && user_cert_combobox_->enabled())
    288     return user_cert_combobox_;
    289   else if (server_ca_cert_combobox_ && server_ca_cert_combobox_->enabled())
    290     return server_ca_cert_combobox_;
    291   else
    292     return NULL;
    293 }
    294 
    295 bool VPNConfigView::CanLogin() {
    296   // Username is always required.
    297   if (GetUsername().empty())
    298     return false;
    299 
    300   // TODO(stevenjb): min kMinPassphraseLen length?
    301   if (service_path_.empty() &&
    302       (GetService().empty() || GetServer().empty()))
    303     return false;
    304 
    305   // Block login if certs are required but user has none.
    306   bool cert_required =
    307       GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
    308   if (cert_required && (!HaveUserCerts() || !IsUserCertValid()))
    309     return false;
    310 
    311   return true;
    312 }
    313 
    314 void VPNConfigView::ContentsChanged(views::Textfield* sender,
    315                                     const string16& new_contents) {
    316   if (sender == server_textfield_ && !service_text_modified_) {
    317     // Set the service name to the server name up to '.', unless it has
    318     // been explicitly set by the user.
    319     string16 server = server_textfield_->text();
    320     string16::size_type n = server.find_first_of(L'.');
    321     service_name_from_server_ = server.substr(0, n);
    322     service_textfield_->SetText(service_name_from_server_);
    323   }
    324   if (sender == service_textfield_) {
    325     if (new_contents.empty())
    326       service_text_modified_ = false;
    327     else if (new_contents != service_name_from_server_)
    328       service_text_modified_ = true;
    329   }
    330   UpdateCanLogin();
    331 }
    332 
    333 bool VPNConfigView::HandleKeyEvent(views::Textfield* sender,
    334                                    const ui::KeyEvent& key_event) {
    335   if ((sender == psk_passphrase_textfield_ ||
    336        sender == user_passphrase_textfield_) &&
    337       key_event.key_code() == ui::VKEY_RETURN) {
    338     parent_->GetDialogClientView()->AcceptWindow();
    339   }
    340   return false;
    341 }
    342 
    343 void VPNConfigView::ButtonPressed(views::Button* sender,
    344                                   const ui::Event& event) {
    345 }
    346 
    347 void VPNConfigView::OnSelectedIndexChanged(views::Combobox* combobox) {
    348   UpdateControls();
    349   UpdateErrorLabel();
    350   UpdateCanLogin();
    351 }
    352 
    353 void VPNConfigView::OnCertificatesLoaded(bool initial_load) {
    354   Refresh();
    355 }
    356 
    357 bool VPNConfigView::Login() {
    358   if (service_path_.empty()) {
    359     base::DictionaryValue properties;
    360     // Identifying properties
    361     properties.SetStringWithoutPathExpansion(
    362         flimflam::kTypeProperty, flimflam::kTypeVPN);
    363     properties.SetStringWithoutPathExpansion(
    364         flimflam::kNameProperty, GetService());
    365     properties.SetStringWithoutPathExpansion(
    366         flimflam::kProviderHostProperty, GetServer());
    367     properties.SetStringWithoutPathExpansion(
    368         flimflam::kProviderTypeProperty, GetProviderTypeString());
    369 
    370     SetConfigProperties(&properties);
    371     ash::network_connect::CreateConfigurationAndConnect(
    372         &properties, false /* not shared */);
    373   } else {
    374     const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
    375         GetNetworkState(service_path_);
    376     if (!vpn) {
    377       // Shill no longer knows about this network (edge case).
    378       // TODO(stevenjb): Add notification for this.
    379       NET_LOG_ERROR("Network not found", service_path_);
    380       return true;  // Close dialog
    381     }
    382     base::DictionaryValue properties;
    383     SetConfigProperties(&properties);
    384     ash::network_connect::ConfigureNetworkAndConnect(
    385         service_path_, properties, false /* not shared */);
    386   }
    387   return true;  // Close dialog.
    388 }
    389 
    390 void VPNConfigView::Cancel() {
    391 }
    392 
    393 void VPNConfigView::InitFocus() {
    394   views::View* view_to_focus = GetInitiallyFocusedView();
    395   if (view_to_focus)
    396     view_to_focus->RequestFocus();
    397 }
    398 
    399 const std::string VPNConfigView::GetService() const {
    400   if (service_textfield_ != NULL)
    401     return GetTextFromField(service_textfield_, true);
    402   return service_path_;
    403 }
    404 
    405 const std::string VPNConfigView::GetServer() const {
    406   if (server_textfield_ != NULL)
    407     return GetTextFromField(server_textfield_, true);
    408   return std::string();
    409 }
    410 
    411 const std::string VPNConfigView::GetPSKPassphrase() const {
    412   if (psk_passphrase_textfield_ &&
    413       enable_psk_passphrase_ &&
    414       psk_passphrase_textfield_->visible())
    415     return GetPassphraseFromField(psk_passphrase_textfield_);
    416   return std::string();
    417 }
    418 
    419 const std::string VPNConfigView::GetUsername() const {
    420   return GetTextFromField(username_textfield_, true);
    421 }
    422 
    423 const std::string VPNConfigView::GetUserPassphrase() const {
    424   return GetPassphraseFromField(user_passphrase_textfield_);
    425 }
    426 
    427 const std::string VPNConfigView::GetGroupName() const {
    428   return GetTextFromField(group_name_textfield_, false);
    429 }
    430 
    431 const std::string VPNConfigView::GetOTP() const {
    432   return GetTextFromField(otp_textfield_, true);
    433 }
    434 
    435 const std::string VPNConfigView::GetServerCACertPEM() const {
    436   int index = server_ca_cert_combobox_ ?
    437       server_ca_cert_combobox_->selected_index() : 0;
    438   if (index == 0) {
    439     // First item is "Default".
    440     return std::string();
    441   } else {
    442     int cert_index = index - 1;
    443     return CertLibrary::Get()->GetCertPEMAt(
    444         CertLibrary::CERT_TYPE_SERVER_CA, cert_index);
    445   }
    446 }
    447 
    448 const std::string VPNConfigView::GetUserCertID() const {
    449   if (!HaveUserCerts()) {
    450     return std::string();  // "None installed"
    451   } else {
    452     // Certificates are listed in the order they appear in the model.
    453     int index = user_cert_combobox_ ? user_cert_combobox_->selected_index() : 0;
    454     return CertLibrary::Get()->GetCertPkcs11IdAt(
    455         CertLibrary::CERT_TYPE_USER, index);
    456   }
    457 }
    458 
    459 bool VPNConfigView::GetSaveCredentials() const {
    460   return save_credentials_checkbox_->checked();
    461 }
    462 
    463 int VPNConfigView::GetProviderTypeIndex() const {
    464   if (provider_type_combobox_)
    465     return provider_type_combobox_->selected_index();
    466   return provider_type_index_;
    467 }
    468 
    469 std::string VPNConfigView::GetProviderTypeString() const {
    470   int index = GetProviderTypeIndex();
    471   switch (index) {
    472     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
    473     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
    474       return flimflam::kProviderL2tpIpsec;
    475     case PROVIDER_TYPE_INDEX_OPEN_VPN:
    476       return flimflam::kProviderOpenVpn;
    477   }
    478   NOTREACHED();
    479   return std::string();
    480 }
    481 
    482 void VPNConfigView::Init() {
    483   const NetworkState* vpn = NULL;
    484   if (!service_path_.empty()) {
    485     vpn = NetworkHandler::Get()->network_state_handler()->
    486         GetNetworkState(service_path_);
    487     DCHECK(vpn && vpn->type() == flimflam::kTypeVPN);
    488   }
    489   layout_ = views::GridLayout::CreatePanel(this);
    490   SetLayoutManager(layout_);
    491 
    492   // Observer any changes to the certificate list.
    493   CertLibrary::Get()->AddObserver(this);
    494 
    495   views::ColumnSet* column_set = layout_->AddColumnSet(0);
    496   // Label.
    497   column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
    498                         views::GridLayout::USE_PREF, 0, 0);
    499   column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
    500   // Textfield, combobox.
    501   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
    502                         views::GridLayout::USE_PREF, 0,
    503                         ChildNetworkConfigView::kInputFieldMinWidth);
    504   column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
    505   // Policy indicator.
    506   column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
    507                         views::GridLayout::USE_PREF, 0, 0);
    508 
    509   // Initialize members.
    510   service_text_modified_ = false;
    511   title_ = vpn ? IDS_OPTIONS_SETTINGS_JOIN_VPN : IDS_OPTIONS_SETTINGS_ADD_VPN;
    512 
    513   // By default enable all controls.
    514   enable_psk_passphrase_ = true;
    515   enable_user_cert_ = true;
    516   enable_server_ca_cert_ = true;
    517   enable_otp_ = true;
    518   enable_group_name_ = true;
    519 
    520   // Server label and input.
    521   // Only provide Server name when configuring a new VPN.
    522   if (service_path_.empty()) {
    523     layout_->StartRow(0, 0);
    524     layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
    525       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME)));
    526     server_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    527     server_textfield_->SetController(this);
    528     layout_->AddView(server_textfield_);
    529     layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    530   } else {
    531     server_textfield_ = NULL;
    532   }
    533 
    534   // Service label and name or input.
    535   layout_->StartRow(0, 0);
    536   layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
    537       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME)));
    538   if (service_path_.empty()) {
    539     service_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    540     service_textfield_->SetController(this);
    541     layout_->AddView(service_textfield_);
    542     service_text_ = NULL;
    543   } else {
    544     service_text_ = new views::Label();
    545     service_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    546     layout_->AddView(service_text_);
    547     service_textfield_ = NULL;
    548   }
    549   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    550 
    551   // Provider type label and select.
    552   layout_->StartRow(0, 0);
    553   layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
    554       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE)));
    555   if (service_path_.empty()) {
    556     provider_type_combobox_model_.reset(
    557         new internal::ProviderTypeComboboxModel);
    558     provider_type_combobox_ = new views::Combobox(
    559         provider_type_combobox_model_.get());
    560     provider_type_combobox_->set_listener(this);
    561     layout_->AddView(provider_type_combobox_);
    562     provider_type_text_label_ = NULL;
    563   } else {
    564     provider_type_text_label_ = new views::Label();
    565     provider_type_text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    566     layout_->AddView(provider_type_text_label_);
    567     provider_type_combobox_ = NULL;
    568   }
    569   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    570 
    571   // PSK passphrase label, input and visible button.
    572   layout_->StartRow(0, 0);
    573   psk_passphrase_label_ =  new views::Label(l10n_util::GetStringUTF16(
    574       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE));
    575   layout_->AddView(psk_passphrase_label_);
    576   psk_passphrase_textfield_ = new PassphraseTextfield();
    577   psk_passphrase_textfield_->SetController(this);
    578   layout_->AddView(psk_passphrase_textfield_);
    579   layout_->AddView(
    580       new ControlledSettingIndicatorView(psk_passphrase_ui_data_));
    581   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    582 
    583   // Server CA certificate
    584   if (service_path_.empty()) {
    585     layout_->StartRow(0, 0);
    586     server_ca_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
    587         IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA));
    588     layout_->AddView(server_ca_cert_label_);
    589     server_ca_cert_combobox_model_.reset(
    590         new internal::VpnServerCACertComboboxModel());
    591     server_ca_cert_combobox_ = new views::Combobox(
    592         server_ca_cert_combobox_model_.get());
    593     layout_->AddView(server_ca_cert_combobox_);
    594     layout_->AddView(new ControlledSettingIndicatorView(ca_cert_ui_data_));
    595     layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    596   } else {
    597     server_ca_cert_label_ = NULL;
    598     server_ca_cert_combobox_ = NULL;
    599   }
    600 
    601   // User certificate label and input.
    602   layout_->StartRow(0, 0);
    603   user_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
    604       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT));
    605   layout_->AddView(user_cert_label_);
    606   user_cert_combobox_model_.reset(
    607       new internal::VpnUserCertComboboxModel());
    608   user_cert_combobox_ = new views::Combobox(user_cert_combobox_model_.get());
    609   user_cert_combobox_->set_listener(this);
    610   layout_->AddView(user_cert_combobox_);
    611   layout_->AddView(new ControlledSettingIndicatorView(user_cert_ui_data_));
    612   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    613 
    614   // Username label and input.
    615   layout_->StartRow(0, 0);
    616   layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
    617       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME)));
    618   username_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    619   username_textfield_->SetController(this);
    620   username_textfield_->SetEnabled(username_ui_data_.IsEditable());
    621   layout_->AddView(username_textfield_);
    622   layout_->AddView(new ControlledSettingIndicatorView(username_ui_data_));
    623   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    624 
    625   // User passphrase label, input and visble button.
    626   layout_->StartRow(0, 0);
    627   layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
    628       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE)));
    629   user_passphrase_textfield_ = new PassphraseTextfield();
    630   user_passphrase_textfield_->SetController(this);
    631   user_passphrase_textfield_->SetEnabled(user_passphrase_ui_data_.IsEditable());
    632   layout_->AddView(user_passphrase_textfield_);
    633   layout_->AddView(
    634       new ControlledSettingIndicatorView(user_passphrase_ui_data_));
    635   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    636 
    637   // OTP label and input.
    638   layout_->StartRow(0, 0);
    639   otp_label_ = new views::Label(l10n_util::GetStringUTF16(
    640       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_OTP));
    641   layout_->AddView(otp_label_);
    642   otp_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    643   otp_textfield_->SetController(this);
    644   layout_->AddView(otp_textfield_);
    645   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    646 
    647   // Group Name label and input.
    648   layout_->StartRow(0, 0);
    649   group_name_label_ = new views::Label(l10n_util::GetStringUTF16(
    650       IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_GROUP_NAME));
    651   layout_->AddView(group_name_label_);
    652   group_name_textfield_ =
    653       new views::Textfield(views::Textfield::STYLE_DEFAULT);
    654   group_name_textfield_->SetController(this);
    655   layout_->AddView(group_name_textfield_);
    656   layout_->AddView(new ControlledSettingIndicatorView(group_name_ui_data_));
    657   layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    658 
    659   // Save credentials
    660   layout_->StartRow(0, 0);
    661   save_credentials_checkbox_ = new views::Checkbox(
    662       l10n_util::GetStringUTF16(
    663           IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SAVE_CREDENTIALS));
    664   save_credentials_checkbox_->SetEnabled(
    665       save_credentials_ui_data_.IsEditable());
    666   layout_->SkipColumns(1);
    667   layout_->AddView(save_credentials_checkbox_);
    668   layout_->AddView(
    669       new ControlledSettingIndicatorView(save_credentials_ui_data_));
    670 
    671   // Error label.
    672   layout_->StartRow(0, 0);
    673   layout_->SkipColumns(1);
    674   error_label_ = new views::Label();
    675   error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
    676   error_label_->SetEnabledColor(SK_ColorRED);
    677   layout_->AddView(error_label_);
    678 
    679   // Set or hide the UI, update comboboxes and error labels.
    680   Refresh();
    681 
    682   if (vpn) {
    683     NetworkHandler::Get()->network_configuration_handler()->GetProperties(
    684         service_path_,
    685         base::Bind(&VPNConfigView::InitFromProperties,
    686                    weak_ptr_factory_.GetWeakPtr()),
    687         base::Bind(&VPNConfigView::GetPropertiesError,
    688                    weak_ptr_factory_.GetWeakPtr()));
    689   }
    690 }
    691 
    692 void VPNConfigView::InitFromProperties(
    693     const std::string& service_path,
    694     const base::DictionaryValue& service_properties) {
    695   const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
    696       GetNetworkState(service_path);
    697   if (!vpn) {
    698     NET_LOG_ERROR("Shill Error getting properties VpnConfigView", service_path);
    699     return;
    700   }
    701 
    702   std::string provider_type, server_hostname, username, group_name;
    703   bool psk_passphrase_required = false;
    704   const base::DictionaryValue* provider_properties;
    705   if (service_properties.GetDictionaryWithoutPathExpansion(
    706           flimflam::kProviderProperty, &provider_properties)) {
    707     provider_properties->GetStringWithoutPathExpansion(
    708         flimflam::kTypeProperty, &provider_type);
    709     provider_properties->GetStringWithoutPathExpansion(
    710         flimflam::kHostProperty, &server_hostname);
    711   }
    712   if (provider_type == flimflam::kProviderL2tpIpsec) {
    713     provider_properties->GetStringWithoutPathExpansion(
    714         flimflam::kL2tpIpsecClientCertIdProperty, &client_cert_id_);
    715     ca_cert_pem_ = GetPemFromDictionary(
    716         provider_properties, shill::kL2tpIpsecCaCertPemProperty);
    717     provider_properties->GetBooleanWithoutPathExpansion(
    718         flimflam::kL2tpIpsecPskRequiredProperty, &psk_passphrase_required);
    719     provider_properties->GetStringWithoutPathExpansion(
    720         flimflam::kL2tpIpsecUserProperty, &username);
    721     provider_properties->GetStringWithoutPathExpansion(
    722         shill::kL2tpIpsecTunnelGroupProperty, &group_name);
    723   } else if (provider_type == flimflam::kProviderOpenVpn) {
    724     provider_properties->GetStringWithoutPathExpansion(
    725         flimflam::kOpenVPNClientCertIdProperty, &client_cert_id_);
    726     ca_cert_pem_ = GetPemFromDictionary(
    727         provider_properties, shill::kOpenVPNCaCertPemProperty);
    728     provider_properties->GetStringWithoutPathExpansion(
    729         flimflam::kOpenVPNUserProperty, &username);
    730   }
    731   bool save_credentials = false;
    732   service_properties.GetBooleanWithoutPathExpansion(
    733       flimflam::kSaveCredentialsProperty, &save_credentials);
    734 
    735   provider_type_index_ = ProviderTypeToIndex(provider_type, client_cert_id_);
    736 
    737   if (service_text_)
    738     service_text_->SetText(ASCIIToUTF16(vpn->name()));
    739   if (provider_type_text_label_)
    740     provider_type_text_label_->SetText(
    741         ProviderTypeIndexToString(provider_type_index_));
    742 
    743   if (server_textfield_ && !server_hostname.empty())
    744     server_textfield_->SetText(UTF8ToUTF16(server_hostname));
    745   if (username_textfield_ && !username.empty())
    746     username_textfield_->SetText(UTF8ToUTF16(username));
    747   if (group_name_textfield_ && !group_name.empty())
    748     group_name_textfield_->SetText(UTF8ToUTF16(group_name));
    749   if (psk_passphrase_textfield_)
    750     psk_passphrase_textfield_->SetShowFake(!psk_passphrase_required);
    751   if (save_credentials_checkbox_)
    752     save_credentials_checkbox_->SetChecked(save_credentials);
    753 
    754   Refresh();
    755 }
    756 
    757 void VPNConfigView::ParseUIProperties(const NetworkState* vpn) {
    758   std::string type_dict_name =
    759       ProviderTypeIndexToONCDictKey(provider_type_index_);
    760   if (provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
    761     ParseVPNUIProperty(vpn, type_dict_name, onc::ipsec::kServerCARef,
    762                        &ca_cert_ui_data_);
    763     ParseVPNUIProperty(vpn, type_dict_name, onc::ipsec::kPSK,
    764                        &psk_passphrase_ui_data_);
    765     ParseVPNUIProperty(vpn, type_dict_name, onc::ipsec::kGroup,
    766                        &group_name_ui_data_);
    767   } else if (provider_type_index_ == PROVIDER_TYPE_INDEX_OPEN_VPN) {
    768     ParseVPNUIProperty(vpn, type_dict_name, onc::openvpn::kServerCARef,
    769                        &ca_cert_ui_data_);
    770   }
    771   ParseVPNUIProperty(vpn, type_dict_name, onc::vpn::kClientCertRef,
    772                      &user_cert_ui_data_);
    773 
    774   const std::string credentials_dict_name(
    775       provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK ?
    776       onc::vpn::kL2TP : type_dict_name);
    777   ParseVPNUIProperty(vpn, credentials_dict_name, onc::vpn::kUsername,
    778                      &username_ui_data_);
    779   ParseVPNUIProperty(vpn, credentials_dict_name, onc::vpn::kPassword,
    780                      &user_passphrase_ui_data_);
    781   ParseVPNUIProperty(vpn, credentials_dict_name, onc::vpn::kSaveCredentials,
    782                      &save_credentials_ui_data_);
    783 }
    784 
    785 void VPNConfigView::GetPropertiesError(
    786     const std::string& error_name,
    787     scoped_ptr<base::DictionaryValue> error_data) {
    788   NET_LOG_ERROR("Shill Error from VpnConfigView: " + error_name, "");
    789 }
    790 
    791 void VPNConfigView::SetConfigProperties(
    792     base::DictionaryValue* properties) {
    793   int provider_type_index = GetProviderTypeIndex();
    794   std::string user_passphrase = GetUserPassphrase();
    795   std::string user_name = GetUsername();
    796   std::string group_name = GetGroupName();
    797   switch (provider_type_index) {
    798     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: {
    799       std::string psk_passphrase = GetPSKPassphrase();
    800       if (!psk_passphrase.empty()) {
    801         properties->SetStringWithoutPathExpansion(
    802             flimflam::kL2tpIpsecPskProperty, GetPSKPassphrase());
    803       }
    804       if (!group_name.empty()) {
    805         properties->SetStringWithoutPathExpansion(
    806             shill::kL2tpIpsecTunnelGroupProperty, group_name);
    807       }
    808       if (!user_name.empty()) {
    809         properties->SetStringWithoutPathExpansion(
    810             flimflam::kL2tpIpsecUserProperty, user_name);
    811       }
    812       if (!user_passphrase.empty()) {
    813         properties->SetStringWithoutPathExpansion(
    814             flimflam::kL2tpIpsecPasswordProperty, user_passphrase);
    815       }
    816       break;
    817     }
    818     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: {
    819       std::string ca_cert_pem = GetServerCACertPEM();
    820       if (!ca_cert_pem.empty()) {
    821         properties->SetStringWithoutPathExpansion(
    822             shill::kL2tpIpsecCaCertPemProperty, ca_cert_pem);
    823       }
    824       properties->SetStringWithoutPathExpansion(
    825           flimflam::kL2tpIpsecClientCertIdProperty, GetUserCertID());
    826       if (!group_name.empty()) {
    827         properties->SetStringWithoutPathExpansion(
    828             shill::kL2tpIpsecTunnelGroupProperty, GetGroupName());
    829       }
    830       if (!user_name.empty()) {
    831         properties->SetStringWithoutPathExpansion(
    832             flimflam::kL2tpIpsecUserProperty, user_name);
    833       }
    834       if (!user_passphrase.empty()) {
    835         properties->SetStringWithoutPathExpansion(
    836             flimflam::kL2tpIpsecPasswordProperty, user_passphrase);
    837       }
    838       break;
    839     }
    840     case PROVIDER_TYPE_INDEX_OPEN_VPN: {
    841       std::string ca_cert_pem = GetServerCACertPEM();
    842       if (!ca_cert_pem.empty()) {
    843         base::ListValue* pem_list = new base::ListValue;
    844         pem_list->AppendString(GetServerCACertPEM());
    845         properties->SetWithoutPathExpansion(
    846             shill::kOpenVPNCaCertPemProperty, pem_list);
    847       }
    848       properties->SetStringWithoutPathExpansion(
    849           flimflam::kOpenVPNClientCertIdProperty, GetUserCertID());
    850       properties->SetStringWithoutPathExpansion(
    851           flimflam::kOpenVPNUserProperty, GetUsername());
    852       if (!user_passphrase.empty()) {
    853         properties->SetStringWithoutPathExpansion(
    854             flimflam::kOpenVPNPasswordProperty, user_passphrase);
    855       }
    856       std::string otp = GetOTP();
    857       if (!otp.empty()) {
    858         properties->SetStringWithoutPathExpansion(
    859             flimflam::kOpenVPNOTPProperty, otp);
    860       }
    861       break;
    862     }
    863     case PROVIDER_TYPE_INDEX_MAX:
    864       NOTREACHED();
    865       break;
    866   }
    867   properties->SetBooleanWithoutPathExpansion(
    868       flimflam::kSaveCredentialsProperty, GetSaveCredentials());
    869 }
    870 
    871 void VPNConfigView::Refresh() {
    872   UpdateControls();
    873 
    874   // Set certificate combo boxes.
    875   if (server_ca_cert_combobox_) {
    876     server_ca_cert_combobox_->ModelChanged();
    877     if (enable_server_ca_cert_ && !ca_cert_pem_.empty()) {
    878       // Select the current server CA certificate in the combobox.
    879       int cert_index = CertLibrary::Get()->GetCertIndexByPEM(
    880           CertLibrary::CERT_TYPE_SERVER_CA, ca_cert_pem_);
    881       if (cert_index >= 0) {
    882         // Skip item for "Default"
    883         server_ca_cert_combobox_->SetSelectedIndex(1 + cert_index);
    884       } else {
    885         server_ca_cert_combobox_->SetSelectedIndex(0);
    886       }
    887     } else {
    888       server_ca_cert_combobox_->SetSelectedIndex(0);
    889     }
    890   }
    891 
    892   if (user_cert_combobox_) {
    893     user_cert_combobox_->ModelChanged();
    894     if (enable_user_cert_ && !client_cert_id_.empty()) {
    895       int cert_index = CertLibrary::Get()->GetCertIndexByPkcs11Id(
    896           CertLibrary::CERT_TYPE_USER, client_cert_id_);
    897       if (cert_index >= 0)
    898         user_cert_combobox_->SetSelectedIndex(cert_index);
    899       else
    900         user_cert_combobox_->SetSelectedIndex(0);
    901     } else {
    902       user_cert_combobox_->SetSelectedIndex(0);
    903     }
    904   }
    905 
    906   UpdateErrorLabel();
    907 }
    908 
    909 void VPNConfigView::UpdateControlsToEnable() {
    910   enable_psk_passphrase_ = false;
    911   enable_user_cert_ = false;
    912   enable_server_ca_cert_ = false;
    913   enable_otp_ = false;
    914   enable_group_name_ = false;
    915   int provider_type_index = GetProviderTypeIndex();
    916   if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
    917     enable_psk_passphrase_ = true;
    918     enable_group_name_ = true;
    919   } else if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT) {
    920     enable_server_ca_cert_ = true;
    921     enable_user_cert_ = HaveUserCerts();
    922     enable_group_name_ = true;
    923   } else {  // PROVIDER_TYPE_INDEX_OPEN_VPN (default)
    924     enable_server_ca_cert_ = true;
    925     enable_user_cert_ = HaveUserCerts();
    926     enable_otp_ = true;
    927   }
    928 }
    929 
    930 void VPNConfigView::UpdateControls() {
    931   UpdateControlsToEnable();
    932 
    933   if (psk_passphrase_label_)
    934     psk_passphrase_label_->SetEnabled(enable_psk_passphrase_);
    935   if (psk_passphrase_textfield_)
    936     psk_passphrase_textfield_->SetEnabled(enable_psk_passphrase_ &&
    937                                           psk_passphrase_ui_data_.IsEditable());
    938 
    939   if (user_cert_label_)
    940     user_cert_label_->SetEnabled(enable_user_cert_);
    941   if (user_cert_combobox_)
    942     user_cert_combobox_->SetEnabled(enable_user_cert_ &&
    943                                     user_cert_ui_data_.IsEditable());
    944 
    945   if (server_ca_cert_label_)
    946     server_ca_cert_label_->SetEnabled(enable_server_ca_cert_);
    947   if (server_ca_cert_combobox_)
    948     server_ca_cert_combobox_->SetEnabled(enable_server_ca_cert_ &&
    949                                          ca_cert_ui_data_.IsEditable());
    950 
    951   if (otp_label_)
    952     otp_label_->SetEnabled(enable_otp_);
    953   if (otp_textfield_)
    954     otp_textfield_->SetEnabled(enable_otp_);
    955 
    956   if (group_name_label_)
    957     group_name_label_->SetEnabled(enable_group_name_);
    958   if (group_name_textfield_)
    959     group_name_textfield_->SetEnabled(enable_group_name_ &&
    960                                       group_name_ui_data_.IsEditable());
    961 }
    962 
    963 void VPNConfigView::UpdateErrorLabel() {
    964   // Error message.
    965   string16 error_msg;
    966   bool cert_required =
    967       GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
    968   if (cert_required && CertLibrary::Get()->CertificatesLoaded()) {
    969     if (!HaveUserCerts()) {
    970       error_msg = l10n_util::GetStringUTF16(
    971           IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT);
    972     } else if (!IsUserCertValid()) {
    973       error_msg = l10n_util::GetStringUTF16(
    974           IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_REQUIRE_HARDWARE_BACKED);
    975     }
    976   }
    977   if (error_msg.empty() && !service_path_.empty()) {
    978     // TODO(kuan): differentiate between bad psk and user passphrases.
    979     const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
    980         GetNetworkState(service_path_);
    981     if (vpn && vpn->connection_state() == flimflam::kStateFailure)
    982       error_msg = ash::network_connect::ErrorString(vpn->error());
    983   }
    984   if (!error_msg.empty()) {
    985     error_label_->SetText(error_msg);
    986     error_label_->SetVisible(true);
    987   } else {
    988     error_label_->SetVisible(false);
    989   }
    990 }
    991 
    992 void VPNConfigView::UpdateCanLogin() {
    993   parent_->GetDialogClientView()->UpdateDialogButtons();
    994 }
    995 
    996 bool VPNConfigView::HaveUserCerts() const {
    997   return CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) > 0;
    998 }
    999 
   1000 bool VPNConfigView::IsUserCertValid() const {
   1001   if (!user_cert_combobox_ || !enable_user_cert_)
   1002     return false;
   1003   int index = user_cert_combobox_->selected_index();
   1004   if (index < 0)
   1005     return false;
   1006   // Currently only hardware-backed user certificates are valid.
   1007   if (CertLibrary::Get()->IsHardwareBacked() &&
   1008       !CertLibrary::Get()->IsCertHardwareBackedAt(
   1009           CertLibrary::CERT_TYPE_USER, index))
   1010     return false;
   1011   return true;
   1012 }
   1013 
   1014 const std::string VPNConfigView::GetTextFromField(views::Textfield* textfield,
   1015                                                   bool trim_whitespace) const {
   1016   if (!textfield)
   1017     return std::string();
   1018   std::string untrimmed = UTF16ToUTF8(textfield->text());
   1019   if (!trim_whitespace)
   1020     return untrimmed;
   1021   std::string result;
   1022   TrimWhitespaceASCII(untrimmed, TRIM_ALL, &result);
   1023   return result;
   1024 }
   1025 
   1026 const std::string VPNConfigView::GetPassphraseFromField(
   1027     PassphraseTextfield* textfield) const {
   1028   if (!textfield)
   1029     return std::string();
   1030   return textfield->GetPassphrase();
   1031 }
   1032 
   1033 void VPNConfigView::ParseVPNUIProperty(
   1034     const NetworkState* network,
   1035     const std::string& dict_key,
   1036     const std::string& key,
   1037     NetworkPropertyUIData* property_ui_data) {
   1038   onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
   1039   const base::DictionaryValue* onc =
   1040       network_connect::FindPolicyForActiveUser(network, &onc_source);
   1041 
   1042   VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->guid();
   1043   property_ui_data->ParseOncProperty(
   1044       onc_source,
   1045       onc,
   1046       base::StringPrintf("%s.%s.%s",
   1047                          onc::network_config::kVPN,
   1048                          dict_key.c_str(),
   1049                          key.c_str()));
   1050 }
   1051 
   1052 }  // namespace chromeos
   1053