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