0

Remove support for double-keyed NAKs

* Remove `NAK::IsCrossSiteFlagSchemeEnabled` (always true).
 * Remove `NAK::IsDoubleKeySchemeEnabled` (always false).
 * Remove leftover declaration of `NAK::IsFrameSiteEnabled`.
 * Remove all test cases for double-keyed NAKs.
 * Remove the kEnableCrossSiteFlagNetworkAnonymizationKey feature.

Bug: 1407287
Change-Id: I0c47f419fc0b07cc15af2462dfa7bc2861c05070
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4244523
Auto-Submit: Dustin Mitchell <djmitche@chromium.org>
Commit-Queue: Dustin Mitchell <djmitche@chromium.org>
Reviewed-by: Brianna Goldstein <brgoldstein@google.com>
Reviewed-by: Alex Ilin <alexilin@chromium.org>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1111226}
This commit is contained in:
Dustin J. Mitchell
2023-02-28 22:50:40 +00:00
committed by Chromium LUCI CQ
parent 3bf767a8ec
commit c9d5d88cfe
19 changed files with 189 additions and 687 deletions

@ -1307,9 +1307,8 @@ IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest,
EXPECT_EQ(2u, connection_tracker()->GetAcceptedSocketCount());
EXPECT_EQ(2u, connection_tracker()->GetReadSocketCount());
} else {
// Otherwise, the preconnected socket is used, so counts remain unchanged
// since the last check.
EXPECT_EQ(2u, connection_tracker()->GetAcceptedSocketCount());
// Otherwise, the preconnected socket cannot be used.
EXPECT_EQ(3u, connection_tracker()->GetAcceptedSocketCount());
EXPECT_EQ(2u, connection_tracker()->GetReadSocketCount());
}

@ -189,8 +189,6 @@ class DomainReliabilityUploaderTest : public testing::Test {
uploader_(
DomainReliabilityUploader::Create(&time_,
url_request_context_.get())) {
scoped_feature_list_.InitAndEnableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
expected_isolation_info_ = net::IsolationInfo::CreateTransient();
auto interceptor =
@ -216,7 +214,6 @@ class DomainReliabilityUploaderTest : public testing::Test {
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::IO};

@ -113,10 +113,6 @@ BASE_FEATURE(kPartitionNelAndReportingByNetworkIsolationKey,
"PartitionNelAndReportingByNetworkIsolationKey",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kEnableCrossSiteFlagNetworkAnonymizationKey,
"EnableCrossSiteFlagNetworkAnonymizationKey",
base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kTLS13KeyUpdate,
"TLS13KeyUpdate",
base::FEATURE_DISABLED_BY_DEFAULT);

@ -148,15 +148,6 @@ NET_EXPORT BASE_DECLARE_FEATURE(kPartitionSSLSessionsByNetworkIsolationKey);
// testing.
NET_EXPORT BASE_DECLARE_FEATURE(kPartitionNelAndReportingByNetworkIsolationKey);
// Creates a <double key + is_cross_site> NetworkAnonymizationKey which is used
// to partition the network state. This double key will have the following
// properties: `top_frame_site` -> the schemeful site of the top level page.
// `frame_site ` -> nullopt
// `is_cross_site` -> true if the `top_frame_site` is cross site when compared
// to the frame site. The frame site will not be stored in this key so the value
// of is_cross_site will be computed at key construction.
NET_EXPORT BASE_DECLARE_FEATURE(kEnableCrossSiteFlagNetworkAnonymizationKey);
// Enables sending TLS 1.3 Key Update messages on TLS 1.3 connections in order
// to ensure that this corner of the spec is exercised. This is currently
// disabled by default because we discovered incompatibilities with some

@ -176,8 +176,7 @@ IsolationInfo IsolationInfo::DoNotUseCreatePartialFromNak(
network_anonymization_key.GetTopFrameSite()->site_as_origin_;
absl::optional<url::Origin> frame_origin;
if (NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled() &&
network_anonymization_key.GetIsCrossSite().value()) {
if (network_anonymization_key.GetIsCrossSite().value()) {
// If we know that the origin is cross site to the top level site, create an
// empty origin to use as the frame origin for the isolation info. This
// should be cross site with the top level origin.

@ -7,7 +7,6 @@
#include <iostream>
#include "base/strings/strcat.h"
#include "base/test/gtest_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/unguessable_token.h"
#include "isolation_info.h"
#include "net/base/features.h"
@ -23,47 +22,10 @@
namespace net {
// `IsolationInfoEnabledFeatureFlagsTestingParam ` allows enabling and disabling
// the feature flags that control the key schemes for NetworkAnonymizationKey.
// This allows us to test the possible combinations of flags that will be
// allowed for experimentation.
//
// Presently, only one flag is used, but future experiments will add more.
struct IsolationInfoEnabledFeatureFlagsTestingParam {
const bool enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey;
};
const IsolationInfoEnabledFeatureFlagsTestingParam kFlagsParam[] = {
// 0. Double-keying is enabled for NetworkAnonymizationKey.
{/*enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey=*/false},
// 1. Double-keying + cross-site-bit is enabled for NetworkAnonymizationKey.
{/*enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey=*/true}};
namespace {
class IsolationInfoTest : public testing::Test,
public testing::WithParamInterface<
IsolationInfoEnabledFeatureFlagsTestingParam> {
class IsolationInfoTest : public testing::Test {
public:
IsolationInfoTest() {
std::vector<base::test::FeatureRef> enabled_features = {};
std::vector<base::test::FeatureRef> disabled_features = {};
if (IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) {
enabled_features.push_back(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
} else {
disabled_features.push_back(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
}
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
static bool IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled() {
return GetParam().enableDoubleKeyAndCrossSiteBitNetworkAnonymizationKey;
}
const url::Origin kOrigin1 = url::Origin::Create(GURL("https://a.foo.test"));
const url::Origin kSite1 = url::Origin::Create(GURL("https://foo.test"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("https://b.bar.test"));
@ -87,16 +49,8 @@ class IsolationInfoTest : public testing::Test,
const base::UnguessableToken kNonce1 = base::UnguessableToken::Create();
const base::UnguessableToken kNonce2 = base::UnguessableToken::Create();
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(All,
IsolationInfoTest,
/*IsolationInfoEnabledFeatureFlagsTestingParam */
testing::ValuesIn(kFlagsParam));
void DuplicateAndCompare(const IsolationInfo& isolation_info) {
absl::optional<IsolationInfo> duplicate_isolation_info =
IsolationInfo::CreateIfConsistent(
@ -112,11 +66,11 @@ void DuplicateAndCompare(const IsolationInfo& isolation_info) {
EXPECT_TRUE(isolation_info.IsEqualForTesting(*duplicate_isolation_info));
}
TEST_P(IsolationInfoTest, IsFrameSiteEnabled) {
TEST_F(IsolationInfoTest, IsFrameSiteEnabled) {
EXPECT_TRUE(IsolationInfo::IsFrameSiteEnabled());
}
TEST_P(IsolationInfoTest, DebugString) {
TEST_F(IsolationInfoTest, DebugString) {
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin2,
SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty, &kNonce1);
@ -138,7 +92,7 @@ TEST_P(IsolationInfoTest, DebugString) {
EXPECT_EQ(isolation_info.DebugString(), base::StrCat(parts));
}
TEST_P(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfo) {
TEST_F(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfo) {
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin2,
SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty, &kNonce1);
@ -162,24 +116,18 @@ TEST_P(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfo) {
kNonce1);
EXPECT_EQ(isolation_info.nonce().value(), kNonce1);
if (!IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) {
// Triple-keyed IsolationInfo + double-keyed NetworkAnonymizationKey case.
EXPECT_EQ(isolation_info.frame_origin(), kOrigin2);
} else {
// Triple-keyed IsolationInfo + double-keyed + cross site bit
// NetworkAnonymizationKey case.
EXPECT_EQ(isolation_info.frame_origin(), kOrigin2);
EXPECT_EQ(isolation_info.network_anonymization_key().GetIsCrossSite(),
true);
EXPECT_EQ(
same_site_isolation_info.network_anonymization_key().GetIsCrossSite(),
false);
}
// Triple-keyed IsolationInfo + double-keyed + cross site bit
// NetworkAnonymizationKey case.
EXPECT_EQ(isolation_info.frame_origin(), kOrigin2);
EXPECT_EQ(isolation_info.network_anonymization_key().GetIsCrossSite(), true);
EXPECT_EQ(
same_site_isolation_info.network_anonymization_key().GetIsCrossSite(),
false);
}
// A 2.5-keyed NAK created with two identical opaque origins should be
// same-site.
TEST_P(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfoOpaque) {
TEST_F(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfoOpaque) {
url::Origin opaque;
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kMainFrame, opaque, opaque,
@ -188,22 +136,16 @@ TEST_P(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfoOpaque) {
isolation_info.CreateNetworkAnonymizationKeyForIsolationInfo(
opaque, opaque, &kNonce1);
if (IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) {
EXPECT_FALSE(nak.GetIsCrossSite().value());
} else {
EXPECT_DCHECK_DEATH(nak.GetIsCrossSite());
}
EXPECT_FALSE(nak.GetIsCrossSite().value());
url::Origin opaque2;
nak = isolation_info.CreateNetworkAnonymizationKeyForIsolationInfo(
opaque, opaque2, &kNonce1);
if (IsDoubleKeyAndCrossSiteBitNetworkAnonymizationKeyEnabled()) {
EXPECT_TRUE(nak.GetIsCrossSite().value());
}
EXPECT_TRUE(nak.GetIsCrossSite().value());
}
TEST_P(IsolationInfoTest, RequestTypeMainFrame) {
TEST_F(IsolationInfoTest, RequestTypeMainFrame) {
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty);
@ -241,7 +183,7 @@ TEST_P(IsolationInfoTest, RequestTypeMainFrame) {
EXPECT_FALSE(redirected_isolation_info.nonce().has_value());
}
TEST_P(IsolationInfoTest, RequestTypeSubFrame) {
TEST_F(IsolationInfoTest, RequestTypeSubFrame) {
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kSubFrame, kOrigin1, kOrigin2,
SiteForCookies::FromOrigin(kOrigin1), kPartyContext1);
@ -279,7 +221,7 @@ TEST_P(IsolationInfoTest, RequestTypeSubFrame) {
EXPECT_FALSE(redirected_isolation_info.nonce().has_value());
}
TEST_P(IsolationInfoTest, RequestTypeMainFrameWithNonce) {
TEST_F(IsolationInfoTest, RequestTypeMainFrameWithNonce) {
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty, &kNonce1);
@ -316,7 +258,7 @@ TEST_P(IsolationInfoTest, RequestTypeMainFrameWithNonce) {
EXPECT_EQ(kNonce1, redirected_isolation_info.nonce().value());
}
TEST_P(IsolationInfoTest, RequestTypeSubFrameWithNonce) {
TEST_F(IsolationInfoTest, RequestTypeSubFrameWithNonce) {
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kSubFrame, kOrigin1, kOrigin2,
SiteForCookies::FromOrigin(kOrigin1), kPartyContext1, &kNonce1);
@ -353,7 +295,7 @@ TEST_P(IsolationInfoTest, RequestTypeSubFrameWithNonce) {
EXPECT_EQ(kNonce1, redirected_isolation_info.nonce().value());
}
TEST_P(IsolationInfoTest, RequestTypeOther) {
TEST_F(IsolationInfoTest, RequestTypeOther) {
IsolationInfo isolation_info;
EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
EXPECT_FALSE(isolation_info.top_frame_origin());
@ -370,7 +312,7 @@ TEST_P(IsolationInfoTest, RequestTypeOther) {
EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
}
TEST_P(IsolationInfoTest, RequestTypeOtherWithSiteForCookies) {
TEST_F(IsolationInfoTest, RequestTypeOtherWithSiteForCookies) {
IsolationInfo isolation_info = IsolationInfo::Create(
IsolationInfo::RequestType::kOther, kOrigin1, kOrigin1,
SiteForCookies::FromOrigin(kOrigin1), kPartyContextEmpty);
@ -395,7 +337,7 @@ TEST_P(IsolationInfoTest, RequestTypeOtherWithSiteForCookies) {
// Test case of a subresource for cross-site subframe (which has an empty
// site-for-cookies).
TEST_P(IsolationInfoTest, RequestTypeOtherWithEmptySiteForCookies) {
TEST_F(IsolationInfoTest, RequestTypeOtherWithEmptySiteForCookies) {
IsolationInfo isolation_info =
IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin1,
kOrigin2, SiteForCookies(), kPartyContext2);
@ -417,7 +359,7 @@ TEST_P(IsolationInfoTest, RequestTypeOtherWithEmptySiteForCookies) {
EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
}
TEST_P(IsolationInfoTest, CreateTransient) {
TEST_F(IsolationInfoTest, CreateTransient) {
IsolationInfo isolation_info = IsolationInfo::CreateTransient();
EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
EXPECT_TRUE(isolation_info.top_frame_origin()->opaque());
@ -435,7 +377,7 @@ TEST_P(IsolationInfoTest, CreateTransient) {
EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
}
TEST_P(IsolationInfoTest, CreateForInternalRequest) {
TEST_F(IsolationInfoTest, CreateForInternalRequest) {
IsolationInfo isolation_info =
IsolationInfo::CreateForInternalRequest(kOrigin1);
EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
@ -459,7 +401,7 @@ TEST_P(IsolationInfoTest, CreateForInternalRequest) {
// Test that in the UpdateNothing case, the SiteForCookies does not have to
// match the frame origin, unlike in the HTTP/HTTPS case.
TEST_P(IsolationInfoTest, CustomSchemeRequestTypeOther) {
TEST_F(IsolationInfoTest, CustomSchemeRequestTypeOther) {
// Have to register the scheme, or url::Origin::Create() will return an
// opaque origin.
url::ScopedSchemeRegistryForTests scoped_registry;
@ -491,7 +433,7 @@ TEST_P(IsolationInfoTest, CustomSchemeRequestTypeOther) {
// Success cases are covered by other tests, so only need a separate test to
// cover the failure cases.
TEST_P(IsolationInfoTest, CreateIfConsistentFails) {
TEST_F(IsolationInfoTest, CreateIfConsistentFails) {
// Main frames with inconsistent SiteForCookies.
EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
@ -553,7 +495,7 @@ TEST_P(IsolationInfoTest, CreateIfConsistentFails) {
SiteForCookies(), absl::nullopt /* party_context */, &kNonce1));
}
TEST_P(IsolationInfoTest, CreateForRedirectPartyContext) {
TEST_F(IsolationInfoTest, CreateForRedirectPartyContext) {
// RequestTypeMainFrame, PartyContext is empty
{
IsolationInfo isolation_info = IsolationInfo::Create(
@ -592,7 +534,7 @@ TEST_P(IsolationInfoTest, CreateForRedirectPartyContext) {
}
}
TEST_P(IsolationInfoTest, Serialization) {
TEST_F(IsolationInfoTest, Serialization) {
EXPECT_FALSE(IsolationInfo::Deserialize(""));
EXPECT_FALSE(IsolationInfo::Deserialize("garbage"));

@ -20,27 +20,25 @@ NetworkAnonymizationKey::NetworkAnonymizationKey(
const absl::optional<bool> is_cross_site,
const absl::optional<base::UnguessableToken> nonce)
: top_frame_site_(top_frame_site),
is_cross_site_(IsCrossSiteFlagSchemeEnabled() ? is_cross_site
: absl::nullopt),
is_cross_site_(is_cross_site),
nonce_(nonce) {
DCHECK(top_frame_site_.has_value());
// If `is_cross_site` is enabled but the value is not populated, and we have
// the information to calculate it, do calculate it.
if (IsCrossSiteFlagSchemeEnabled() && !is_cross_site_.has_value() &&
frame_site.has_value()) {
if (!is_cross_site_.has_value() && frame_site.has_value()) {
is_cross_site_ = frame_site.value() != top_frame_site_.value();
}
if (IsCrossSiteFlagSchemeEnabled()) {
// If `frame_site_` is populated, `is_cross_site_` must be as well.
DCHECK(is_cross_site_.has_value());
}
// `is_cross_site_` must be populated.
// TODO(crbug.com/1407287): update constructor signature so this is not
// optional.
DCHECK(is_cross_site_.has_value());
}
NetworkAnonymizationKey NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
const net::NetworkIsolationKey& network_isolation_key) {
// If NIK is double-keyed, a 2.5-keyed NAK cannot be constructed from it.
DCHECK(NetworkIsolationKey::IsFrameSiteEnabled() ||
IsDoubleKeySchemeEnabled());
DCHECK(NetworkIsolationKey::IsFrameSiteEnabled());
// We cannot create a valid NetworkAnonymizationKey from a NetworkIsolationKey
// that is not fully populated.
@ -48,16 +46,9 @@ NetworkAnonymizationKey NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
return NetworkAnonymizationKey();
}
// If we are unable to determine the value of `is_cross_site` from the
// NetworkIsolationKey, we default the value to `nullopt`. Otherwise we
// calculate what the value will be. If the NetworkAnonymizationKey is being
// constructed in a scheme where the is cross site value is not used this
// value will be overridden in the constructor and set to `nullopt`.
absl::optional<bool> nak_is_cross_site = absl::nullopt;
if (NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled()) {
nak_is_cross_site = network_isolation_key.GetTopFrameSite().value() !=
network_isolation_key.GetFrameSite().value();
}
// Determine is_cross_site based on the NIK's triple-key
bool nak_is_cross_site = network_isolation_key.GetTopFrameSite().value() !=
network_isolation_key.GetFrameSite().value();
return NetworkAnonymizationKey(
network_isolation_key.GetTopFrameSite().value(), absl::nullopt,
@ -87,14 +78,12 @@ NetworkAnonymizationKey NetworkAnonymizationKey::CreateTransient() {
}
std::string NetworkAnonymizationKey::ToDebugString() const {
if (!IsFullyPopulated()) {
return "null";
}
std::string str = GetSiteDebugString(top_frame_site_);
std::string cross_site_str =
IsCrossSiteFlagSchemeEnabled()
? (!GetIsCrossSite().has_value() ? " with empty is_cross_site value"
: GetIsCrossSite().value() ? " cross_site"
: " same_site")
: "";
str += cross_site_str;
str += GetIsCrossSite().value() ? " cross_site" : " same_site";
// Currently, if the NAK has a nonce it will be marked transient. For debug
// purposes we will print the value but if called via
@ -111,8 +100,7 @@ bool NetworkAnonymizationKey::IsEmpty() const {
}
bool NetworkAnonymizationKey::IsFullyPopulated() const {
return top_frame_site_.has_value() &&
(!IsCrossSiteFlagSchemeEnabled() || is_cross_site_.has_value());
return top_frame_site_.has_value() && is_cross_site_.has_value();
}
bool NetworkAnonymizationKey::IsTransient() const {
@ -123,20 +111,9 @@ bool NetworkAnonymizationKey::IsTransient() const {
}
absl::optional<bool> NetworkAnonymizationKey::GetIsCrossSite() const {
DCHECK(IsCrossSiteFlagSchemeEnabled());
return is_cross_site_;
}
bool NetworkAnonymizationKey::IsDoubleKeySchemeEnabled() {
return !base::FeatureList::IsEnabled(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
}
bool NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled() {
return base::FeatureList::IsEnabled(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
}
bool NetworkAnonymizationKey::ToValue(base::Value* out_value) const {
if (IsEmpty()) {
*out_value = base::Value(base::Value::Type::LIST);
@ -153,14 +130,8 @@ bool NetworkAnonymizationKey::ToValue(base::Value* out_value) const {
base::Value::List list;
list.Append(std::move(top_frame_value).value());
// Append frame site for tripe key scheme or is_cross_site flag for double key
// with cross site flag scheme.
if (IsCrossSiteFlagSchemeEnabled()) {
const absl::optional<bool> is_cross_site = GetIsCrossSite();
if (is_cross_site.has_value()) {
list.Append(is_cross_site.value());
}
}
const absl::optional<bool> is_cross_site = GetIsCrossSite();
list.Append(is_cross_site.value());
*out_value = base::Value(std::move(list));
return true;
@ -178,10 +149,12 @@ bool NetworkAnonymizationKey::FromValue(
return true;
}
// Check top_level_site is valid for any key scheme
if (list.size() < 1 || !list[0].is_string()) {
// Check the format.
if (list.size() != 2 || !list[0].is_string() || !list[1].is_bool()) {
return false;
}
// Check top_level_site is valid for any key scheme
absl::optional<SchemefulSite> top_frame_site =
SchemefulSite::DeserializeWithNonce(list[0].GetString());
if (!top_frame_site) {
@ -191,21 +164,7 @@ bool NetworkAnonymizationKey::FromValue(
absl::optional<SchemefulSite> frame_site = absl::nullopt;
absl::optional<bool> is_cross_site = absl::nullopt;
// If double key scheme is enabled `list` must be of length 1. list[0] will be
// top_frame_site.
if (IsDoubleKeySchemeEnabled()) {
if (list.size() != 1) {
return false;
}
} else /* if (IsCrossSiteFlagSchemeEnabled()) */ {
// If double key + is cross site scheme is enabled `list` must be of
// length 2. list[0] will be top_frame_site and list[1] will be
// is_cross_site.
if (list.size() != 2 || !list[1].is_bool()) {
return false;
}
is_cross_site = list[1].GetBool();
}
is_cross_site = list[1].GetBool();
*network_anonymization_key =
NetworkAnonymizationKey(std::move(top_frame_site.value()),

@ -31,12 +31,9 @@ namespace net {
// In order to separate first and third party context from each other this field
// will always be populated.
//`is_cross_site` is an expiremental boolean that will be used with the
//`top_frame_site` to create a partition key that separates the
//`top_frame_site`s first party partition from any cross-site iframes. This will
// be used only when `kEnableCrossSiteFlagNetworkAnonymizationKey` is enabled.
// When `kEnableCrossSiteFlagNetworkAnonymizationKey` is disabled,
// `is_cross_site_` will be an empty optional.
// `is_cross_site` is used with the `top_frame_site` to create a partition key
// that separates the `top_frame_site`s first party partition from any
// cross-site iframes.
// The following show how the `is_cross_site` boolean is populated for the
// innermost frame in the chain.
@ -147,29 +144,6 @@ class NET_EXPORT NetworkAnonymizationKey {
return nonce_;
}
// Returns true if the NetworkAnonymizationKey has a triple keyed scheme. This
// means the values of the NetworkAnonymizationKey are as follows:
// `top_frame_site` -> the schemeful site of the top level page.
// `frame_site ` -> the schemeful site of the requestor frame
// `is_cross_site` -> nullopt
static bool IsFrameSiteEnabled();
// Returns true if the NetworkAnonymizationKey has a double keyed scheme. This
// means the values of the NetworkAnonymizationKey are as follows:
// `top_frame_site` -> the schemeful site of the top level page.
// `frame_site ` -> nullopt
// `is_cross_site` -> nullopt
static bool IsDoubleKeySchemeEnabled();
// Returns true if the NetworkAnonymizationKey has a <double keyed +
// is_cross_site> scheme. This means the values of the NetworkAnonymizationKey
// are as follows:
// `top_frame_site` -> the schemeful site of the top level page.
// `frame_site ` -> nullopt
// `is_cross_site` -> a boolean indicating if the requestor frame site is
// cross site from the top level site.
static bool IsCrossSiteFlagSchemeEnabled();
// Returns a representation of |this| as a base::Value. Returns false on
// failure. Succeeds if either IsEmpty() or !IsTransient().
[[nodiscard]] bool ToValue(base::Value* out_value) const;

@ -18,79 +18,15 @@
namespace net {
// `EnabledFeatureFlagsTestingParam ` allows enabling and disabling
// the feature flags that control the key schemes for NetworkAnonymizationKey.
// This allows us to test the possible combinations of flags that will be
// allowed for experimentation.
struct EnabledFeatureFlagsTestingParam {
// True = 2.5-keyed NAK, false = double-keyed NAK.
const bool enableCrossSiteFlagNetworkAnonymizationKey;
};
const EnabledFeatureFlagsTestingParam kFlagsParam[] = {
// 0. Double-keying is enabled for NetworkAnonymizationKey.
{/*enableCrossSiteFlagNetworkAnonymizationKey=*/false},
// 1. Double-keying + cross-site-bit is enabled for NetworkAnonymizationKey.
{/*enableCrossSiteFlagNetworkAnonymizationKey=*/true}};
class NetworkAnonymizationKeyTest
: public testing::Test,
public testing::WithParamInterface<EnabledFeatureFlagsTestingParam> {
public:
void SetUp() override {
std::vector<base::test::FeatureRef> enabled_features = {};
std::vector<base::test::FeatureRef> disabled_features = {};
if (IsCrossSiteFlagEnabled()) {
enabled_features.push_back(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
} else {
disabled_features.push_back(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
}
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
bool IsCrossSiteFlagEnabled() {
return GetParam().enableCrossSiteFlagNetworkAnonymizationKey;
}
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();
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_SUITE_P(All,
NetworkAnonymizationKeyTest,
testing::ValuesIn(kFlagsParam));
TEST_P(NetworkAnonymizationKeyTest, IsDoubleKeySchemeEnabled) {
// Double key scheme is enabled only when
// `kEnableCrossSiteFlagNetworkAnonymizationKey` is not.
if (!IsCrossSiteFlagEnabled()) {
EXPECT_TRUE(NetworkAnonymizationKey::IsDoubleKeySchemeEnabled());
} else {
EXPECT_FALSE(NetworkAnonymizationKey::IsDoubleKeySchemeEnabled());
}
}
TEST_P(NetworkAnonymizationKeyTest, IsCrossSiteFlagSchemeEnabled) {
// Double key with cross site flag scheme is enabled whenever
// `kEnableCrossSiteFlagNetworkAnonymizationKey` is enabled.
if (IsCrossSiteFlagEnabled()) {
EXPECT_TRUE(NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled());
} else {
EXPECT_FALSE(NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled());
}
}
TEST_P(NetworkAnonymizationKeyTest, CreateFromNetworkIsolationKey) {
TEST_F(NetworkAnonymizationKeyTest, CreateFromNetworkIsolationKey) {
SchemefulSite site_a = SchemefulSite(GURL("http://a.test/"));
SchemefulSite site_b = SchemefulSite(GURL("http://b.test/"));
SchemefulSite opaque = SchemefulSite(url::Origin());
@ -102,12 +38,12 @@ TEST_P(NetworkAnonymizationKeyTest, CreateFromNetworkIsolationKey) {
&nik_nonce);
NetworkIsolationKey empty_nik;
NetworkAnonymizationKey nak_from_cross_site_nik =
NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
populated_cross_site_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);
@ -118,47 +54,27 @@ TEST_P(NetworkAnonymizationKeyTest, CreateFromNetworkIsolationKey) {
// empty NAK.
EXPECT_TRUE(nak_from_empty_nik.IsEmpty());
// Double-keyed NetworkAnonymizationKey case.
if (!IsCrossSiteFlagEnabled()) {
// Top site should be populated correctly.
EXPECT_EQ(nak_from_cross_site_nik.GetTopFrameSite(), site_a);
EXPECT_EQ(nak_from_same_site_nik.GetTopFrameSite(), site_a);
EXPECT_EQ(nak_from_same_site_opaque_nik.GetTopFrameSite(), opaque);
// 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_cross_site_nik.GetNonce(), nik_nonce);
EXPECT_EQ(nak_from_same_site_nik.GetNonce(), nik_nonce);
EXPECT_EQ(nak_from_same_site_opaque_nik.GetNonce(), nik_nonce);
// 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);
// Double-keyed NAKs created from different third party cross site contexts
// should be the same.
EXPECT_TRUE(nak_from_same_site_nik == nak_from_cross_site_nik);
}
// Is cross site boolean should be populated correctly.
EXPECT_EQ(nak_from_same_site_nik.GetIsCrossSite(), false);
EXPECT_EQ(nak_from_cross_site_nik.GetIsCrossSite(), true);
EXPECT_EQ(nak_from_same_site_opaque_nik.GetIsCrossSite(), false);
// Double-keyed + cross site bit NetworkAnonymizationKey case.
if (IsCrossSiteFlagEnabled()) {
// Top site should be populated correctly.
EXPECT_EQ(nak_from_cross_site_nik.GetTopFrameSite(), site_a);
EXPECT_EQ(nak_from_same_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_EQ(nak_from_same_site_nik.GetIsCrossSite(), false);
EXPECT_EQ(nak_from_cross_site_nik.GetIsCrossSite(), true);
EXPECT_EQ(nak_from_same_site_opaque_nik.GetIsCrossSite(), false);
// 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);
}
// 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_P(NetworkAnonymizationKeyTest, IsEmpty) {
TEST_F(NetworkAnonymizationKeyTest, IsEmpty) {
NetworkAnonymizationKey empty_key;
NetworkAnonymizationKey populated_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
@ -169,7 +85,7 @@ TEST_P(NetworkAnonymizationKeyTest, IsEmpty) {
EXPECT_FALSE(populated_key.IsEmpty());
}
TEST_P(NetworkAnonymizationKeyTest, CreateTransient) {
TEST_F(NetworkAnonymizationKeyTest, CreateTransient) {
NetworkAnonymizationKey transient_key1 =
NetworkAnonymizationKey::CreateTransient();
NetworkAnonymizationKey transient_key2 =
@ -180,7 +96,7 @@ TEST_P(NetworkAnonymizationKeyTest, CreateTransient) {
EXPECT_FALSE(transient_key1 == transient_key2);
}
TEST_P(NetworkAnonymizationKeyTest, IsTransient) {
TEST_F(NetworkAnonymizationKeyTest, IsTransient) {
NetworkAnonymizationKey empty_key;
NetworkAnonymizationKey populated_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
@ -215,7 +131,7 @@ TEST_P(NetworkAnonymizationKeyTest, IsTransient) {
EXPECT_FALSE(populated_double_key.IsTransient());
}
TEST_P(NetworkAnonymizationKeyTest, IsFullyPopulated) {
TEST_F(NetworkAnonymizationKeyTest, IsFullyPopulated) {
NetworkAnonymizationKey empty_key;
NetworkAnonymizationKey populated_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
@ -234,63 +150,59 @@ TEST_P(NetworkAnonymizationKeyTest, IsFullyPopulated) {
/*nonce=*/absl::nullopt);
EXPECT_TRUE(empty_frame_site_key.IsFullyPopulated());
// is_cross_site is required when
// `kEnableCrossSiteFlagNetworkAnonymizationKey` is enabled.
// Since we have both the top_frame_site and frame_site values the constructor
// should calculate and set `is_cross_site`.
// is_cross_site is required. Since we have both the top_frame_site and
// frame_site values the constructor should calculate and set `is_cross_site`.
EXPECT_TRUE(empty_cross_site_flag_key.IsFullyPopulated());
}
TEST_P(NetworkAnonymizationKeyTest, IsCrossSiteFlagCalculatedInConstructor) {
if (IsCrossSiteFlagEnabled()) {
NetworkAnonymizationKey cross_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
/*is_cross_site=*/true);
NetworkAnonymizationKey equal_cross_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB);
EXPECT_EQ(cross_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(equal_cross_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(cross_site_key, equal_cross_site_key);
TEST_F(NetworkAnonymizationKeyTest, IsCrossSiteFlagCalculatedInConstructor) {
NetworkAnonymizationKey cross_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
/*is_cross_site=*/true);
NetworkAnonymizationKey equal_cross_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB);
EXPECT_EQ(cross_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(equal_cross_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(cross_site_key, equal_cross_site_key);
NetworkAnonymizationKey same_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteA,
/*is_cross_site=*/false);
NetworkAnonymizationKey equal_same_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteA);
EXPECT_EQ(same_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(equal_same_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(same_site_key, equal_same_site_key);
NetworkAnonymizationKey same_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteA,
/*is_cross_site=*/false);
NetworkAnonymizationKey equal_same_site_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteA);
EXPECT_EQ(same_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(equal_same_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(same_site_key, equal_same_site_key);
SchemefulSite opaque = SchemefulSite(url::Origin());
NetworkAnonymizationKey same_opaque_site_key(/*top_frame_site=*/opaque,
/*frame_site=*/opaque,
/*is_cross_site=*/false);
NetworkAnonymizationKey equal_same_opaque_site_key(
/*top_frame_site=*/opaque,
/*frame_site=*/opaque);
EXPECT_EQ(same_opaque_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(equal_same_opaque_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(same_opaque_site_key, equal_same_opaque_site_key);
SchemefulSite opaque = SchemefulSite(url::Origin());
NetworkAnonymizationKey same_opaque_site_key(/*top_frame_site=*/opaque,
/*frame_site=*/opaque,
/*is_cross_site=*/false);
NetworkAnonymizationKey equal_same_opaque_site_key(
/*top_frame_site=*/opaque,
/*frame_site=*/opaque);
EXPECT_EQ(same_opaque_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(equal_same_opaque_site_key.GetIsCrossSite().value(), false);
EXPECT_EQ(same_opaque_site_key, equal_same_opaque_site_key);
SchemefulSite opaque2 = SchemefulSite(url::Origin());
NetworkAnonymizationKey diff_opaque_site_key(/*top_frame_site=*/opaque,
/*frame_site=*/opaque2,
/*is_cross_site=*/true);
NetworkAnonymizationKey equal_diff_opaque_site_key(
/*top_frame_site=*/opaque,
/*frame_site=*/opaque2);
EXPECT_EQ(diff_opaque_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(equal_diff_opaque_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(diff_opaque_site_key, equal_diff_opaque_site_key);
SchemefulSite opaque2 = SchemefulSite(url::Origin());
NetworkAnonymizationKey diff_opaque_site_key(/*top_frame_site=*/opaque,
/*frame_site=*/opaque2,
/*is_cross_site=*/true);
NetworkAnonymizationKey equal_diff_opaque_site_key(
/*top_frame_site=*/opaque,
/*frame_site=*/opaque2);
EXPECT_EQ(diff_opaque_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(equal_diff_opaque_site_key.GetIsCrossSite().value(), true);
EXPECT_EQ(diff_opaque_site_key, equal_diff_opaque_site_key);
NetworkAnonymizationKey double_key_cross_site(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/absl::nullopt,
true);
EXPECT_EQ(double_key_cross_site.GetIsCrossSite().value(), true);
}
NetworkAnonymizationKey double_key_cross_site(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/absl::nullopt,
true);
EXPECT_EQ(double_key_cross_site.GetIsCrossSite().value(), true);
}
TEST_P(NetworkAnonymizationKeyTest, Getters) {
TEST_F(NetworkAnonymizationKeyTest, Getters) {
NetworkAnonymizationKey key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
/*is_cross_site=*/true, kNonce);
@ -298,41 +210,25 @@ TEST_P(NetworkAnonymizationKeyTest, Getters) {
EXPECT_EQ(key.GetTopFrameSite(), kTestSiteA);
EXPECT_EQ(key.GetNonce(), kNonce);
// is_cross_site should only be true when
// `kEnableCrossSiteFlagNetworkAnonymizationKey` is enabled.
if (IsCrossSiteFlagEnabled()) {
EXPECT_TRUE(key.GetIsCrossSite());
}
EXPECT_TRUE(key.GetIsCrossSite().value());
}
TEST_P(NetworkAnonymizationKeyTest, ToDebugString) {
TEST_F(NetworkAnonymizationKeyTest, ToDebugString) {
NetworkAnonymizationKey key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
/*is_cross_site=*/true, kNonce);
NetworkAnonymizationKey empty_key;
if (!IsCrossSiteFlagEnabled()) {
// When double key scheme is enabled, the `is_cross_site` flag is always
// forced to false.
std::string double_key_expected_string_value =
kTestSiteA.GetDebugString() + " (with nonce " + kNonce.ToString() + ")";
EXPECT_EQ(key.ToDebugString(), double_key_expected_string_value);
EXPECT_EQ(empty_key.ToDebugString(), "null");
} else {
// When double key + cross site flag scheme is enabled frame site is null,
// but `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);
// is_cross_site_ will be stored as nullopt when it's not populated even if
// IsCrossSiteFlagEnabled is enabled.
EXPECT_EQ(empty_key.ToDebugString(), "null with empty is_cross_site value");
}
// `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_P(NetworkAnonymizationKeyTest, Equality) {
TEST_F(NetworkAnonymizationKeyTest, Equality) {
NetworkAnonymizationKey key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
/*is_cross_site=*/false, kNonce);
@ -347,17 +243,10 @@ TEST_P(NetworkAnonymizationKeyTest, Equality) {
/*frame_site=*/kTestSiteB,
/*is_cross_site=*/true, kNonce);
// The `is_cross_site` flag only changes the NAK when
// `kEnableCrossSiteFlagNetworkAnonymizationKey` is enabled.
if (IsCrossSiteFlagEnabled()) {
EXPECT_FALSE(key == key_cross_site);
EXPECT_TRUE(key != key_cross_site);
EXPECT_TRUE(key < key_cross_site);
} else {
EXPECT_TRUE(key == key_cross_site);
EXPECT_FALSE(key != key_cross_site);
EXPECT_FALSE(key < key_cross_site);
}
// 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(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
@ -401,7 +290,7 @@ TEST_P(NetworkAnonymizationKeyTest, Equality) {
EXPECT_TRUE(empty_key < key);
}
TEST_P(NetworkAnonymizationKeyTest, ValueRoundTripCrossSite) {
TEST_F(NetworkAnonymizationKeyTest, ValueRoundTripCrossSite) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB,
@ -415,7 +304,7 @@ TEST_P(NetworkAnonymizationKeyTest, ValueRoundTripCrossSite) {
EXPECT_EQ(original_key, from_value_key);
}
TEST_P(NetworkAnonymizationKeyTest, ValueRoundTripSameSite) {
TEST_F(NetworkAnonymizationKeyTest, ValueRoundTripSameSite) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key(/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteA,
@ -429,7 +318,7 @@ TEST_P(NetworkAnonymizationKeyTest, ValueRoundTripSameSite) {
EXPECT_EQ(original_key, from_value_key);
}
TEST_P(NetworkAnonymizationKeyTest, TransientValueRoundTrip) {
TEST_F(NetworkAnonymizationKeyTest, TransientValueRoundTrip) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key =
NetworkAnonymizationKey::CreateTransient();
@ -437,7 +326,7 @@ TEST_P(NetworkAnonymizationKeyTest, TransientValueRoundTrip) {
ASSERT_FALSE(original_key.ToValue(&value));
}
TEST_P(NetworkAnonymizationKeyTest, EmptyValueRoundTrip) {
TEST_F(NetworkAnonymizationKeyTest, EmptyValueRoundTrip) {
const SchemefulSite kOpaqueSite = SchemefulSite(GURL("data:text/html,junk"));
NetworkAnonymizationKey original_key;
base::Value value;
@ -457,20 +346,27 @@ TEST(NetworkAnonymizationKeyFeatureShiftTest,
const SchemefulSite kTestSiteB = SchemefulSite(GURL("http://b.test/"));
NetworkAnonymizationKey expected_failure_nak = NetworkAnonymizationKey();
// Turn double keying on (or disable 2.5-keying)
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndDisableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
// Create a cross site double key + cross site flag NetworkAnonymizationKey.
NetworkAnonymizationKey original_cross_site_double_key(
/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB, false);
base::Value cross_site_double_key_value;
ASSERT_TRUE(
original_cross_site_double_key.ToValue(&cross_site_double_key_value));
// Create a double keyed NetworkAnonymizationKey.
NetworkAnonymizationKey original_double_key(/*top_frame_site=*/kTestSiteA);
// Serialize key to value while double keying is enabled.
base::Value double_key_value;
ASSERT_TRUE(original_double_key.ToValue(&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 fails. Such values
// cannot be constructed, but may still exist on-disk.
base::Value serialized_site = double_key_value.GetList()[0].Clone();
// 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));
@ -478,49 +374,12 @@ TEST(NetworkAnonymizationKeyFeatureShiftTest,
EXPECT_FALSE(NetworkAnonymizationKey::FromValue(triple_key_value,
&expected_failure_nak));
// Convert it back to a double keyed NetworkAnonymizationKey.
NetworkAnonymizationKey from_value_double_key = NetworkAnonymizationKey();
EXPECT_TRUE(NetworkAnonymizationKey::FromValue(double_key_value,
&from_value_double_key));
EXPECT_EQ(original_double_key, from_value_double_key);
// Turn double keying + cross site flag on.
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndEnableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
// Check that deserializing the triple keyed value fails.
EXPECT_FALSE(NetworkAnonymizationKey::FromValue(triple_key_value,
&expected_failure_nak));
// Check that deserializing the double keyed value fails.
EXPECT_FALSE(NetworkAnonymizationKey::FromValue(double_key_value,
&expected_failure_nak));
// Create a cross site double key + cross site flag NetworkAnonymizationKey.
NetworkAnonymizationKey original_cross_site_double_key(
/*top_frame_site=*/kTestSiteA,
/*frame_site=*/kTestSiteB, false);
// Serialize key to value while double key + cross site flag is enabled.
base::Value cross_site_double_key_value;
ASSERT_TRUE(
original_cross_site_double_key.ToValue(&cross_site_double_key_value));
// Convert it back to a double keyed NetworkAnonymizationKey.
// 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);
// Turn double keying on (or disable 2.5-keying)
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndDisableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
// Check that deserializing the cross site double keyed value fails.
EXPECT_FALSE(NetworkAnonymizationKey::FromValue(cross_site_double_key_value,
&expected_failure_nak));
}
} // namespace net

@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "net/http/http_request_info.h"
#include "base/test/scoped_feature_list.h"
#include "net/base/features.h"
#include "net/base/network_anonymization_key.h"
#include "net/base/network_isolation_key.h"
@ -12,30 +11,20 @@
namespace net {
TEST(HTTPRequestInfoTest, IsConsistent) {
// TODO(brgoldstein): refactor this test with new testing config enum when
// you update NetworkAnonymizationKey tests and IsolationInfo tests.
const SchemefulSite kTestSiteA = SchemefulSite(GURL("http://a.test/"));
const SchemefulSite kTestSiteB = SchemefulSite(GURL("http://b.test/"));
net::HttpRequestInfo triple_nik_double_nak_request_info;
triple_nik_double_nak_request_info.network_isolation_key =
net::HttpRequestInfo with_anon_nak;
with_anon_nak.network_isolation_key =
NetworkIsolationKey(kTestSiteA, kTestSiteB);
EXPECT_FALSE(with_anon_nak.IsConsistent());
// Triple key NIK and double key NAK.
base::test::ScopedFeatureList scoped_feature_list_;
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndDisableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
EXPECT_FALSE(triple_nik_double_nak_request_info.IsConsistent());
net::HttpRequestInfo triple_nik_double_xsite_bit_nak_request_info;
triple_nik_double_xsite_bit_nak_request_info.network_isolation_key =
net::HttpRequestInfo cross_site;
cross_site.network_isolation_key =
NetworkIsolationKey(kTestSiteA, kTestSiteB);
triple_nik_double_xsite_bit_nak_request_info.network_anonymization_key =
cross_site.network_anonymization_key =
NetworkAnonymizationKey(kTestSiteA, kTestSiteB, true);
EXPECT_TRUE(triple_nik_double_xsite_bit_nak_request_info.IsConsistent());
EXPECT_TRUE(cross_site.IsConsistent());
}
} // namespace net

@ -1151,7 +1151,7 @@ TEST_P(NetworkErrorLoggingServiceTest, StatusAsValue) {
{
"originPolicies": [
{
"NetworkAnonymizationKey": "https://example.com",
"NetworkAnonymizationKey": "https://example.com same_site",
"origin": "https://example.com",
"includeSubdomains": false,
"expires": "86400000",
@ -1160,7 +1160,7 @@ TEST_P(NetworkErrorLoggingServiceTest, StatusAsValue) {
"failureFraction": 1.0,
},
{
"NetworkAnonymizationKey": "https://example.com",
"NetworkAnonymizationKey": "https://example.com same_site",
"origin": "https://invalid-types.example.com",
"includeSubdomains": false,
"expires": "86400000",
@ -1169,7 +1169,7 @@ TEST_P(NetworkErrorLoggingServiceTest, StatusAsValue) {
"failureFraction": 1.0,
},
{
"NetworkAnonymizationKey": "https://example.com",
"NetworkAnonymizationKey": "https://example.com same_site",
"origin": "https://somewhere-else.com",
"includeSubdomains": false,
"expires": "86400000",
@ -1178,7 +1178,7 @@ TEST_P(NetworkErrorLoggingServiceTest, StatusAsValue) {
"failureFraction": 1.0,
},
{
"NetworkAnonymizationKey": "https://somewhere-else.com",
"NetworkAnonymizationKey": "https://somewhere-else.com same_site",
"origin": "https://subdomain.example.com",
"includeSubdomains": true,
"expires": "86400000",

@ -148,7 +148,7 @@ TEST(ClientSocketPool, GroupIdToString) {
SecureDnsPolicy::kAllow)
.ToString());
EXPECT_EQ("https://foo <https://foo.test>",
EXPECT_EQ("https://foo <https://foo.test cross_site>",
ClientSocketPool::GroupId(
url::SchemeHostPort(url::kHttpsScheme, "foo", 443),
PrivacyMode::PRIVACY_MODE_DISABLED,

@ -1188,8 +1188,7 @@ IsolationInfo URLRequest::CreateIsolationInfoFromNetworkAnonymizationKey(
network_anonymization_key.GetTopFrameSite()->site_as_origin_;
absl::optional<url::Origin> frame_origin;
if (NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled() &&
network_anonymization_key.GetIsCrossSite().value()) {
if (network_anonymization_key.GetIsCrossSite().value()) {
// If we know that the origin is cross site to the top level site, create an
// empty origin to use as the frame origin for the isolation info. This
// should be cross site with the top level origin.

@ -12883,12 +12883,7 @@ TEST_F(URLRequestTest, SetURLChain) {
}
}
TEST_F(URLRequestTest,
SetIsolationInfoFromNakTripleNikDoublePlusCrossSiteBitNak) {
base::test::ScopedFeatureList scoped_feature_list_;
scoped_feature_list_.InitAndEnableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
TEST_F(URLRequestTest, SetIsolationInfoFromNak) {
TestDelegate d;
SchemefulSite site_a = SchemefulSite(GURL("https://a.com/"));
SchemefulSite site_b = SchemefulSite(GURL("https://b.com/"));
@ -12946,119 +12941,6 @@ TEST_F(URLRequestTest,
d.RunUntilComplete();
}
TEST_F(URLRequestTest, SetIsolationInfoFromNakTripleNikDoubleNak) {
base::test::ScopedFeatureList scoped_feature_list_;
scoped_feature_list_.InitAndDisableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
TestDelegate d;
SchemefulSite site_a = SchemefulSite(GURL("https://a.com/"));
SchemefulSite site_b = SchemefulSite(GURL("https://b.com/"));
base::UnguessableToken nak_nonce = base::UnguessableToken::Create();
NetworkAnonymizationKey populated_cross_site_nak(site_a, site_b, true,
nak_nonce);
NetworkAnonymizationKey populated_same_site_nak(site_a, site_a, false,
nak_nonce);
IsolationInfo expected_isolation_info_populated_same_site_nak =
IsolationInfo::Create(IsolationInfo::RequestType::kOther,
url::Origin::Create(GURL("https://a.com/")),
url::Origin::Create(GURL("https://a.com/")),
SiteForCookies(),
/*party_context=*/absl::nullopt, &nak_nonce);
NetworkAnonymizationKey empty_nak;
GURL original_url("http://localhost");
std::unique_ptr<URLRequest> r(default_context().CreateRequest(
original_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
r->set_isolation_info_from_network_anonymization_key(
populated_cross_site_nak);
r->SetLoadFlags(LOAD_DISABLE_CACHE);
r->set_allow_credentials(false);
EXPECT_TRUE(r->is_created_from_network_anonymization_key());
EXPECT_EQ(r->isolation_info().network_anonymization_key(),
populated_cross_site_nak);
EXPECT_EQ(r->isolation_info().top_frame_origin(),
url::Origin::Create(GURL("https://a.com/")));
// When double key is enabled for NAK but not for NIK, the frame site of the
// IsolationInfo will be set to the top level site.
EXPECT_EQ(r->isolation_info().frame_origin(),
url::Origin::Create(GURL("https://a.com/")));
r->set_isolation_info_from_network_anonymization_key(populated_same_site_nak);
EXPECT_TRUE(r->is_created_from_network_anonymization_key());
EXPECT_TRUE(r->load_flags() & LOAD_DISABLE_CACHE);
EXPECT_EQ(r->isolation_info().network_anonymization_key(),
populated_same_site_nak);
EXPECT_TRUE(r->isolation_info().IsEqualForTesting(
expected_isolation_info_populated_same_site_nak));
r->set_isolation_info_from_network_anonymization_key(empty_nak);
EXPECT_TRUE(r->is_created_from_network_anonymization_key());
EXPECT_TRUE(r->load_flags() & LOAD_DISABLE_CACHE);
EXPECT_EQ(r->isolation_info().network_anonymization_key(), empty_nak);
EXPECT_FALSE(r->isolation_info().top_frame_origin());
EXPECT_FALSE(r->isolation_info().frame_origin());
r->Start();
d.RunUntilComplete();
}
TEST_F(URLRequestTest,
SetIsolationInfoFromNakTripleNikDoubleWithCrossSiteFlagNak) {
base::test::ScopedFeatureList scoped_feature_list_;
scoped_feature_list_.InitAndEnableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
TestDelegate d;
SchemefulSite site_a = SchemefulSite(GURL("https://a.com/"));
SchemefulSite site_b = SchemefulSite(GURL("https://b.com/"));
base::UnguessableToken nak_nonce = base::UnguessableToken::Create();
NetworkAnonymizationKey populated_cross_site_nak(
site_a, site_b, /*is_cross_site=*/true, nak_nonce);
NetworkAnonymizationKey populated_same_site_nak(
site_a, site_a, /*is_cross_site=*/false, nak_nonce);
NetworkAnonymizationKey empty_nak;
GURL original_url("http://localhost");
std::unique_ptr<URLRequest> r(default_context().CreateRequest(
original_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
r->set_isolation_info_from_network_anonymization_key(
populated_cross_site_nak);
r->SetLoadFlags(LOAD_DISABLE_CACHE);
r->set_allow_credentials(false);
EXPECT_TRUE(r->is_created_from_network_anonymization_key());
EXPECT_TRUE(r->load_flags() & LOAD_DISABLE_CACHE);
EXPECT_EQ(r->isolation_info().network_anonymization_key().ToDebugString(),
populated_cross_site_nak.ToDebugString());
EXPECT_EQ(r->isolation_info().top_frame_origin(),
url::Origin::Create(GURL("https://a.com/")));
// When double key is enabled for NAK but not for NIK, the frame site of the
// IsolationInfo will be set to the top level site.
EXPECT_TRUE(r->isolation_info().frame_origin());
r->set_isolation_info_from_network_anonymization_key(populated_same_site_nak);
EXPECT_TRUE(r->is_created_from_network_anonymization_key());
EXPECT_TRUE(r->load_flags() & LOAD_DISABLE_CACHE);
EXPECT_EQ(r->isolation_info().network_anonymization_key().ToDebugString(),
populated_same_site_nak.ToDebugString());
EXPECT_EQ(r->isolation_info().top_frame_origin(),
url::Origin::Create(GURL("https://a.com/")));
// Cross site double keyed NAKs should set a cross site dummy origin on the
// IsolationInfo.
EXPECT_TRUE(r->isolation_info().frame_origin());
r->set_isolation_info_from_network_anonymization_key(empty_nak);
EXPECT_TRUE(r->is_created_from_network_anonymization_key());
EXPECT_TRUE(r->load_flags() & LOAD_DISABLE_CACHE);
EXPECT_EQ(r->isolation_info().network_anonymization_key(), empty_nak);
EXPECT_FALSE(r->isolation_info().top_frame_origin());
EXPECT_FALSE(r->isolation_info().frame_origin());
r->Start();
d.RunUntilComplete();
}
TEST_F(URLRequestTest, CookiePartitionKey) {
const url::Origin kOrigin = url::Origin::Create(GURL("http://foo.test/"));
@ -13172,53 +13054,14 @@ INSTANTIATE_TEST_SUITE_P(,
URLRequestMaybeAsyncFirstPartySetsTest,
testing::Bool());
namespace {
// `EnabledFeatureFlagsTestingParam ` allows enabling and disabling
// the feature flags that control the key schemes for NetworkAnonymizationKey.
// This allows us to test the possible combinations of flags that will be
// allowed for experimentation.
//
// Presently, only one flag is used, but future experiments will add more.
struct EnabledFeatureFlagsTestingParam {
// True = 2.5-keyed NAK, false = double-keyed NAK.
const bool enable_cross_site_flag_network_anonymization_key;
};
const EnabledFeatureFlagsTestingParam kFlagsParam[] = {
// 0. Double-keying is enabled for NetworkAnonymizationKey.
{/*enable_cross_site_flag_network_anonymization_key=*/false},
// 1. Double-keying + cross-site-bit is enabled for NetworkAnonymizationKey.
{/*enable_cross_site_flag_network_anonymization_key=*/true}};
} // namespace
class PartitionConnectionsByNetworkAnonymizationKey
: public URLRequestTest,
public testing::WithParamInterface<EnabledFeatureFlagsTestingParam> {
class PartitionConnectionsByNetworkAnonymizationKey : public URLRequestTest {
public:
PartitionConnectionsByNetworkAnonymizationKey() {
std::vector<base::test::FeatureRef> enabled_features = {
net::features::kPartitionConnectionsByNetworkIsolationKey,
net::features::kPartitionSSLSessionsByNetworkIsolationKey};
std::vector<base::test::FeatureRef> disabled_features = {};
if (IsCrossSiteFlagEnabled()) {
enabled_features.push_back(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
} else {
disabled_features.push_back(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
}
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
scoped_feature_list_.InitWithFeatures(
{net::features::kPartitionConnectionsByNetworkIsolationKey,
net::features::kPartitionSSLSessionsByNetworkIsolationKey},
{});
}
bool IsCrossSiteFlagEnabled() const {
return GetParam().enable_cross_site_flag_network_anonymization_key;
}
const SchemefulSite kTestSiteA = SchemefulSite(GURL("http://a.test/"));
const SchemefulSite kTestSiteB = SchemefulSite(GURL("http://b.test/"));
const SchemefulSite kTestSiteC = SchemefulSite(GURL("http://c.test/"));
@ -13229,7 +13072,7 @@ class PartitionConnectionsByNetworkAnonymizationKey
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(PartitionConnectionsByNetworkAnonymizationKey,
TEST_F(PartitionConnectionsByNetworkAnonymizationKey,
DifferentTopFrameSitesNeverShareConnections) {
// Start server
EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
@ -13289,7 +13132,7 @@ TEST_P(PartitionConnectionsByNetworkAnonymizationKey,
}
}
TEST_P(PartitionConnectionsByNetworkAnonymizationKey,
TEST_F(PartitionConnectionsByNetworkAnonymizationKey,
FirstPartyIsSeparatedFromCrossSiteFrames) {
// Start server
EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
@ -13343,17 +13186,12 @@ TEST_P(PartitionConnectionsByNetworkAnonymizationKey,
d.RunUntilComplete();
EXPECT_THAT(d.request_status(), IsOk());
// We should only share a connection with r1 if double key
// NetworkAnonymizationKey scheme is enabled.
if (!IsCrossSiteFlagEnabled()) {
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, r2->ssl_info().handshake_type);
} else {
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, r2->ssl_info().handshake_type);
}
// We should not share a connection with r1.
EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, r2->ssl_info().handshake_type);
}
}
TEST_P(
TEST_F(
PartitionConnectionsByNetworkAnonymizationKey,
DifferentCrossSiteFramesAreSeparatedOnlyWhenNetworkAnonymizationKeyIsTripleKeyed) {
// Start server
@ -13415,7 +13253,7 @@ TEST_P(
}
}
TEST_P(PartitionConnectionsByNetworkAnonymizationKey,
TEST_F(PartitionConnectionsByNetworkAnonymizationKey,
DifferentNoncesAreAlwaysSeparated) {
// Start server
EmbeddedTestServer test_server(EmbeddedTestServer::TYPE_HTTPS);
@ -13479,8 +13317,4 @@ TEST_P(PartitionConnectionsByNetworkAnonymizationKey,
}
}
INSTANTIATE_TEST_SUITE_P(All,
PartitionConnectionsByNetworkAnonymizationKey,
testing::ValuesIn(kFlagsParam));
} // namespace net

@ -23,8 +23,7 @@ bool StructTraits<network::mojom::NetworkAnonymizationKeyDataView,
// Read is_cross_site boolean flag value.
absl::optional<bool> is_cross_site = absl::nullopt;
if (net::NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled() &&
top_frame_site.has_value()) {
if (top_frame_site.has_value()) {
is_cross_site = data.is_cross_site();
}

@ -29,9 +29,6 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
}
static bool is_cross_site(const net::NetworkAnonymizationKey& input) {
if (!net::NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled()) {
return false;
}
return input.GetIsCrossSite().value_or(false);
}

@ -15,38 +15,10 @@
#include "url/origin.h"
namespace mojo {
TEST(NetworkAnonymizationKeyMojomTraitsTest, SerializeAndDeserializeDoubleKey) {
// Enable double keying.
base::test::ScopedFeatureList scoped_feature_list_;
scoped_feature_list_.InitAndDisableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
base::UnguessableToken token = base::UnguessableToken::Create();
std::vector<net::NetworkAnonymizationKey> keys = {
net::NetworkAnonymizationKey(),
net::NetworkAnonymizationKey::CreateTransient(),
net::NetworkAnonymizationKey(net::SchemefulSite(GURL("http://a.test/")),
net::SchemefulSite(GURL("http://b.test/")),
&token),
net::NetworkAnonymizationKey(net::SchemefulSite(GURL("http://a.test/")))};
for (auto& original : keys) {
SCOPED_TRACE(original.ToDebugString());
net::NetworkAnonymizationKey copied;
EXPECT_TRUE(mojo::test::SerializeAndDeserialize<
network::mojom::NetworkAnonymizationKey>(original, copied));
EXPECT_EQ(original, copied);
}
}
// TODO(crbug.com/1371667): Test is failing.
TEST(NetworkAnonymizationKeyMojomTraitsTest,
DISABLED_SerializeAndDeserializeDoubleKeyWithCrossSiteFlag) {
// Enable double keying with cross site flag.
base::test::ScopedFeatureList scoped_feature_list_;
scoped_feature_list_.InitAndEnableFeature(
net::features::kEnableCrossSiteFlagNetworkAnonymizationKey);
base::UnguessableToken token = base::UnguessableToken::Create();
std::vector<net::NetworkAnonymizationKey> keys = {
net::NetworkAnonymizationKey(),

@ -10,9 +10,6 @@ import "services/network/public/mojom/schemeful_site.mojom";
// Mapped to net::NetworkAnonymizationKey.
struct NetworkAnonymizationKey {
SchemefulSite? top_frame_site;
// This has no effect unless
//`NetworkAnonymizationKey::IsCrossSiteFlagSchemeEnabled()`
// is true.
bool is_cross_site;
mojo_base.mojom.UnguessableToken? nonce;

@ -8902,7 +8902,6 @@
{
"name": "enabled_triple_nik_cross_site_flag_nak_rollout",
"enable_features": [
"EnableCrossSiteFlagNetworkAnonymizationKey",
"PartitionConnectionsByNetworkIsolationKey",
"PartitionDomainReliabilityByNetworkIsolationKey",
"PartitionHttpServerPropertiesByNetworkIsolationKey",