chromium/chrome/browser/ash/net/system_proxy_manager_unittest.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/net/system_proxy_manager.h"

#include "ash/components/arc/arc_prefs.h"
#include "ash/constants/ash_features.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "chrome/browser/ash/settings/device_settings_test_helper.h"
#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/ash/components/dbus/system_proxy/system_proxy_client.h"
#include "chromeos/ash/components/dbus/system_proxy/system_proxy_service.pb.h"
#include "chromeos/ash/components/login/login_state/login_state.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "components/prefs/pref_service.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/proxy_config/proxy_prefs.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_cache.h"
#include "net/http/http_network_session.h"
#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
#include "services/network/network_context.h"
#include "services/network/network_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"

namespace ash {

namespace {

constexpr char kBrowserUsername[] = "browser_username";
constexpr char16_t kBrowserUsername16[] = u"browser_username";
constexpr char kBrowserPassword[] = "browser_password";
constexpr char16_t kBrowserPassword16[] = u"browser_password";
constexpr char kPolicyUsername[] = "policy_username";
constexpr char kPolicyPassword[] = "policy_password";
constexpr char kKerberosActivePrincipalName[] = "kerberos_princ_name";
constexpr char kProxyAuthUrl[] = "http://example.com:3128";
constexpr char kProxyAuthEmptyPath[] = "http://example.com:3128/";
constexpr char kRealm[] = "My proxy";
constexpr char kScheme[] = "dIgEsT";
constexpr char kProxyAuthChallenge[] = "challenge";
constexpr char kLocalProxyAddress[] = "local-proxy.com:3128";

std::unique_ptr<network::NetworkContext>
CreateNetworkContextForDefaultStoragePartition(
    network::NetworkService* network_service,
    content::BrowserContext* browser_context) {
  mojo::PendingRemote<network::mojom::NetworkContext> network_context_remote;
  auto params = network::mojom::NetworkContextParams::New();
  params->cert_verifier_params = content::GetCertVerifierParams(
      cert_verifier::mojom::CertVerifierCreationParams::New());
  auto network_context = std::make_unique<network::NetworkContext>(
      network_service, network_context_remote.InitWithNewPipeAndPassReceiver(),
      std::move(params));
  browser_context->GetDefaultStoragePartition()->SetNetworkContextForTesting(
      std::move(network_context_remote));
  return network_context;
}

network::NetworkService* GetNetworkService() {
  content::GetNetworkService();
  // Wait for the Network Service to initialize on the IO thread.
  content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
  return network::NetworkService::GetNetworkServiceForTesting();
}

void SetManagedProxy(Profile* profile) {
  // Configure a proxy via user policy.
  auto proxy_config = base::Value::Dict()
                          .Set("mode", ProxyPrefs::kFixedServersProxyModeName)
                          .Set("server", kProxyAuthUrl);
  profile->GetPrefs()->SetDict(proxy_config::prefs::kProxy,
                               std::move(proxy_config));
  base::RunLoop().RunUntilIdle();
}

net::AuthChallengeInfo GetAuthInfo() {
  net::AuthChallengeInfo auth_info;
  auth_info.is_proxy = true;
  auth_info.scheme = kScheme;
  return auth_info;
}

}  // namespace

// TODO(acostinas, https://crbug.com/1102351) Replace RunUntilIdle() in tests
// with RunLoop::Run() with explicit RunLoop::QuitClosure().
class SystemProxyManagerTest : public testing::Test {
 public:
  SystemProxyManagerTest() : local_state_(TestingBrowserProcess::GetGlobal()) {}
  ~SystemProxyManagerTest() override = default;

  // testing::Test
  void SetUp() override {
    testing::Test::SetUp();
    network_handler_test_helper_ = std::make_unique<NetworkHandlerTestHelper>();
    LoginState::Initialize();

    profile_ = std::make_unique<TestingProfile>();
    SystemProxyClient::InitializeFake();
    system_proxy_manager_ =
        std::make_unique<SystemProxyManager>(local_state_.Get());
    // Listen for pref changes for the primary profile.
    system_proxy_manager_->StartObservingPrimaryProfilePrefs(profile_.get());
    NetworkHandler::Get()->InitializePrefServices(profile_->GetPrefs(),
                                                  local_state_.Get());
  }

  void TearDown() override {
    system_proxy_manager_->StopObservingPrimaryProfilePrefs();
    system_proxy_manager_.reset();
    LoginState::Shutdown();
    SystemProxyClient::Shutdown();
    network_handler_test_helper_.reset();
  }

 protected:
  void SetPolicy(bool system_proxy_enabled,
                 const std::string& system_services_username,
                 const std::string& system_services_password) {
    system_proxy_manager_->SetPolicySettings(
        system_proxy_enabled, system_services_username,
        system_services_password, /*auth_schemes=*/{});
  }

  SystemProxyClient::TestInterface* client_test_interface() {
    return SystemProxyClient::Get()->GetTestInterface();
  }

  content::BrowserTaskEnvironment task_environment_;
  std::unique_ptr<NetworkHandlerTestHelper> network_handler_test_helper_;
  ScopedTestingLocalState local_state_;
  std::unique_ptr<SystemProxyManager> system_proxy_manager_;
  std::unique_ptr<TestingProfile> profile_;
};

// Tests that |SystemProxyManager| sends the correct Kerberos details and
// updates to System-proxy.
TEST_F(SystemProxyManagerTest, KerberosConfig) {
  int expected_set_auth_details_call_count = 0;
  SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
            "" /* system_services_password */);
  EXPECT_EQ(++expected_set_auth_details_call_count,
            client_test_interface()->GetSetAuthenticationDetailsCallCount());

  local_state_.Get()->SetBoolean(prefs::kKerberosEnabled, true);
  EXPECT_EQ(++expected_set_auth_details_call_count,
            client_test_interface()->GetSetAuthenticationDetailsCallCount());

  system_proxy::SetAuthenticationDetailsRequest request =
      client_test_interface()->GetLastAuthenticationDetailsRequest();
  EXPECT_FALSE(request.has_credentials());
  EXPECT_TRUE(request.kerberos_enabled());
  EXPECT_EQ(request.traffic_type(), system_proxy::TrafficOrigin::SYSTEM);

  // Set an active principal name.
  profile_->GetPrefs()->SetString(prefs::kKerberosActivePrincipalName,
                                  kKerberosActivePrincipalName);
  EXPECT_EQ(++expected_set_auth_details_call_count,
            client_test_interface()->GetSetAuthenticationDetailsCallCount());

  profile_->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, true);
  EXPECT_EQ(++expected_set_auth_details_call_count,
            client_test_interface()->GetSetAuthenticationDetailsCallCount());

  request = client_test_interface()->GetLastAuthenticationDetailsRequest();
  EXPECT_EQ(kKerberosActivePrincipalName, request.active_principal_name());
  EXPECT_EQ(request.traffic_type(), system_proxy::TrafficOrigin::ALL);

  // Remove the active principal name.
  profile_->GetPrefs()->SetString(prefs::kKerberosActivePrincipalName, "");
  request = client_test_interface()->GetLastAuthenticationDetailsRequest();
  EXPECT_EQ("", request.active_principal_name());
  EXPECT_TRUE(request.kerberos_enabled());

  // Disable kerberos.
  local_state_.Get()->SetBoolean(prefs::kKerberosEnabled, false);
  request = client_test_interface()->GetLastAuthenticationDetailsRequest();
  EXPECT_FALSE(request.kerberos_enabled());
}

// Tests that when no user is signed in, credential requests are resolved to a
// D-Bus call which sends back to System-proxy empty credentials for the
// specified protection space.
TEST_F(SystemProxyManagerTest, UserCredentialsRequiredNoUser) {
  SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
            "" /* system_services_password */);
  system_proxy_manager_->StopObservingPrimaryProfilePrefs();
  system_proxy::ProtectionSpace protection_space;
  protection_space.set_origin(kProxyAuthUrl);
  protection_space.set_scheme(kScheme);
  protection_space.set_realm(kRealm);

  system_proxy::AuthenticationRequiredDetails details;
  details.set_bad_cached_credentials(false);
  *details.mutable_proxy_protection_space() = protection_space;

  client_test_interface()->SendAuthenticationRequiredSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_EQ(2, client_test_interface()->GetSetAuthenticationDetailsCallCount());

  system_proxy::SetAuthenticationDetailsRequest request =
      client_test_interface()->GetLastAuthenticationDetailsRequest();

  ASSERT_TRUE(request.has_protection_space());
  ASSERT_EQ(protection_space.SerializeAsString(),
            request.protection_space().SerializeAsString());

  ASSERT_TRUE(request.has_credentials());
  EXPECT_EQ("", request.credentials().username());
  EXPECT_EQ("", request.credentials().password());
  system_proxy_manager_->StartObservingPrimaryProfilePrefs(profile_.get());
}

// Tests that credential requests are resolved to a  D-Bus call which sends back
// to System-proxy credentials acquired from the NetworkService.
TEST_F(SystemProxyManagerTest, UserCredentialsRequestedFromNetworkService) {
  SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
            "" /* system_services_password */);

  // Setup the NetworkContext with credentials.
  std::unique_ptr<network::NetworkContext> network_context =
      CreateNetworkContextForDefaultStoragePartition(GetNetworkService(),
                                                     profile_.get());
  network_context->url_request_context()
      ->http_transaction_factory()
      ->GetSession()
      ->http_auth_cache()
      ->Add(url::SchemeHostPort(GURL(kProxyAuthEmptyPath)),
            net::HttpAuth::AUTH_PROXY, kRealm,
            net::HttpAuth::AUTH_SCHEME_DIGEST, net::NetworkAnonymizationKey(),
            kProxyAuthChallenge,
            net::AuthCredentials(kBrowserUsername16, kBrowserPassword16),
            std::string() /* path */);

  system_proxy::ProtectionSpace protection_space;
  protection_space.set_origin(kProxyAuthUrl);
  protection_space.set_scheme(kScheme);
  protection_space.set_realm(kRealm);

  system_proxy::AuthenticationRequiredDetails details;
  *details.mutable_proxy_protection_space() = protection_space;

  EXPECT_EQ(1, client_test_interface()->GetSetAuthenticationDetailsCallCount());

  client_test_interface()->SendAuthenticationRequiredSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_EQ(2, client_test_interface()->GetSetAuthenticationDetailsCallCount());

  system_proxy::SetAuthenticationDetailsRequest request =
      client_test_interface()->GetLastAuthenticationDetailsRequest();

  ASSERT_TRUE(request.has_protection_space());
  EXPECT_EQ(protection_space.SerializeAsString(),
            request.protection_space().SerializeAsString());

  ASSERT_TRUE(request.has_credentials());
  EXPECT_EQ(kBrowserUsername, request.credentials().username());
  EXPECT_EQ(kBrowserPassword, request.credentials().password());
  EXPECT_EQ(request.traffic_type(), system_proxy::TrafficOrigin::SYSTEM);

  // Enable ARC and verify that the credentials are sent both for user and
  // system traffic.
  profile_->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, true);
  task_environment_.RunUntilIdle();
  client_test_interface()->SendAuthenticationRequiredSignal(details);
  task_environment_.RunUntilIdle();
  request = client_test_interface()->GetLastAuthenticationDetailsRequest();
  EXPECT_EQ(request.traffic_type(), system_proxy::TrafficOrigin::ALL);
}

// Tests that |SystemProxyManager| sends requests to start and shut down the
// worker which tunnels ARC++ traffic according to policy.
TEST_F(SystemProxyManagerTest, EnableArcWorker) {
  int expected_set_auth_details_call_count = 0;
  int expected_shutdown_calls = 0;
  EXPECT_EQ(expected_shutdown_calls,
            client_test_interface()->GetShutDownCallCount());

  SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
            "" /* system_services_password */);

  EXPECT_EQ(++expected_set_auth_details_call_count,
            client_test_interface()->GetSetAuthenticationDetailsCallCount());

  profile_->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, true);
  task_environment_.RunUntilIdle();
  EXPECT_EQ(++expected_set_auth_details_call_count,
            client_test_interface()->GetSetAuthenticationDetailsCallCount());

  profile_->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, false);
  EXPECT_EQ(++expected_shutdown_calls,
            client_test_interface()->GetShutDownCallCount());
}

// Tests that the user preference used by ARC++ to point to the local proxy is
// kept in sync.
TEST_F(SystemProxyManagerTest, ArcWorkerAddressPrefSynced) {
  SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
            "" /* system_services_password */);

  system_proxy::WorkerActiveSignalDetails details;
  details.set_traffic_origin(system_proxy::TrafficOrigin::USER);
  details.set_local_proxy_url(kLocalProxyAddress);
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();
  EXPECT_EQ(kLocalProxyAddress,
            profile_->GetPrefs()->GetString(
                ::prefs::kSystemProxyUserTrafficHostAndPort));

  // The preference shouldn't be updated if the signal is send for system
  // traffic.
  details.set_traffic_origin(system_proxy::TrafficOrigin::SYSTEM);
  details.set_local_proxy_url("other address");
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();
  EXPECT_EQ(kLocalProxyAddress,
            profile_->GetPrefs()->GetString(
                ::prefs::kSystemProxyUserTrafficHostAndPort));

  SetPolicy(false /* system_proxy_enabled */, "" /* system_services_username */,
            "" /* system_services_password */);

  EXPECT_TRUE(profile_->GetPrefs()
                  ->GetString(::prefs::kSystemProxyUserTrafficHostAndPort)
                  .empty());
}

// Verifies that only MGS and Kiosk can use the policy provided credentials.
TEST_F(SystemProxyManagerTest, CanUsePolicyCredentialsUserType) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/kPolicyUsername,
            /*system_services_password=*/kPolicyPassword);
  SetManagedProxy(profile_.get());

  LoginState::Get()->SetLoggedInState(
      LoginState::LOGGED_IN_ACTIVE, LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT);

  EXPECT_TRUE(system_proxy_manager_->CanUsePolicyCredentials(
      GetAuthInfo(), /*first_auth_attempt=*/true));

  LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
                                      LoginState::LOGGED_IN_USER_KIOSK);

  EXPECT_TRUE(system_proxy_manager_->CanUsePolicyCredentials(
      GetAuthInfo(), /*first_auth_attempt=*/true));

  LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
                                      LoginState::LOGGED_IN_USER_REGULAR);

  EXPECT_FALSE(system_proxy_manager_->CanUsePolicyCredentials(
      GetAuthInfo(), /*first_auth_attempt=*/true));
}

// Verifies that the policy provided credentials are only used for proxy auth.
TEST_F(SystemProxyManagerTest, CanUsePolicyCredentialsOriginServer) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/kPolicyUsername,
            /*system_services_password=*/kPolicyPassword);
  SetManagedProxy(profile_.get());

  net::AuthChallengeInfo auth_info = GetAuthInfo();
  auth_info.is_proxy = false;
  LoginState::Get()->SetLoggedInState(
      LoginState::LOGGED_IN_ACTIVE, LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT);

  EXPECT_FALSE(system_proxy_manager_->CanUsePolicyCredentials(
      auth_info, /*first_auth_attempt=*/true));
}

// Verifies that the policy provided credentials are only used for managed
// proxies.
TEST_F(SystemProxyManagerTest, CanUsePolicyCredentialsNoManagedProxy) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/kPolicyUsername,
            /*system_services_password=*/kPolicyPassword);

  LoginState::Get()->SetLoggedInState(
      LoginState::LOGGED_IN_ACTIVE, LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT);

  EXPECT_FALSE(system_proxy_manager_->CanUsePolicyCredentials(
      GetAuthInfo(), /*first_auth_attempt=*/true));
}

// Verifies that `CanUsePolicyCredentials` returns false if no credentials are
// specified by policy.
TEST_F(SystemProxyManagerTest, NoPolicyCredentials) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/"",
            /*system_services_password=*/"");
  SetManagedProxy(profile_.get());

  LoginState::Get()->SetLoggedInState(
      LoginState::LOGGED_IN_ACTIVE, LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT);

  EXPECT_FALSE(system_proxy_manager_->CanUsePolicyCredentials(
      GetAuthInfo(), /*first_auth_attempt=*/true));
}

// Verifies that `CanUsePolicyCredentials` is only returning true for the first
// auth attempt.
TEST_F(SystemProxyManagerTest, CanUsePolicyCredentialsMgsMaxTries) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/kPolicyUsername,
            /*system_services_password=*/kPolicyPassword);
  SetManagedProxy(profile_.get());

  LoginState::Get()->SetLoggedInState(
      LoginState::LOGGED_IN_ACTIVE, LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT);
  EXPECT_TRUE(system_proxy_manager_->CanUsePolicyCredentials(
      GetAuthInfo(), /*first_auth_attempt=*/true));
  EXPECT_FALSE(system_proxy_manager_->CanUsePolicyCredentials(
      GetAuthInfo(), /*first_auth_attempt=*/false));
}

TEST_F(SystemProxyManagerTest, SystemServicesProxyPacStringDefault) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/kPolicyUsername,
            /*system_services_password=*/kPolicyPassword);
  system_proxy::WorkerActiveSignalDetails details;
  details.set_traffic_origin(system_proxy::TrafficOrigin::SYSTEM);
  details.set_local_proxy_url(kProxyAuthUrl);
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_EQ(system_proxy_manager_->SystemServicesProxyPacString(
                chromeos::SystemProxyOverride::kDefault),
            "PROXY http://example.com:3128");
}

TEST_F(SystemProxyManagerTest, SystemServicesProxyPacStringOptOut) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/kPolicyUsername,
            /*system_services_password=*/kPolicyPassword);
  system_proxy::WorkerActiveSignalDetails details;
  details.set_traffic_origin(system_proxy::TrafficOrigin::SYSTEM);
  details.set_local_proxy_url(kProxyAuthUrl);
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_TRUE(
      system_proxy_manager_
          ->SystemServicesProxyPacString(chromeos::SystemProxyOverride::kOptOut)
          .empty());
}

// Tests the behaviour of SystemProxyManager when enabled via the feature flag
// `features::kSystemProxyForSystemServices`.
class FeatureEnabledSystemProxyTest : public SystemProxyManagerTest {
 public:
  FeatureEnabledSystemProxyTest() : SystemProxyManagerTest() {}
  ~FeatureEnabledSystemProxyTest() override = default;

  // testing::Test
  void SetUp() override {
    scoped_feature_list_.InitAndEnableFeature(
        features::kSystemProxyForSystemServices);
    SystemProxyManagerTest::SetUp();
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

// Tests that system services get the address of the local proxy worker for
// system services.
TEST_F(FeatureEnabledSystemProxyTest, SystemServicesDefault) {
  system_proxy::WorkerActiveSignalDetails details;
  details.set_traffic_origin(system_proxy::TrafficOrigin::SYSTEM);
  details.set_local_proxy_url(kLocalProxyAddress);
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_TRUE(system_proxy_manager_
                  ->SystemServicesProxyPacString(
                      chromeos::SystemProxyOverride::kDefault)
                  .empty());
}

TEST_F(FeatureEnabledSystemProxyTest, SystemServicesOptIn) {
  system_proxy::WorkerActiveSignalDetails details;
  details.set_traffic_origin(system_proxy::TrafficOrigin::SYSTEM);
  details.set_local_proxy_url(kLocalProxyAddress);
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_EQ(system_proxy_manager_->SystemServicesProxyPacString(
                chromeos::SystemProxyOverride::kOptIn),
            "PROXY local-proxy.com:3128");
}

// Tests that the pref which sets the local proxy worker address for ARC++ is
// not set when the flag is enabled.
TEST_F(FeatureEnabledSystemProxyTest, Arc) {
  system_proxy::WorkerActiveSignalDetails details;
  details.set_traffic_origin(system_proxy::TrafficOrigin::USER);
  details.set_local_proxy_url(kLocalProxyAddress);
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_TRUE(profile_->GetPrefs()
                  ->GetString(::prefs::kSystemProxyUserTrafficHostAndPort)
                  .empty());
}

// Tests that enabling system-proxy via policy will still work as expected for
// ARC++.
TEST_F(FeatureEnabledSystemProxyTest, ArcPolicyEnabled) {
  SetPolicy(/*system_proxy_enabled=*/true,
            /*system_services_username=*/"",
            /*system_services_password=*/"");

  system_proxy::WorkerActiveSignalDetails details;
  details.set_traffic_origin(system_proxy::TrafficOrigin::USER);
  details.set_local_proxy_url(kLocalProxyAddress);
  client_test_interface()->SendWorkerActiveSignal(details);
  task_environment_.RunUntilIdle();

  EXPECT_EQ(kLocalProxyAddress,
            profile_->GetPrefs()->GetString(
                ::prefs::kSystemProxyUserTrafficHostAndPort));
}

}  // namespace ash