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