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