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
37namespace {
38
39enum 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
46base::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
62int 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.
77std::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
89std::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
102namespace chromeos {
103
104namespace internal {
105
106class 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
119class 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
132class 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
147ProviderTypeComboboxModel::ProviderTypeComboboxModel() {
148}
149
150ProviderTypeComboboxModel::~ProviderTypeComboboxModel() {
151}
152
153int ProviderTypeComboboxModel::GetItemCount() const {
154  return PROVIDER_TYPE_INDEX_MAX;
155}
156
157base::string16 ProviderTypeComboboxModel::GetItemAt(int index) {
158  return ProviderTypeIndexToString(index);
159}
160
161// VpnServerCACertComboboxModel ------------------------------------------------
162
163VpnServerCACertComboboxModel::VpnServerCACertComboboxModel() {
164}
165
166VpnServerCACertComboboxModel::~VpnServerCACertComboboxModel() {
167}
168
169int 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
177base::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
191VpnUserCertComboboxModel::VpnUserCertComboboxModel() {
192}
193
194VpnUserCertComboboxModel::~VpnUserCertComboboxModel() {
195}
196
197int 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
207base::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
222VPNConfigView::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
257VPNConfigView::~VPNConfigView() {
258  RemoveAllChildViews(true);  // Destroy children before models
259  CertLibrary::Get()->RemoveObserver(this);
260}
261
262base::string16 VPNConfigView::GetTitle() const {
263  DCHECK_NE(title_, 0);
264  return l10n_util::GetStringUTF16(title_);
265}
266
267views::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
290bool 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
309void 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
328bool 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
338void VPNConfigView::ButtonPressed(views::Button* sender,
339                                  const ui::Event& event) {
340}
341
342void VPNConfigView::OnPerformAction(views::Combobox* combobox) {
343  UpdateControls();
344  UpdateErrorLabel();
345  UpdateCanLogin();
346}
347
348void VPNConfigView::OnCertificatesLoaded(bool initial_load) {
349  Refresh();
350}
351
352bool 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
395void VPNConfigView::Cancel() {
396}
397
398void VPNConfigView::InitFocus() {
399  views::View* view_to_focus = GetInitiallyFocusedView();
400  if (view_to_focus)
401    view_to_focus->RequestFocus();
402}
403
404const std::string VPNConfigView::GetService() const {
405  if (service_textfield_ != NULL)
406    return GetTextFromField(service_textfield_, true);
407  return service_path_;
408}
409
410const std::string VPNConfigView::GetServer() const {
411  if (server_textfield_ != NULL)
412    return GetTextFromField(server_textfield_, true);
413  return std::string();
414}
415
416const 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
424const std::string VPNConfigView::GetUsername() const {
425  return GetTextFromField(username_textfield_, true);
426}
427
428const std::string VPNConfigView::GetUserPassphrase() const {
429  return GetPassphraseFromField(user_passphrase_textfield_);
430}
431
432const std::string VPNConfigView::GetGroupName() const {
433  return GetTextFromField(group_name_textfield_, false);
434}
435
436const std::string VPNConfigView::GetOTP() const {
437  return GetTextFromField(otp_textfield_, true);
438}
439
440const 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
452void 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
470bool VPNConfigView::GetSaveCredentials() const {
471  return save_credentials_checkbox_->checked();
472}
473
474int VPNConfigView::GetProviderTypeIndex() const {
475  if (provider_type_combobox_)
476    return provider_type_combobox_->selected_index();
477  return provider_type_index_;
478}
479
480std::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
493void 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
704void 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
775void 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
803void 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
809void 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
891void 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
929void 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
950void 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
983void 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
1013void VPNConfigView::UpdateCanLogin() {
1014  parent_->GetDialogClientView()->UpdateDialogButtons();
1015}
1016
1017bool VPNConfigView::HaveUserCerts() const {
1018  return CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) > 0;
1019}
1020
1021bool 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
1035const 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
1047const std::string VPNConfigView::GetPassphraseFromField(
1048    PassphraseTextfield* textfield) const {
1049  if (!textfield)
1050    return std::string();
1051  return textfield->GetPassphrase();
1052}
1053
1054void 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