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