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