blob: e247b77cfd564c3f96d114eb98505a9ef385534f [file] [log] [blame]
// 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/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 "chromeos/network/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/events/event.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/resource/resource_bundle.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 {
// Root CA certificates that are built into Chrome use this token name.
const char* const kRootCertificateTokenName = "Builtin Object Token";
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,
};
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 string16();
}
int ProviderTypeToIndex(const std::string& provider_type,
const std::string& client_cert_id) {
if (provider_type == flimflam::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 == flimflam::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 chromeos::onc::vpn::kIPsec;
case PROVIDER_TYPE_INDEX_OPEN_VPN:
return chromeos::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;
}
void ShillError(const std::string& function,
const std::string& error_name,
scoped_ptr<base::DictionaryValue> error_data) {
NET_LOG_ERROR("Shill Error from VpnConfigView: " + error_name, function);
}
} // namespace
namespace chromeos {
namespace internal {
class ProviderTypeComboboxModel : public ui::ComboboxModel {
public:
ProviderTypeComboboxModel();
virtual ~ProviderTypeComboboxModel();
// Overridden from ui::ComboboxModel:
virtual int GetItemCount() const OVERRIDE;
virtual 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 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 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;
}
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;
}
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;
}
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() {
CertLibrary::Get()->RemoveObserver(this);
}
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 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.
string16 server = server_textfield_->text();
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(
flimflam::kTypeProperty, flimflam::kTypeVPN);
properties.SetStringWithoutPathExpansion(
flimflam::kNameProperty, GetService());
properties.SetStringWithoutPathExpansion(
flimflam::kProviderHostProperty, GetServer());
properties.SetStringWithoutPathExpansion(
flimflam::kProviderTypeProperty, GetProviderTypeString());
SetConfigProperties(&properties);
ash::network_connect::CreateConfigurationAndConnect(
&properties, false /* not 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 flimflam::kProviderL2tpIpsec;
case PROVIDER_TYPE_INDEX_OPEN_VPN:
return flimflam::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() == flimflam::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(
flimflam::kProviderProperty, &provider_properties)) {
provider_properties->GetStringWithoutPathExpansion(
flimflam::kTypeProperty, &provider_type);
provider_properties->GetStringWithoutPathExpansion(
flimflam::kHostProperty, &server_hostname);
}
if (provider_type == flimflam::kProviderL2tpIpsec) {
provider_properties->GetStringWithoutPathExpansion(
flimflam::kL2tpIpsecClientCertIdProperty, &client_cert_id_);
ca_cert_pem_ = GetPemFromDictionary(
provider_properties, shill::kL2tpIpsecCaCertPemProperty);
provider_properties->GetBooleanWithoutPathExpansion(
flimflam::kL2tpIpsecPskRequiredProperty, &psk_passphrase_required);
provider_properties->GetStringWithoutPathExpansion(
flimflam::kL2tpIpsecUserProperty, &username);
provider_properties->GetStringWithoutPathExpansion(
shill::kL2tpIpsecTunnelGroupProperty, &group_name);
} else if (provider_type == flimflam::kProviderOpenVpn) {
provider_properties->GetStringWithoutPathExpansion(
flimflam::kOpenVPNClientCertIdProperty, &client_cert_id_);
ca_cert_pem_ = GetPemFromDictionary(
provider_properties, shill::kOpenVPNCaCertPemProperty);
provider_properties->GetStringWithoutPathExpansion(
flimflam::kOpenVPNUserProperty, &username);
}
bool save_credentials = false;
service_properties.GetBooleanWithoutPathExpansion(
flimflam::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(
flimflam::kL2tpIpsecPskProperty, GetPSKPassphrase());
}
if (!group_name.empty()) {
properties->SetStringWithoutPathExpansion(
shill::kL2tpIpsecTunnelGroupProperty, group_name);
}
if (!user_name.empty()) {
properties->SetStringWithoutPathExpansion(
flimflam::kL2tpIpsecUserProperty, user_name);
}
if (!user_passphrase.empty()) {
properties->SetStringWithoutPathExpansion(
flimflam::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(
flimflam::kL2tpIpsecClientCertIdProperty, GetUserCertID());
if (!group_name.empty()) {
properties->SetStringWithoutPathExpansion(
shill::kL2tpIpsecTunnelGroupProperty, GetGroupName());
}
if (!user_name.empty()) {
properties->SetStringWithoutPathExpansion(
flimflam::kL2tpIpsecUserProperty, user_name);
}
if (!user_passphrase.empty()) {
properties->SetStringWithoutPathExpansion(
flimflam::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(
flimflam::kOpenVPNClientCertIdProperty, GetUserCertID());
properties->SetStringWithoutPathExpansion(
flimflam::kOpenVPNUserProperty, GetUsername());
if (!user_passphrase.empty()) {
properties->SetStringWithoutPathExpansion(
flimflam::kOpenVPNPasswordProperty, user_passphrase);
}
std::string otp = GetOTP();
if (!otp.empty()) {
properties->SetStringWithoutPathExpansion(
flimflam::kOpenVPNOTPProperty, otp);
}
break;
}
case PROVIDER_TYPE_INDEX_MAX:
NOTREACHED();
break;
}
properties->SetBooleanWithoutPathExpansion(
flimflam::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.
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() == flimflam::kStateFailure)
error_msg = ash::network_connect::ErrorString(vpn->error());
}
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