blob: eded456dbdf8a342f7ecc1093b1cddf930d962f9 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/base/network_anonymization_key.h"
#include "base/test/gtest_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/schemeful_site.h"
#include "network_anonymization_key.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
#include "url/url_util.h"
namespace net {
class NetworkAnonymizationKeyTest : public testing::Test {
protected:
const SchemefulSite kTestSiteA = SchemefulSite(GURL("http://a.test/"));
const SchemefulSite kTestSiteB = SchemefulSite(GURL("http://b.test/"));
const SchemefulSite kDataSite = SchemefulSite(GURL("data:foo"));
const base::UnguessableToken kNonce = base::UnguessableToken::Create();
};
class NetworkAnonymizationKeyTestWithNikMode
: public NetworkAnonymizationKeyTest,
public testing::WithParamInterface<NetworkIsolationKey::Mode> {
public:
NetworkAnonymizationKeyTestWithNikMode() {
switch (GetParam()) {
case net::NetworkIsolationKey::Mode::kFrameSiteEnabled:
scoped_feature_list_.InitWithFeatures(
{},
{net::features::kEnableCrossSiteFlagNetworkIsolationKey,
net::features::kEnableFrameSiteSharedOpaqueNetworkIsolationKey});
break;
case net::NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
scoped_feature_list_.InitWithFeatures(
{net::features::kEnableFrameSiteSharedOpaqueNetworkIsolationKey},
{
net::features::kEnableCrossSiteFlagNetworkIsolationKey,
});
break;
case net::NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
scoped_feature_list_.InitWithFeatures(
{net::features::kEnableCrossSiteFlagNetworkIsolationKey},
{net::features::kEnableFrameSiteSharedOpaqueNetworkIsolationKey});
break;
}
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(
Tests,
NetworkAnonymizationKeyTestWithNikMode,
testing::ValuesIn(
{NetworkIsolationKey::Mode::kFrameSiteEnabled,
NetworkIsolationKey::Mode::kCrossSiteFlagEnabled,
NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled}),
[](const testing::TestParamInfo<NetworkIsolationKey::Mode>& info) {
switch (info.param) {
case NetworkIsolationKey::Mode::kFrameSiteEnabled:
return "FrameSiteEnabled";
case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
return "CrossSiteFlagEnabled";
case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
return "FrameSiteSharedOpaqueEnabled";
}
});
TEST_P(NetworkAnonymizationKeyTestWithNikMode, CreateFromNetworkIsolationKey) {
SchemefulSite site_a = SchemefulSite(GURL("http://a.test/"));
SchemefulSite site_b = SchemefulSite(GURL("http://b.test/"));
SchemefulSite opaque = SchemefulSite(url::Origin());
base::UnguessableToken nik_nonce = base::UnguessableToken::Create();
NetworkIsolationKey populated_cross_site_nik(site_a, site_b, nik_nonce);
NetworkIsolationKey populated_same_site_nik(site_a, site_a, nik_nonce);
NetworkIsolationKey populated_same_site_opaque_nik(opaque, opaque, nik_nonce);
NetworkIsolationKey empty_nik;
NetworkAnonymizationKey nak_from_same_site_nik =
NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
populated_same_site_nik);
NetworkAnonymizationKey nak_from_cross_site_nik =
NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
populated_cross_site_nik);
NetworkAnonymizationKey nak_from_same_site_opaque_nik =
NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
populated_same_site_opaque_nik);
NetworkAnonymizationKey nak_from_empty_nik =
NetworkAnonymizationKey::CreateFromNetworkIsolationKey(empty_nik);
// NAKs created when there is no top frame site on the NIK should create an
// empty NAK.
EXPECT_TRUE(nak_from_empty_nik.IsEmpty());
// Top site should be populated correctly.
EXPECT_EQ(nak_from_same_site_nik.GetTopFrameSite(), site_a);
EXPECT_EQ(nak_from_cross_site_nik.GetTopFrameSite(), site_a);
EXPECT_EQ(nak_from_same_site_opaque_nik.GetTopFrameSite(), opaque);
// Nonce should be populated correctly.
EXPECT_EQ(nak_from_same_site_nik.GetNonce(), nik_nonce);
EXPECT_EQ(nak_from_cross_site_nik.GetNonce(), nik_nonce);
EXPECT_EQ(nak_from_same_site_opaque_nik.GetNonce(), nik_nonce);
// Is cross site boolean should be populated correctly.
EXPECT_TRUE(nak_from_same_site_nik.IsSameSite());
EXPECT_TRUE(nak_from_cross_site_nik.IsCrossSite());
EXPECT_TRUE(nak_from_same_site_opaque_nik.IsSameSite());
// Double-keyed + cross site bit NAKs created from different third party
// cross site contexts should be the different.
EXPECT_FALSE(nak_from_same_site_nik == nak_from_cross_site_nik);
}
TEST_F(NetworkAnonymizationKeyTest, CreateSameSite) {
SchemefulSite site = SchemefulSite(GURL("http://a.test/"));
SchemefulSite opaque = SchemefulSite(url::Origin());
NetworkAnonymizationKey key;
key = NetworkAnonymizationKey::CreateSameSite(site);
EXPECT_EQ(key.GetTopFrameSite(), site);
EXPECT_FALSE(key.GetNonce().has_value());
EXPECT_TRUE(key.IsSameSite());
key = NetworkAnonymizationKey::CreateSameSite(opaque);
EXPECT_EQ(key.GetTopFrameSite(), opaque);
EXPECT_FALSE(key.GetNonce().has_value());
EXPECT_TRUE(key.IsSameSite());
}
TEST_F(NetworkAnonymizationKeyTest, CreateCrossSite) {
SchemefulSite site = SchemefulSite(GURL("http://a.test/"));
SchemefulSite opaque = SchemefulSite(url::Origin());
NetworkAnonymizationKey key;
key = NetworkAnonymizationKey::CreateCrossSite(site);
EXPECT_EQ(key.GetTopFrameSite(), site);
EXPECT_FALSE(key.GetNonce().has_value());
EXPECT_TRUE(key.IsCrossSite());
key = NetworkAnonymizationKey::CreateCrossSite(opaque);
EXPECT_EQ(key.GetTopFrameSite(), opaque);
EXPECT_FALSE(key.GetNonce().has_value());
EXPECT_TRUE(key.IsCrossSite());
}
TEST_F(NetworkAnonymizationKeyTest, CreateFromFrameSite) {
SchemefulSite site_a = SchemefulSite(GURL("http://a.test/"));
SchemefulSite site_b = SchemefulSite(GURL("http://b.test/"));
SchemefulSite opaque = SchemefulSite(url::Origin());
base::UnguessableToken nonce = base::UnguessableToken::Create();
NetworkAnonymizationKey nak_from_same_site =
NetworkAnonymizationKey::CreateFromFrameSite(site_a, site_a, nonce);
NetworkAnonymizationKey nak_from_cross_site =
NetworkAnonymizationKey::CreateFromFrameSite(site_a, site_b, nonce);
NetworkAnonymizationKey nak_from_same_site_opaque =
NetworkAnonymizationKey::CreateFromFrameSite(opaque, opaque, nonce);
// Top site should be populated correctly.
EXPECT_EQ(nak_from_same_site.GetTopFrameSite(), site_a);
EXPECT_EQ(nak_from_cross_site.GetTopFrameSite(), site_a);
EXPECT_EQ(nak_from_same_site_opaque.GetTopFrameSite(), opaque);
// Nonce should be populated correctly.
EXPECT_EQ(nak_from_same_site.GetNonce(), nonce);
EXPECT_EQ(nak_from_cross_site.GetNonce(), nonce);
EXPECT_EQ(nak_from_same_site_opaque.GetNonce(), nonce);
// Is cross site boolean should be populated correctly.
EXPECT_TRUE(nak_from_same_site.IsSameSite());
EXPECT_TRUE(nak_from_cross_site.IsCrossSite());
EXPECT_TRUE(nak_from_same_site_opaque.IsSameSite());
// Double-keyed + cross site bit NAKs created from different third party
// cross site contexts should be the different.
EXPECT_FALSE(nak_from_same_site == nak_from_cross_site);
}
TEST_F(NetworkAnonymizationKeyTest, IsEmpty) {
NetworkAnonymizationKey empty_key;
NetworkAnonymizationKey populated_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
EXPECT_TRUE(empty_key.IsEmpty());
EXPECT_FALSE(populated_key.IsEmpty());
}
TEST_F(NetworkAnonymizationKeyTest, CreateTransient) {
NetworkAnonymizationKey transient_key1 =
NetworkAnonymizationKey::CreateTransient();
NetworkAnonymizationKey transient_key2 =
NetworkAnonymizationKey::CreateTransient();
EXPECT_TRUE(transient_key1.IsTransient());
EXPECT_TRUE(transient_key2.IsTransient());
EXPECT_FALSE(transient_key1 == transient_key2);
}
TEST_F(NetworkAnonymizationKeyTest, IsTransient) {
NetworkAnonymizationKey empty_key;
NetworkAnonymizationKey populated_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
NetworkAnonymizationKey data_top_frame_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kDataSite,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
NetworkAnonymizationKey populated_key_with_nonce =
NetworkAnonymizationKey::CreateFromParts(
/*top_frame_site=*/kTestSiteA,
/*is_cross_site*/ false, base::UnguessableToken::Create());
NetworkAnonymizationKey data_frame_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
NetworkAnonymizationKey from_create_transient =
NetworkAnonymizationKey::CreateTransient();
EXPECT_TRUE(empty_key.IsTransient());
EXPECT_FALSE(populated_key.IsTransient());
EXPECT_TRUE(data_top_frame_key.IsTransient());
EXPECT_TRUE(populated_key_with_nonce.IsTransient());
EXPECT_TRUE(from_create_transient.IsTransient());
NetworkAnonymizationKey populated_double_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
EXPECT_FALSE(data_frame_key.IsTransient());
EXPECT_FALSE(populated_double_key.IsTransient());
}
TEST_F(NetworkAnonymizationKeyTest, IsFullyPopulated) {
NetworkAnonymizationKey empty_key;
NetworkAnonymizationKey populated_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
EXPECT_TRUE(populated_key.IsFullyPopulated());
EXPECT_FALSE(empty_key.IsFullyPopulated());
NetworkAnonymizationKey empty_frame_site_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
EXPECT_TRUE(empty_frame_site_key.IsFullyPopulated());
}
TEST_F(NetworkAnonymizationKeyTest, Getters) {
NetworkAnonymizationKey key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/true, kNonce);
EXPECT_EQ(key.GetTopFrameSite(), kTestSiteA);
EXPECT_EQ(key.GetNonce(), kNonce);
EXPECT_TRUE(key.IsCrossSite());
}
TEST_F(NetworkAnonymizationKeyTest, ToDebugString) {
NetworkAnonymizationKey key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/true, kNonce);
NetworkAnonymizationKey empty_key;
// `is_cross_site` holds the value the key is created with.
std::string double_key_with_cross_site_flag_expected_string_value =
kTestSiteA.GetDebugString() + " cross_site (with nonce " +
kNonce.ToString() + ")";
EXPECT_EQ(key.ToDebugString(),
double_key_with_cross_site_flag_expected_string_value);
EXPECT_EQ(empty_key.ToDebugString(), "null");
}
TEST_F(NetworkAnonymizationKeyTest, Equality) {
NetworkAnonymizationKey key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false, kNonce);
NetworkAnonymizationKey key_duplicate =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false, kNonce);
EXPECT_TRUE(key == key_duplicate);
EXPECT_FALSE(key != key_duplicate);
EXPECT_FALSE(key < key_duplicate);
NetworkAnonymizationKey key_cross_site =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/true, kNonce);
// The `is_cross_site` flag changes the NAK.
EXPECT_FALSE(key == key_cross_site);
EXPECT_TRUE(key != key_cross_site);
EXPECT_TRUE(key < key_cross_site);
NetworkAnonymizationKey key_no_nonce =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/absl::nullopt);
EXPECT_FALSE(key == key_no_nonce);
EXPECT_TRUE(key != key_no_nonce);
EXPECT_FALSE(key < key_no_nonce);
NetworkAnonymizationKey key_different_nonce =
NetworkAnonymizationKey::CreateFromParts(
/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false,
/*nonce=*/base::UnguessableToken::Create());
EXPECT_FALSE(key == key_different_nonce);
EXPECT_TRUE(key != key_different_nonce);
NetworkAnonymizationKey key_different_frame_site =
NetworkAnonymizationKey::CreateFromParts(
/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false, kNonce);
EXPECT_TRUE(key == key_different_frame_site);
EXPECT_FALSE(key != key_different_frame_site);
EXPECT_FALSE(key < key_different_frame_site);
NetworkAnonymizationKey key_different_top_level_site =
NetworkAnonymizationKey::CreateFromParts(
/*top_frame_site=*/kTestSiteB,
/*is_cross_site=*/false, kNonce);
EXPECT_FALSE(key == key_different_top_level_site);
EXPECT_TRUE(key != key_different_top_level_site);
EXPECT_TRUE(key < key_different_top_level_site);
NetworkAnonymizationKey empty_key;
NetworkAnonymizationKey empty_key_duplicate;
EXPECT_TRUE(empty_key == empty_key_duplicate);
EXPECT_FALSE(empty_key != empty_key_duplicate);
EXPECT_FALSE(empty_key < empty_key_duplicate);
EXPECT_FALSE(empty_key == key);
EXPECT_TRUE(empty_key != key);
EXPECT_TRUE(empty_key < key);
}
TEST_F(NetworkAnonymizationKeyTest, ValueRoundTripCrossSite) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/true);
base::Value value;
ASSERT_TRUE(original_key.ToValue(&value));
// Fill initial value with opaque data, to make sure it's overwritten.
NetworkAnonymizationKey from_value_key = NetworkAnonymizationKey();
EXPECT_TRUE(NetworkAnonymizationKey::FromValue(value, &from_value_key));
EXPECT_EQ(original_key, from_value_key);
}
TEST_F(NetworkAnonymizationKeyTest, ValueRoundTripSameSite) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key =
NetworkAnonymizationKey::CreateFromParts(/*top_frame_site=*/kTestSiteA,
/*is_cross_site=*/false);
base::Value value;
ASSERT_TRUE(original_key.ToValue(&value));
// Fill initial value with opaque data, to make sure it's overwritten.
NetworkAnonymizationKey from_value_key = NetworkAnonymizationKey();
EXPECT_TRUE(NetworkAnonymizationKey::FromValue(value, &from_value_key));
EXPECT_EQ(original_key, from_value_key);
}
TEST_F(NetworkAnonymizationKeyTest, TransientValueRoundTrip) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key =
NetworkAnonymizationKey::CreateTransient();
base::Value value;
ASSERT_FALSE(original_key.ToValue(&value));
}
TEST_F(NetworkAnonymizationKeyTest, EmptyValueRoundTrip) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key;
base::Value value;
ASSERT_TRUE(original_key.ToValue(&value));
// Fill initial value with opaque data, to make sure it's overwritten.
NetworkAnonymizationKey from_value_key = NetworkAnonymizationKey();
EXPECT_TRUE(NetworkAnonymizationKey::FromValue(value, &from_value_key));
EXPECT_EQ(original_key, from_value_key);
}
TEST(NetworkAnonymizationKeyFeatureShiftTest,
ValueRoundTripKeySchemeMissmatch) {
base::test::ScopedFeatureList scoped_feature_list_;
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
const SchemefulSite kTestSiteA = SchemefulSite(GURL("http://a.test/"));
const SchemefulSite kTestSiteB = SchemefulSite(GURL("http://b.test/"));
NetworkAnonymizationKey expected_failure_nak = NetworkAnonymizationKey();
// Create a cross site double key + cross site flag NetworkAnonymizationKey.
NetworkAnonymizationKey original_cross_site_double_key =
NetworkAnonymizationKey::CreateFromParts(kTestSiteA, false);
base::Value cross_site_double_key_value;
ASSERT_TRUE(
original_cross_site_double_key.ToValue(&cross_site_double_key_value));
// Check that deserializing a double keyed NetworkAnonymizationKey (a
// one-element list) fails, using the serialized site from
// `cross_site_double_key_value` to build it.
base::Value serialized_site =
cross_site_double_key_value.GetList()[0].Clone();
base::Value::List double_key_list;
double_key_list.Append(serialized_site.Clone());
base::Value double_key_value = base::Value(std::move(double_key_list));
EXPECT_FALSE(NetworkAnonymizationKey::FromValue(double_key_value,
&expected_failure_nak));
// Check that deserializing a triple keyed value (a 2-element list
// containing two sites) fails.
base::Value::List triple_key_list;
triple_key_list.Append(serialized_site.Clone());
triple_key_list.Append(std::move(serialized_site));
base::Value triple_key_value = base::Value(std::move(triple_key_list));
EXPECT_FALSE(NetworkAnonymizationKey::FromValue(triple_key_value,
&expected_failure_nak));
// Convert the successful value back to a NAK and verify.
NetworkAnonymizationKey from_value_cross_site_double_key =
NetworkAnonymizationKey();
EXPECT_TRUE(NetworkAnonymizationKey::FromValue(
cross_site_double_key_value, &from_value_cross_site_double_key));
EXPECT_EQ(original_cross_site_double_key, from_value_cross_site_double_key);
}
} // namespace net