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