blob: 8d78516c332f9152ed61414b4bb670623a74d73b [file] [log] [blame]
// Copyright 2018 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/net/system_network_context_manager.h"
#include <memory>
#include <string>
#include <vector>
#include "base/deferred_sequenced_task_runner.h"
#include "base/feature_list.h"
#include "base/optional.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/net/dns_util.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/policy/core/browser/browser_policy_connector.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/prefs/pref_service.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/system_connector.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/network_service_util.h"
#include "content/public/common/service_names.mojom.h"
#include "content/public/common/user_agent.h"
#include "net/socket/client_socket_pool_manager.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
namespace {
void GetStubResolverConfig(
bool* insecure_stub_resolver_enabled,
net::DnsConfig::SecureDnsMode* secure_dns_mode,
base::Optional<std::vector<network::mojom::DnsOverHttpsServerPtr>>*
dns_over_https_servers) {
dns_over_https_servers->reset();
SystemNetworkContextManager::GetStubResolverConfigForTesting(
insecure_stub_resolver_enabled, secure_dns_mode, dns_over_https_servers);
}
// Checks that the values returned by GetStubResolverConfigForTesting() match
// |async_dns_feature_enabled| (With empty DNS over HTTPS prefs). Then sets
// various DoH modes and DoH template strings and makes sure the settings are
// respected.
void RunStubResolverConfigTests(bool async_dns_feature_enabled) {
// Check initial state.
bool insecure_stub_resolver_enabled = !async_dns_feature_enabled;
net::DnsConfig::SecureDnsMode secure_dns_mode;
base::Optional<std::vector<network::mojom::DnsOverHttpsServerPtr>>
dns_over_https_servers;
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
EXPECT_FALSE(dns_over_https_servers.has_value());
std::string good_post_template = "https://foo.test/";
std::string good_get_template = "https://bar.test/dns-query{?dns}";
std::string bad_template = "dns-query{?dns}";
std::string good_then_bad_template = good_get_template + " " + bad_template;
std::string bad_then_good_template = bad_template + " " + good_get_template;
std::string multiple_good_templates =
" " + good_get_template + " " + good_post_template + " ";
PrefService* local_state = g_browser_process->local_state();
local_state->SetString(prefs::kDnsOverHttpsMode, kDnsOverHttpsModeSecure);
local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_template);
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::SECURE, secure_dns_mode);
EXPECT_FALSE(dns_over_https_servers.has_value());
local_state->SetString(prefs::kDnsOverHttpsTemplates, good_post_template);
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::SECURE, secure_dns_mode);
ASSERT_TRUE(dns_over_https_servers.has_value());
ASSERT_EQ(1u, dns_over_https_servers->size());
EXPECT_EQ(good_post_template, dns_over_https_servers->at(0)->server_template);
EXPECT_EQ(true, dns_over_https_servers->at(0)->use_post);
local_state->SetString(prefs::kDnsOverHttpsMode, kDnsOverHttpsModeAutomatic);
local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_template);
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
EXPECT_FALSE(dns_over_https_servers.has_value());
local_state->SetString(prefs::kDnsOverHttpsTemplates, good_then_bad_template);
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
ASSERT_TRUE(dns_over_https_servers.has_value());
ASSERT_EQ(1u, dns_over_https_servers->size());
EXPECT_EQ(good_get_template, dns_over_https_servers->at(0)->server_template);
EXPECT_FALSE(dns_over_https_servers->at(0)->use_post);
local_state->SetString(prefs::kDnsOverHttpsTemplates, bad_then_good_template);
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
ASSERT_TRUE(dns_over_https_servers.has_value());
ASSERT_EQ(1u, dns_over_https_servers->size());
EXPECT_EQ(good_get_template, dns_over_https_servers->at(0)->server_template);
EXPECT_FALSE(dns_over_https_servers->at(0)->use_post);
local_state->SetString(prefs::kDnsOverHttpsTemplates,
multiple_good_templates);
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::AUTOMATIC, secure_dns_mode);
ASSERT_TRUE(dns_over_https_servers.has_value());
ASSERT_EQ(2u, dns_over_https_servers->size());
EXPECT_EQ(good_get_template, dns_over_https_servers->at(0)->server_template);
EXPECT_FALSE(dns_over_https_servers->at(0)->use_post);
EXPECT_EQ(good_post_template, dns_over_https_servers->at(1)->server_template);
EXPECT_TRUE(dns_over_https_servers->at(1)->use_post);
local_state->SetString(prefs::kDnsOverHttpsMode, kDnsOverHttpsModeOff);
local_state->SetString(prefs::kDnsOverHttpsTemplates, good_get_template);
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
EXPECT_FALSE(dns_over_https_servers.has_value());
local_state->SetString(prefs::kDnsOverHttpsMode, "no_match");
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
EXPECT_FALSE(dns_over_https_servers.has_value());
// Test case with policy BuiltInDnsClientEnabled enabled. The DoH fields
// should be unaffected.
local_state->Set(prefs::kBuiltInDnsClientEnabled,
base::Value(!async_dns_feature_enabled));
GetStubResolverConfig(&insecure_stub_resolver_enabled, &secure_dns_mode,
&dns_over_https_servers);
EXPECT_EQ(!async_dns_feature_enabled, insecure_stub_resolver_enabled);
EXPECT_EQ(net::DnsConfig::SecureDnsMode::OFF, secure_dns_mode);
EXPECT_FALSE(dns_over_https_servers.has_value());
}
} // namespace
using SystemNetworkContextManagerBrowsertest = InProcessBrowserTest;
IN_PROC_BROWSER_TEST_F(SystemNetworkContextManagerBrowsertest,
StubResolverDefaultConfig) {
RunStubResolverConfigTests(base::FeatureList::IsEnabled(features::kAsyncDns));
}
IN_PROC_BROWSER_TEST_F(SystemNetworkContextManagerBrowsertest,
StaticAuthParams) {
// Test defaults.
network::mojom::HttpAuthStaticParamsPtr static_params =
SystemNetworkContextManager::GetHttpAuthStaticParamsForTesting();
EXPECT_THAT(static_params->supported_schemes,
testing::ElementsAre("basic", "digest", "ntlm", "negotiate"));
EXPECT_EQ("", static_params->gssapi_library_name);
// Test that prefs are reflected in params.
PrefService* local_state = g_browser_process->local_state();
local_state->SetString(prefs::kAuthSchemes, "basic");
static_params =
SystemNetworkContextManager::GetHttpAuthStaticParamsForTesting();
EXPECT_THAT(static_params->supported_schemes, testing::ElementsAre("basic"));
#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
const char dev_null[] = "/dev/null";
local_state->SetString(prefs::kGSSAPILibraryName, dev_null);
static_params =
SystemNetworkContextManager::GetHttpAuthStaticParamsForTesting();
EXPECT_EQ(dev_null, static_params->gssapi_library_name);
#endif
}
IN_PROC_BROWSER_TEST_F(SystemNetworkContextManagerBrowsertest, AuthParams) {
// Test defaults.
network::mojom::HttpAuthDynamicParamsPtr dynamic_params =
SystemNetworkContextManager::GetHttpAuthDynamicParamsForTesting();
EXPECT_EQ(false, dynamic_params->negotiate_disable_cname_lookup);
EXPECT_EQ(false, dynamic_params->enable_negotiate_port);
EXPECT_EQ("", dynamic_params->server_allowlist);
EXPECT_EQ("", dynamic_params->delegate_allowlist);
EXPECT_FALSE(dynamic_params->delegate_by_kdc_policy);
PrefService* local_state = g_browser_process->local_state();
local_state->SetBoolean(prefs::kDisableAuthNegotiateCnameLookup, true);
dynamic_params =
SystemNetworkContextManager::GetHttpAuthDynamicParamsForTesting();
EXPECT_EQ(true, dynamic_params->negotiate_disable_cname_lookup);
EXPECT_EQ(false, dynamic_params->enable_negotiate_port);
EXPECT_EQ("", dynamic_params->server_allowlist);
EXPECT_EQ("", dynamic_params->delegate_allowlist);
EXPECT_FALSE(dynamic_params->delegate_by_kdc_policy);
local_state->SetBoolean(prefs::kEnableAuthNegotiatePort, true);
dynamic_params =
SystemNetworkContextManager::GetHttpAuthDynamicParamsForTesting();
EXPECT_EQ(true, dynamic_params->negotiate_disable_cname_lookup);
EXPECT_EQ(true, dynamic_params->enable_negotiate_port);
EXPECT_EQ("", dynamic_params->server_allowlist);
EXPECT_EQ("", dynamic_params->delegate_allowlist);
EXPECT_FALSE(dynamic_params->delegate_by_kdc_policy);
const char kServerAllowList[] = "foo";
local_state->SetString(prefs::kAuthServerWhitelist, kServerAllowList);
dynamic_params =
SystemNetworkContextManager::GetHttpAuthDynamicParamsForTesting();
EXPECT_EQ(true, dynamic_params->negotiate_disable_cname_lookup);
EXPECT_EQ(true, dynamic_params->enable_negotiate_port);
EXPECT_EQ(kServerAllowList, dynamic_params->server_allowlist);
EXPECT_EQ("", dynamic_params->delegate_allowlist);
const char kDelegateAllowList[] = "bar, baz";
local_state->SetString(prefs::kAuthNegotiateDelegateWhitelist,
kDelegateAllowList);
dynamic_params =
SystemNetworkContextManager::GetHttpAuthDynamicParamsForTesting();
EXPECT_EQ(true, dynamic_params->negotiate_disable_cname_lookup);
EXPECT_EQ(true, dynamic_params->enable_negotiate_port);
EXPECT_EQ(kServerAllowList, dynamic_params->server_allowlist);
EXPECT_EQ(kDelegateAllowList, dynamic_params->delegate_allowlist);
EXPECT_FALSE(dynamic_params->delegate_by_kdc_policy);
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
local_state->SetBoolean(prefs::kAuthNegotiateDelegateByKdcPolicy, true);
dynamic_params =
SystemNetworkContextManager::GetHttpAuthDynamicParamsForTesting();
EXPECT_EQ(true, dynamic_params->negotiate_disable_cname_lookup);
EXPECT_EQ(true, dynamic_params->enable_negotiate_port);
EXPECT_EQ(kServerAllowList, dynamic_params->server_allowlist);
EXPECT_EQ(kDelegateAllowList, dynamic_params->delegate_allowlist);
EXPECT_TRUE(dynamic_params->delegate_by_kdc_policy);
#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
#if defined(OS_CHROMEOS)
// The kerberos.enabled pref is false and the device is not Active Directory
// managed by default.
EXPECT_EQ(false, dynamic_params->allow_gssapi_library_load);
local_state->SetBoolean(prefs::kKerberosEnabled, true);
dynamic_params =
SystemNetworkContextManager::GetHttpAuthDynamicParamsForTesting();
EXPECT_EQ(true, dynamic_params->allow_gssapi_library_load);
#endif // defined(OS_CHROMEOS)
}
IN_PROC_BROWSER_TEST_F(SystemNetworkContextManagerBrowsertest,
DefaultMaxConnectionsPerProxy) {
int max_connections = 0;
if (content::IsInProcessNetworkService()) {
base::RunLoop run_loop;
content::GetNetworkTaskRunner()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&run_loop, &max_connections] {
max_connections =
net::ClientSocketPoolManager::max_sockets_per_proxy_server(
net::HttpNetworkSession::NORMAL_SOCKET_POOL);
run_loop.Quit();
}));
run_loop.Run();
} else {
network::mojom::NetworkServiceTestPtr network_service_test;
content::GetSystemConnector()->BindInterface(
content::mojom::kNetworkServiceName, &network_service_test);
mojo::ScopedAllowSyncCallForTesting allow_sync_call;
bool available =
network_service_test->GetMaxConnectionsPerProxy(&max_connections);
EXPECT_TRUE(available);
}
EXPECT_EQ(net::DefaultMaxValues::kDefaultMaxSocketsPerProxyServer,
max_connections);
}
class SystemNetworkContextManagerMaxConnectionsPerProxyBrowsertest
: public SystemNetworkContextManagerBrowsertest {
public:
const int kTestMaxConnectionsPerProxy = 42;
SystemNetworkContextManagerMaxConnectionsPerProxyBrowsertest() = default;
~SystemNetworkContextManagerMaxConnectionsPerProxyBrowsertest() override =
default;
void SetUpInProcessBrowserTestFixture() override {
EXPECT_CALL(provider_, IsInitializationComplete(testing::_))
.WillRepeatedly(testing::Return(true));
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
policy::PolicyMap policies;
policies.Set(policy::key::kMaxConnectionsPerProxy,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(kTestMaxConnectionsPerProxy),
/*external_data_fetcher=*/nullptr);
provider_.UpdateChromePolicy(policies);
}
private:
policy::MockConfigurationPolicyProvider provider_;
};
// Flaky on Linux Tests. https://crbug.com/993059
IN_PROC_BROWSER_TEST_F(
SystemNetworkContextManagerMaxConnectionsPerProxyBrowsertest,
DISABLED_MaxConnectionsPerProxy) {
network::mojom::NetworkServiceTestPtr network_service_test;
content::GetSystemConnector()->BindInterface(
content::mojom::kNetworkServiceName, &network_service_test);
mojo::ScopedAllowSyncCallForTesting allow_sync_call;
int max_connections = 0;
bool available =
network_service_test->GetMaxConnectionsPerProxy(&max_connections);
EXPECT_TRUE(available);
EXPECT_EQ(kTestMaxConnectionsPerProxy, max_connections);
}
class SystemNetworkContextManagerStubResolverBrowsertest
: public SystemNetworkContextManagerBrowsertest,
public testing::WithParamInterface<bool> {
public:
SystemNetworkContextManagerStubResolverBrowsertest() {
scoped_feature_list_.InitWithFeatureState(features::kAsyncDns, GetParam());
}
~SystemNetworkContextManagerStubResolverBrowsertest() override {}
void SetUpOnMainThread() override {}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(SystemNetworkContextManagerStubResolverBrowsertest,
StubResolverConfig) {
RunStubResolverConfigTests(GetParam());
}
INSTANTIATE_TEST_SUITE_P(,
SystemNetworkContextManagerStubResolverBrowsertest,
::testing::Values(false, true));
class SystemNetworkContextManagerFreezeQUICUaBrowsertest
: public SystemNetworkContextManagerBrowsertest,
public testing::WithParamInterface<bool> {
public:
SystemNetworkContextManagerFreezeQUICUaBrowsertest() {
scoped_feature_list_.InitWithFeatureState(blink::features::kFreezeUserAgent,
GetParam());
}
~SystemNetworkContextManagerFreezeQUICUaBrowsertest() override {}
void SetUpOnMainThread() override {}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
bool ContainsSubstring(std::string super, std::string sub) {
return super.find(sub) != std::string::npos;
}
IN_PROC_BROWSER_TEST_P(SystemNetworkContextManagerFreezeQUICUaBrowsertest,
QUICUaConfig) {
network::mojom::NetworkContextParamsPtr network_context_params =
g_browser_process->system_network_context_manager()
->CreateDefaultNetworkContextParams();
std::string quic_ua = network_context_params->quic_user_agent_id;
if (GetParam()) { // if the UA Freeze feature is turned on
EXPECT_EQ("", quic_ua);
} else {
EXPECT_TRUE(ContainsSubstring(quic_ua, chrome::GetChannelName()));
EXPECT_TRUE(ContainsSubstring(
quic_ua, version_info::GetProductNameAndVersionForUserAgent()));
EXPECT_TRUE(ContainsSubstring(quic_ua, content::BuildOSCpuInfo(false)));
}
}
INSTANTIATE_TEST_SUITE_P(,
SystemNetworkContextManagerFreezeQUICUaBrowsertest,
::testing::Values(true, false));