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