Commit b43b430e authored by Andreea Costinas's avatar Andreea Costinas Committed by Commit Bot

system-proxy: Secure policy credentials

Currently System-proxy sends the policy set credentials with every
connect request to a remote proxy. Since less secure authentication
schemes send the credentials in clear to the proxy, an attacker can
easily obtain the policy set credentials.

This CL allows admins to restrict the auth schemes for which
System-proxy can use the policy set credentials.

      - manually tested proxies set by extensions (managed and user
      installed extensions)

Bug: 1132247
Test: - browser_tests  --gtest_filter=SystemProxyManagerPolicyCredentialsBrowserTest
Change-Id: I4583762b565ec43bfdad8be4c6db87d3e2bec223
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2484444Reviewed-by: default avatarPavol Marko <pmarko@chromium.org>
Reviewed-by: default avatarOmar Morsi <omorsi@google.com>
Commit-Queue: Andreea-Elena Costinas <acostinas@google.com>
Cr-Commit-Position: refs/heads/master@{#823964}
parent 5647239f
...@@ -20,12 +20,17 @@ ...@@ -20,12 +20,17 @@
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chromeos/dbus/system_proxy/system_proxy_client.h" #include "chromeos/dbus/system_proxy/system_proxy_client.h"
#include "chromeos/network/network_event_log.h" #include "chromeos/network/network_event_log.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/proxy/proxy_config_service_impl.h"
#include "chromeos/network/proxy/ui_proxy_config_service.h"
#include "chromeos/settings/cros_settings_names.h" #include "chromeos/settings/cros_settings_names.h"
#include "chromeos/settings/cros_settings_provider.h" #include "chromeos/settings/cros_settings_provider.h"
#include "components/arc/arc_prefs.h" #include "components/arc/arc_prefs.h"
#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/user_manager/user.h" #include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h" #include "components/user_manager/user_manager.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
...@@ -70,12 +75,18 @@ SystemProxyManager::SystemProxyManager(chromeos::CrosSettings* cros_settings, ...@@ -70,12 +75,18 @@ SystemProxyManager::SystemProxyManager(chromeos::CrosSettings* cros_settings,
prefs::kKerberosEnabled, prefs::kKerberosEnabled,
base::BindRepeating(&SystemProxyManager::OnKerberosEnabledChanged, base::BindRepeating(&SystemProxyManager::OnKerberosEnabledChanged,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
DCHECK(chromeos::NetworkHandler::IsInitialized());
chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver(
this, FROM_HERE);
// Fire it once so we're sure we get an invocation on startup. // Fire it once so we're sure we get an invocation on startup.
OnSystemProxySettingsPolicyChanged(); OnSystemProxySettingsPolicyChanged();
} }
SystemProxyManager::~SystemProxyManager() = default; SystemProxyManager::~SystemProxyManager() {
DCHECK(chromeos::NetworkHandler::IsInitialized());
chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver(
this, FROM_HERE);
}
std::string SystemProxyManager::SystemServicesProxyPacString() const { std::string SystemProxyManager::SystemServicesProxyPacString() const {
return system_proxy_enabled_ && !system_services_address_.empty() return system_proxy_enabled_ && !system_services_address_.empty()
...@@ -85,6 +96,7 @@ std::string SystemProxyManager::SystemServicesProxyPacString() const { ...@@ -85,6 +96,7 @@ std::string SystemProxyManager::SystemServicesProxyPacString() const {
void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) { void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) {
primary_profile_ = profile; primary_profile_ = profile;
extension_prefs_util_ = std::make_unique<extensions::PrefsUtil>(profile);
// Listen to pref changes. // Listen to pref changes.
profile_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); profile_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
profile_pref_change_registrar_->Init(primary_profile_->GetPrefs()); profile_pref_change_registrar_->Init(primary_profile_->GetPrefs());
...@@ -96,7 +108,12 @@ void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) { ...@@ -96,7 +108,12 @@ void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) {
arc::prefs::kArcEnabled, arc::prefs::kArcEnabled,
base::BindRepeating(&SystemProxyManager::OnArcEnabledChanged, base::BindRepeating(&SystemProxyManager::OnArcEnabledChanged,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
profile_pref_change_registrar_->Add(
proxy_config::prefs::kProxy,
base::BindRepeating(&SystemProxyManager::OnProxyConfigChanged,
base::Unretained(this)));
if (system_proxy_enabled_) { if (system_proxy_enabled_) {
OnProxyConfigChanged();
OnKerberosAccountChanged(); OnKerberosAccountChanged();
OnArcEnabledChanged(); OnArcEnabledChanged();
} }
...@@ -105,6 +122,7 @@ void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) { ...@@ -105,6 +122,7 @@ void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) {
void SystemProxyManager::StopObservingPrimaryProfilePrefs() { void SystemProxyManager::StopObservingPrimaryProfilePrefs() {
profile_pref_change_registrar_->RemoveAll(); profile_pref_change_registrar_->RemoveAll();
profile_pref_change_registrar_.reset(); profile_pref_change_registrar_.reset();
extension_prefs_util_.reset();
primary_profile_ = nullptr; primary_profile_ = nullptr;
} }
...@@ -153,8 +171,6 @@ void SystemProxyManager::OnSystemProxySettingsPolicyChanged() { ...@@ -153,8 +171,6 @@ void SystemProxyManager::OnSystemProxySettingsPolicyChanged() {
CloseAuthenticationUI(); CloseAuthenticationUI();
return; return;
} }
system_proxy::SetAuthenticationDetailsRequest request;
system_proxy::Credentials credentials;
const std::string* username = proxy_settings->FindStringKey( const std::string* username = proxy_settings->FindStringKey(
chromeos::kSystemProxySettingsKeySystemServicesUsername); chromeos::kSystemProxySettingsKeySystemServicesUsername);
...@@ -165,16 +181,26 @@ void SystemProxyManager::OnSystemProxySettingsPolicyChanged() { ...@@ -165,16 +181,26 @@ void SystemProxyManager::OnSystemProxySettingsPolicyChanged() {
NET_LOG(DEBUG) << "Proxy credentials for system traffic not set: " NET_LOG(DEBUG) << "Proxy credentials for system traffic not set: "
<< kSystemProxyService; << kSystemProxyService;
} else { } else {
credentials.set_username(*username); system_services_username_ = *username;
credentials.set_password(*password); system_services_password_ = *password;
*request.mutable_credentials() = credentials; }
if (IsManagedProxyConfigured()) {
SendPolicyAuthenticationCredentials(system_services_username_,
system_services_password_,
/*force_send=*/true);
} else {
// To avoid leaking the policy set credentials, don't send them to
// System-proxy if there's no managed proxy on the network.
// Note: When SystemProxyManager is starting, the credentials are empty and
// they were never sent before. We need to force send them, otherwise
// `SendPolicyAuthenticationCredentials` will detect that no change to the
// credentials occurred and will not trigger a D-Bus request. This means the
// worker service for Chrome OS system services will not be started.
SendPolicyAuthenticationCredentials(/*username=*/"",
/*password=*/"",
/*force_send=*/true);
} }
request.set_traffic_type(system_proxy::TrafficOrigin::SYSTEM);
chromeos::SystemProxyClient::Get()->SetAuthenticationDetails(
request, base::BindOnce(&SystemProxyManager::OnSetAuthenticationDetails,
weak_factory_.GetWeakPtr()));
// Fire once to cover the case where the SystemProxySetting policy is set // Fire once to cover the case where the SystemProxySetting policy is set
// during a user session. // during a user session.
if (IsArcEnabled()) { if (IsArcEnabled()) {
...@@ -251,6 +277,35 @@ void SystemProxyManager::SendUserAuthenticationCredentials( ...@@ -251,6 +277,35 @@ void SystemProxyManager::SendUserAuthenticationCredentials(
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
void SystemProxyManager::SendPolicyAuthenticationCredentials(
const std::string& username,
const std::string& password,
bool force_send) {
if (!system_proxy_enabled_)
return;
if (!force_send &&
(last_sent_username_ == username && last_sent_password_ == password)) {
// Credentials were already sent.
return;
}
last_sent_username_ = username;
last_sent_password_ = password;
system_proxy::SetAuthenticationDetailsRequest request;
system_proxy::Credentials credentials;
credentials.set_username(username);
credentials.set_password(password);
*request.mutable_credentials() = credentials;
request.set_traffic_type(system_proxy::TrafficOrigin::SYSTEM);
chromeos::SystemProxyClient::Get()->SetAuthenticationDetails(
request, base::BindOnce(&SystemProxyManager::OnSetAuthenticationDetails,
weak_factory_.GetWeakPtr()));
}
void SystemProxyManager::SendKerberosAuthenticationDetails() { void SystemProxyManager::SendKerberosAuthenticationDetails() {
if (!system_proxy_enabled_) { if (!system_proxy_enabled_) {
return; return;
...@@ -322,6 +377,62 @@ void SystemProxyManager::OnSetAuthenticationDetails( ...@@ -322,6 +377,62 @@ void SystemProxyManager::OnSetAuthenticationDetails(
send_auth_details_closure_for_test_.Run(); send_auth_details_closure_for_test_.Run();
} }
// This function is called when the default network changes or when any of its
// properties change.
void SystemProxyManager::DefaultNetworkChanged(
const chromeos::NetworkState* network) {
if (!network)
return;
OnProxyConfigChanged();
}
void SystemProxyManager::OnProxyConfigChanged() {
if (!IsManagedProxyConfigured()) {
SendPolicyAuthenticationCredentials(/*username=*/"", /*password=*/"",
/*force_send=*/false);
return;
}
SendPolicyAuthenticationCredentials(system_services_username_,
system_services_password_,
/*force_send=*/false);
}
bool SystemProxyManager::IsManagedProxyConfigured() {
DCHECK(chromeos::NetworkHandler::IsInitialized());
chromeos::NetworkHandler* network_handler = chromeos::NetworkHandler::Get();
base::Value proxy_settings(base::Value::Type::DICTIONARY);
// |ui_proxy_config_service| may be missing in tests. If the device is offline
// (no network connected) the |DefaultNetwork| is null.
if (chromeos::NetworkHandler::HasUiProxyConfigService() &&
network_handler->network_state_handler()->DefaultNetwork()) {
// Check if proxy is enforced by user policy, force installed extension or
// ONC policies. This will only read managed settings.
chromeos::NetworkHandler::GetUiProxyConfigService()
->MergeEnforcedProxyConfig(
network_handler->network_state_handler()->DefaultNetwork()->guid(),
&proxy_settings);
}
if (proxy_settings.DictEmpty())
return false; // no managed proxy set
if (IsProxyConfiguredByUserViaExtension())
return false;
// Proxy was configured by the admin
return true;
}
bool SystemProxyManager::IsProxyConfiguredByUserViaExtension() {
if (!extension_prefs_util_)
return false;
std::unique_ptr<extensions::api::settings_private::PrefObject> pref =
extension_prefs_util_->GetPref(proxy_config::prefs::kProxy);
return pref && pref->extension_can_be_disabled &&
*pref->extension_can_be_disabled;
}
void SystemProxyManager::OnShutDownProcess( void SystemProxyManager::OnShutDownProcess(
const system_proxy::ShutDownResponse& response) { const system_proxy::ShutDownResponse& response) {
if (response.has_error_message() && !response.error_message().empty()) { if (response.has_error_message() && !response.error_message().empty()) {
......
...@@ -13,10 +13,13 @@ ...@@ -13,10 +13,13 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/extensions/api/settings_private/prefs_util.h"
#include "chromeos/dbus/system_proxy/system_proxy_service.pb.h" #include "chromeos/dbus/system_proxy/system_proxy_service.pb.h"
#include "chromeos/network/network_state_handler_observer.h"
#include "net/base/auth.h" #include "net/base/auth.h"
namespace chromeos { namespace chromeos {
class NetworkState;
class RequestSystemProxyCredentialsView; class RequestSystemProxyCredentialsView;
class SystemProxyNotification; class SystemProxyNotification;
} // namespace chromeos } // namespace chromeos
...@@ -43,7 +46,9 @@ namespace policy { ...@@ -43,7 +46,9 @@ namespace policy {
// also listens for the |WorkerActive| dbus signal sent by the System-proxy // also listens for the |WorkerActive| dbus signal sent by the System-proxy
// daemon and stores connection information regarding the active worker // daemon and stores connection information regarding the active worker
// processes. // processes.
class SystemProxyManager { // TODO(acostinas, https://crbug.com/1145174): Move the logic that tracks
// managed network changes to another class.
class SystemProxyManager : public chromeos::NetworkStateHandlerObserver {
public: public:
SystemProxyManager(chromeos::CrosSettings* cros_settings, SystemProxyManager(chromeos::CrosSettings* cros_settings,
PrefService* local_state); PrefService* local_state);
...@@ -51,7 +56,7 @@ class SystemProxyManager { ...@@ -51,7 +56,7 @@ class SystemProxyManager {
SystemProxyManager& operator=(const SystemProxyManager&) = delete; SystemProxyManager& operator=(const SystemProxyManager&) = delete;
~SystemProxyManager(); ~SystemProxyManager() override;
// If System-proxy is enabled by policy, it returns the URL of the local proxy // If System-proxy is enabled by policy, it returns the URL of the local proxy
// instance that authenticates system services, in PAC format, e.g. // instance that authenticates system services, in PAC format, e.g.
...@@ -76,6 +81,18 @@ class SystemProxyManager { ...@@ -76,6 +81,18 @@ class SystemProxyManager {
static void RegisterProfilePrefs(PrefRegistrySimple* registry); static void RegisterProfilePrefs(PrefRegistrySimple* registry);
private: private:
// NetworkStateHandlerObserver implementation
void DefaultNetworkChanged(const chromeos::NetworkState* network) override;
// Called when the proxy configurations may have changed either by updates to
// the kProxy policy or updates to the default network.
void OnProxyConfigChanged();
// Returns true if there's a policy configured proxy on the default network
// (via device or user ONC policy, user policy or force installed extension).
bool IsManagedProxyConfigured();
// Returns true if the `kProxy` preference set by an extension can be changed
// by the user.
bool IsProxyConfiguredByUserViaExtension();
void OnSetAuthenticationDetails( void OnSetAuthenticationDetails(
const system_proxy::SetAuthenticationDetailsResponse& response); const system_proxy::SetAuthenticationDetailsResponse& response);
void OnShutDownProcess(const system_proxy::ShutDownResponse& response); void OnShutDownProcess(const system_proxy::ShutDownResponse& response);
...@@ -95,6 +112,14 @@ class SystemProxyManager { ...@@ -95,6 +112,14 @@ class SystemProxyManager {
const system_proxy::ProtectionSpace& protection_space, const system_proxy::ProtectionSpace& protection_space,
const std::string& username, const std::string& username,
const std::string& password); const std::string& password);
// Sends policy set credentials to System-proxy via D-Bus. Credentials are
// sent only if `username` and `password` are different than
// `last_sent_username_` and `last_sent_password_` or if `force_send` is true.
void SendPolicyAuthenticationCredentials(const std::string& username,
const std::string& password,
bool force_send);
// Send the Kerberos enabled state and active principal name to System-proxy // Send the Kerberos enabled state and active principal name to System-proxy
// via D-Bus. // via D-Bus.
void SendKerberosAuthenticationDetails(); void SendKerberosAuthenticationDetails();
...@@ -153,6 +178,15 @@ class SystemProxyManager { ...@@ -153,6 +178,15 @@ class SystemProxyManager {
// The authority URI in the format host:port of the local proxy worker for // The authority URI in the format host:port of the local proxy worker for
// system services. // system services.
std::string system_services_address_; std::string system_services_address_;
std::string system_services_username_;
std::string system_services_password_;
// The credentials which were last sent to System-proxy. They can differ from
// `system_services_username_` and `system_services_username_` if the proxy
// configuration is not managed; in this case `last_sent_username_` and
// `last_sent_password_` are both empty even if credentials were specified by
// policy.
std::string last_sent_username_;
std::string last_sent_password_;
// Local state prefs, not owned. // Local state prefs, not owned.
PrefService* local_state_ = nullptr; PrefService* local_state_ = nullptr;
...@@ -168,6 +202,7 @@ class SystemProxyManager { ...@@ -168,6 +202,7 @@ class SystemProxyManager {
// Primary profile, not owned. // Primary profile, not owned.
Profile* primary_profile_ = nullptr; Profile* primary_profile_ = nullptr;
std::unique_ptr<extensions::PrefsUtil> extension_prefs_util_;
// Observer for Kerberos-related prefs. // Observer for Kerberos-related prefs.
std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_; std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_;
......
...@@ -2,21 +2,48 @@ ...@@ -2,21 +2,48 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <set>
#include <string>
#include "base/bind.h" #include "base/bind.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/task/current_thread.h" #include "base/task/current_thread.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "chrome/browser/chromeos/login/test/device_state_mixin.h"
#include "chrome/browser/chromeos/policy/affiliation_test_helper.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
#include "chrome/browser/chromeos/policy/system_proxy_manager.h" #include "chrome/browser/chromeos/policy/system_proxy_manager.h"
#include "chrome/browser/chromeos/ui/request_system_proxy_credentials_view.h" #include "chrome/browser/chromeos/ui/request_system_proxy_credentials_view.h"
#include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/browser/notifications/notification_display_service_tester.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
#include "chromeos/dbus/shill/shill_profile_client.h"
#include "chromeos/dbus/shill/shill_service_client.h"
#include "chromeos/dbus/system_proxy/system_proxy_client.h" #include "chromeos/dbus/system_proxy/system_proxy_client.h"
#include "chromeos/dbus/system_proxy/system_proxy_service.pb.h" #include "chromeos/dbus/system_proxy/system_proxy_service.pb.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/proxy/proxy_config_handler.h"
#include "chromeos/settings/cros_settings_names.h"
#include "chromeos/tpm/stub_install_attributes.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "components/prefs/pref_service.h"
#include "components/proxy_config/proxy_config_dictionary.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/proxy_config/proxy_prefs.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h" #include "content/public/browser/notification_service.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
...@@ -24,6 +51,9 @@ ...@@ -24,6 +51,9 @@
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield.h"
using testing::_;
using testing::Return;
namespace policy { namespace policy {
namespace { namespace {
...@@ -33,6 +63,84 @@ constexpr char kProxyAuthUrl[] = "http://example.com:3128"; ...@@ -33,6 +63,84 @@ constexpr char kProxyAuthUrl[] = "http://example.com:3128";
constexpr char kSystemProxyNotificationId[] = "system-proxy.auth_required"; constexpr char kSystemProxyNotificationId[] = "system-proxy.auth_required";
constexpr char kUsername[] = "testuser"; constexpr char kUsername[] = "testuser";
constexpr char kPassword[] = "testpwd"; constexpr char kPassword[] = "testpwd";
constexpr char kUserProfilePath[] = "user_profile";
constexpr char kDefaultServicePath[] = "default_wifi";
constexpr char kDefaultServiceSsid[] = "default_wifi_guid";
constexpr char kDefaultServiceGuid[] = "eth0";
constexpr char kWifiServicePath[] = "stub_wifi";
constexpr char kWifiSsid[] = "wifi0";
constexpr char kWifiGuid[] = "{wifi0_guid}";
constexpr char kONCPolicyWifi0Proxy[] =
R"({
"NetworkConfigurations": [ {
"GUID": "{wifi0_guid}",
"Name": "wifi0",
"ProxySettings": {
"Manual": {
"HTTPProxy": {
"Host": "proxyhost",
"Port": 3128
},
"SecureHTTPProxy": {
"Host": "proxyhost",
"Port": 3128
}
},
"Type": "Manual"
},
"Type": "WiFi",
"WiFi": {
"AutoConnect": true,
"HiddenSSID": false,
"SSID": "wifi0",
"Security": "None"
}
} ]
})";
constexpr char kONCPolicyWifi0AltProxy[] =
R"({
"NetworkConfigurations": [ {
"GUID": "{wifi0_guid}",
"Name": "wifi0",
"ProxySettings": {
"Manual": {
"HTTPProxy": {
"Host": "proxyhostalt",
"Port": 3129
},
"SecureHTTPProxy": {
"Host": "proxyhostalt",
"Port": 3129
}
},
"Type": "Manual"
},
"Type": "WiFi",
"WiFi": {
"AutoConnect": true,
"HiddenSSID": false,
"SSID": "wifi0",
"Security": "None"
}
} ]
})";
constexpr char kSystemProxyPolicyJson[] =
R"({
"system_proxy_enabled": true,
"system_services_username": "%s",
"system_services_password": "%s",
})";
void RunUntilIdle() {
DCHECK(base::CurrentThread::Get());
base::RunLoop loop;
loop.RunUntilIdle();
}
} // namespace } // namespace
class SystemProxyManagerBrowserTest : public InProcessBrowserTest { class SystemProxyManagerBrowserTest : public InProcessBrowserTest {
...@@ -211,4 +319,258 @@ IN_PROC_BROWSER_TEST_F(SystemProxyManagerBrowserTest, ...@@ -211,4 +319,258 @@ IN_PROC_BROWSER_TEST_F(SystemProxyManagerBrowserTest,
EXPECT_TRUE(dialog()->error_label_for_testing()->GetVisible()); EXPECT_TRUE(dialog()->error_label_for_testing()->GetVisible());
} }
class SystemProxyManagerPolicyCredentialsBrowserTest
: public MixinBasedInProcessBrowserTest {
public:
SystemProxyManagerPolicyCredentialsBrowserTest() {
device_state_.SetState(
chromeos::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED);
device_state_.set_skip_initial_policy_setup(true);
}
SystemProxyManagerPolicyCredentialsBrowserTest(
const SystemProxyManagerPolicyCredentialsBrowserTest&) = delete;
SystemProxyManagerPolicyCredentialsBrowserTest& operator=(
const SystemProxyManagerPolicyCredentialsBrowserTest&) = delete;
~SystemProxyManagerPolicyCredentialsBrowserTest() override = default;
void SetUpInProcessBrowserTestFixture() override {
chromeos::SessionManagerClient::InitializeFakeInMemory();
MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
const std::string kAffiliationID = "id";
// Initialize device policy.
std::set<std::string> device_affiliation_ids;
device_affiliation_ids.insert(kAffiliationID);
auto affiliation_helper = AffiliationTestHelper::CreateForCloud(
chromeos::FakeSessionManagerClient::Get());
ASSERT_NO_FATAL_FAILURE((affiliation_helper.SetDeviceAffiliationIDs(
&policy_helper_, device_affiliation_ids)));
EXPECT_CALL(provider_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
}
void SetUpOnMainThread() override { SetupNetworkEnvironment(); }
protected:
void SetPolicyCredentials(const std::string& username,
const std::string& password) {
const std::string policy_value = base::StringPrintf(
kSystemProxyPolicyJson, username.c_str(), password.c_str());
enterprise_management::ChromeDeviceSettingsProto& proto(
policy_helper_.device_policy()->payload());
proto.mutable_system_proxy_settings()->set_system_proxy_settings(
policy_value);
policy_helper_.RefreshPolicyAndWaitUntilDeviceSettingsUpdated(
{chromeos::kSystemProxySettings});
RunUntilIdle();
}
void SetOncPolicy(const std::string& policy_json, PolicyScope scope) {
policy::PolicyMap policy;
policy.Set(policy::key::kOpenNetworkConfiguration,
policy::POLICY_LEVEL_MANDATORY, scope,
policy::POLICY_SOURCE_CLOUD, base::Value(policy_json), nullptr);
provider_.UpdateChromePolicy(policy);
RunUntilIdle();
}
void DisconnectNetworkService(const std::string& service_path) {
chromeos::ShillServiceClient::TestInterface* service_test =
chromeos::DBusThreadManager::Get()
->GetShillServiceClient()
->GetTestInterface();
base::Value value(shill::kStateIdle);
service_test->SetServiceProperty(service_path, shill::kStateProperty,
value);
RunUntilIdle();
}
void ConnectWifiNetworkService(const std::string& service_path,
const std::string& guid,
const std::string& ssid) {
chromeos::ShillServiceClient::TestInterface* service_test =
chromeos::DBusThreadManager::Get()
->GetShillServiceClient()
->GetTestInterface();
service_test->AddService(service_path, guid, ssid, shill::kTypeWifi,
shill::kStateOnline, true /* add_to_visible */);
service_test->SetServiceProperty(service_path, shill::kProfileProperty,
base::Value(kUserProfilePath));
RunUntilIdle();
}
void SetProxyConfigForNetworkService(const std::string& service_path,
base::Value proxy_config) {
ProxyConfigDictionary proxy_config_dict(std::move(proxy_config));
DCHECK(chromeos::NetworkHandler::IsInitialized());
const chromeos::NetworkState* network = chromeos::NetworkHandler::Get()
->network_state_handler()
->GetNetworkState(service_path);
ASSERT_TRUE(network);
chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config_dict,
*network);
}
void ExpectSystemCredentialsSent(const std::string& username,
const std::string& password) {
system_proxy::SetAuthenticationDetailsRequest request =
client_test_interface()->GetLastAuthenticationDetailsRequest();
EXPECT_EQ(username, request.credentials().username());
EXPECT_EQ(password, request.credentials().password());
EXPECT_EQ(system_proxy::TrafficOrigin::SYSTEM, request.traffic_type());
}
chromeos::SystemProxyClient::TestInterface* client_test_interface() {
return chromeos::SystemProxyClient::Get()->GetTestInterface();
}
private:
void SetupNetworkEnvironment() {
chromeos::ShillProfileClient::TestInterface* profile_test =
chromeos::DBusThreadManager::Get()
->GetShillProfileClient()
->GetTestInterface();
chromeos::ShillServiceClient::TestInterface* service_test =
chromeos::DBusThreadManager::Get()
->GetShillServiceClient()
->GetTestInterface();
profile_test->AddProfile(kUserProfilePath, "user");
service_test->ClearServices();
ConnectWifiNetworkService(kDefaultServicePath, kDefaultServiceSsid,
kDefaultServiceGuid);
}
chromeos::DeviceStateMixin device_state_{
&mixin_host_, chromeos::DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED};
chromeos::ScopedStubInstallAttributes test_install_attributes_;
MockConfigurationPolicyProvider provider_;
DevicePolicyCrosTestHelper policy_helper_;
};
// Tests that the SystemProxyManager syncs credentials correctly for managed
// proxies configured via device ONC policy. It also tests the overall policy
// credentials syncing behaviour, more specifically that SystemProxyManager:
// - sends a D-Bus request when enabled by policy;
// - doesn't send redundant requests to set credentials, i.e. when the default
// network is updated;
// - sends requests to clear credentials if the network is not managed.
IN_PROC_BROWSER_TEST_F(SystemProxyManagerPolicyCredentialsBrowserTest,
DeviceONCPolicyUpdates) {
int set_auth_details_call_count = 0;
SetPolicyCredentials(/*username=*/"", /*password=*/"");
// Expect that if System-proxy policy is enabled, one initial call to set
// empty credentials is sent, regardless of network configuration.
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent("", "");
DisconnectNetworkService(kDefaultServicePath);
ConnectWifiNetworkService(kWifiServicePath, kWifiGuid, kWifiSsid);
// Set an ONC policy with proxy configuration and expect that no D-Bus call to
// update credentials is sent, since the credentials were not changed.
SetOncPolicy(kONCPolicyWifi0Proxy, policy::POLICY_SCOPE_MACHINE);
EXPECT_EQ(set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
// Set policy credentials for the remote proxy and expect that a D-Bus request
// to set policy credentials was sent.
SetPolicyCredentials(kUsername, kPassword);
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent(kUsername, kPassword);
// Connect to a different managed proxy and expect that no additional request
// is sent to System-proxy since credentials were not changed.
SetOncPolicy(kONCPolicyWifi0AltProxy, policy::POLICY_SCOPE_MACHINE);
EXPECT_EQ(set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
// Change credentials and expect that a D-Bus request to set the new
// credentials is sent to System-proxy.
SetPolicyCredentials("test_user_alt", "test_pwd_alt");
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent("test_user_alt", "test_pwd_alt");
DisconnectNetworkService(kWifiServicePath);
// Expect credentials are cleared on non-managed networks.
ConnectWifiNetworkService(kDefaultServicePath, kDefaultServiceSsid,
kDefaultServiceGuid);
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent("", "");
}
// Tests that the SystemProxyManager syncs credentials correctly for managed
// proxies configured via user ONC policy.
IN_PROC_BROWSER_TEST_F(SystemProxyManagerPolicyCredentialsBrowserTest,
UserONCPolicy) {
int set_auth_details_call_count = 0;
SetPolicyCredentials(kUsername, kPassword);
// Expect that credentials were not sent, since there's no managed proxy
// configured.
ExpectSystemCredentialsSent("", "");
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
DisconnectNetworkService(kDefaultServicePath);
// Configure a proxy via user ONC policy and expect that credentials were
// forwarded to System-proxy.
SetOncPolicy(kONCPolicyWifi0Proxy, policy::POLICY_SCOPE_USER);
ConnectWifiNetworkService(kWifiServicePath, kWifiGuid, kWifiSsid);
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent(kUsername, kPassword);
}
// Tests that the SystemProxyManager syncs credentials correctly for managed
// proxies configured via the user policy which sets the kProxy pref.
IN_PROC_BROWSER_TEST_F(SystemProxyManagerPolicyCredentialsBrowserTest,
UserPolicy) {
int set_auth_details_call_count = 0;
SetPolicyCredentials(kUsername, kPassword);
// Expect that credentials were not sent, since there's no managed proxy
// configured.
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent("", "");
// Configure a proxy via user policy.
base::Value proxy_config(base::Value::Type::DICTIONARY);
proxy_config.SetKey("mode", base::Value(ProxyPrefs::kPacScriptProxyModeName));
proxy_config.SetKey("pac_url", base::Value("http://proxy"));
browser()->profile()->GetPrefs()->Set(proxy_config::prefs::kProxy,
proxy_config);
RunUntilIdle();
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent(kUsername, kPassword);
}
// Tests that the SystemProxyManager doesn't send credentials for user
// configured proxies.
IN_PROC_BROWSER_TEST_F(SystemProxyManagerPolicyCredentialsBrowserTest,
UserSetProxy) {
SetPolicyCredentials(kUsername, kPassword);
base::Value proxy_config(base::Value::Type::DICTIONARY);
proxy_config.SetKey("mode",
base::Value(ProxyPrefs::kFixedServersProxyModeName));
proxy_config.SetKey("server", base::Value("proxy:8080"));
SetProxyConfigForNetworkService(kDefaultServicePath, std::move(proxy_config));
RunUntilIdle();
int set_auth_details_call_count = 0;
EXPECT_EQ(++set_auth_details_call_count,
client_test_interface()->GetSetAuthenticationDetailsCallCount());
ExpectSystemCredentialsSent("", "");
}
} // namespace policy } // namespace policy
...@@ -14,8 +14,10 @@ ...@@ -14,8 +14,10 @@
#include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "chromeos/dbus/shill/shill_clients.h"
#include "chromeos/dbus/system_proxy/system_proxy_client.h" #include "chromeos/dbus/system_proxy/system_proxy_client.h"
#include "chromeos/dbus/system_proxy/system_proxy_service.pb.h" #include "chromeos/dbus/system_proxy/system_proxy_service.pb.h"
#include "chromeos/network/network_handler.h"
#include "components/arc/arc_prefs.h" #include "components/arc/arc_prefs.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "content/public/browser/network_service_instance.h" #include "content/public/browser/network_service_instance.h"
...@@ -39,8 +41,6 @@ using testing::Invoke; ...@@ -39,8 +41,6 @@ using testing::Invoke;
using testing::WithArg; using testing::WithArg;
namespace { namespace {
constexpr char kSystemServicesUsername[] = "test_username";
constexpr char kSystemServicesPassword[] = "test_password";
constexpr char kBrowserUsername[] = "browser_username"; constexpr char kBrowserUsername[] = "browser_username";
constexpr char kBrowserPassword[] = "browser_password"; constexpr char kBrowserPassword[] = "browser_password";
constexpr char kKerberosActivePrincipalName[] = "kerberos_princ_name"; constexpr char kKerberosActivePrincipalName[] = "kerberos_princ_name";
...@@ -86,6 +86,9 @@ class SystemProxyManagerTest : public testing::Test { ...@@ -86,6 +86,9 @@ class SystemProxyManagerTest : public testing::Test {
// testing::Test // testing::Test
void SetUp() override { void SetUp() override {
testing::Test::SetUp(); testing::Test::SetUp();
chromeos::shill_clients::InitializeFakes();
chromeos::NetworkHandler::Initialize();
profile_ = std::make_unique<TestingProfile>(); profile_ = std::make_unique<TestingProfile>();
chromeos::SystemProxyClient::InitializeFake(); chromeos::SystemProxyClient::InitializeFake();
system_proxy_manager_ = std::make_unique<SystemProxyManager>( system_proxy_manager_ = std::make_unique<SystemProxyManager>(
...@@ -96,7 +99,10 @@ class SystemProxyManagerTest : public testing::Test { ...@@ -96,7 +99,10 @@ class SystemProxyManagerTest : public testing::Test {
void TearDown() override { void TearDown() override {
system_proxy_manager_->StopObservingPrimaryProfilePrefs(); system_proxy_manager_->StopObservingPrimaryProfilePrefs();
system_proxy_manager_.reset();
chromeos::SystemProxyClient::Shutdown(); chromeos::SystemProxyClient::Shutdown();
chromeos::NetworkHandler::Shutdown();
chromeos::shill_clients::Shutdown();
} }
protected: protected:
...@@ -127,28 +133,6 @@ class SystemProxyManagerTest : public testing::Test { ...@@ -127,28 +133,6 @@ class SystemProxyManagerTest : public testing::Test {
chromeos::ScopedStubInstallAttributes test_install_attributes_; chromeos::ScopedStubInstallAttributes test_install_attributes_;
}; };
// Verifies that System-proxy is configured with the system traffic credentials
// set by |kSystemProxySettings| policy.
TEST_F(SystemProxyManagerTest, SetAuthenticationDetails) {
EXPECT_EQ(0, client_test_interface()->GetSetAuthenticationDetailsCallCount());
SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
"" /* system_services_password */);
// Don't send empty credentials.
EXPECT_EQ(1, client_test_interface()->GetSetAuthenticationDetailsCallCount());
SetPolicy(true /* system_proxy_enabled */, kSystemServicesUsername,
kSystemServicesPassword);
EXPECT_EQ(2, client_test_interface()->GetSetAuthenticationDetailsCallCount());
system_proxy::SetAuthenticationDetailsRequest request =
client_test_interface()->GetLastAuthenticationDetailsRequest();
ASSERT_TRUE(request.has_credentials());
EXPECT_EQ(kSystemServicesUsername, request.credentials().username());
EXPECT_EQ(kSystemServicesPassword, request.credentials().password());
}
// Verifies requests to shut down are sent to System-proxy according to the // Verifies requests to shut down are sent to System-proxy according to the
// |kSystemProxySettings| policy. // |kSystemProxySettings| policy.
TEST_F(SystemProxyManagerTest, ShutDownDaemon) { TEST_F(SystemProxyManagerTest, ShutDownDaemon) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment