| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/options/vpn_config_view.h" |
| |
| #include "ash/system/chromeos/network/network_connect.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/chromeos/enrollment_dialog_view.h" |
| #include "chrome/browser/chromeos/net/onc_utils.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/common/net/x509_certificate_model.h" |
| #include "chromeos/login/login_state.h" |
| #include "chromeos/network/network_configuration_handler.h" |
| #include "chromeos/network/network_event_log.h" |
| #include "chromeos/network/network_state.h" |
| #include "chromeos/network/network_state_handler.h" |
| #include "chromeos/network/network_ui_data.h" |
| #include "components/onc/onc_constants.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "grit/locale_settings.h" |
| #include "grit/theme_resources.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/models/combobox_model.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/events/event.h" |
| #include "ui/views/controls/button/checkbox.h" |
| #include "ui/views/controls/combobox/combobox.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/controls/textfield/textfield.h" |
| #include "ui/views/layout/grid_layout.h" |
| #include "ui/views/layout/layout_constants.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/window/dialog_client_view.h" |
| |
| namespace { |
| |
| enum ProviderTypeIndex { |
| PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK = 0, |
| PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT = 1, |
| PROVIDER_TYPE_INDEX_OPEN_VPN = 2, |
| PROVIDER_TYPE_INDEX_MAX = 3, |
| }; |
| |
| base::string16 ProviderTypeIndexToString(int index) { |
| switch (index) { |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: |
| return l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK); |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: |
| return l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT); |
| case PROVIDER_TYPE_INDEX_OPEN_VPN: |
| return l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN); |
| } |
| NOTREACHED(); |
| return base::string16(); |
| } |
| |
| int ProviderTypeToIndex(const std::string& provider_type, |
| const std::string& client_cert_id) { |
| if (provider_type == shill::kProviderL2tpIpsec) { |
| if (!client_cert_id.empty()) |
| return PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT; |
| else |
| return PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK; |
| } else { |
| DCHECK(provider_type == shill::kProviderOpenVpn); |
| return PROVIDER_TYPE_INDEX_OPEN_VPN; |
| } |
| } |
| |
| // Translates the provider type to the name of the respective ONC dictionary |
| // containing configuration data for the type. |
| std::string ProviderTypeIndexToONCDictKey(int provider_type_index) { |
| switch (provider_type_index) { |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: |
| return onc::vpn::kIPsec; |
| case PROVIDER_TYPE_INDEX_OPEN_VPN: |
| return onc::vpn::kOpenVPN; |
| } |
| NOTREACHED() << "Unhandled provider type index " << provider_type_index; |
| return std::string(); |
| } |
| |
| std::string GetPemFromDictionary( |
| const base::DictionaryValue* provider_properties, |
| const std::string& key) { |
| const base::ListValue* pems = NULL; |
| if (!provider_properties->GetListWithoutPathExpansion(key, &pems)) |
| return std::string(); |
| std::string pem; |
| pems->GetString(0, &pem); |
| return pem; |
| } |
| |
| } // namespace |
| |
| namespace chromeos { |
| |
| namespace internal { |
| |
| class ProviderTypeComboboxModel : public ui::ComboboxModel { |
| public: |
| ProviderTypeComboboxModel(); |
| virtual ~ProviderTypeComboboxModel(); |
| |
| // Overridden from ui::ComboboxModel: |
| virtual int GetItemCount() const OVERRIDE; |
| virtual base::string16 GetItemAt(int index) OVERRIDE; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ProviderTypeComboboxModel); |
| }; |
| |
| class VpnServerCACertComboboxModel : public ui::ComboboxModel { |
| public: |
| VpnServerCACertComboboxModel(); |
| virtual ~VpnServerCACertComboboxModel(); |
| |
| // Overridden from ui::ComboboxModel: |
| virtual int GetItemCount() const OVERRIDE; |
| virtual base::string16 GetItemAt(int index) OVERRIDE; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(VpnServerCACertComboboxModel); |
| }; |
| |
| class VpnUserCertComboboxModel : public ui::ComboboxModel { |
| public: |
| VpnUserCertComboboxModel(); |
| virtual ~VpnUserCertComboboxModel(); |
| |
| // Overridden from ui::ComboboxModel: |
| virtual int GetItemCount() const OVERRIDE; |
| virtual base::string16 GetItemAt(int index) OVERRIDE; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(VpnUserCertComboboxModel); |
| }; |
| |
| // ProviderTypeComboboxModel --------------------------------------------------- |
| |
| ProviderTypeComboboxModel::ProviderTypeComboboxModel() { |
| } |
| |
| ProviderTypeComboboxModel::~ProviderTypeComboboxModel() { |
| } |
| |
| int ProviderTypeComboboxModel::GetItemCount() const { |
| return PROVIDER_TYPE_INDEX_MAX; |
| } |
| |
| base::string16 ProviderTypeComboboxModel::GetItemAt(int index) { |
| return ProviderTypeIndexToString(index); |
| } |
| |
| // VpnServerCACertComboboxModel ------------------------------------------------ |
| |
| VpnServerCACertComboboxModel::VpnServerCACertComboboxModel() { |
| } |
| |
| VpnServerCACertComboboxModel::~VpnServerCACertComboboxModel() { |
| } |
| |
| int VpnServerCACertComboboxModel::GetItemCount() const { |
| if (CertLibrary::Get()->CertificatesLoading()) |
| return 1; // "Loading" |
| // "Default" + certs. |
| return CertLibrary::Get()->NumCertificates( |
| CertLibrary::CERT_TYPE_SERVER_CA) + 1; |
| } |
| |
| base::string16 VpnServerCACertComboboxModel::GetItemAt(int index) { |
| if (CertLibrary::Get()->CertificatesLoading()) |
| return l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING); |
| if (index == 0) |
| return l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA_DEFAULT); |
| int cert_index = index - 1; |
| return CertLibrary::Get()->GetCertDisplayStringAt( |
| CertLibrary::CERT_TYPE_SERVER_CA, cert_index); |
| } |
| |
| // VpnUserCertComboboxModel ---------------------------------------------------- |
| |
| VpnUserCertComboboxModel::VpnUserCertComboboxModel() { |
| } |
| |
| VpnUserCertComboboxModel::~VpnUserCertComboboxModel() { |
| } |
| |
| int VpnUserCertComboboxModel::GetItemCount() const { |
| if (CertLibrary::Get()->CertificatesLoading()) |
| return 1; // "Loading" |
| int num_certs = |
| CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER); |
| if (num_certs == 0) |
| return 1; // "None installed" |
| return num_certs; |
| } |
| |
| base::string16 VpnUserCertComboboxModel::GetItemAt(int index) { |
| if (CertLibrary::Get()->CertificatesLoading()) { |
| return l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING); |
| } |
| if (CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) == 0) { |
| return l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USER_CERT_NONE_INSTALLED); |
| } |
| return CertLibrary::Get()->GetCertDisplayStringAt( |
| CertLibrary::CERT_TYPE_USER, index); |
| } |
| |
| } // namespace internal |
| |
| VPNConfigView::VPNConfigView(NetworkConfigView* parent, |
| const std::string& service_path) |
| : ChildNetworkConfigView(parent, service_path), |
| service_text_modified_(false), |
| enable_psk_passphrase_(false), |
| enable_user_cert_(false), |
| enable_server_ca_cert_(false), |
| enable_otp_(false), |
| enable_group_name_(false), |
| title_(0), |
| layout_(NULL), |
| server_textfield_(NULL), |
| service_text_(NULL), |
| service_textfield_(NULL), |
| provider_type_combobox_(NULL), |
| provider_type_text_label_(NULL), |
| psk_passphrase_label_(NULL), |
| psk_passphrase_textfield_(NULL), |
| user_cert_label_(NULL), |
| user_cert_combobox_(NULL), |
| server_ca_cert_label_(NULL), |
| server_ca_cert_combobox_(NULL), |
| username_textfield_(NULL), |
| user_passphrase_textfield_(NULL), |
| otp_label_(NULL), |
| otp_textfield_(NULL), |
| group_name_label_(NULL), |
| group_name_textfield_(NULL), |
| save_credentials_checkbox_(NULL), |
| error_label_(NULL), |
| provider_type_index_(PROVIDER_TYPE_INDEX_MAX), |
| weak_ptr_factory_(this) { |
| Init(); |
| } |
| |
| VPNConfigView::~VPNConfigView() { |
| RemoveAllChildViews(true); // Destroy children before models |
| CertLibrary::Get()->RemoveObserver(this); |
| } |
| |
| base::string16 VPNConfigView::GetTitle() const { |
| DCHECK_NE(title_, 0); |
| return l10n_util::GetStringUTF16(title_); |
| } |
| |
| views::View* VPNConfigView::GetInitiallyFocusedView() { |
| if (service_path_.empty()) { |
| // Put focus in the first editable field. |
| if (server_textfield_) |
| return server_textfield_; |
| else if (service_textfield_) |
| return service_textfield_; |
| else if (provider_type_combobox_) |
| return provider_type_combobox_; |
| else if (psk_passphrase_textfield_ && psk_passphrase_textfield_->enabled()) |
| return psk_passphrase_textfield_; |
| else if (user_cert_combobox_ && user_cert_combobox_->enabled()) |
| return user_cert_combobox_; |
| else if (server_ca_cert_combobox_ && server_ca_cert_combobox_->enabled()) |
| return server_ca_cert_combobox_; |
| } |
| if (user_passphrase_textfield_) |
| return user_passphrase_textfield_; |
| else if (otp_textfield_) |
| return otp_textfield_; |
| return NULL; |
| } |
| |
| bool VPNConfigView::CanLogin() { |
| // Username is always required. |
| if (GetUsername().empty()) |
| return false; |
| |
| // TODO(stevenjb): min kMinPassphraseLen length? |
| if (service_path_.empty() && |
| (GetService().empty() || GetServer().empty())) |
| return false; |
| |
| // Block login if certs are required but user has none. |
| bool cert_required = |
| GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT; |
| if (cert_required && (!HaveUserCerts() || !IsUserCertValid())) |
| return false; |
| |
| return true; |
| } |
| |
| void VPNConfigView::ContentsChanged(views::Textfield* sender, |
| const base::string16& new_contents) { |
| if (sender == server_textfield_ && !service_text_modified_) { |
| // Set the service name to the server name up to '.', unless it has |
| // been explicitly set by the user. |
| base::string16 server = server_textfield_->text(); |
| base::string16::size_type n = server.find_first_of(L'.'); |
| service_name_from_server_ = server.substr(0, n); |
| service_textfield_->SetText(service_name_from_server_); |
| } |
| if (sender == service_textfield_) { |
| if (new_contents.empty()) |
| service_text_modified_ = false; |
| else if (new_contents != service_name_from_server_) |
| service_text_modified_ = true; |
| } |
| UpdateCanLogin(); |
| } |
| |
| bool VPNConfigView::HandleKeyEvent(views::Textfield* sender, |
| const ui::KeyEvent& key_event) { |
| if ((sender == psk_passphrase_textfield_ || |
| sender == user_passphrase_textfield_) && |
| key_event.key_code() == ui::VKEY_RETURN) { |
| parent_->GetDialogClientView()->AcceptWindow(); |
| } |
| return false; |
| } |
| |
| void VPNConfigView::ButtonPressed(views::Button* sender, |
| const ui::Event& event) { |
| } |
| |
| void VPNConfigView::OnSelectedIndexChanged(views::Combobox* combobox) { |
| UpdateControls(); |
| UpdateErrorLabel(); |
| UpdateCanLogin(); |
| } |
| |
| void VPNConfigView::OnCertificatesLoaded(bool initial_load) { |
| Refresh(); |
| } |
| |
| bool VPNConfigView::Login() { |
| if (service_path_.empty()) { |
| base::DictionaryValue properties; |
| // Identifying properties |
| properties.SetStringWithoutPathExpansion( |
| shill::kTypeProperty, shill::kTypeVPN); |
| properties.SetStringWithoutPathExpansion( |
| shill::kNameProperty, GetService()); |
| properties.SetStringWithoutPathExpansion( |
| shill::kProviderHostProperty, GetServer()); |
| properties.SetStringWithoutPathExpansion( |
| shill::kProviderTypeProperty, GetProviderTypeString()); |
| |
| SetConfigProperties(&properties); |
| bool shared = !LoginState::Get()->IsUserAuthenticated(); |
| |
| bool only_policy_autoconnect = |
| onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!shared); |
| if (only_policy_autoconnect) { |
| properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty, |
| false); |
| } |
| |
| ash::network_connect::CreateConfigurationAndConnect(&properties, shared); |
| } else { |
| const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()-> |
| GetNetworkState(service_path_); |
| if (!vpn) { |
| // Shill no longer knows about this network (edge case). |
| // TODO(stevenjb): Add notification for this. |
| NET_LOG_ERROR("Network not found", service_path_); |
| return true; // Close dialog |
| } |
| base::DictionaryValue properties; |
| SetConfigProperties(&properties); |
| ash::network_connect::ConfigureNetworkAndConnect( |
| service_path_, properties, false /* not shared */); |
| } |
| return true; // Close dialog. |
| } |
| |
| void VPNConfigView::Cancel() { |
| } |
| |
| void VPNConfigView::InitFocus() { |
| views::View* view_to_focus = GetInitiallyFocusedView(); |
| if (view_to_focus) |
| view_to_focus->RequestFocus(); |
| } |
| |
| const std::string VPNConfigView::GetService() const { |
| if (service_textfield_ != NULL) |
| return GetTextFromField(service_textfield_, true); |
| return service_path_; |
| } |
| |
| const std::string VPNConfigView::GetServer() const { |
| if (server_textfield_ != NULL) |
| return GetTextFromField(server_textfield_, true); |
| return std::string(); |
| } |
| |
| const std::string VPNConfigView::GetPSKPassphrase() const { |
| if (psk_passphrase_textfield_ && |
| enable_psk_passphrase_ && |
| psk_passphrase_textfield_->visible()) |
| return GetPassphraseFromField(psk_passphrase_textfield_); |
| return std::string(); |
| } |
| |
| const std::string VPNConfigView::GetUsername() const { |
| return GetTextFromField(username_textfield_, true); |
| } |
| |
| const std::string VPNConfigView::GetUserPassphrase() const { |
| return GetPassphraseFromField(user_passphrase_textfield_); |
| } |
| |
| const std::string VPNConfigView::GetGroupName() const { |
| return GetTextFromField(group_name_textfield_, false); |
| } |
| |
| const std::string VPNConfigView::GetOTP() const { |
| return GetTextFromField(otp_textfield_, true); |
| } |
| |
| const std::string VPNConfigView::GetServerCACertPEM() const { |
| int index = server_ca_cert_combobox_ ? |
| server_ca_cert_combobox_->selected_index() : 0; |
| if (index == 0) { |
| // First item is "Default". |
| return std::string(); |
| } else { |
| int cert_index = index - 1; |
| return CertLibrary::Get()->GetCertPEMAt( |
| CertLibrary::CERT_TYPE_SERVER_CA, cert_index); |
| } |
| } |
| |
| const std::string VPNConfigView::GetUserCertID() const { |
| if (!HaveUserCerts()) { |
| return std::string(); // "None installed" |
| } else { |
| // Certificates are listed in the order they appear in the model. |
| int index = user_cert_combobox_ ? user_cert_combobox_->selected_index() : 0; |
| return CertLibrary::Get()->GetCertPkcs11IdAt( |
| CertLibrary::CERT_TYPE_USER, index); |
| } |
| } |
| |
| bool VPNConfigView::GetSaveCredentials() const { |
| return save_credentials_checkbox_->checked(); |
| } |
| |
| int VPNConfigView::GetProviderTypeIndex() const { |
| if (provider_type_combobox_) |
| return provider_type_combobox_->selected_index(); |
| return provider_type_index_; |
| } |
| |
| std::string VPNConfigView::GetProviderTypeString() const { |
| int index = GetProviderTypeIndex(); |
| switch (index) { |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: |
| return shill::kProviderL2tpIpsec; |
| case PROVIDER_TYPE_INDEX_OPEN_VPN: |
| return shill::kProviderOpenVpn; |
| } |
| NOTREACHED(); |
| return std::string(); |
| } |
| |
| void VPNConfigView::Init() { |
| const NetworkState* vpn = NULL; |
| if (!service_path_.empty()) { |
| vpn = NetworkHandler::Get()->network_state_handler()-> |
| GetNetworkState(service_path_); |
| DCHECK(vpn && vpn->type() == shill::kTypeVPN); |
| } |
| layout_ = views::GridLayout::CreatePanel(this); |
| SetLayoutManager(layout_); |
| |
| // Observer any changes to the certificate list. |
| CertLibrary::Get()->AddObserver(this); |
| |
| views::ColumnSet* column_set = layout_->AddColumnSet(0); |
| // Label. |
| column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1, |
| views::GridLayout::USE_PREF, 0, 0); |
| column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing); |
| // Textfield, combobox. |
| column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, |
| views::GridLayout::USE_PREF, 0, |
| ChildNetworkConfigView::kInputFieldMinWidth); |
| column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing); |
| // Policy indicator. |
| column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, |
| views::GridLayout::USE_PREF, 0, 0); |
| |
| // Initialize members. |
| service_text_modified_ = false; |
| title_ = vpn ? IDS_OPTIONS_SETTINGS_JOIN_VPN : IDS_OPTIONS_SETTINGS_ADD_VPN; |
| |
| // By default enable all controls. |
| enable_psk_passphrase_ = true; |
| enable_user_cert_ = true; |
| enable_server_ca_cert_ = true; |
| enable_otp_ = true; |
| enable_group_name_ = true; |
| |
| // Server label and input. |
| layout_->StartRow(0, 0); |
| views::View* server_label = |
| new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME)); |
| layout_->AddView(server_label); |
| server_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); |
| server_textfield_->SetController(this); |
| layout_->AddView(server_textfield_); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| if (!service_path_.empty()) { |
| server_label->SetEnabled(false); |
| server_textfield_->SetEnabled(false); |
| } |
| |
| // Service label and name or input. |
| layout_->StartRow(0, 0); |
| layout_->AddView(new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME))); |
| if (service_path_.empty()) { |
| service_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); |
| service_textfield_->SetController(this); |
| layout_->AddView(service_textfield_); |
| service_text_ = NULL; |
| } else { |
| service_text_ = new views::Label(); |
| service_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| layout_->AddView(service_text_); |
| service_textfield_ = NULL; |
| } |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // Provider type label and select. |
| layout_->StartRow(0, 0); |
| layout_->AddView(new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE))); |
| if (service_path_.empty()) { |
| provider_type_combobox_model_.reset( |
| new internal::ProviderTypeComboboxModel); |
| provider_type_combobox_ = new views::Combobox( |
| provider_type_combobox_model_.get()); |
| provider_type_combobox_->set_listener(this); |
| layout_->AddView(provider_type_combobox_); |
| provider_type_text_label_ = NULL; |
| } else { |
| provider_type_text_label_ = new views::Label(); |
| provider_type_text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| layout_->AddView(provider_type_text_label_); |
| provider_type_combobox_ = NULL; |
| } |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // PSK passphrase label, input and visible button. |
| layout_->StartRow(0, 0); |
| psk_passphrase_label_ = new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE)); |
| layout_->AddView(psk_passphrase_label_); |
| psk_passphrase_textfield_ = new PassphraseTextfield(); |
| psk_passphrase_textfield_->SetController(this); |
| layout_->AddView(psk_passphrase_textfield_); |
| layout_->AddView( |
| new ControlledSettingIndicatorView(psk_passphrase_ui_data_)); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // Server CA certificate |
| if (service_path_.empty()) { |
| layout_->StartRow(0, 0); |
| server_ca_cert_label_ = new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA)); |
| layout_->AddView(server_ca_cert_label_); |
| server_ca_cert_combobox_model_.reset( |
| new internal::VpnServerCACertComboboxModel()); |
| server_ca_cert_combobox_ = new views::Combobox( |
| server_ca_cert_combobox_model_.get()); |
| layout_->AddView(server_ca_cert_combobox_); |
| layout_->AddView(new ControlledSettingIndicatorView(ca_cert_ui_data_)); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| } else { |
| server_ca_cert_label_ = NULL; |
| server_ca_cert_combobox_ = NULL; |
| } |
| |
| // User certificate label and input. |
| layout_->StartRow(0, 0); |
| user_cert_label_ = new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT)); |
| layout_->AddView(user_cert_label_); |
| user_cert_combobox_model_.reset( |
| new internal::VpnUserCertComboboxModel()); |
| user_cert_combobox_ = new views::Combobox(user_cert_combobox_model_.get()); |
| user_cert_combobox_->set_listener(this); |
| layout_->AddView(user_cert_combobox_); |
| layout_->AddView(new ControlledSettingIndicatorView(user_cert_ui_data_)); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // Username label and input. |
| layout_->StartRow(0, 0); |
| layout_->AddView(new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME))); |
| username_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); |
| username_textfield_->SetController(this); |
| username_textfield_->SetEnabled(username_ui_data_.IsEditable()); |
| layout_->AddView(username_textfield_); |
| layout_->AddView(new ControlledSettingIndicatorView(username_ui_data_)); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // User passphrase label, input and visble button. |
| layout_->StartRow(0, 0); |
| layout_->AddView(new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE))); |
| user_passphrase_textfield_ = new PassphraseTextfield(); |
| user_passphrase_textfield_->SetController(this); |
| user_passphrase_textfield_->SetEnabled(user_passphrase_ui_data_.IsEditable()); |
| layout_->AddView(user_passphrase_textfield_); |
| layout_->AddView( |
| new ControlledSettingIndicatorView(user_passphrase_ui_data_)); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // OTP label and input. |
| layout_->StartRow(0, 0); |
| otp_label_ = new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_OTP)); |
| layout_->AddView(otp_label_); |
| otp_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); |
| otp_textfield_->SetController(this); |
| layout_->AddView(otp_textfield_); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // Group Name label and input. |
| layout_->StartRow(0, 0); |
| group_name_label_ = new views::Label(l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_GROUP_NAME)); |
| layout_->AddView(group_name_label_); |
| group_name_textfield_ = |
| new views::Textfield(views::Textfield::STYLE_DEFAULT); |
| group_name_textfield_->SetController(this); |
| layout_->AddView(group_name_textfield_); |
| layout_->AddView(new ControlledSettingIndicatorView(group_name_ui_data_)); |
| layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); |
| |
| // Save credentials |
| layout_->StartRow(0, 0); |
| save_credentials_checkbox_ = new views::Checkbox( |
| l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SAVE_CREDENTIALS)); |
| save_credentials_checkbox_->SetEnabled( |
| save_credentials_ui_data_.IsEditable()); |
| layout_->SkipColumns(1); |
| layout_->AddView(save_credentials_checkbox_); |
| layout_->AddView( |
| new ControlledSettingIndicatorView(save_credentials_ui_data_)); |
| |
| // Error label. |
| layout_->StartRow(0, 0); |
| layout_->SkipColumns(1); |
| error_label_ = new views::Label(); |
| error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| error_label_->SetEnabledColor(SK_ColorRED); |
| layout_->AddView(error_label_); |
| |
| // Set or hide the UI, update comboboxes and error labels. |
| Refresh(); |
| |
| if (vpn) { |
| NetworkHandler::Get()->network_configuration_handler()->GetProperties( |
| service_path_, |
| base::Bind(&VPNConfigView::InitFromProperties, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::Bind(&VPNConfigView::GetPropertiesError, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| } |
| |
| void VPNConfigView::InitFromProperties( |
| const std::string& service_path, |
| const base::DictionaryValue& service_properties) { |
| const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()-> |
| GetNetworkState(service_path); |
| if (!vpn) { |
| NET_LOG_ERROR("Shill Error getting properties VpnConfigView", service_path); |
| return; |
| } |
| |
| std::string provider_type, server_hostname, username, group_name; |
| bool psk_passphrase_required = false; |
| const base::DictionaryValue* provider_properties; |
| if (service_properties.GetDictionaryWithoutPathExpansion( |
| shill::kProviderProperty, &provider_properties)) { |
| provider_properties->GetStringWithoutPathExpansion( |
| shill::kTypeProperty, &provider_type); |
| provider_properties->GetStringWithoutPathExpansion( |
| shill::kHostProperty, &server_hostname); |
| } |
| if (provider_type == shill::kProviderL2tpIpsec) { |
| provider_properties->GetStringWithoutPathExpansion( |
| shill::kL2tpIpsecClientCertIdProperty, &client_cert_id_); |
| ca_cert_pem_ = GetPemFromDictionary( |
| provider_properties, shill::kL2tpIpsecCaCertPemProperty); |
| provider_properties->GetBooleanWithoutPathExpansion( |
| shill::kL2tpIpsecPskRequiredProperty, &psk_passphrase_required); |
| provider_properties->GetStringWithoutPathExpansion( |
| shill::kL2tpIpsecUserProperty, &username); |
| provider_properties->GetStringWithoutPathExpansion( |
| shill::kL2tpIpsecTunnelGroupProperty, &group_name); |
| } else if (provider_type == shill::kProviderOpenVpn) { |
| provider_properties->GetStringWithoutPathExpansion( |
| shill::kOpenVPNClientCertIdProperty, &client_cert_id_); |
| ca_cert_pem_ = GetPemFromDictionary( |
| provider_properties, shill::kOpenVPNCaCertPemProperty); |
| provider_properties->GetStringWithoutPathExpansion( |
| shill::kOpenVPNUserProperty, &username); |
| } |
| bool save_credentials = false; |
| service_properties.GetBooleanWithoutPathExpansion( |
| shill::kSaveCredentialsProperty, &save_credentials); |
| |
| provider_type_index_ = ProviderTypeToIndex(provider_type, client_cert_id_); |
| |
| if (service_text_) |
| service_text_->SetText(ASCIIToUTF16(vpn->name())); |
| if (provider_type_text_label_) |
| provider_type_text_label_->SetText( |
| ProviderTypeIndexToString(provider_type_index_)); |
| |
| if (server_textfield_ && !server_hostname.empty()) |
| server_textfield_->SetText(UTF8ToUTF16(server_hostname)); |
| if (username_textfield_ && !username.empty()) |
| username_textfield_->SetText(UTF8ToUTF16(username)); |
| if (group_name_textfield_ && !group_name.empty()) |
| group_name_textfield_->SetText(UTF8ToUTF16(group_name)); |
| if (psk_passphrase_textfield_) |
| psk_passphrase_textfield_->SetShowFake(!psk_passphrase_required); |
| if (save_credentials_checkbox_) |
| save_credentials_checkbox_->SetChecked(save_credentials); |
| |
| Refresh(); |
| } |
| |
| void VPNConfigView::ParseUIProperties(const NetworkState* vpn) { |
| std::string type_dict_name = |
| ProviderTypeIndexToONCDictKey(provider_type_index_); |
| if (provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) { |
| ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kServerCARef, |
| &ca_cert_ui_data_); |
| ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kPSK, |
| &psk_passphrase_ui_data_); |
| ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kGroup, |
| &group_name_ui_data_); |
| } else if (provider_type_index_ == PROVIDER_TYPE_INDEX_OPEN_VPN) { |
| ParseVPNUIProperty(vpn, type_dict_name, ::onc::openvpn::kServerCARef, |
| &ca_cert_ui_data_); |
| } |
| ParseVPNUIProperty(vpn, type_dict_name, ::onc::vpn::kClientCertRef, |
| &user_cert_ui_data_); |
| |
| const std::string credentials_dict_name( |
| provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK ? |
| ::onc::vpn::kL2TP : type_dict_name); |
| ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kUsername, |
| &username_ui_data_); |
| ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kPassword, |
| &user_passphrase_ui_data_); |
| ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kSaveCredentials, |
| &save_credentials_ui_data_); |
| } |
| |
| void VPNConfigView::GetPropertiesError( |
| const std::string& error_name, |
| scoped_ptr<base::DictionaryValue> error_data) { |
| NET_LOG_ERROR("Shill Error from VpnConfigView: " + error_name, ""); |
| } |
| |
| void VPNConfigView::SetConfigProperties( |
| base::DictionaryValue* properties) { |
| int provider_type_index = GetProviderTypeIndex(); |
| std::string user_passphrase = GetUserPassphrase(); |
| std::string user_name = GetUsername(); |
| std::string group_name = GetGroupName(); |
| switch (provider_type_index) { |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: { |
| std::string psk_passphrase = GetPSKPassphrase(); |
| if (!psk_passphrase.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecPskProperty, GetPSKPassphrase()); |
| } |
| if (!group_name.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecTunnelGroupProperty, group_name); |
| } |
| if (!user_name.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecUserProperty, user_name); |
| } |
| if (!user_passphrase.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecPasswordProperty, user_passphrase); |
| } |
| break; |
| } |
| case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: { |
| std::string ca_cert_pem = GetServerCACertPEM(); |
| if (!ca_cert_pem.empty()) { |
| base::ListValue* pem_list = new base::ListValue; |
| pem_list->AppendString(ca_cert_pem); |
| properties->SetWithoutPathExpansion( |
| shill::kL2tpIpsecCaCertPemProperty, pem_list); |
| } |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecClientCertIdProperty, GetUserCertID()); |
| if (!group_name.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecTunnelGroupProperty, GetGroupName()); |
| } |
| if (!user_name.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecUserProperty, user_name); |
| } |
| if (!user_passphrase.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kL2tpIpsecPasswordProperty, user_passphrase); |
| } |
| break; |
| } |
| case PROVIDER_TYPE_INDEX_OPEN_VPN: { |
| std::string ca_cert_pem = GetServerCACertPEM(); |
| if (!ca_cert_pem.empty()) { |
| base::ListValue* pem_list = new base::ListValue; |
| pem_list->AppendString(ca_cert_pem); |
| properties->SetWithoutPathExpansion( |
| shill::kOpenVPNCaCertPemProperty, pem_list); |
| } |
| properties->SetStringWithoutPathExpansion( |
| shill::kOpenVPNClientCertIdProperty, GetUserCertID()); |
| properties->SetStringWithoutPathExpansion( |
| shill::kOpenVPNUserProperty, GetUsername()); |
| if (!user_passphrase.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kOpenVPNPasswordProperty, user_passphrase); |
| } |
| std::string otp = GetOTP(); |
| if (!otp.empty()) { |
| properties->SetStringWithoutPathExpansion( |
| shill::kOpenVPNOTPProperty, otp); |
| } |
| break; |
| } |
| case PROVIDER_TYPE_INDEX_MAX: |
| NOTREACHED(); |
| break; |
| } |
| properties->SetBooleanWithoutPathExpansion( |
| shill::kSaveCredentialsProperty, GetSaveCredentials()); |
| } |
| |
| void VPNConfigView::Refresh() { |
| UpdateControls(); |
| |
| // Set certificate combo boxes. |
| if (server_ca_cert_combobox_) { |
| server_ca_cert_combobox_->ModelChanged(); |
| if (enable_server_ca_cert_ && !ca_cert_pem_.empty()) { |
| // Select the current server CA certificate in the combobox. |
| int cert_index = CertLibrary::Get()->GetCertIndexByPEM( |
| CertLibrary::CERT_TYPE_SERVER_CA, ca_cert_pem_); |
| if (cert_index >= 0) { |
| // Skip item for "Default" |
| server_ca_cert_combobox_->SetSelectedIndex(1 + cert_index); |
| } else { |
| server_ca_cert_combobox_->SetSelectedIndex(0); |
| } |
| } else { |
| server_ca_cert_combobox_->SetSelectedIndex(0); |
| } |
| } |
| |
| if (user_cert_combobox_) { |
| user_cert_combobox_->ModelChanged(); |
| if (enable_user_cert_ && !client_cert_id_.empty()) { |
| int cert_index = CertLibrary::Get()->GetCertIndexByPkcs11Id( |
| CertLibrary::CERT_TYPE_USER, client_cert_id_); |
| if (cert_index >= 0) |
| user_cert_combobox_->SetSelectedIndex(cert_index); |
| else |
| user_cert_combobox_->SetSelectedIndex(0); |
| } else { |
| user_cert_combobox_->SetSelectedIndex(0); |
| } |
| } |
| |
| UpdateErrorLabel(); |
| } |
| |
| void VPNConfigView::UpdateControlsToEnable() { |
| enable_psk_passphrase_ = false; |
| enable_user_cert_ = false; |
| enable_server_ca_cert_ = false; |
| enable_otp_ = false; |
| enable_group_name_ = false; |
| int provider_type_index = GetProviderTypeIndex(); |
| if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) { |
| enable_psk_passphrase_ = true; |
| enable_group_name_ = true; |
| } else if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT) { |
| enable_server_ca_cert_ = true; |
| enable_user_cert_ = HaveUserCerts(); |
| enable_group_name_ = true; |
| } else { // PROVIDER_TYPE_INDEX_OPEN_VPN (default) |
| enable_server_ca_cert_ = true; |
| enable_user_cert_ = HaveUserCerts(); |
| enable_otp_ = true; |
| } |
| } |
| |
| void VPNConfigView::UpdateControls() { |
| UpdateControlsToEnable(); |
| |
| if (psk_passphrase_label_) |
| psk_passphrase_label_->SetEnabled(enable_psk_passphrase_); |
| if (psk_passphrase_textfield_) |
| psk_passphrase_textfield_->SetEnabled(enable_psk_passphrase_ && |
| psk_passphrase_ui_data_.IsEditable()); |
| |
| if (user_cert_label_) |
| user_cert_label_->SetEnabled(enable_user_cert_); |
| if (user_cert_combobox_) |
| user_cert_combobox_->SetEnabled(enable_user_cert_ && |
| user_cert_ui_data_.IsEditable()); |
| |
| if (server_ca_cert_label_) |
| server_ca_cert_label_->SetEnabled(enable_server_ca_cert_); |
| if (server_ca_cert_combobox_) |
| server_ca_cert_combobox_->SetEnabled(enable_server_ca_cert_ && |
| ca_cert_ui_data_.IsEditable()); |
| |
| if (otp_label_) |
| otp_label_->SetEnabled(enable_otp_); |
| if (otp_textfield_) |
| otp_textfield_->SetEnabled(enable_otp_); |
| |
| if (group_name_label_) |
| group_name_label_->SetEnabled(enable_group_name_); |
| if (group_name_textfield_) |
| group_name_textfield_->SetEnabled(enable_group_name_ && |
| group_name_ui_data_.IsEditable()); |
| } |
| |
| void VPNConfigView::UpdateErrorLabel() { |
| // Error message. |
| base::string16 error_msg; |
| bool cert_required = |
| GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT; |
| if (cert_required && CertLibrary::Get()->CertificatesLoaded()) { |
| if (!HaveUserCerts()) { |
| error_msg = l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT); |
| } else if (!IsUserCertValid()) { |
| error_msg = l10n_util::GetStringUTF16( |
| IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_REQUIRE_HARDWARE_BACKED); |
| } |
| } |
| if (error_msg.empty() && !service_path_.empty()) { |
| // TODO(kuan): differentiate between bad psk and user passphrases. |
| const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()-> |
| GetNetworkState(service_path_); |
| if (vpn && vpn->connection_state() == shill::kStateFailure) |
| error_msg = ash::network_connect::ErrorString(vpn->error(), vpn->path()); |
| } |
| if (!error_msg.empty()) { |
| error_label_->SetText(error_msg); |
| error_label_->SetVisible(true); |
| } else { |
| error_label_->SetVisible(false); |
| } |
| } |
| |
| void VPNConfigView::UpdateCanLogin() { |
| parent_->GetDialogClientView()->UpdateDialogButtons(); |
| } |
| |
| bool VPNConfigView::HaveUserCerts() const { |
| return CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) > 0; |
| } |
| |
| bool VPNConfigView::IsUserCertValid() const { |
| if (!user_cert_combobox_ || !enable_user_cert_) |
| return false; |
| int index = user_cert_combobox_->selected_index(); |
| if (index < 0) |
| return false; |
| // Currently only hardware-backed user certificates are valid. |
| if (CertLibrary::Get()->IsHardwareBacked() && |
| !CertLibrary::Get()->IsCertHardwareBackedAt( |
| CertLibrary::CERT_TYPE_USER, index)) |
| return false; |
| return true; |
| } |
| |
| const std::string VPNConfigView::GetTextFromField(views::Textfield* textfield, |
| bool trim_whitespace) const { |
| if (!textfield) |
| return std::string(); |
| std::string untrimmed = UTF16ToUTF8(textfield->text()); |
| if (!trim_whitespace) |
| return untrimmed; |
| std::string result; |
| TrimWhitespaceASCII(untrimmed, TRIM_ALL, &result); |
| return result; |
| } |
| |
| const std::string VPNConfigView::GetPassphraseFromField( |
| PassphraseTextfield* textfield) const { |
| if (!textfield) |
| return std::string(); |
| return textfield->GetPassphrase(); |
| } |
| |
| void VPNConfigView::ParseVPNUIProperty( |
| const NetworkState* network, |
| const std::string& dict_key, |
| const std::string& key, |
| NetworkPropertyUIData* property_ui_data) { |
| ::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE; |
| const base::DictionaryValue* onc = |
| onc::FindPolicyForActiveUser(network->guid(), &onc_source); |
| |
| VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->guid(); |
| property_ui_data->ParseOncProperty( |
| onc_source, |
| onc, |
| base::StringPrintf("%s.%s.%s", |
| ::onc::network_config::kVPN, |
| dict_key.c_str(), |
| key.c_str())); |
| } |
| |
| } // namespace chromeos |