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