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.
5 #include "chrome/browser/chromeos/options/vpn_config_view.h"
7 #include "ash/system/chromeos/network/network_connect.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"
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,
49 base::string16 ProviderTypeIndexToString(int 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);
62 return base::string16();
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;
71 return PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK;
73 DCHECK(provider_type == shill::kProviderOpenVpn);
74 return PROVIDER_TYPE_INDEX_OPEN_VPN;
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;
88 NOTREACHED() << "Unhandled provider type index " << provider_type_index;
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))
99 pems->GetString(0, &pem);
109 class ProviderTypeComboboxModel : public ui::ComboboxModel {
111 ProviderTypeComboboxModel();
112 virtual ~ProviderTypeComboboxModel();
114 // Overridden from ui::ComboboxModel:
115 virtual int GetItemCount() const OVERRIDE;
116 virtual base::string16 GetItemAt(int index) OVERRIDE;
119 DISALLOW_COPY_AND_ASSIGN(ProviderTypeComboboxModel);
122 class VpnServerCACertComboboxModel : public ui::ComboboxModel {
124 VpnServerCACertComboboxModel();
125 virtual ~VpnServerCACertComboboxModel();
127 // Overridden from ui::ComboboxModel:
128 virtual int GetItemCount() const OVERRIDE;
129 virtual base::string16 GetItemAt(int index) OVERRIDE;
132 DISALLOW_COPY_AND_ASSIGN(VpnServerCACertComboboxModel);
135 class VpnUserCertComboboxModel : public ui::ComboboxModel {
137 VpnUserCertComboboxModel();
138 virtual ~VpnUserCertComboboxModel();
140 // Overridden from ui::ComboboxModel:
141 virtual int GetItemCount() const OVERRIDE;
142 virtual base::string16 GetItemAt(int index) OVERRIDE;
145 DISALLOW_COPY_AND_ASSIGN(VpnUserCertComboboxModel);
148 // ProviderTypeComboboxModel ---------------------------------------------------
150 ProviderTypeComboboxModel::ProviderTypeComboboxModel() {
153 ProviderTypeComboboxModel::~ProviderTypeComboboxModel() {
156 int ProviderTypeComboboxModel::GetItemCount() const {
157 return PROVIDER_TYPE_INDEX_MAX;
160 base::string16 ProviderTypeComboboxModel::GetItemAt(int index) {
161 return ProviderTypeIndexToString(index);
164 // VpnServerCACertComboboxModel ------------------------------------------------
166 VpnServerCACertComboboxModel::VpnServerCACertComboboxModel() {
169 VpnServerCACertComboboxModel::~VpnServerCACertComboboxModel() {
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;
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);
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);
192 // VpnUserCertComboboxModel ----------------------------------------------------
194 VpnUserCertComboboxModel::VpnUserCertComboboxModel() {
197 VpnUserCertComboboxModel::~VpnUserCertComboboxModel() {
200 int VpnUserCertComboboxModel::GetItemCount() const {
201 if (CertLibrary::Get()->CertificatesLoading())
202 return 1; // "Loading"
204 CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER);
206 return 1; // "None installed"
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);
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);
219 return CertLibrary::Get()->GetCertDisplayStringAt(
220 CertLibrary::CERT_TYPE_USER, index);
223 } // namespace internal
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),
233 enable_group_name_(false),
236 server_textfield_(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),
250 otp_textfield_(NULL),
251 group_name_label_(NULL),
252 group_name_textfield_(NULL),
253 save_credentials_checkbox_(NULL),
255 provider_type_index_(PROVIDER_TYPE_INDEX_MAX),
256 weak_ptr_factory_(this) {
260 VPNConfigView::~VPNConfigView() {
261 RemoveAllChildViews(true); // Destroy children before models
262 CertLibrary::Get()->RemoveObserver(this);
265 base::string16 VPNConfigView::GetTitle() const {
266 DCHECK_NE(title_, 0);
267 return l10n_util::GetStringUTF16(title_);
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_;
286 if (user_passphrase_textfield_)
287 return user_passphrase_textfield_;
288 else if (otp_textfield_)
289 return otp_textfield_;
293 bool VPNConfigView::CanLogin() {
294 // Username is always required.
295 if (GetUsername().empty())
298 // TODO(stevenjb): min kMinPassphraseLen length?
299 if (service_path_.empty() &&
300 (GetService().empty() || GetServer().empty()))
303 // Block login if certs are required but user has none.
305 GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
306 if (cert_required && (!HaveUserCerts() || !IsUserCertValid()))
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_);
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;
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();
341 void VPNConfigView::ButtonPressed(views::Button* sender,
342 const ui::Event& event) {
345 void VPNConfigView::OnPerformAction(views::Combobox* combobox) {
351 void VPNConfigView::OnCertificatesLoaded(bool initial_load) {
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());
368 SetConfigProperties(&properties);
370 bool modifiable = false;
371 ChildNetworkConfigView::GetShareStateForLoginState(&shared, &modifiable);
373 bool only_policy_autoconnect =
374 onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!shared);
375 if (only_policy_autoconnect) {
376 properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty,
380 ash::network_connect::CreateConfigurationAndConnect(&properties, shared);
382 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
383 GetNetworkState(service_path_);
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
390 base::DictionaryValue properties;
391 SetConfigProperties(&properties);
392 ash::network_connect::ConfigureNetworkAndConnect(
393 service_path_, properties, false /* not shared */);
395 return true; // Close dialog.
398 void VPNConfigView::Cancel() {
401 void VPNConfigView::InitFocus() {
402 views::View* view_to_focus = GetInitiallyFocusedView();
404 view_to_focus->RequestFocus();
407 const std::string VPNConfigView::GetService() const {
408 if (service_textfield_ != NULL)
409 return GetTextFromField(service_textfield_, true);
410 return service_path_;
413 const std::string VPNConfigView::GetServer() const {
414 if (server_textfield_ != NULL)
415 return GetTextFromField(server_textfield_, true);
416 return std::string();
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();
427 const std::string VPNConfigView::GetUsername() const {
428 return GetTextFromField(username_textfield_, true);
431 const std::string VPNConfigView::GetUserPassphrase() const {
432 return GetPassphraseFromField(user_passphrase_textfield_);
435 const std::string VPNConfigView::GetGroupName() const {
436 return GetTextFromField(group_name_textfield_, false);
439 const std::string VPNConfigView::GetOTP() const {
440 return GetTextFromField(otp_textfield_, true);
443 const std::string VPNConfigView::GetServerCACertPEM() const {
444 int index = server_ca_cert_combobox_ ?
445 server_ca_cert_combobox_->selected_index() : 0;
447 // First item is "Default".
448 return std::string();
450 int cert_index = index - 1;
451 return CertLibrary::Get()->GetServerCACertPEMAt(cert_index);
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);
463 // Certificates are listed in the order they appear in the model.
464 int index = user_cert_combobox_ ? user_cert_combobox_->selected_index() : 0;
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);
473 bool VPNConfigView::GetSaveCredentials() const {
474 return save_credentials_checkbox_->checked();
477 int VPNConfigView::GetProviderTypeIndex() const {
478 if (provider_type_combobox_)
479 return provider_type_combobox_->selected_index();
480 return provider_type_index_;
483 std::string VPNConfigView::GetProviderTypeString() const {
484 int index = GetProviderTypeIndex();
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;
493 return std::string();
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);
503 layout_ = views::GridLayout::CreatePanel(this);
504 SetLayoutManager(layout_);
506 // Observer any changes to the certificate list.
507 CertLibrary::Get()->AddObserver(this);
509 views::ColumnSet* column_set = layout_->AddColumnSet(0);
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);
520 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
521 views::GridLayout::USE_PREF, 0, 0);
523 // Initialize members.
524 service_text_modified_ = false;
525 title_ = vpn ? IDS_OPTIONS_SETTINGS_JOIN_VPN : IDS_OPTIONS_SETTINGS_ADD_VPN;
527 // By default enable all controls.
528 enable_psk_passphrase_ = true;
529 enable_user_cert_ = true;
530 enable_server_ca_cert_ = true;
532 enable_group_name_ = true;
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);
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;
559 service_text_ = new views::Label();
560 service_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
561 layout_->AddView(service_text_);
562 service_textfield_ = NULL;
564 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
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;
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;
584 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
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_);
595 new ControlledSettingIndicatorView(psk_passphrase_ui_data_));
596 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
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);
612 server_ca_cert_label_ = NULL;
613 server_ca_cert_combobox_ = NULL;
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);
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);
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_);
649 new ControlledSettingIndicatorView(user_passphrase_ui_data_));
650 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
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);
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);
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_);
684 new ControlledSettingIndicatorView(save_credentials_ui_data_));
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_);
694 // Set or hide the UI, update comboboxes and error labels.
698 NetworkHandler::Get()->network_configuration_handler()->GetProperties(
700 base::Bind(&VPNConfigView::InitFromProperties,
701 weak_ptr_factory_.GetWeakPtr()),
702 base::Bind(&VPNConfigView::GetPropertiesError,
703 weak_ptr_factory_.GetWeakPtr()));
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);
713 NET_LOG_ERROR("Shill Error getting properties VpnConfigView", service_path);
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);
749 bool save_credentials = false;
750 service_properties.GetBooleanWithoutPathExpansion(
751 shill::kSaveCredentialsProperty, &save_credentials);
753 provider_type_index_ = ProviderTypeToIndex(provider_type, client_cert_id_);
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_));
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);
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,
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,
792 ParseVPNUIProperty(vpn, type_dict_name, ::onc::client_cert::kClientCertRef,
793 &user_cert_ui_data_);
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,
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_);
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, "");
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());
825 if (!group_name.empty()) {
826 properties->SetStringWithoutPathExpansion(
827 shill::kL2tpIpsecTunnelGroupProperty, group_name);
829 if (!user_name.empty()) {
830 properties->SetStringWithoutPathExpansion(
831 shill::kL2tpIpsecUserProperty, user_name);
833 if (!user_passphrase.empty()) {
834 properties->SetStringWithoutPathExpansion(
835 shill::kL2tpIpsecPasswordProperty, user_passphrase);
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);
847 SetUserCertProperties(client_cert::CONFIG_TYPE_IPSEC, properties);
848 if (!group_name.empty()) {
849 properties->SetStringWithoutPathExpansion(
850 shill::kL2tpIpsecTunnelGroupProperty, GetGroupName());
852 if (!user_name.empty()) {
853 properties->SetStringWithoutPathExpansion(
854 shill::kL2tpIpsecUserProperty, user_name);
856 if (!user_passphrase.empty()) {
857 properties->SetStringWithoutPathExpansion(
858 shill::kL2tpIpsecPasswordProperty, user_passphrase);
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);
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);
877 std::string otp = GetOTP();
879 properties->SetStringWithoutPathExpansion(
880 shill::kOpenVPNOTPProperty, otp);
884 case PROVIDER_TYPE_INDEX_MAX:
888 properties->SetBooleanWithoutPathExpansion(
889 shill::kSaveCredentialsProperty, GetSaveCredentials());
892 void VPNConfigView::Refresh() {
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.
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);
906 server_ca_cert_combobox_->SetSelectedIndex(0);
909 server_ca_cert_combobox_->SetSelectedIndex(0);
913 if (user_cert_combobox_) {
914 user_cert_combobox_->ModelChanged();
915 if (enable_user_cert_ && !client_cert_id_.empty()) {
917 CertLibrary::Get()->GetUserCertIndexByPkcs11Id(client_cert_id_);
919 user_cert_combobox_->SetSelectedIndex(cert_index);
921 user_cert_combobox_->SetSelectedIndex(0);
923 user_cert_combobox_->SetSelectedIndex(0);
930 void VPNConfigView::UpdateControlsToEnable() {
931 enable_psk_passphrase_ = false;
932 enable_user_cert_ = false;
933 enable_server_ca_cert_ = 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();
951 void VPNConfigView::UpdateControls() {
952 UpdateControlsToEnable();
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());
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());
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());
973 otp_label_->SetEnabled(enable_otp_);
975 otp_textfield_->SetEnabled(enable_otp_);
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());
984 void VPNConfigView::UpdateErrorLabel() {
986 base::string16 error_msg;
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);
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());
1006 if (!error_msg.empty()) {
1007 error_label_->SetText(error_msg);
1008 error_label_->SetVisible(true);
1010 error_label_->SetVisible(false);
1014 void VPNConfigView::UpdateCanLogin() {
1015 parent_->GetDialogClientView()->UpdateDialogButtons();
1018 bool VPNConfigView::HaveUserCerts() const {
1019 return CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) > 0;
1022 bool VPNConfigView::IsUserCertValid() const {
1023 if (!user_cert_combobox_ || !enable_user_cert_)
1025 int index = user_cert_combobox_->selected_index();
1028 // Currently only hardware-backed user certificates are valid.
1029 if (CertLibrary::Get()->IsHardwareBacked() &&
1030 !CertLibrary::Get()->IsCertHardwareBackedAt(
1031 CertLibrary::CERT_TYPE_USER, index))
1036 const std::string VPNConfigView::GetTextFromField(views::Textfield* textfield,
1037 bool trim_whitespace) const {
1039 return std::string();
1040 std::string untrimmed = base::UTF16ToUTF8(textfield->text());
1041 if (!trim_whitespace)
1044 base::TrimWhitespaceASCII(untrimmed, base::TRIM_ALL, &result);
1048 const std::string VPNConfigView::GetPassphraseFromField(
1049 PassphraseTextfield* textfield) const {
1051 return std::string();
1052 return textfield->GetPassphrase();
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);
1064 VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->guid();
1065 property_ui_data->ParseOncProperty(
1068 base::StringPrintf("%s.%s.%s",
1069 ::onc::network_config::kVPN,
1074 } // namespace chromeos