vpn_config_view.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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
41namespace {
42
43enum 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
50base::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
66int 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.
81std::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
93std::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
106namespace chromeos {
107
108namespace internal {
109
110class 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
123class 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
136class 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
151ProviderTypeComboboxModel::ProviderTypeComboboxModel() {
152}
153
154ProviderTypeComboboxModel::~ProviderTypeComboboxModel() {
155}
156
157int ProviderTypeComboboxModel::GetItemCount() const {
158  return PROVIDER_TYPE_INDEX_MAX;
159}
160
161base::string16 ProviderTypeComboboxModel::GetItemAt(int index) {
162  return ProviderTypeIndexToString(index);
163}
164
165// VpnServerCACertComboboxModel ------------------------------------------------
166
167VpnServerCACertComboboxModel::VpnServerCACertComboboxModel() {
168}
169
170VpnServerCACertComboboxModel::~VpnServerCACertComboboxModel() {
171}
172
173int 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
181base::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
195VpnUserCertComboboxModel::VpnUserCertComboboxModel() {
196}
197
198VpnUserCertComboboxModel::~VpnUserCertComboboxModel() {
199}
200
201int 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
211base::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
226VPNConfigView::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
261VPNConfigView::~VPNConfigView() {
262  RemoveAllChildViews(true);  // Destroy children before models
263  CertLibrary::Get()->RemoveObserver(this);
264}
265
266base::string16 VPNConfigView::GetTitle() const {
267  DCHECK_NE(title_, 0);
268  return l10n_util::GetStringUTF16(title_);
269}
270
271views::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
294bool 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
313void 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
332bool 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
342void VPNConfigView::ButtonPressed(views::Button* sender,
343                                  const ui::Event& event) {
344}
345
346void VPNConfigView::OnPerformAction(views::Combobox* combobox) {
347  UpdateControls();
348  UpdateErrorLabel();
349  UpdateCanLogin();
350}
351
352void VPNConfigView::OnCertificatesLoaded(bool initial_load) {
353  Refresh();
354}
355
356bool 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 = !LoginState::Get()->IsUserAuthenticated();
371
372    bool only_policy_autoconnect =
373        onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!shared);
374    if (only_policy_autoconnect) {
375      properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty,
376                                                false);
377    }
378
379    ash::network_connect::CreateConfigurationAndConnect(&properties, shared);
380  } else {
381    const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
382        GetNetworkState(service_path_);
383    if (!vpn) {
384      // Shill no longer knows about this network (edge case).
385      // TODO(stevenjb): Add notification for this.
386      NET_LOG_ERROR("Network not found", service_path_);
387      return true;  // Close dialog
388    }
389    base::DictionaryValue properties;
390    SetConfigProperties(&properties);
391    ash::network_connect::ConfigureNetworkAndConnect(
392        service_path_, properties, false /* not shared */);
393  }
394  return true;  // Close dialog.
395}
396
397void VPNConfigView::Cancel() {
398}
399
400void VPNConfigView::InitFocus() {
401  views::View* view_to_focus = GetInitiallyFocusedView();
402  if (view_to_focus)
403    view_to_focus->RequestFocus();
404}
405
406const std::string VPNConfigView::GetService() const {
407  if (service_textfield_ != NULL)
408    return GetTextFromField(service_textfield_, true);
409  return service_path_;
410}
411
412const std::string VPNConfigView::GetServer() const {
413  if (server_textfield_ != NULL)
414    return GetTextFromField(server_textfield_, true);
415  return std::string();
416}
417
418const std::string VPNConfigView::GetPSKPassphrase() const {
419  if (psk_passphrase_textfield_ &&
420      enable_psk_passphrase_ &&
421      psk_passphrase_textfield_->visible())
422    return GetPassphraseFromField(psk_passphrase_textfield_);
423  return std::string();
424}
425
426const std::string VPNConfigView::GetUsername() const {
427  return GetTextFromField(username_textfield_, true);
428}
429
430const std::string VPNConfigView::GetUserPassphrase() const {
431  return GetPassphraseFromField(user_passphrase_textfield_);
432}
433
434const std::string VPNConfigView::GetGroupName() const {
435  return GetTextFromField(group_name_textfield_, false);
436}
437
438const std::string VPNConfigView::GetOTP() const {
439  return GetTextFromField(otp_textfield_, true);
440}
441
442const std::string VPNConfigView::GetServerCACertPEM() const {
443  int index = server_ca_cert_combobox_ ?
444      server_ca_cert_combobox_->selected_index() : 0;
445  if (index == 0) {
446    // First item is "Default".
447    return std::string();
448  } else {
449    int cert_index = index - 1;
450    return CertLibrary::Get()->GetServerCACertPEMAt(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()->GetUserCertPkcs11IdAt(index);
461  }
462}
463
464bool VPNConfigView::GetSaveCredentials() const {
465  return save_credentials_checkbox_->checked();
466}
467
468int VPNConfigView::GetProviderTypeIndex() const {
469  if (provider_type_combobox_)
470    return provider_type_combobox_->selected_index();
471  return provider_type_index_;
472}
473
474std::string VPNConfigView::GetProviderTypeString() const {
475  int index = GetProviderTypeIndex();
476  switch (index) {
477    case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
478    case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
479      return shill::kProviderL2tpIpsec;
480    case PROVIDER_TYPE_INDEX_OPEN_VPN:
481      return shill::kProviderOpenVpn;
482  }
483  NOTREACHED();
484  return std::string();
485}
486
487void VPNConfigView::Init() {
488  const NetworkState* vpn = NULL;
489  if (!service_path_.empty()) {
490    vpn = NetworkHandler::Get()->network_state_handler()->
491        GetNetworkState(service_path_);
492    DCHECK(vpn && vpn->type() == shill::kTypeVPN);
493  }
494  layout_ = views::GridLayout::CreatePanel(this);
495  SetLayoutManager(layout_);
496
497  // Observer any changes to the certificate list.
498  CertLibrary::Get()->AddObserver(this);
499
500  views::ColumnSet* column_set = layout_->AddColumnSet(0);
501  // Label.
502  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
503                        views::GridLayout::USE_PREF, 0, 0);
504  column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
505  // Textfield, combobox.
506  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
507                        views::GridLayout::USE_PREF, 0,
508                        ChildNetworkConfigView::kInputFieldMinWidth);
509  column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
510  // Policy indicator.
511  column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
512                        views::GridLayout::USE_PREF, 0, 0);
513
514  // Initialize members.
515  service_text_modified_ = false;
516  title_ = vpn ? IDS_OPTIONS_SETTINGS_JOIN_VPN : IDS_OPTIONS_SETTINGS_ADD_VPN;
517
518  // By default enable all controls.
519  enable_psk_passphrase_ = true;
520  enable_user_cert_ = true;
521  enable_server_ca_cert_ = true;
522  enable_otp_ = true;
523  enable_group_name_ = true;
524
525  // Server label and input.
526  layout_->StartRow(0, 0);
527  views::View* server_label =
528      new views::Label(l10n_util::GetStringUTF16(
529          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME));
530  layout_->AddView(server_label);
531  server_textfield_ = new views::Textfield();
532  server_textfield_->set_controller(this);
533  layout_->AddView(server_textfield_);
534  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
535  if (!service_path_.empty()) {
536    server_label->SetEnabled(false);
537    server_textfield_->SetEnabled(false);
538  }
539
540  // Service label and name or input.
541  layout_->StartRow(0, 0);
542  layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
543      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME)));
544  if (service_path_.empty()) {
545    service_textfield_ = new views::Textfield();
546    service_textfield_->set_controller(this);
547    layout_->AddView(service_textfield_);
548    service_text_ = NULL;
549  } else {
550    service_text_ = new views::Label();
551    service_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
552    layout_->AddView(service_text_);
553    service_textfield_ = NULL;
554  }
555  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
556
557  // Provider type label and select.
558  layout_->StartRow(0, 0);
559  layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
560      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE)));
561  if (service_path_.empty()) {
562    provider_type_combobox_model_.reset(
563        new internal::ProviderTypeComboboxModel);
564    provider_type_combobox_ = new views::Combobox(
565        provider_type_combobox_model_.get());
566    provider_type_combobox_->set_listener(this);
567    layout_->AddView(provider_type_combobox_);
568    provider_type_text_label_ = NULL;
569  } else {
570    provider_type_text_label_ = new views::Label();
571    provider_type_text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
572    layout_->AddView(provider_type_text_label_);
573    provider_type_combobox_ = NULL;
574  }
575  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
576
577  // PSK passphrase label, input and visible button.
578  layout_->StartRow(0, 0);
579  psk_passphrase_label_ =  new views::Label(l10n_util::GetStringUTF16(
580      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE));
581  layout_->AddView(psk_passphrase_label_);
582  psk_passphrase_textfield_ = new PassphraseTextfield();
583  psk_passphrase_textfield_->set_controller(this);
584  layout_->AddView(psk_passphrase_textfield_);
585  layout_->AddView(
586      new ControlledSettingIndicatorView(psk_passphrase_ui_data_));
587  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
588
589  // Server CA certificate
590  if (service_path_.empty()) {
591    layout_->StartRow(0, 0);
592    server_ca_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
593        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA));
594    layout_->AddView(server_ca_cert_label_);
595    server_ca_cert_combobox_model_.reset(
596        new internal::VpnServerCACertComboboxModel());
597    server_ca_cert_combobox_ = new views::Combobox(
598        server_ca_cert_combobox_model_.get());
599    layout_->AddView(server_ca_cert_combobox_);
600    layout_->AddView(new ControlledSettingIndicatorView(ca_cert_ui_data_));
601    layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
602  } else {
603    server_ca_cert_label_ = NULL;
604    server_ca_cert_combobox_ = NULL;
605  }
606
607  // User certificate label and input.
608  layout_->StartRow(0, 0);
609  user_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
610      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT));
611  layout_->AddView(user_cert_label_);
612  user_cert_combobox_model_.reset(
613      new internal::VpnUserCertComboboxModel());
614  user_cert_combobox_ = new views::Combobox(user_cert_combobox_model_.get());
615  user_cert_combobox_->set_listener(this);
616  layout_->AddView(user_cert_combobox_);
617  layout_->AddView(new ControlledSettingIndicatorView(user_cert_ui_data_));
618  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
619
620  // Username label and input.
621  layout_->StartRow(0, 0);
622  layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
623      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME)));
624  username_textfield_ = new views::Textfield();
625  username_textfield_->set_controller(this);
626  username_textfield_->SetEnabled(username_ui_data_.IsEditable());
627  layout_->AddView(username_textfield_);
628  layout_->AddView(new ControlledSettingIndicatorView(username_ui_data_));
629  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
630
631  // User passphrase label, input and visble button.
632  layout_->StartRow(0, 0);
633  layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
634      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE)));
635  user_passphrase_textfield_ = new PassphraseTextfield();
636  user_passphrase_textfield_->set_controller(this);
637  user_passphrase_textfield_->SetEnabled(user_passphrase_ui_data_.IsEditable());
638  layout_->AddView(user_passphrase_textfield_);
639  layout_->AddView(
640      new ControlledSettingIndicatorView(user_passphrase_ui_data_));
641  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
642
643  // OTP label and input.
644  layout_->StartRow(0, 0);
645  otp_label_ = new views::Label(l10n_util::GetStringUTF16(
646      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_OTP));
647  layout_->AddView(otp_label_);
648  otp_textfield_ = new views::Textfield();
649  otp_textfield_->set_controller(this);
650  layout_->AddView(otp_textfield_);
651  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
652
653  // Group Name label and input.
654  layout_->StartRow(0, 0);
655  group_name_label_ = new views::Label(l10n_util::GetStringUTF16(
656      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_GROUP_NAME));
657  layout_->AddView(group_name_label_);
658  group_name_textfield_ =
659      new views::Textfield();
660  group_name_textfield_->set_controller(this);
661  layout_->AddView(group_name_textfield_);
662  layout_->AddView(new ControlledSettingIndicatorView(group_name_ui_data_));
663  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
664
665  // Save credentials
666  layout_->StartRow(0, 0);
667  save_credentials_checkbox_ = new views::Checkbox(
668      l10n_util::GetStringUTF16(
669          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SAVE_CREDENTIALS));
670  save_credentials_checkbox_->SetEnabled(
671      save_credentials_ui_data_.IsEditable());
672  layout_->SkipColumns(1);
673  layout_->AddView(save_credentials_checkbox_);
674  layout_->AddView(
675      new ControlledSettingIndicatorView(save_credentials_ui_data_));
676
677  // Error label.
678  layout_->StartRow(0, 0);
679  layout_->SkipColumns(1);
680  error_label_ = new views::Label();
681  error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
682  error_label_->SetEnabledColor(SK_ColorRED);
683  layout_->AddView(error_label_);
684
685  // Set or hide the UI, update comboboxes and error labels.
686  Refresh();
687
688  if (vpn) {
689    NetworkHandler::Get()->network_configuration_handler()->GetProperties(
690        service_path_,
691        base::Bind(&VPNConfigView::InitFromProperties,
692                   weak_ptr_factory_.GetWeakPtr()),
693        base::Bind(&VPNConfigView::GetPropertiesError,
694                   weak_ptr_factory_.GetWeakPtr()));
695  }
696}
697
698void VPNConfigView::InitFromProperties(
699    const std::string& service_path,
700    const base::DictionaryValue& service_properties) {
701  const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
702      GetNetworkState(service_path);
703  if (!vpn) {
704    NET_LOG_ERROR("Shill Error getting properties VpnConfigView", service_path);
705    return;
706  }
707
708  std::string provider_type, server_hostname, username, group_name;
709  bool psk_passphrase_required = false;
710  const base::DictionaryValue* provider_properties;
711  if (service_properties.GetDictionaryWithoutPathExpansion(
712          shill::kProviderProperty, &provider_properties)) {
713    provider_properties->GetStringWithoutPathExpansion(
714        shill::kTypeProperty, &provider_type);
715    provider_properties->GetStringWithoutPathExpansion(
716        shill::kHostProperty, &server_hostname);
717  }
718  if (provider_type == shill::kProviderL2tpIpsec) {
719    provider_properties->GetStringWithoutPathExpansion(
720        shill::kL2tpIpsecClientCertIdProperty, &client_cert_id_);
721    ca_cert_pem_ = GetPemFromDictionary(
722        provider_properties, shill::kL2tpIpsecCaCertPemProperty);
723    provider_properties->GetBooleanWithoutPathExpansion(
724        shill::kL2tpIpsecPskRequiredProperty, &psk_passphrase_required);
725    provider_properties->GetStringWithoutPathExpansion(
726        shill::kL2tpIpsecUserProperty, &username);
727    provider_properties->GetStringWithoutPathExpansion(
728        shill::kL2tpIpsecTunnelGroupProperty, &group_name);
729  } else if (provider_type == shill::kProviderOpenVpn) {
730    provider_properties->GetStringWithoutPathExpansion(
731        shill::kOpenVPNClientCertIdProperty, &client_cert_id_);
732    ca_cert_pem_ = GetPemFromDictionary(
733        provider_properties, shill::kOpenVPNCaCertPemProperty);
734    provider_properties->GetStringWithoutPathExpansion(
735        shill::kOpenVPNUserProperty, &username);
736  }
737  bool save_credentials = false;
738  service_properties.GetBooleanWithoutPathExpansion(
739      shill::kSaveCredentialsProperty, &save_credentials);
740
741  provider_type_index_ = ProviderTypeToIndex(provider_type, client_cert_id_);
742
743  if (service_text_)
744    service_text_->SetText(base::ASCIIToUTF16(vpn->name()));
745  if (provider_type_text_label_)
746    provider_type_text_label_->SetText(
747        ProviderTypeIndexToString(provider_type_index_));
748
749  if (server_textfield_ && !server_hostname.empty())
750    server_textfield_->SetText(base::UTF8ToUTF16(server_hostname));
751  if (username_textfield_ && !username.empty())
752    username_textfield_->SetText(base::UTF8ToUTF16(username));
753  if (group_name_textfield_ && !group_name.empty())
754    group_name_textfield_->SetText(base::UTF8ToUTF16(group_name));
755  if (psk_passphrase_textfield_)
756    psk_passphrase_textfield_->SetShowFake(!psk_passphrase_required);
757  if (save_credentials_checkbox_)
758    save_credentials_checkbox_->SetChecked(save_credentials);
759
760  Refresh();
761}
762
763void VPNConfigView::ParseUIProperties(const NetworkState* vpn) {
764  std::string type_dict_name =
765      ProviderTypeIndexToONCDictKey(provider_type_index_);
766  if (provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
767    ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kServerCARef,
768                       &ca_cert_ui_data_);
769    ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kPSK,
770                       &psk_passphrase_ui_data_);
771    ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kGroup,
772                       &group_name_ui_data_);
773  } else if (provider_type_index_ == PROVIDER_TYPE_INDEX_OPEN_VPN) {
774    ParseVPNUIProperty(vpn, type_dict_name, ::onc::openvpn::kServerCARef,
775                       &ca_cert_ui_data_);
776  }
777  ParseVPNUIProperty(vpn, type_dict_name, ::onc::vpn::kClientCertRef,
778                     &user_cert_ui_data_);
779
780  const std::string credentials_dict_name(
781      provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK ?
782      ::onc::vpn::kL2TP : type_dict_name);
783  ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kUsername,
784                     &username_ui_data_);
785  ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kPassword,
786                     &user_passphrase_ui_data_);
787  ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kSaveCredentials,
788                     &save_credentials_ui_data_);
789}
790
791void VPNConfigView::GetPropertiesError(
792    const std::string& error_name,
793    scoped_ptr<base::DictionaryValue> error_data) {
794  NET_LOG_ERROR("Shill Error from VpnConfigView: " + error_name, "");
795}
796
797void VPNConfigView::SetConfigProperties(
798    base::DictionaryValue* properties) {
799  int provider_type_index = GetProviderTypeIndex();
800  std::string user_passphrase = GetUserPassphrase();
801  std::string user_name = GetUsername();
802  std::string group_name = GetGroupName();
803  switch (provider_type_index) {
804    case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: {
805      std::string psk_passphrase = GetPSKPassphrase();
806      if (!psk_passphrase.empty()) {
807        properties->SetStringWithoutPathExpansion(
808            shill::kL2tpIpsecPskProperty, GetPSKPassphrase());
809      }
810      if (!group_name.empty()) {
811        properties->SetStringWithoutPathExpansion(
812            shill::kL2tpIpsecTunnelGroupProperty, group_name);
813      }
814      if (!user_name.empty()) {
815        properties->SetStringWithoutPathExpansion(
816            shill::kL2tpIpsecUserProperty, user_name);
817      }
818      if (!user_passphrase.empty()) {
819        properties->SetStringWithoutPathExpansion(
820            shill::kL2tpIpsecPasswordProperty, user_passphrase);
821      }
822      break;
823    }
824    case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: {
825      std::string ca_cert_pem = GetServerCACertPEM();
826      if (!ca_cert_pem.empty()) {
827        base::ListValue* pem_list = new base::ListValue;
828        pem_list->AppendString(ca_cert_pem);
829        properties->SetWithoutPathExpansion(
830            shill::kL2tpIpsecCaCertPemProperty, pem_list);
831      }
832      properties->SetStringWithoutPathExpansion(
833          shill::kL2tpIpsecClientCertIdProperty, GetUserCertID());
834      if (!group_name.empty()) {
835        properties->SetStringWithoutPathExpansion(
836            shill::kL2tpIpsecTunnelGroupProperty, GetGroupName());
837      }
838      if (!user_name.empty()) {
839        properties->SetStringWithoutPathExpansion(
840            shill::kL2tpIpsecUserProperty, user_name);
841      }
842      if (!user_passphrase.empty()) {
843        properties->SetStringWithoutPathExpansion(
844            shill::kL2tpIpsecPasswordProperty, user_passphrase);
845      }
846      break;
847    }
848    case PROVIDER_TYPE_INDEX_OPEN_VPN: {
849      std::string ca_cert_pem = GetServerCACertPEM();
850      if (!ca_cert_pem.empty()) {
851        base::ListValue* pem_list = new base::ListValue;
852        pem_list->AppendString(ca_cert_pem);
853        properties->SetWithoutPathExpansion(
854            shill::kOpenVPNCaCertPemProperty, pem_list);
855      }
856      properties->SetStringWithoutPathExpansion(
857          shill::kOpenVPNClientCertIdProperty, GetUserCertID());
858      properties->SetStringWithoutPathExpansion(
859          shill::kOpenVPNUserProperty, GetUsername());
860      if (!user_passphrase.empty()) {
861        properties->SetStringWithoutPathExpansion(
862            shill::kOpenVPNPasswordProperty, user_passphrase);
863      }
864      std::string otp = GetOTP();
865      if (!otp.empty()) {
866        properties->SetStringWithoutPathExpansion(
867            shill::kOpenVPNOTPProperty, otp);
868      }
869      break;
870    }
871    case PROVIDER_TYPE_INDEX_MAX:
872      NOTREACHED();
873      break;
874  }
875  properties->SetBooleanWithoutPathExpansion(
876      shill::kSaveCredentialsProperty, GetSaveCredentials());
877}
878
879void VPNConfigView::Refresh() {
880  UpdateControls();
881
882  // Set certificate combo boxes.
883  if (server_ca_cert_combobox_) {
884    server_ca_cert_combobox_->ModelChanged();
885    if (enable_server_ca_cert_ && !ca_cert_pem_.empty()) {
886      // Select the current server CA certificate in the combobox.
887      int cert_index =
888          CertLibrary::Get()->GetServerCACertIndexByPEM(ca_cert_pem_);
889      if (cert_index >= 0) {
890        // Skip item for "Default"
891        server_ca_cert_combobox_->SetSelectedIndex(1 + cert_index);
892      } else {
893        server_ca_cert_combobox_->SetSelectedIndex(0);
894      }
895    } else {
896      server_ca_cert_combobox_->SetSelectedIndex(0);
897    }
898  }
899
900  if (user_cert_combobox_) {
901    user_cert_combobox_->ModelChanged();
902    if (enable_user_cert_ && !client_cert_id_.empty()) {
903      int cert_index =
904          CertLibrary::Get()->GetUserCertIndexByPkcs11Id(client_cert_id_);
905      if (cert_index >= 0)
906        user_cert_combobox_->SetSelectedIndex(cert_index);
907      else
908        user_cert_combobox_->SetSelectedIndex(0);
909    } else {
910      user_cert_combobox_->SetSelectedIndex(0);
911    }
912  }
913
914  UpdateErrorLabel();
915}
916
917void VPNConfigView::UpdateControlsToEnable() {
918  enable_psk_passphrase_ = false;
919  enable_user_cert_ = false;
920  enable_server_ca_cert_ = false;
921  enable_otp_ = false;
922  enable_group_name_ = false;
923  int provider_type_index = GetProviderTypeIndex();
924  if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
925    enable_psk_passphrase_ = true;
926    enable_group_name_ = true;
927  } else if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT) {
928    enable_server_ca_cert_ = true;
929    enable_user_cert_ = HaveUserCerts();
930    enable_group_name_ = true;
931  } else {  // PROVIDER_TYPE_INDEX_OPEN_VPN (default)
932    enable_server_ca_cert_ = true;
933    enable_user_cert_ = HaveUserCerts();
934    enable_otp_ = true;
935  }
936}
937
938void VPNConfigView::UpdateControls() {
939  UpdateControlsToEnable();
940
941  if (psk_passphrase_label_)
942    psk_passphrase_label_->SetEnabled(enable_psk_passphrase_);
943  if (psk_passphrase_textfield_)
944    psk_passphrase_textfield_->SetEnabled(enable_psk_passphrase_ &&
945                                          psk_passphrase_ui_data_.IsEditable());
946
947  if (user_cert_label_)
948    user_cert_label_->SetEnabled(enable_user_cert_);
949  if (user_cert_combobox_)
950    user_cert_combobox_->SetEnabled(enable_user_cert_ &&
951                                    user_cert_ui_data_.IsEditable());
952
953  if (server_ca_cert_label_)
954    server_ca_cert_label_->SetEnabled(enable_server_ca_cert_);
955  if (server_ca_cert_combobox_)
956    server_ca_cert_combobox_->SetEnabled(enable_server_ca_cert_ &&
957                                         ca_cert_ui_data_.IsEditable());
958
959  if (otp_label_)
960    otp_label_->SetEnabled(enable_otp_);
961  if (otp_textfield_)
962    otp_textfield_->SetEnabled(enable_otp_);
963
964  if (group_name_label_)
965    group_name_label_->SetEnabled(enable_group_name_);
966  if (group_name_textfield_)
967    group_name_textfield_->SetEnabled(enable_group_name_ &&
968                                      group_name_ui_data_.IsEditable());
969}
970
971void VPNConfigView::UpdateErrorLabel() {
972  // Error message.
973  base::string16 error_msg;
974  bool cert_required =
975      GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
976  if (cert_required && CertLibrary::Get()->CertificatesLoaded()) {
977    if (!HaveUserCerts()) {
978      error_msg = l10n_util::GetStringUTF16(
979          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT);
980    } else if (!IsUserCertValid()) {
981      error_msg = l10n_util::GetStringUTF16(
982          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_REQUIRE_HARDWARE_BACKED);
983    }
984  }
985  if (error_msg.empty() && !service_path_.empty()) {
986    // TODO(kuan): differentiate between bad psk and user passphrases.
987    const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
988        GetNetworkState(service_path_);
989    if (vpn && vpn->connection_state() == shill::kStateFailure)
990      error_msg = ash::network_connect::ErrorString(
991          vpn->last_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 = base::UTF16ToUTF8(textfield->text());
1028  if (!trim_whitespace)
1029    return untrimmed;
1030  std::string result;
1031  base::TrimWhitespaceASCII(untrimmed, base::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