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