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