mirror of https://github.com/electron/electron
2360 lines
110 KiB
Diff
2360 lines
110 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Keeley Hammond <vertedinde@electronjs.org>
|
|
Date: Thu, 21 Sep 2023 16:21:29 -0700
|
|
Subject: fix: revert sameparty cookie attribute removal
|
|
|
|
The SameParty cookie attribute, which is used for same-party, cross-site
|
|
contexts with First Party Sets, has been removed upstream by Chrome, but is
|
|
depended on by some Electron consumers. This patch is meant to restore the
|
|
removed SameParty cookie origin trail functionality and supported methods, while
|
|
Chrome completes other API options to use in place of SameParty cookies.
|
|
|
|
This patch can be removed when Storage Access API cookie support or
|
|
equivalent support is completed upstream.
|
|
|
|
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
|
|
index 128e46bff2164d437b75cdb2ea9eb0c9967f3509..72a0667ea16c42ab6aa35c5e9e33aa912b5a26e3 100644
|
|
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
|
|
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.cc
|
|
@@ -116,6 +116,7 @@ void FirstPartySetsPolicyService::Init() {
|
|
void FirstPartySetsPolicyService::ComputeFirstPartySetMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
if (!is_enabled()) {
|
|
@@ -127,17 +128,18 @@ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadata(
|
|
on_ready_callbacks_.push_back(base::BindOnce(
|
|
&FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal,
|
|
weak_factory_.GetWeakPtr(), site, base::OptionalFromPtr(top_frame_site),
|
|
- std::move(callback)));
|
|
+ party_context, std::move(callback)));
|
|
return;
|
|
}
|
|
|
|
content::FirstPartySetsHandler::GetInstance()->ComputeFirstPartySetMetadata(
|
|
- site, top_frame_site, *config_, std::move(callback));
|
|
+ site, top_frame_site, party_context, *config_, std::move(callback));
|
|
}
|
|
|
|
void FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
CHECK(config_.has_value());
|
|
@@ -148,7 +150,8 @@ void FirstPartySetsPolicyService::ComputeFirstPartySetMetadataInternal(
|
|
}
|
|
|
|
content::FirstPartySetsHandler::GetInstance()->ComputeFirstPartySetMetadata(
|
|
- site, base::OptionalToPtr(top_frame_site), *config_, std::move(callback));
|
|
+ site, base::OptionalToPtr(top_frame_site), party_context, *config_,
|
|
+ std::move(callback));
|
|
}
|
|
|
|
void FirstPartySetsPolicyService::AddRemoteAccessDelegate(
|
|
diff --git a/chrome/browser/first_party_sets/first_party_sets_policy_service.h b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
|
|
index 1e0a49b7d2ec489f1be24a4bbcdd2741b789b85d..246d521b71d88c0e8a838a9711b7265fa59bf1ed 100644
|
|
--- a/chrome/browser/first_party_sets/first_party_sets_policy_service.h
|
|
+++ b/chrome/browser/first_party_sets/first_party_sets_policy_service.h
|
|
@@ -49,6 +49,7 @@ class FirstPartySetsPolicyService : public KeyedService {
|
|
void ComputeFirstPartySetMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
|
|
|
|
// Stores `access_delegate` in a RemoteSet for later IPC calls on it when this
|
|
@@ -152,6 +153,7 @@ class FirstPartySetsPolicyService : public KeyedService {
|
|
void ComputeFirstPartySetMetadataInternal(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
|
|
|
|
// Clears the content settings associated with `profile` that were
|
|
diff --git a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
|
|
index b0167e5b1c77f66809a47526a2c0dcfe9ea2928b..55705bf4286f6307c05da20f5e10a96dab43bf70 100644
|
|
--- a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
|
|
+++ b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.cc
|
|
@@ -9,6 +9,7 @@
|
|
#include "base/feature_list.h"
|
|
#include "base/functional/callback.h"
|
|
#include "base/task/sequenced_task_runner.h"
|
|
+#include "base/types/optional_util.h"
|
|
#include "content/public/browser/first_party_sets_handler.h"
|
|
#include "content/public/common/content_features.h"
|
|
#include "net/first_party_sets/first_party_set_metadata.h"
|
|
@@ -75,10 +76,11 @@ void ScopedMockFirstPartySetsHandler::ClearSiteDataOnChangedSetsForContext(
|
|
void ScopedMockFirstPartySetsHandler::ComputeFirstPartySetMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
net::FirstPartySetMetadata metadata =
|
|
- global_sets_.ComputeMetadata(site, top_frame_site, config);
|
|
+ global_sets_.ComputeMetadata(site, top_frame_site, party_context, config);
|
|
if (invoke_callbacks_asynchronously_) {
|
|
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
|
|
FROM_HERE, base::BindOnce(std::move(callback), std::move(metadata)));
|
|
diff --git a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
|
|
index a93e67a33f5ca5c845fa48606c8255ef51c4f5c8..817785f539deaa30621b76690de0db367565e922 100644
|
|
--- a/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
|
|
+++ b/chrome/browser/first_party_sets/scoped_mock_first_party_sets_handler.h
|
|
@@ -61,6 +61,7 @@ class ScopedMockFirstPartySetsHandler : public content::FirstPartySetsHandler {
|
|
void ComputeFirstPartySetMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) override;
|
|
|
|
diff --git a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
|
|
index 6d7f753d6c6d0197e63bb77356bc437778e01304..715eb5fddeb08bdc9aa06c3e6ebff43d60013109 100644
|
|
--- a/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
|
|
+++ b/chrome/browser/storage_access_api/storage_access_grant_permission_context.cc
|
|
@@ -301,6 +301,7 @@ void StorageAccessGrantPermissionContext::DecidePermission(
|
|
browser_context())
|
|
->ComputeFirstPartySetMetadata(
|
|
requesting_site, &embedding_site,
|
|
+ /*party_context=*/{},
|
|
base::BindOnce(&StorageAccessGrantPermissionContext::
|
|
CheckForAutoGrantOrAutoDenial,
|
|
weak_factory_.GetWeakPtr(), std::move(request_data),
|
|
diff --git a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
|
|
index 900e17bcf2d379facf8a6efd3b4e03fce8f00bab..994269dbab5b6afa6d548676b70128208575d039 100644
|
|
--- a/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
|
|
+++ b/chrome/browser/top_level_storage_access_api/top_level_storage_access_permission_context.cc
|
|
@@ -96,6 +96,7 @@ void TopLevelStorageAccessPermissionContext::DecidePermission(
|
|
browser_context())
|
|
->ComputeFirstPartySetMetadata(
|
|
requesting_site, &embedding_site,
|
|
+ /*party_context=*/{},
|
|
base::BindOnce(&TopLevelStorageAccessPermissionContext::
|
|
CheckForAutoGrantOrAutoDenial,
|
|
weak_factory_.GetWeakPtr(), std::move(request_data),
|
|
diff --git a/content/browser/cookie_store/cookie_change_subscription.cc b/content/browser/cookie_store/cookie_change_subscription.cc
|
|
index dbe3c5b8a6c83c5e8d26b109f24e77b4ab2e604e..fd51ab0f749b63fda2a7848594bb616fe6a48730 100644
|
|
--- a/content/browser/cookie_store/cookie_change_subscription.cc
|
|
+++ b/content/browser/cookie_store/cookie_change_subscription.cc
|
|
@@ -9,8 +9,10 @@
|
|
#include "content/browser/cookie_store/cookie_change_subscriptions.pb.h"
|
|
#include "content/public/browser/content_browser_client.h"
|
|
#include "content/public/common/content_client.h"
|
|
+#include "net/base/features.h"
|
|
#include "net/cookies/cookie_constants.h"
|
|
#include "net/cookies/cookie_util.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "services/network/public/cpp/is_potentially_trustworthy.h"
|
|
|
|
namespace content {
|
|
@@ -169,17 +171,26 @@ bool CookieChangeSubscription::ShouldObserveChangeTo(
|
|
break;
|
|
}
|
|
|
|
- // We assume that this is a same-site context.
|
|
+ // We assume that this is a same-site, same-party context.
|
|
net::CookieOptions net_options;
|
|
net_options.set_same_site_cookie_context(
|
|
net::CookieOptions::SameSiteCookieContext::MakeInclusive());
|
|
+ net_options.set_same_party_context(net::SamePartyContext::MakeInclusive());
|
|
+ // It doesn't matter which we choose here, since both SameParty and SameSite
|
|
+ // semantics should allow this access. But we make a choice to be explicit.
|
|
+ net_options.set_is_in_nontrivial_first_party_set(true);
|
|
|
|
return cookie
|
|
- .IncludeForRequestURL(url_, net_options,
|
|
- net::CookieAccessParams{
|
|
- access_semantics,
|
|
- network::IsUrlPotentiallyTrustworthy(url_),
|
|
- })
|
|
+ .IncludeForRequestURL(
|
|
+ url_, net_options,
|
|
+ net::CookieAccessParams{
|
|
+ access_semantics,
|
|
+ network::IsUrlPotentiallyTrustworthy(url_),
|
|
+ net::cookie_util::GetSamePartyStatus(
|
|
+ cookie, net_options,
|
|
+ base::FeatureList::IsEnabled(
|
|
+ net::features::kSamePartyAttributeEnabled)),
|
|
+ })
|
|
.status.IsInclude();
|
|
}
|
|
|
|
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
|
|
index 74737944f75cdc45b07ae110551ec4b2f250abc7..26a051883a10964168122f9b4ce8ac37f4efa006 100644
|
|
--- a/content/browser/devtools/protocol/network_handler.cc
|
|
+++ b/content/browser/devtools/protocol/network_handler.cc
|
|
@@ -783,6 +783,11 @@ GetProtocolBlockedSetCookieReason(net::CookieInclusionStatus status) {
|
|
blockedReasons->push_back(
|
|
Network::SetCookieBlockedReasonEnum::ThirdPartyBlockedInFirstPartySet);
|
|
}
|
|
+ if (status.HasExclusionReason(
|
|
+ net::CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT)) {
|
|
+ blockedReasons->push_back(
|
|
+ Network::SetCookieBlockedReasonEnum::SamePartyFromCrossPartyContext);
|
|
+ }
|
|
if (status.HasExclusionReason(
|
|
net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE)) {
|
|
blockedReasons->push_back(Network::SetCookieBlockedReasonEnum::SyntaxError);
|
|
@@ -807,6 +812,11 @@ GetProtocolBlockedSetCookieReason(net::CookieInclusionStatus status) {
|
|
blockedReasons->push_back(
|
|
Network::SetCookieBlockedReasonEnum::InvalidPrefix);
|
|
}
|
|
+ if (status.HasExclusionReason(
|
|
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY)) {
|
|
+ blockedReasons->push_back(Network::SetCookieBlockedReasonEnum::
|
|
+ SamePartyConflictsWithOtherAttributes);
|
|
+ }
|
|
if (status.HasExclusionReason(net::CookieInclusionStatus::
|
|
EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE)) {
|
|
blockedReasons->push_back(
|
|
@@ -889,6 +899,11 @@ GetProtocolBlockedCookieReason(net::CookieInclusionStatus status) {
|
|
blockedReasons->push_back(
|
|
Network::CookieBlockedReasonEnum::ThirdPartyBlockedInFirstPartySet);
|
|
}
|
|
+ if (status.HasExclusionReason(
|
|
+ net::CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT)) {
|
|
+ blockedReasons->push_back(
|
|
+ Network::CookieBlockedReasonEnum::SamePartyFromCrossPartyContext);
|
|
+ }
|
|
if (status.HasExclusionReason(net::CookieInclusionStatus::
|
|
EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE)) {
|
|
blockedReasons->push_back(
|
|
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.cc b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
|
|
index cefd0827b70fb092012d37357ad20444655db9a2..fef5f9ee7c9e3d005d1e366a332e408a1b4cab22 100644
|
|
--- a/content/browser/first_party_sets/first_party_sets_handler_impl.cc
|
|
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.cc
|
|
@@ -443,6 +443,7 @@ void FirstPartySetsHandlerImpl::DidClearSiteDataOnChangedSetsForContext(
|
|
void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
@@ -450,17 +451,19 @@ void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadata(
|
|
EnqueuePendingTask(base::BindOnce(
|
|
&FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal,
|
|
base::Unretained(this), site, base::OptionalFromPtr(top_frame_site),
|
|
- config.Clone(), base::ElapsedTimer(), std::move(callback)));
|
|
+ party_context, config.Clone(), base::ElapsedTimer(),
|
|
+ std::move(callback)));
|
|
return;
|
|
}
|
|
|
|
- std::move(callback).Run(
|
|
- global_sets_->ComputeMetadata(site, top_frame_site, config));
|
|
+ std::move(callback).Run(global_sets_->ComputeMetadata(site, top_frame_site,
|
|
+ party_context, config));
|
|
}
|
|
|
|
void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& config,
|
|
const base::ElapsedTimer& timer,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
@@ -472,7 +475,7 @@ void FirstPartySetsHandlerImpl::ComputeFirstPartySetMetadataInternal(
|
|
timer.Elapsed());
|
|
|
|
std::move(callback).Run(global_sets_->ComputeMetadata(
|
|
- site, base::OptionalToPtr(top_frame_site), config));
|
|
+ site, base::OptionalToPtr(top_frame_site), party_context, config));
|
|
}
|
|
|
|
net::FirstPartySetsContextConfig
|
|
diff --git a/content/browser/first_party_sets/first_party_sets_handler_impl.h b/content/browser/first_party_sets/first_party_sets_handler_impl.h
|
|
index 877f713c77542d0aab7d9bcd309c9346f97467f5..61e0cc95484e8fb1396d6734f73745b7c7ae16b5 100644
|
|
--- a/content/browser/first_party_sets/first_party_sets_handler_impl.h
|
|
+++ b/content/browser/first_party_sets/first_party_sets_handler_impl.h
|
|
@@ -110,6 +110,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
|
|
void ComputeFirstPartySetMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) override;
|
|
|
|
@@ -174,6 +175,7 @@ class CONTENT_EXPORT FirstPartySetsHandlerImpl : public FirstPartySetsHandler {
|
|
void ComputeFirstPartySetMetadataInternal(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite>& top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& config,
|
|
const base::ElapsedTimer& timer,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
|
|
diff --git a/content/browser/renderer_host/cookie_utils.cc b/content/browser/renderer_host/cookie_utils.cc
|
|
index 47707316874d2c23948c804321abea17a5300bf5..71d3ac287ef911589391c6fa6f1cdf9b2c1f5234 100644
|
|
--- a/content/browser/renderer_host/cookie_utils.cc
|
|
+++ b/content/browser/renderer_host/cookie_utils.cc
|
|
@@ -104,6 +104,8 @@ void RecordSchemefulContextDowngradeUKM(
|
|
bool ShouldReportDevToolsIssueForStatus(
|
|
const net::CookieInclusionStatus& status) {
|
|
return status.ShouldWarn() ||
|
|
+ status.HasExclusionReason(
|
|
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY) ||
|
|
status.HasExclusionReason(
|
|
net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII) ||
|
|
status.HasExclusionReason(
|
|
@@ -173,6 +175,10 @@ void EmitCookieWarningsAndMetrics(
|
|
bool breaking_context_downgrade = false;
|
|
bool lax_allow_unsafe_cookies = false;
|
|
|
|
+ bool same_party = false;
|
|
+ bool same_party_exclusion_overruled_samesite = false;
|
|
+ bool same_party_inclusion_overruled_samesite = false;
|
|
+
|
|
bool samesite_cookie_inclusion_changed_by_cross_site_redirect = false;
|
|
|
|
bool partitioned_cookies_exist = false;
|
|
@@ -217,6 +223,22 @@ void EmitCookieWarningsAndMetrics(
|
|
net::CookieInclusionStatus::
|
|
WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
|
|
|
|
+ same_party = same_party ||
|
|
+ status.HasWarningReason(
|
|
+ net::CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
|
|
+
|
|
+ same_party_exclusion_overruled_samesite =
|
|
+ same_party_exclusion_overruled_samesite ||
|
|
+ status.HasWarningReason(
|
|
+ net::CookieInclusionStatus::
|
|
+ WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
|
|
+
|
|
+ same_party_inclusion_overruled_samesite =
|
|
+ same_party_inclusion_overruled_samesite ||
|
|
+ status.HasWarningReason(
|
|
+ net::CookieInclusionStatus::
|
|
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
|
|
+
|
|
samesite_cookie_inclusion_changed_by_cross_site_redirect =
|
|
samesite_cookie_inclusion_changed_by_cross_site_redirect ||
|
|
status.HasWarningReason(
|
|
@@ -304,6 +326,23 @@ void EmitCookieWarningsAndMetrics(
|
|
rfh, blink::mojom::WebFeature::kLaxAllowingUnsafeCookies);
|
|
}
|
|
|
|
+ if (same_party) {
|
|
+ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
+ rfh, blink::mojom::WebFeature::kSamePartyCookieAttribute);
|
|
+ }
|
|
+
|
|
+ if (same_party_exclusion_overruled_samesite) {
|
|
+ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
+ rfh,
|
|
+ blink::mojom::WebFeature::kSamePartyCookieExclusionOverruledSameSite);
|
|
+ }
|
|
+
|
|
+ if (same_party_inclusion_overruled_samesite) {
|
|
+ GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
+ rfh,
|
|
+ blink::mojom::WebFeature::kSamePartyCookieInclusionOverruledSameSite);
|
|
+ }
|
|
+
|
|
if (samesite_cookie_inclusion_changed_by_cross_site_redirect) {
|
|
GetContentClient()->browser()->LogWebFeatureForCurrentPage(
|
|
rfh, blink::mojom::WebFeature::
|
|
diff --git a/content/public/browser/first_party_sets_handler.h b/content/public/browser/first_party_sets_handler.h
|
|
index 6d829bf3aec1abd6747492d1bf9b82e8081946af..6814bcf8f4d7549cb026743b94c93f0f9d8a5e6f 100644
|
|
--- a/content/public/browser/first_party_sets_handler.h
|
|
+++ b/content/public/browser/first_party_sets_handler.h
|
|
@@ -195,6 +195,7 @@ class CONTENT_EXPORT FirstPartySetsHandler {
|
|
virtual void ComputeFirstPartySetMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) = 0;
|
|
};
|
|
diff --git a/net/BUILD.gn b/net/BUILD.gn
|
|
index f0493cfd8456000f88f1536e908fdc8ace227a28..68a30283eda63918f14efcc4cb40971180dc6ea8 100644
|
|
--- a/net/BUILD.gn
|
|
+++ b/net/BUILD.gn
|
|
@@ -584,6 +584,8 @@ component("net") {
|
|
"first_party_sets/first_party_sets_context_config.h",
|
|
"first_party_sets/global_first_party_sets.cc",
|
|
"first_party_sets/global_first_party_sets.h",
|
|
+ "first_party_sets/same_party_context.cc",
|
|
+ "first_party_sets/same_party_context.h",
|
|
"http/alternative_service.cc",
|
|
"http/alternative_service.h",
|
|
"http/bidirectional_stream.cc",
|
|
diff --git a/net/base/features.cc b/net/base/features.cc
|
|
index 1745b75fcc07c17602c3aaa3494e8fedb9f40431..1c660a21ec29a49b78792ba11f27bda0272487c6 100644
|
|
--- a/net/base/features.cc
|
|
+++ b/net/base/features.cc
|
|
@@ -247,6 +247,10 @@ BASE_FEATURE(kCookieSameSiteConsidersRedirectChain,
|
|
"CookieSameSiteConsidersRedirectChain",
|
|
base::FEATURE_DISABLED_BY_DEFAULT);
|
|
|
|
+BASE_FEATURE(kSamePartyAttributeEnabled,
|
|
+ "SamePartyAttributeEnabled",
|
|
+ base::FEATURE_DISABLED_BY_DEFAULT);
|
|
+
|
|
BASE_FEATURE(kWaitForFirstPartySetsInit,
|
|
"WaitForFirstPartySetsInit",
|
|
base::FEATURE_ENABLED_BY_DEFAULT);
|
|
diff --git a/net/base/features.h b/net/base/features.h
|
|
index a5fa693d239a542da6431a5eb6023c5804a5e1d7..6dd3ad7782944bd459bb2aecc8677db115e471f2 100644
|
|
--- a/net/base/features.h
|
|
+++ b/net/base/features.h
|
|
@@ -297,6 +297,12 @@ NET_EXPORT BASE_DECLARE_FEATURE(kUdpSocketPosixAlwaysUpdateBytesReceived);
|
|
// See spec changes in https://github.com/httpwg/http-extensions/pull/1348
|
|
NET_EXPORT BASE_DECLARE_FEATURE(kCookieSameSiteConsidersRedirectChain);
|
|
|
|
+// When this feature is enabled, the SameParty attribute is enabled. (Note that
|
|
+// when this feature is disabled, the SameParty attribute is still parsed and
|
|
+// saved for cookie-sets, but it has no associated semantics (when setting or
|
|
+// reading cookies).)
|
|
+NET_EXPORT BASE_DECLARE_FEATURE(kSamePartyAttributeEnabled);
|
|
+
|
|
// When this feature is enabled, the network service will wait until First-Party
|
|
// Sets are initialized before issuing requests that use the HTTP cache or
|
|
// cookies.
|
|
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
|
|
index 089443aab299000b7a10b42b90f3367318aa7730..cc2742ff7d3b04e42988b5e0e927d91af5c12389 100644
|
|
--- a/net/cookies/canonical_cookie.cc
|
|
+++ b/net/cookies/canonical_cookie.cc
|
|
@@ -339,9 +339,11 @@ bool HasValidHostPrefixAttributes(const GURL& url,
|
|
} // namespace
|
|
|
|
CookieAccessParams::CookieAccessParams(CookieAccessSemantics access_semantics,
|
|
- bool delegate_treats_url_as_trustworthy)
|
|
+ bool delegate_treats_url_as_trustworthy,
|
|
+ CookieSamePartyStatus same_party_status)
|
|
: access_semantics(access_semantics),
|
|
- delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy) {}
|
|
+ delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy),
|
|
+ same_party_status(same_party_status) {}
|
|
|
|
CanonicalCookie::CanonicalCookie() = default;
|
|
|
|
@@ -614,6 +616,12 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
|
|
status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
|
|
}
|
|
|
|
+ bool is_same_party_valid = IsCookieSamePartyValid(parsed_cookie);
|
|
+ if (!is_same_party_valid) {
|
|
+ status->AddExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
|
|
+ }
|
|
+
|
|
bool partition_has_nonce = CookiePartitionKey::HasNonce(cookie_partition_key);
|
|
bool is_partitioned_valid =
|
|
IsCookiePartitionedValid(url, parsed_cookie, partition_has_nonce);
|
|
@@ -879,6 +887,10 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
|
|
net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
|
|
}
|
|
|
|
+ if (!IsCookieSamePartyValid(same_party, secure, same_site)) {
|
|
+ status->AddExclusionReason(
|
|
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
|
|
+ }
|
|
if (!IsCookiePartitionedValid(url, secure,
|
|
/*is_partitioned=*/partition_key.has_value(),
|
|
/*partition_has_nonce=*/
|
|
@@ -1180,11 +1192,56 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL(
|
|
CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
|
|
}
|
|
|
|
- // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
- ApplySameSiteCookieWarningToStatus(SameSite(), effective_same_site,
|
|
- IsSecure(),
|
|
- options.same_site_cookie_context(),
|
|
- &status, false /* is_cookie_being_set */);
|
|
+ switch (params.same_party_status) {
|
|
+ case CookieSamePartyStatus::kEnforceSamePartyExclude:
|
|
+ DCHECK(IsSameParty());
|
|
+ status.AddExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
|
|
+ [[fallthrough]];
|
|
+ case CookieSamePartyStatus::kEnforceSamePartyInclude: {
|
|
+ status.AddWarningReason(CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
|
|
+ // Remove any SameSite exclusion reasons, since SameParty overrides
|
|
+ // SameSite.
|
|
+ DCHECK(!status.HasExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
|
|
+ DCHECK_NE(effective_same_site, CookieEffectiveSameSite::STRICT_MODE);
|
|
+ bool included_by_samesite =
|
|
+ !status.HasExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
|
|
+ !status.HasExclusionReason(
|
|
+ CookieInclusionStatus::
|
|
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
|
|
+ if (!included_by_samesite) {
|
|
+ status.RemoveExclusionReasons({
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
|
+ });
|
|
+ }
|
|
+
|
|
+ // Update metrics.
|
|
+ if (status.HasOnlyExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
|
|
+ included_by_samesite) {
|
|
+ status.AddWarningReason(
|
|
+ CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
|
|
+ }
|
|
+ if (status.IsInclude()) {
|
|
+ if (!included_by_samesite) {
|
|
+ status.AddWarningReason(
|
|
+ CookieInclusionStatus::
|
|
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case CookieSamePartyStatus::kNoSamePartyEnforcement:
|
|
+ // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
+ ApplySameSiteCookieWarningToStatus(
|
|
+ SameSite(), effective_same_site, IsSecure(),
|
|
+ options.same_site_cookie_context(), &status,
|
|
+ false /* is_cookie_being_set */);
|
|
+ break;
|
|
+ }
|
|
|
|
if (status.IsInclude()) {
|
|
UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedRequestEffectiveSameSite",
|
|
@@ -1354,11 +1411,59 @@ CookieAccessResult CanonicalCookie::IsSetPermittedInContext(
|
|
break;
|
|
}
|
|
|
|
- // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
- ApplySameSiteCookieWarningToStatus(
|
|
- SameSite(), access_result.effective_same_site, IsSecure(),
|
|
- options.same_site_cookie_context(), &access_result.status,
|
|
- true /* is_cookie_being_set */);
|
|
+ switch (params.same_party_status) {
|
|
+ case CookieSamePartyStatus::kEnforceSamePartyExclude:
|
|
+ DCHECK(IsSameParty());
|
|
+ access_result.status.AddExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
|
|
+ [[fallthrough]];
|
|
+ case CookieSamePartyStatus::kEnforceSamePartyInclude: {
|
|
+ DCHECK(IsSameParty());
|
|
+ access_result.status.AddWarningReason(
|
|
+ CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
|
|
+ // Remove any SameSite exclusion reasons, since SameParty overrides
|
|
+ // SameSite.
|
|
+ DCHECK(!access_result.status.HasExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
|
|
+ DCHECK_NE(access_result.effective_same_site,
|
|
+ CookieEffectiveSameSite::STRICT_MODE);
|
|
+ bool included_by_samesite =
|
|
+ !access_result.status.HasExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
|
|
+ !access_result.status.HasExclusionReason(
|
|
+ CookieInclusionStatus::
|
|
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
|
|
+ if (!included_by_samesite) {
|
|
+ access_result.status.RemoveExclusionReasons({
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
|
|
+ CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
|
+ });
|
|
+ }
|
|
+
|
|
+ // Update metrics.
|
|
+ if (access_result.status.HasOnlyExclusionReason(
|
|
+ CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
|
|
+ included_by_samesite) {
|
|
+ access_result.status.AddWarningReason(
|
|
+ CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
|
|
+ }
|
|
+ if (access_result.status.IsInclude()) {
|
|
+ if (!included_by_samesite) {
|
|
+ access_result.status.AddWarningReason(
|
|
+ CookieInclusionStatus::
|
|
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case CookieSamePartyStatus::kNoSamePartyEnforcement:
|
|
+ // Only apply SameSite-related warnings if SameParty is not in effect.
|
|
+ ApplySameSiteCookieWarningToStatus(
|
|
+ SameSite(), access_result.effective_same_site, IsSecure(),
|
|
+ options.same_site_cookie_context(), &access_result.status,
|
|
+ true /* is_cookie_being_set */);
|
|
+ break;
|
|
+ }
|
|
|
|
if (access_result.status.IsInclude()) {
|
|
UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedResponseEffectiveSameSite",
|
|
@@ -1465,6 +1570,9 @@ bool CanonicalCookie::IsCanonicalForFromStorage() const {
|
|
if (name_ == "" && HasHiddenPrefixName(value_))
|
|
return false;
|
|
|
|
+ if (!IsCookieSamePartyValid(same_party_, secure_, same_site_))
|
|
+ return false;
|
|
+
|
|
if (IsPartitioned()) {
|
|
if (CookiePartitionKey::HasNonce(partition_key_))
|
|
return true;
|
|
@@ -1711,6 +1819,23 @@ bool CanonicalCookie::IsRecentlyCreated(base::TimeDelta age_threshold) const {
|
|
return (base::Time::Now() - creation_date_) <= age_threshold;
|
|
}
|
|
|
|
+// static
|
|
+bool CanonicalCookie::IsCookieSamePartyValid(
|
|
+ const ParsedCookie& parsed_cookie) {
|
|
+ return IsCookieSamePartyValid(parsed_cookie.IsSameParty(),
|
|
+ parsed_cookie.IsSecure(),
|
|
+ parsed_cookie.SameSite());
|
|
+}
|
|
+
|
|
+// static
|
|
+bool CanonicalCookie::IsCookieSamePartyValid(bool is_same_party,
|
|
+ bool is_secure,
|
|
+ CookieSameSite same_site) {
|
|
+ if (!is_same_party)
|
|
+ return true;
|
|
+ return is_secure && (same_site != CookieSameSite::STRICT_MODE);
|
|
+}
|
|
+
|
|
// static
|
|
bool CanonicalCookie::IsCookiePartitionedValid(
|
|
const GURL& url,
|
|
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
|
|
index 6a86240fd610b1c1148e5df39c2243f715d10975..5744b3644a615ba256573887047e2f3917123b96 100644
|
|
--- a/net/cookies/canonical_cookie.h
|
|
+++ b/net/cookies/canonical_cookie.h
|
|
@@ -43,7 +43,8 @@ using CookieAccessResultList = std::vector<CookieWithAccessResult>;
|
|
struct NET_EXPORT CookieAccessParams {
|
|
CookieAccessParams() = delete;
|
|
CookieAccessParams(CookieAccessSemantics access_semantics,
|
|
- bool delegate_treats_url_as_trustworthy);
|
|
+ bool delegate_treats_url_as_trustworthy,
|
|
+ CookieSamePartyStatus same_party_status);
|
|
|
|
// |access_semantics| is the access mode of the cookie access check.
|
|
CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN;
|
|
@@ -51,6 +52,10 @@ struct NET_EXPORT CookieAccessParams {
|
|
// CookieAccessDelegate has authorized access to secure cookies from URLs
|
|
// which might not otherwise be able to do so.
|
|
bool delegate_treats_url_as_trustworthy = false;
|
|
+ // |same_party_status| indicates whether, and how, SameParty restrictions
|
|
+ // should be enforced.
|
|
+ CookieSamePartyStatus same_party_status =
|
|
+ CookieSamePartyStatus::kNoSamePartyEnforcement;
|
|
};
|
|
|
|
class NET_EXPORT CanonicalCookie {
|
|
@@ -537,6 +542,14 @@ class NET_EXPORT CanonicalCookie {
|
|
// Returns whether the cookie was created at most |age_threshold| ago.
|
|
bool IsRecentlyCreated(base::TimeDelta age_threshold) const;
|
|
|
|
+ // Returns true iff the cookie does not violate any rules associated with
|
|
+ // creating a cookie with the SameParty attribute. In particular, if a cookie
|
|
+ // has SameParty, then it must be Secure and must not be SameSite=Strict.
|
|
+ static bool IsCookieSamePartyValid(const ParsedCookie& parsed_cookie);
|
|
+ static bool IsCookieSamePartyValid(bool is_same_party,
|
|
+ bool is_secure,
|
|
+ CookieSameSite same_site);
|
|
+
|
|
// Returns true iff the cookie is a partitioned cookie with a nonce or that
|
|
// does not violate the semantics of the Partitioned attribute:
|
|
// - Must have the Secure attribute OR the cookie partition contains a nonce.
|
|
diff --git a/net/cookies/cookie_access_delegate.cc b/net/cookies/cookie_access_delegate.cc
|
|
index 256dd856cce9fb482926f7a0c8bb80676a37e0e7..9811f944fff0a20a1a7b431e214f3578ed30785b 100644
|
|
--- a/net/cookies/cookie_access_delegate.cc
|
|
+++ b/net/cookies/cookie_access_delegate.cc
|
|
@@ -4,7 +4,13 @@
|
|
|
|
#include "net/cookies/cookie_access_delegate.h"
|
|
|
|
-class GURL;
|
|
+#include <set>
|
|
+
|
|
+#include "base/functional/callback.h"
|
|
+#include "net/base/schemeful_site.h"
|
|
+#include "net/cookies/cookie_partition_key.h"
|
|
+#include "net/first_party_sets/first_party_set_entry.h"
|
|
+#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
|
namespace net {
|
|
|
|
diff --git a/net/cookies/cookie_access_delegate.h b/net/cookies/cookie_access_delegate.h
|
|
index 203434ee5d078284e396c5711617ec0dd7f2e174..ee8e3d0fab27ef7f087194ad8fcfb6f17b042592 100644
|
|
--- a/net/cookies/cookie_access_delegate.h
|
|
+++ b/net/cookies/cookie_access_delegate.h
|
|
@@ -5,6 +5,8 @@
|
|
#ifndef NET_COOKIES_COOKIE_ACCESS_DELEGATE_H_
|
|
#define NET_COOKIES_COOKIE_ACCESS_DELEGATE_H_
|
|
|
|
+#include <set>
|
|
+
|
|
#include "base/containers/flat_map.h"
|
|
#include "base/containers/flat_set.h"
|
|
#include "base/functional/callback_forward.h"
|
|
@@ -15,6 +17,7 @@
|
|
#include "net/cookies/cookie_partition_key.h"
|
|
#include "net/first_party_sets/first_party_set_entry.h"
|
|
#include "net/first_party_sets/first_party_set_metadata.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
#include "url/gurl.h"
|
|
|
|
@@ -49,8 +52,10 @@ class NET_EXPORT CookieAccessDelegate {
|
|
const GURL& url,
|
|
const SiteForCookies& site_for_cookies) const = 0;
|
|
|
|
- // Calls `callback` with First-Party Sets metadata about `site` and
|
|
- // `top_frame_site`.
|
|
+ // Calls `callback` with metadata indicating whether `site` is same-party with
|
|
+ // `party_context` and `top_frame_site`; and `site`'s owner, if applicable..
|
|
+ // If `top_frame_site` is nullptr, then `site` will be checked only against
|
|
+ // `party_context`.
|
|
//
|
|
// This may return a result synchronously, or asynchronously invoke `callback`
|
|
// with the result. The callback will be invoked iff the return value is
|
|
@@ -60,6 +65,7 @@ class NET_EXPORT CookieAccessDelegate {
|
|
ComputeFirstPartySetMetadataMaybeAsync(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(FirstPartySetMetadata)> callback) const = 0;
|
|
|
|
// Returns the entries of a set of sites if the sites are in non-trivial sets.
|
|
diff --git a/net/cookies/cookie_constants.h b/net/cookies/cookie_constants.h
|
|
index 725517694b1eda27181e683be3b631ebecb63486..5a7913ca669eabafb9fef59267a1b40632e11165 100644
|
|
--- a/net/cookies/cookie_constants.h
|
|
+++ b/net/cookies/cookie_constants.h
|
|
@@ -118,6 +118,16 @@ enum class CookieAccessSemantics {
|
|
LEGACY,
|
|
};
|
|
|
|
+enum class CookieSamePartyStatus {
|
|
+ // Used when there should be no SameParty enforcement (either because the
|
|
+ // cookie is not marked SameParty, or the enforcement is irrelevant).
|
|
+ kNoSamePartyEnforcement = 0,
|
|
+ // Used when SameParty enforcement says to exclude the cookie.
|
|
+ kEnforceSamePartyExclude = 1,
|
|
+ // Used when SameParty enforcement says to include the cookie.
|
|
+ kEnforceSamePartyInclude = 2,
|
|
+};
|
|
+
|
|
// What scheme was used in the setting of a cookie.
|
|
// Do not renumber.
|
|
enum class CookieSourceScheme {
|
|
diff --git a/net/cookies/cookie_inclusion_status.cc b/net/cookies/cookie_inclusion_status.cc
|
|
index 117fca1e81b6a77bd787368151ed984648e20175..d23a2ac82762667e332abc414fe0c25c4d47f09e 100644
|
|
--- a/net/cookies/cookie_inclusion_status.cc
|
|
+++ b/net/cookies/cookie_inclusion_status.cc
|
|
@@ -231,6 +231,9 @@ std::string CookieInclusionStatus::GetDebugString() const {
|
|
{EXCLUDE_SHADOWING_DOMAIN, "EXCLUDE_SHADOWING_DOMAIN"},
|
|
{EXCLUDE_DISALLOWED_CHARACTER, "EXCLUDE_DISALLOWED_CHARACTER"},
|
|
{EXCLUDE_THIRD_PARTY_PHASEOUT, "EXCLUDE_THIRD_PARTY_PHASEOUT"},
|
|
+ {EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT,
|
|
+ "EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT"},
|
|
+ {EXCLUDE_INVALID_SAMEPARTY, "EXCLUDE_INVALID_SAMEPARTY"},
|
|
};
|
|
static_assert(
|
|
std::size(exclusion_reasons) == ExclusionReason::NUM_EXCLUSION_REASONS,
|
|
@@ -280,6 +283,11 @@ std::string CookieInclusionStatus::GetDebugString() const {
|
|
"WARN_TENTATIVELY_ALLOWING_SECURE_SOURCE_SCHEME"},
|
|
{WARN_SHADOWING_DOMAIN, "WARN_SHADOWING_DOMAIN"},
|
|
{WARN_THIRD_PARTY_PHASEOUT, "WARN_THIRD_PARTY_PHASEOUT"},
|
|
+ {WARN_TREATED_AS_SAMEPARTY, "WARN_TREATED_AS_SAMEPARTY"},
|
|
+ {WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE,
|
|
+ "WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE"},
|
|
+ {WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE,
|
|
+ "WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE"},
|
|
};
|
|
static_assert(
|
|
std::size(warning_reasons) == WarningReason::NUM_WARNING_REASONS,
|
|
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h
|
|
index e197c984d721171f5a131a1a7a8913cc9292719b..566e94489cbac6f0fa3d325a636ea1b71fb5615e 100644
|
|
--- a/net/cookies/cookie_inclusion_status.h
|
|
+++ b/net/cookies/cookie_inclusion_status.h
|
|
@@ -107,6 +107,12 @@ class NET_EXPORT CookieInclusionStatus {
|
|
EXCLUDE_DISALLOWED_CHARACTER = 24,
|
|
// Cookie is blocked for third-party cookie phaseout.
|
|
EXCLUDE_THIRD_PARTY_PHASEOUT = 25,
|
|
+ // The cookie specified SameParty, but was used in a cross-party context.
|
|
+ EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT = 26,
|
|
+ // Cookie was set with an invalid SameParty attribute in combination with
|
|
+ // other attributes. (SameParty is invalid if Secure is not present, or if
|
|
+ // SameSite=Strict is present.)
|
|
+ EXCLUDE_INVALID_SAMEPARTY = 27,
|
|
|
|
// This should be kept last.
|
|
NUM_EXCLUSION_REASONS
|
|
@@ -226,6 +232,24 @@ class NET_EXPORT CookieInclusionStatus {
|
|
// This cookie will be blocked for third-party cookie phaseout.
|
|
WARN_THIRD_PARTY_PHASEOUT = 16,
|
|
|
|
+ // The cookie was treated as SameParty. This is different from looking at
|
|
+ // whether the cookie has the SameParty attribute, since we may choose to
|
|
+ // ignore that attribute for one reason or another. E.g., we ignore the
|
|
+ // SameParty attribute if the site is not a member of a nontrivial
|
|
+ // First-Party Set.
|
|
+ WARN_TREATED_AS_SAMEPARTY = 17,
|
|
+
|
|
+ // The cookie was excluded solely for SameParty reasons (i.e. it was in
|
|
+ // cross-party context), but would have been included by SameSite. (This can
|
|
+ // only occur in cross-party, cross-site contexts, for cookies that are
|
|
+ // 'SameParty; SameSite=None'.)
|
|
+ WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE = 18,
|
|
+
|
|
+ // The cookie was included due to SameParty, even though it would have been
|
|
+ // excluded by SameSite. (This can only occur in same-party, cross-site
|
|
+ // contexts, for cookies that are 'SameParty; SameSite=Lax'.)
|
|
+ WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE = 19,
|
|
+
|
|
// This should be kept last.
|
|
NUM_WARNING_REASONS
|
|
};
|
|
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
|
|
index 0c3ce2e289b5944d38315790cca829e851c31e19..5c4352bb9fc1fd85373ee413b59a12967bd02710 100644
|
|
--- a/net/cookies/cookie_monster.cc
|
|
+++ b/net/cookies/cookie_monster.cc
|
|
@@ -377,7 +377,9 @@ CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
|
|
CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
|
|
base::TimeDelta last_access_threshold,
|
|
NetLog* net_log)
|
|
- : change_dispatcher_(this),
|
|
+ : same_party_attribute_enabled_(base::FeatureList::IsEnabled(
|
|
+ net::features::kSamePartyAttributeEnabled)),
|
|
+ change_dispatcher_(this, same_party_attribute_enabled_),
|
|
net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
|
|
store_(std::move(store)),
|
|
last_access_threshold_(last_access_threshold),
|
|
@@ -739,9 +741,13 @@ bool CookieMonster::MatchCookieDeletionInfo(
|
|
delete_info.url.value());
|
|
}
|
|
|
|
+ // Deletion uses all inclusive options, so it's ok to get the
|
|
+ // `CookieSamePartyStatus` wrong here.
|
|
return delete_info.Matches(
|
|
- cookie, CookieAccessParams{GetAccessSemanticsForCookie(cookie),
|
|
- delegate_treats_url_as_trustworthy});
|
|
+ cookie,
|
|
+ CookieAccessParams{GetAccessSemanticsForCookie(cookie),
|
|
+ delegate_treats_url_as_trustworthy,
|
|
+ CookieSamePartyStatus::kNoSamePartyEnforcement});
|
|
}
|
|
|
|
void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
|
|
@@ -1205,8 +1211,11 @@ void CookieMonster::FilterCookiesWithOptions(
|
|
// cookie |options|.
|
|
CookieAccessResult access_result = cookie_ptr->IncludeForRequestURL(
|
|
url, options,
|
|
- CookieAccessParams{GetAccessSemanticsForCookie(*cookie_ptr),
|
|
- delegate_treats_url_as_trustworthy});
|
|
+ CookieAccessParams{
|
|
+ GetAccessSemanticsForCookie(*cookie_ptr),
|
|
+ delegate_treats_url_as_trustworthy,
|
|
+ cookie_util::GetSamePartyStatus(*cookie_ptr, options,
|
|
+ same_party_attribute_enabled_)});
|
|
cookies_and_access_results.emplace_back(cookie_ptr, access_result);
|
|
|
|
// Record the names of all origin cookies that would be included if both
|
|
@@ -1549,7 +1558,9 @@ void CookieMonster::SetCanonicalCookie(
|
|
CookieAccessResult access_result = cc->IsSetPermittedInContext(
|
|
source_url, options,
|
|
CookieAccessParams(GetAccessSemanticsForCookie(*cc),
|
|
- delegate_treats_url_as_trustworthy),
|
|
+ delegate_treats_url_as_trustworthy,
|
|
+ cookie_util::GetSamePartyStatus(
|
|
+ *cc, options, same_party_attribute_enabled_)),
|
|
cookieable_schemes_, cookie_access_result);
|
|
|
|
const std::string key(GetKey(cc->Domain()));
|
|
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
|
|
index 3ca2c691cfd00acf34f7648dfc6c9f6692be470a..6086953c99f55bd8a1034f0fa33ea77e4af9ec0d 100644
|
|
--- a/net/cookies/cookie_monster.h
|
|
+++ b/net/cookies/cookie_monster.h
|
|
@@ -734,6 +734,8 @@ class NET_EXPORT CookieMonster : public CookieStore {
|
|
// nonce.
|
|
size_t num_nonced_partitioned_cookie_bytes_ = 0u;
|
|
|
|
+ bool same_party_attribute_enabled_ = false;
|
|
+
|
|
CookieMonsterChangeDispatcher change_dispatcher_;
|
|
|
|
// Indicates whether the cookie store has been initialized.
|
|
diff --git a/net/cookies/cookie_monster_change_dispatcher.cc b/net/cookies/cookie_monster_change_dispatcher.cc
|
|
index 61bd41e5a273e9d8d467deb587794600257feae6..34448cfee892b93558016c4fba22123c9522f6c4 100644
|
|
--- a/net/cookies/cookie_monster_change_dispatcher.cc
|
|
+++ b/net/cookies/cookie_monster_change_dispatcher.cc
|
|
@@ -37,6 +37,7 @@ CookieMonsterChangeDispatcher::Subscription::Subscription(
|
|
std::string name_key,
|
|
GURL url,
|
|
CookiePartitionKeyCollection cookie_partition_key_collection,
|
|
+ bool same_party_attribute_enabled,
|
|
net::CookieChangeCallback callback)
|
|
: change_dispatcher_(std::move(change_dispatcher)),
|
|
domain_key_(std::move(domain_key)),
|
|
@@ -45,6 +46,7 @@ CookieMonsterChangeDispatcher::Subscription::Subscription(
|
|
cookie_partition_key_collection_(
|
|
std::move(cookie_partition_key_collection)),
|
|
callback_(std::move(callback)),
|
|
+ same_party_attribute_enabled_(same_party_attribute_enabled),
|
|
task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
|
|
DCHECK(url_.is_valid() || url_.is_empty());
|
|
DCHECK_EQ(url_.is_empty(), domain_key_ == kGlobalDomainKey);
|
|
@@ -73,11 +75,14 @@ void CookieMonsterChangeDispatcher::Subscription::DispatchChange(
|
|
cookie_access_delegate &&
|
|
cookie_access_delegate->ShouldTreatUrlAsTrustworthy(url_);
|
|
CookieOptions options = CookieOptions::MakeAllInclusive();
|
|
+ CookieSamePartyStatus same_party_status = cookie_util::GetSamePartyStatus(
|
|
+ cookie, options, same_party_attribute_enabled_);
|
|
if (!cookie
|
|
.IncludeForRequestURL(
|
|
url_, options,
|
|
CookieAccessParams{change.access_result.access_semantics,
|
|
- delegate_treats_url_as_trustworthy})
|
|
+ delegate_treats_url_as_trustworthy,
|
|
+ same_party_status})
|
|
.status.IsInclude()) {
|
|
return;
|
|
}
|
|
@@ -111,8 +116,10 @@ void CookieMonsterChangeDispatcher::Subscription::DoDispatchChange(
|
|
}
|
|
|
|
CookieMonsterChangeDispatcher::CookieMonsterChangeDispatcher(
|
|
- const CookieMonster* cookie_monster)
|
|
- : cookie_monster_(cookie_monster) {}
|
|
+ const CookieMonster* cookie_monster,
|
|
+ bool same_party_attribute_enabled)
|
|
+ : cookie_monster_(cookie_monster),
|
|
+ same_party_attribute_enabled_(same_party_attribute_enabled) {}
|
|
|
|
CookieMonsterChangeDispatcher::~CookieMonsterChangeDispatcher() {
|
|
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
|
@@ -154,7 +161,7 @@ CookieMonsterChangeDispatcher::AddCallbackForCookie(
|
|
std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
|
|
weak_ptr_factory_.GetWeakPtr(), DomainKey(url), NameKey(name), url,
|
|
CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
|
|
- std::move(callback));
|
|
+ same_party_attribute_enabled_, std::move(callback));
|
|
|
|
LinkSubscription(subscription.get());
|
|
return subscription;
|
|
@@ -171,7 +178,7 @@ CookieMonsterChangeDispatcher::AddCallbackForUrl(
|
|
weak_ptr_factory_.GetWeakPtr(), DomainKey(url),
|
|
std::string(kGlobalNameKey), url,
|
|
CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
|
|
- std::move(callback));
|
|
+ same_party_attribute_enabled_, std::move(callback));
|
|
|
|
LinkSubscription(subscription.get());
|
|
return subscription;
|
|
@@ -185,7 +192,8 @@ CookieMonsterChangeDispatcher::AddCallbackForAllChanges(
|
|
std::unique_ptr<Subscription> subscription = std::make_unique<Subscription>(
|
|
weak_ptr_factory_.GetWeakPtr(), std::string(kGlobalDomainKey),
|
|
std::string(kGlobalNameKey), GURL(""),
|
|
- CookiePartitionKeyCollection::ContainsAll(), std::move(callback));
|
|
+ CookiePartitionKeyCollection::ContainsAll(),
|
|
+ same_party_attribute_enabled_, std::move(callback));
|
|
|
|
LinkSubscription(subscription.get());
|
|
return subscription;
|
|
diff --git a/net/cookies/cookie_monster_change_dispatcher.h b/net/cookies/cookie_monster_change_dispatcher.h
|
|
index d6f449140b0244263b0c248e9163eb9940407541..31ca1e979ce1133dd6a78a7d8d09a6aba8f0ee44 100644
|
|
--- a/net/cookies/cookie_monster_change_dispatcher.h
|
|
+++ b/net/cookies/cookie_monster_change_dispatcher.h
|
|
@@ -33,7 +33,8 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
base::RepeatingCallbackList<void(const CookieChangeInfo&)>;
|
|
|
|
// Expects |cookie_monster| to outlive this.
|
|
- explicit CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster);
|
|
+ CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster,
|
|
+ bool same_party_attribute_enabled);
|
|
|
|
CookieMonsterChangeDispatcher(const CookieMonsterChangeDispatcher&) = delete;
|
|
CookieMonsterChangeDispatcher& operator=(
|
|
@@ -78,6 +79,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
std::string name_key,
|
|
GURL url,
|
|
CookiePartitionKeyCollection cookie_partition_key_collection,
|
|
+ bool same_party_attribute_enabled,
|
|
net::CookieChangeCallback callback);
|
|
|
|
Subscription(const Subscription&) = delete;
|
|
@@ -105,6 +107,7 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
const GURL url_; // empty() means no URL-based filtering.
|
|
const CookiePartitionKeyCollection cookie_partition_key_collection_;
|
|
const net::CookieChangeCallback callback_;
|
|
+ bool same_party_attribute_enabled_;
|
|
|
|
void DoDispatchChange(const CookieChangeInfo& change) const;
|
|
|
|
@@ -154,6 +157,8 @@ class CookieMonsterChangeDispatcher : public CookieChangeDispatcher {
|
|
|
|
CookieDomainMap cookie_domain_map_;
|
|
|
|
+ const bool same_party_attribute_enabled_;
|
|
+
|
|
THREAD_CHECKER(thread_checker_);
|
|
|
|
// Vends weak pointers to subscriptions.
|
|
diff --git a/net/cookies/cookie_options.cc b/net/cookies/cookie_options.cc
|
|
index d3e96410b39057e3a8d20078d69cbd728f7c8bde..42eb151094e5b26671ea576bf402f8a877e862a3 100644
|
|
--- a/net/cookies/cookie_options.cc
|
|
+++ b/net/cookies/cookie_options.cc
|
|
@@ -8,7 +8,9 @@
|
|
|
|
#include <tuple>
|
|
|
|
+#include "base/metrics/histogram_functions.h"
|
|
#include "net/cookies/cookie_util.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
|
|
namespace net {
|
|
|
|
@@ -99,6 +101,8 @@ CookieOptions CookieOptions::MakeAllInclusive() {
|
|
options.set_include_httponly();
|
|
options.set_same_site_cookie_context(SameSiteCookieContext::MakeInclusive());
|
|
options.set_do_not_update_access_time();
|
|
+ options.set_same_party_context(SamePartyContext::MakeInclusive());
|
|
+ options.set_is_in_nontrivial_first_party_set(true);
|
|
return options;
|
|
}
|
|
|
|
diff --git a/net/cookies/cookie_options.h b/net/cookies/cookie_options.h
|
|
index 183c1f61c1fbe94c8c85dd4f9a27695a04aad816..fc7cddad43a74945d5af6c2100893720f3895734 100644
|
|
--- a/net/cookies/cookie_options.h
|
|
+++ b/net/cookies/cookie_options.h
|
|
@@ -10,8 +10,11 @@
|
|
#include <ostream>
|
|
#include <string>
|
|
|
|
-#include "base/check_op.h"
|
|
#include "net/base/net_export.h"
|
|
+#include "net/cookies/cookie_constants.h"
|
|
+#include "net/cookies/cookie_inclusion_status.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
+#include "url/gurl.h"
|
|
|
|
namespace net {
|
|
|
|
@@ -266,6 +269,26 @@ class NET_EXPORT CookieOptions {
|
|
void unset_return_excluded_cookies() { return_excluded_cookies_ = false; }
|
|
bool return_excluded_cookies() const { return return_excluded_cookies_; }
|
|
|
|
+ void set_same_party_context(const SamePartyContext& context) {
|
|
+ same_party_context_ = context;
|
|
+ }
|
|
+ const SamePartyContext& same_party_context() const {
|
|
+ return same_party_context_;
|
|
+ }
|
|
+
|
|
+ // Getter/setter of |full_party_context_size_| for logging purposes.
|
|
+ void set_full_party_context_size(uint32_t len) {
|
|
+ full_party_context_size_ = len;
|
|
+ }
|
|
+ uint32_t full_party_context_size() const { return full_party_context_size_; }
|
|
+
|
|
+ void set_is_in_nontrivial_first_party_set(bool is_member) {
|
|
+ is_in_nontrivial_first_party_set_ = is_member;
|
|
+ }
|
|
+ bool is_in_nontrivial_first_party_set() const {
|
|
+ return is_in_nontrivial_first_party_set_;
|
|
+ }
|
|
+
|
|
// Convenience method for where you need a CookieOptions that will
|
|
// work for getting/setting all types of cookies, including HttpOnly and
|
|
// SameSite cookies. Also specifies not to update the access time, because
|
|
@@ -281,6 +304,19 @@ class NET_EXPORT CookieOptions {
|
|
SameSiteCookieContext same_site_cookie_context_;
|
|
bool update_access_time_ = true;
|
|
bool return_excluded_cookies_ = false;
|
|
+
|
|
+ SamePartyContext same_party_context_;
|
|
+
|
|
+ // The size of the isolation_info.party_context plus the top-frame site.
|
|
+ // Stored for logging purposes.
|
|
+ uint32_t full_party_context_size_ = 0;
|
|
+ // Whether the site requesting cookie access (as opposed to e.g. the
|
|
+ // `site_for_cookies`) is a member (or owner) of a nontrivial First-Party
|
|
+ // Set.
|
|
+ // This is included here temporarily, for the purpose of ignoring SameParty
|
|
+ // for sites that are not participating in the Origin Trial.
|
|
+ // TODO(https://crbug.com/1163990): remove this field.
|
|
+ bool is_in_nontrivial_first_party_set_ = false;
|
|
};
|
|
|
|
NET_EXPORT bool operator==(
|
|
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
|
|
index 5e4748bf6fc8d06a8207642e1e2a9b3122b3b75e..e2670576d72bfcc2267d8cc9b1865210d8162a4f 100644
|
|
--- a/net/cookies/cookie_util.cc
|
|
+++ b/net/cookies/cookie_util.cc
|
|
@@ -32,6 +32,7 @@
|
|
#include "net/cookies/cookie_monster.h"
|
|
#include "net/cookies/cookie_options.h"
|
|
#include "net/first_party_sets/first_party_set_metadata.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "net/http/http_util.h"
|
|
#include "url/gurl.h"
|
|
#include "url/url_constants.h"
|
|
@@ -897,13 +898,16 @@ absl::optional<FirstPartySetMetadata> ComputeFirstPartySetMetadataMaybeAsync(
|
|
const SchemefulSite& request_site,
|
|
const IsolationInfo& isolation_info,
|
|
const CookieAccessDelegate* cookie_access_delegate,
|
|
+ bool force_ignore_top_frame_party,
|
|
base::OnceCallback<void(FirstPartySetMetadata)> callback) {
|
|
if (isolation_info.party_context().has_value() && cookie_access_delegate) {
|
|
return cookie_access_delegate->ComputeFirstPartySetMetadataMaybeAsync(
|
|
request_site,
|
|
- base::OptionalToPtr(
|
|
- isolation_info.network_isolation_key().GetTopFrameSite()),
|
|
- std::move(callback));
|
|
+ force_ignore_top_frame_party
|
|
+ ? nullptr
|
|
+ : base::OptionalToPtr(
|
|
+ isolation_info.network_isolation_key().GetTopFrameSite()),
|
|
+ isolation_info.party_context().value(), std::move(callback));
|
|
}
|
|
|
|
return FirstPartySetMetadata();
|
|
@@ -935,6 +939,23 @@ HttpMethodStringToEnum(const std::string& in) {
|
|
return HttpMethod::kUnknown;
|
|
}
|
|
|
|
+CookieSamePartyStatus GetSamePartyStatus(
|
|
+ const CanonicalCookie& cookie,
|
|
+ const CookieOptions& options,
|
|
+ const bool same_party_attribute_enabled) {
|
|
+ if (!same_party_attribute_enabled || !cookie.IsSameParty() ||
|
|
+ !options.is_in_nontrivial_first_party_set()) {
|
|
+ return CookieSamePartyStatus::kNoSamePartyEnforcement;
|
|
+ }
|
|
+
|
|
+ switch (options.same_party_context().context_type()) {
|
|
+ case SamePartyContext::Type::kCrossParty:
|
|
+ return CookieSamePartyStatus::kEnforceSamePartyExclude;
|
|
+ case SamePartyContext::Type::kSameParty:
|
|
+ return CookieSamePartyStatus::kEnforceSamePartyInclude;
|
|
+ };
|
|
+}
|
|
+
|
|
bool IsCookieAccessResultInclude(CookieAccessResult cookie_access_result) {
|
|
return cookie_access_result.status.IsInclude();
|
|
}
|
|
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
|
|
index 1ea066648012400453f56dcd437c891439199c2d..1a424e940524830fa396032bc567e0eb4db9d99a 100644
|
|
--- a/net/cookies/cookie_util.h
|
|
+++ b/net/cookies/cookie_util.h
|
|
@@ -295,6 +295,7 @@ ComputeFirstPartySetMetadataMaybeAsync(
|
|
const SchemefulSite& request_site,
|
|
const IsolationInfo& isolation_info,
|
|
const CookieAccessDelegate* cookie_access_delegate,
|
|
+ bool force_ignore_top_frame_party,
|
|
base::OnceCallback<void(FirstPartySetMetadata)> callback);
|
|
|
|
// Converts a string representing the http request method to its enum
|
|
@@ -302,6 +303,14 @@ ComputeFirstPartySetMetadataMaybeAsync(
|
|
NET_EXPORT CookieOptions::SameSiteCookieContext::ContextMetadata::HttpMethod
|
|
HttpMethodStringToEnum(const std::string& in);
|
|
|
|
+// Get the SameParty inclusion status. If the cookie is not SameParty, returns
|
|
+// kNoSamePartyEnforcement; if the cookie is SameParty but does not have a
|
|
+// valid context, returns kEnforceSamePartyExclude.
|
|
+NET_EXPORT CookieSamePartyStatus
|
|
+GetSamePartyStatus(const CanonicalCookie& cookie,
|
|
+ const CookieOptions& options,
|
|
+ bool same_party_attribute_enabled);
|
|
+
|
|
// Takes a CookieAccessResult and returns a bool, returning true if the
|
|
// CookieInclusionStatus in CookieAccessResult was set to "include", else
|
|
// returning false.
|
|
diff --git a/net/cookies/test_cookie_access_delegate.cc b/net/cookies/test_cookie_access_delegate.cc
|
|
index 1e90c180f9ca510b273a9d35ce4d427423506d33..988a25e98959f7ee65abcdfa59c9064f3966d68e 100644
|
|
--- a/net/cookies/test_cookie_access_delegate.cc
|
|
+++ b/net/cookies/test_cookie_access_delegate.cc
|
|
@@ -21,6 +21,7 @@
|
|
#include "net/cookies/cookie_util.h"
|
|
#include "net/first_party_sets/first_party_set_entry.h"
|
|
#include "net/first_party_sets/first_party_set_metadata.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
|
|
namespace net {
|
|
|
|
@@ -62,11 +63,13 @@ absl::optional<FirstPartySetMetadata>
|
|
TestCookieAccessDelegate::ComputeFirstPartySetMetadataMaybeAsync(
|
|
const SchemefulSite& site,
|
|
const SchemefulSite* top_frame_site,
|
|
+ const std::set<SchemefulSite>& party_context,
|
|
base::OnceCallback<void(FirstPartySetMetadata)> callback) const {
|
|
absl::optional<FirstPartySetEntry> top_frame_owner =
|
|
top_frame_site ? FindFirstPartySetEntry(*top_frame_site) : absl::nullopt;
|
|
return RunMaybeAsync(
|
|
- FirstPartySetMetadata(base::OptionalToPtr(FindFirstPartySetEntry(site)),
|
|
+ FirstPartySetMetadata(SamePartyContext(),
|
|
+ base::OptionalToPtr(FindFirstPartySetEntry(site)),
|
|
base::OptionalToPtr(top_frame_owner)),
|
|
std::move(callback));
|
|
}
|
|
diff --git a/net/cookies/test_cookie_access_delegate.h b/net/cookies/test_cookie_access_delegate.h
|
|
index 35957aafe9ad0867ab1500cfb49bdbf95eaec4d8..a2324fdf7746b2ef967fd7cbb8ef2704902ad2e9 100644
|
|
--- a/net/cookies/test_cookie_access_delegate.h
|
|
+++ b/net/cookies/test_cookie_access_delegate.h
|
|
@@ -43,6 +43,7 @@ class TestCookieAccessDelegate : public CookieAccessDelegate {
|
|
absl::optional<FirstPartySetMetadata> ComputeFirstPartySetMetadataMaybeAsync(
|
|
const SchemefulSite& site,
|
|
const SchemefulSite* top_frame_site,
|
|
+ const std::set<SchemefulSite>& party_context,
|
|
base::OnceCallback<void(FirstPartySetMetadata)> callback) const override;
|
|
absl::optional<base::flat_map<SchemefulSite, FirstPartySetEntry>>
|
|
FindFirstPartySetEntries(
|
|
diff --git a/net/first_party_sets/first_party_set_metadata.cc b/net/first_party_sets/first_party_set_metadata.cc
|
|
index 75f41ad79ac067f806d4bea8b687a4781778e37a..26521fa5f9b4a93f892212cbd45e77ce41fc0f29 100644
|
|
--- a/net/first_party_sets/first_party_set_metadata.cc
|
|
+++ b/net/first_party_sets/first_party_set_metadata.cc
|
|
@@ -13,9 +13,11 @@ namespace net {
|
|
|
|
FirstPartySetMetadata::FirstPartySetMetadata() = default;
|
|
FirstPartySetMetadata::FirstPartySetMetadata(
|
|
+ const SamePartyContext& context,
|
|
const FirstPartySetEntry* frame_entry,
|
|
const FirstPartySetEntry* top_frame_entry)
|
|
- : frame_entry_(base::OptionalFromPtr(frame_entry)),
|
|
+ : context_(context),
|
|
+ frame_entry_(base::OptionalFromPtr(frame_entry)),
|
|
top_frame_entry_(base::OptionalFromPtr(top_frame_entry)) {}
|
|
|
|
FirstPartySetMetadata::FirstPartySetMetadata(FirstPartySetMetadata&&) = default;
|
|
@@ -26,8 +28,8 @@ FirstPartySetMetadata::~FirstPartySetMetadata() = default;
|
|
|
|
bool FirstPartySetMetadata::operator==(
|
|
const FirstPartySetMetadata& other) const {
|
|
- return std::tie(frame_entry_, top_frame_entry_) ==
|
|
- std::tie(other.frame_entry_, other.top_frame_entry_);
|
|
+ return std::tie(context_, frame_entry_, top_frame_entry_) ==
|
|
+ std::tie(other.context_, other.frame_entry_, other.top_frame_entry_);
|
|
}
|
|
|
|
bool FirstPartySetMetadata::operator!=(
|
|
@@ -37,7 +39,8 @@ bool FirstPartySetMetadata::operator!=(
|
|
|
|
std::ostream& operator<<(std::ostream& os,
|
|
const FirstPartySetMetadata& metadata) {
|
|
- os << "{" << base::OptionalToPtr(metadata.frame_entry()) << ", "
|
|
+ os << "{" << metadata.context() << ", "
|
|
+ << base::OptionalToPtr(metadata.frame_entry()) << ", "
|
|
<< base::OptionalToPtr(metadata.top_frame_entry()) << "}";
|
|
return os;
|
|
}
|
|
diff --git a/net/first_party_sets/first_party_set_metadata.h b/net/first_party_sets/first_party_set_metadata.h
|
|
index b23e52575bc2ae0634075890782eb46716116217..77cf13c75599522be3efda658b8685b21532c41c 100644
|
|
--- a/net/first_party_sets/first_party_set_metadata.h
|
|
+++ b/net/first_party_sets/first_party_set_metadata.h
|
|
@@ -7,6 +7,7 @@
|
|
|
|
#include "net/base/net_export.h"
|
|
#include "net/first_party_sets/first_party_set_entry.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
|
namespace net {
|
|
@@ -20,7 +21,8 @@ class NET_EXPORT FirstPartySetMetadata {
|
|
// `frame_entry` and `top_frame_entry` must live for the duration of the ctor;
|
|
// nullptr indicates that there's no First-Party Set that's associated with
|
|
// the current frame or the top frame, respectively, in the given context.
|
|
- FirstPartySetMetadata(const FirstPartySetEntry* frame_entry,
|
|
+ FirstPartySetMetadata(const SamePartyContext& context,
|
|
+ const FirstPartySetEntry* frame_entry,
|
|
const FirstPartySetEntry* top_frame_entry);
|
|
|
|
FirstPartySetMetadata(FirstPartySetMetadata&&);
|
|
@@ -31,6 +33,10 @@ class NET_EXPORT FirstPartySetMetadata {
|
|
bool operator==(const FirstPartySetMetadata& other) const;
|
|
bool operator!=(const FirstPartySetMetadata& other) const;
|
|
|
|
+ const SamePartyContext& context() const { return context_; }
|
|
+
|
|
+ // Returns a optional<T>& instead of a T* so that operator== can be defined
|
|
+ // more easily.
|
|
const absl::optional<FirstPartySetEntry>& frame_entry() const {
|
|
return frame_entry_;
|
|
}
|
|
@@ -43,6 +49,7 @@ class NET_EXPORT FirstPartySetMetadata {
|
|
bool AreSitesInSameFirstPartySet() const;
|
|
|
|
private:
|
|
+ SamePartyContext context_ = SamePartyContext();
|
|
absl::optional<FirstPartySetEntry> frame_entry_ = absl::nullopt;
|
|
absl::optional<FirstPartySetEntry> top_frame_entry_ = absl::nullopt;
|
|
};
|
|
diff --git a/net/first_party_sets/global_first_party_sets.cc b/net/first_party_sets/global_first_party_sets.cc
|
|
index 29d34cd442ae19006d399b09b766c19dd5b12c76..ae2845f897ee9eb23f4888871b07edf28b62234c 100644
|
|
--- a/net/first_party_sets/global_first_party_sets.cc
|
|
+++ b/net/first_party_sets/global_first_party_sets.cc
|
|
@@ -28,6 +28,13 @@ namespace {
|
|
using FlattenedSets = base::flat_map<SchemefulSite, FirstPartySetEntry>;
|
|
using SingleSet = base::flat_map<SchemefulSite, FirstPartySetEntry>;
|
|
|
|
+// Converts WS to HTTP, and WSS to HTTPS.
|
|
+SchemefulSite NormalizeScheme(const SchemefulSite& site) {
|
|
+ SchemefulSite normalized_site = site;
|
|
+ normalized_site.ConvertWebSocketToHttp();
|
|
+ return normalized_site;
|
|
+}
|
|
+
|
|
// Converts a list of First-Party Sets from a SingleSet to a FlattenedSet
|
|
// representation.
|
|
FlattenedSets SetListToFlattenedSets(const std::vector<SingleSet>& set_list) {
|
|
@@ -59,6 +66,11 @@ const SchemefulSite& ProjectKey(
|
|
return p.first;
|
|
}
|
|
|
|
+SamePartyContext::Type ContextTypeFromBool(bool is_same_party) {
|
|
+ return is_same_party ? SamePartyContext::Type::kSameParty
|
|
+ : SamePartyContext::Type::kCrossParty;
|
|
+}
|
|
+
|
|
} // namespace
|
|
|
|
GlobalFirstPartySets::GlobalFirstPartySets() = default;
|
|
@@ -126,9 +138,11 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
const SchemefulSite& site,
|
|
const FirstPartySetsContextConfig* config) const {
|
|
- // Check if `site` can be found in the customizations first.
|
|
+ const SchemefulSite normalized_site = NormalizeScheme(site);
|
|
+
|
|
+ // Check if `normalized_site` can be found in the customizations first.
|
|
if (config) {
|
|
- if (const auto override = config->FindOverride(site);
|
|
+ if (const auto override = config->FindOverride(normalized_site);
|
|
override.has_value()) {
|
|
return override->IsDeletion() ? absl::nullopt
|
|
: absl::make_optional(override->GetEntry());
|
|
@@ -136,7 +150,7 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
}
|
|
|
|
// Now see if it's in the manual config (with or without a manual alias).
|
|
- if (const auto manual_override = manual_config_.FindOverride(site);
|
|
+ if (const auto manual_override = manual_config_.FindOverride(normalized_site);
|
|
manual_override.has_value()) {
|
|
return manual_override->IsDeletion()
|
|
? absl::nullopt
|
|
@@ -144,9 +158,9 @@ absl::optional<FirstPartySetEntry> GlobalFirstPartySets::FindEntry(
|
|
}
|
|
|
|
// Finally, look up in `entries_`, applying an alias if applicable.
|
|
- const auto canonical_it = aliases_.find(site);
|
|
+ const auto canonical_it = aliases_.find(normalized_site);
|
|
const SchemefulSite& canonical_site =
|
|
- canonical_it == aliases_.end() ? site : canonical_it->second;
|
|
+ canonical_it == aliases_.end() ? normalized_site : canonical_it->second;
|
|
if (const auto entry_it = entries_.find(canonical_site);
|
|
entry_it != entries_.end()) {
|
|
return entry_it->second;
|
|
@@ -172,16 +186,50 @@ GlobalFirstPartySets::FindEntries(
|
|
FirstPartySetMetadata GlobalFirstPartySets::ComputeMetadata(
|
|
const SchemefulSite& site,
|
|
const SchemefulSite* top_frame_site,
|
|
+ const std::set<SchemefulSite>& party_context,
|
|
const FirstPartySetsContextConfig& fps_context_config) const {
|
|
+ const base::ElapsedTimer timer;
|
|
+
|
|
+ SamePartyContext::Type context_type =
|
|
+ ContextTypeFromBool(IsContextSamePartyWithSite(
|
|
+ site, top_frame_site, party_context, fps_context_config));
|
|
+
|
|
+ SamePartyContext context(context_type);
|
|
+
|
|
absl::optional<FirstPartySetEntry> top_frame_entry =
|
|
top_frame_site ? FindEntry(*top_frame_site, fps_context_config)
|
|
: absl::nullopt;
|
|
|
|
return FirstPartySetMetadata(
|
|
- base::OptionalToPtr(FindEntry(site, fps_context_config)),
|
|
+ context, base::OptionalToPtr(FindEntry(site, fps_context_config)),
|
|
base::OptionalToPtr(top_frame_entry));
|
|
}
|
|
|
|
+bool GlobalFirstPartySets::IsContextSamePartyWithSite(
|
|
+ const SchemefulSite& site,
|
|
+ const SchemefulSite* top_frame_site,
|
|
+ const std::set<SchemefulSite>& party_context,
|
|
+ const FirstPartySetsContextConfig& fps_context_config) const {
|
|
+ const absl::optional<FirstPartySetEntry> site_entry =
|
|
+ FindEntry(site, fps_context_config);
|
|
+ if (!site_entry.has_value())
|
|
+ return false;
|
|
+
|
|
+ const auto is_in_same_set_as_frame_site =
|
|
+ [this, &site_entry,
|
|
+ &fps_context_config](const SchemefulSite& context_site) -> bool {
|
|
+ const absl::optional<FirstPartySetEntry> context_entry =
|
|
+ FindEntry(context_site, fps_context_config);
|
|
+ return context_entry.has_value() &&
|
|
+ context_entry->primary() == site_entry->primary();
|
|
+ };
|
|
+
|
|
+ if (top_frame_site && !is_in_same_set_as_frame_site(*top_frame_site))
|
|
+ return false;
|
|
+
|
|
+ return base::ranges::all_of(party_context, is_in_same_set_as_frame_site);
|
|
+}
|
|
+
|
|
void GlobalFirstPartySets::ApplyManuallySpecifiedSet(
|
|
const base::flat_map<SchemefulSite, FirstPartySetEntry>& manual_entries) {
|
|
CHECK(manual_config_.empty());
|
|
diff --git a/net/first_party_sets/global_first_party_sets.h b/net/first_party_sets/global_first_party_sets.h
|
|
index f4f4e99189e0f3b8accfa884e136a127d0128bab..dc12d5fc440cecf291931cef98256b5f7ac58886 100644
|
|
--- a/net/first_party_sets/global_first_party_sets.h
|
|
+++ b/net/first_party_sets/global_first_party_sets.h
|
|
@@ -10,6 +10,8 @@
|
|
#include "base/containers/flat_map.h"
|
|
#include "base/containers/flat_set.h"
|
|
#include "base/functional/function_ref.h"
|
|
+#include "base/time/time.h"
|
|
+#include "base/timer/elapsed_timer.h"
|
|
#include "base/version.h"
|
|
#include "net/base/net_export.h"
|
|
#include "net/base/schemeful_site.h"
|
|
@@ -83,6 +85,7 @@ class NET_EXPORT GlobalFirstPartySets {
|
|
FirstPartySetMetadata ComputeMetadata(
|
|
const SchemefulSite& site,
|
|
const SchemefulSite* top_frame_site,
|
|
+ const std::set<SchemefulSite>& party_context,
|
|
const FirstPartySetsContextConfig& fps_context_config) const;
|
|
|
|
// Modifies this instance such that it will respect the given
|
|
@@ -166,6 +169,12 @@ class NET_EXPORT GlobalFirstPartySets {
|
|
const std::vector<base::flat_map<SchemefulSite, FirstPartySetEntry>>&
|
|
addition_sets) const;
|
|
|
|
+ bool IsContextSamePartyWithSite(
|
|
+ const SchemefulSite& site,
|
|
+ const SchemefulSite* top_frame_site,
|
|
+ const std::set<SchemefulSite>& party_context,
|
|
+ const FirstPartySetsContextConfig& fps_context_config) const;
|
|
+
|
|
// Same as the public version of ForEachEffectiveSetEntry, but is allowed to
|
|
// omit the `config` argument (i.e. pass nullptr instead of a reference).
|
|
bool ForEachEffectiveSetEntry(
|
|
diff --git a/net/first_party_sets/same_party_context.cc b/net/first_party_sets/same_party_context.cc
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..afa9ddf645cc8776d7c9303da9d93725b945a5d7
|
|
--- /dev/null
|
|
+++ b/net/first_party_sets/same_party_context.cc
|
|
@@ -0,0 +1,28 @@
|
|
+// Copyright 2021 The Chromium Authors
|
|
+// Use of this source code is governed by a BSD-style license that can be
|
|
+// found in the LICENSE file.
|
|
+
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
+
|
|
+#include <ostream>
|
|
+
|
|
+namespace net {
|
|
+
|
|
+SamePartyContext::SamePartyContext(Type context_type)
|
|
+ : context_type_(context_type) {}
|
|
+
|
|
+bool SamePartyContext::operator==(const SamePartyContext& other) const {
|
|
+ return context_type_ == other.context_type_;
|
|
+}
|
|
+
|
|
+std::ostream& operator<<(std::ostream& os, const SamePartyContext& spc) {
|
|
+ os << "{" << static_cast<int>(spc.context_type()) << "}";
|
|
+ return os;
|
|
+}
|
|
+
|
|
+// static
|
|
+SamePartyContext SamePartyContext::MakeInclusive() {
|
|
+ return SamePartyContext(Type::kSameParty);
|
|
+}
|
|
+
|
|
+} // namespace net
|
|
diff --git a/net/first_party_sets/same_party_context.h b/net/first_party_sets/same_party_context.h
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..448f000d8ab368f071d73da887e0e857c33e8973
|
|
--- /dev/null
|
|
+++ b/net/first_party_sets/same_party_context.h
|
|
@@ -0,0 +1,51 @@
|
|
+// Copyright 2021 The Chromium Authors
|
|
+// Use of this source code is governed by a BSD-style license that can be
|
|
+// found in the LICENSE file.
|
|
+
|
|
+#ifndef NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
|
|
+#define NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
|
|
+
|
|
+#include <ostream>
|
|
+
|
|
+#include "net/base/net_export.h"
|
|
+
|
|
+namespace net {
|
|
+
|
|
+// This struct bundles together a few different notions of same-party-ness.
|
|
+// `context_type()` gives the notion of same-party-ness that Chromium should use
|
|
+// in all cases except metrics; other accessors are just for metrics purposes,
|
|
+// to explore the impact of different definitions of "same-party".
|
|
+class NET_EXPORT SamePartyContext {
|
|
+ public:
|
|
+ // Computed for every cookie access attempt but is only relevant for SameParty
|
|
+ // cookies.
|
|
+ enum class Type {
|
|
+ // The opposite to kSameParty. Should be the default value.
|
|
+ kCrossParty = 0,
|
|
+ // If the request URL is in the same First-Party Sets as the top-frame site
|
|
+ // and each member of the isolation_info.party_context.
|
|
+ kSameParty = 1,
|
|
+ };
|
|
+
|
|
+ SamePartyContext() = default;
|
|
+ explicit SamePartyContext(Type context_type);
|
|
+
|
|
+ bool operator==(const SamePartyContext& other) const;
|
|
+
|
|
+ // How trusted is the current browser environment when it comes to accessing
|
|
+ // SameParty cookies. Default is not trusted, e.g. kCrossParty.
|
|
+ Type context_type() const { return context_type_; }
|
|
+
|
|
+ // Creates a SamePartyContext that is as permissive as possible.
|
|
+ static SamePartyContext MakeInclusive();
|
|
+
|
|
+ private:
|
|
+ Type context_type_ = Type::kCrossParty;
|
|
+};
|
|
+
|
|
+NET_EXPORT std::ostream& operator<<(std::ostream& os,
|
|
+ const SamePartyContext& spc);
|
|
+
|
|
+} // namespace net
|
|
+
|
|
+#endif // NET_FIRST_PARTY_SETS_SAME_PARTY_CONTEXT_H_
|
|
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
|
|
index 3c9516b7d80c09d97ce014859f15a0b4a2c634cc..88838c902460eec1aa45e558c8c04f5b9e6059cf 100644
|
|
--- a/net/url_request/url_request.h
|
|
+++ b/net/url_request/url_request.h
|
|
@@ -315,6 +315,16 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
|
|
force_ignore_site_for_cookies_ = attach;
|
|
}
|
|
|
|
+ // Indicates whether the top frame party will be considered same-party to the
|
|
+ // request URL (regardless of what it is), for the purpose of SameParty
|
|
+ // cookies.
|
|
+ bool force_ignore_top_frame_party_for_cookies() const {
|
|
+ return force_ignore_top_frame_party_for_cookies_;
|
|
+ }
|
|
+ void set_force_ignore_top_frame_party_for_cookies(bool force) {
|
|
+ force_ignore_top_frame_party_for_cookies_ = force;
|
|
+ }
|
|
+
|
|
// Indicates if the request should be treated as a main frame navigation for
|
|
// SameSite cookie computations. This flag overrides the IsolationInfo
|
|
// request type associated with fetches from a service worker context.
|
|
@@ -961,6 +971,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
|
|
absl::optional<CookiePartitionKey> cookie_partition_key_ = absl::nullopt;
|
|
|
|
bool force_ignore_site_for_cookies_ = false;
|
|
+ bool force_ignore_top_frame_party_for_cookies_ = false;
|
|
bool force_main_frame_for_same_site_cookies_ = false;
|
|
CookieSettingOverrides cookie_setting_overrides_;
|
|
|
|
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
|
|
index eac944172789c28deda9e86e880d31d7e0dae1cf..f25f62a4ab8f826d5d1a4b25d8593f0a18428073 100644
|
|
--- a/net/url_request/url_request_http_job.cc
|
|
+++ b/net/url_request/url_request_http_job.cc
|
|
@@ -63,6 +63,7 @@
|
|
#include "net/filter/zstd_source_stream.h"
|
|
#include "net/first_party_sets/first_party_set_entry.h"
|
|
#include "net/first_party_sets/first_party_set_metadata.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "net/http/http_content_disposition.h"
|
|
#include "net/http/http_log_util.h"
|
|
#include "net/http/http_network_session.h"
|
|
@@ -165,11 +166,22 @@ void LogTrustAnchor(const net::HashValueVector& spki_hashes) {
|
|
}
|
|
|
|
net::CookieOptions CreateCookieOptions(
|
|
- net::CookieOptions::SameSiteCookieContext same_site_context) {
|
|
+ net::CookieOptions::SameSiteCookieContext same_site_context,
|
|
+ const net::SamePartyContext& same_party_context,
|
|
+ const net::IsolationInfo& isolation_info,
|
|
+ bool is_in_nontrivial_first_party_set) {
|
|
net::CookieOptions options;
|
|
options.set_return_excluded_cookies();
|
|
options.set_include_httponly();
|
|
options.set_same_site_cookie_context(same_site_context);
|
|
+ options.set_same_party_context(same_party_context);
|
|
+ if (isolation_info.party_context().has_value()) {
|
|
+ // Count the top-frame site since it's not in the party_context.
|
|
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
|
|
+ 1);
|
|
+ }
|
|
+ options.set_is_in_nontrivial_first_party_set(
|
|
+ is_in_nontrivial_first_party_set);
|
|
return options;
|
|
}
|
|
|
|
@@ -322,6 +334,7 @@ void URLRequestHttpJob::Start() {
|
|
cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
|
|
SchemefulSite(request()->url()), request()->isolation_info(),
|
|
request()->context()->cookie_store()->cookie_access_delegate(),
|
|
+ request()->force_ignore_top_frame_party_for_cookies(),
|
|
base::BindOnce(&URLRequestHttpJob::OnGotFirstPartySetMetadata,
|
|
weak_factory_.GetWeakPtr()));
|
|
|
|
@@ -684,7 +697,11 @@ void URLRequestHttpJob::AddCookieHeaderAndStart() {
|
|
request_->site_for_cookies(), request_->initiator(),
|
|
is_main_frame_navigation, force_ignore_site_for_cookies);
|
|
|
|
- CookieOptions options = CreateCookieOptions(same_site_context);
|
|
+ bool is_in_nontrivial_first_party_set =
|
|
+ first_party_set_metadata_.frame_entry().has_value();
|
|
+ CookieOptions options = CreateCookieOptions(
|
|
+ same_site_context, first_party_set_metadata_.context(),
|
|
+ request_->isolation_info(), is_in_nontrivial_first_party_set);
|
|
|
|
cookie_store->GetCookieListWithOptionsAsync(
|
|
request_->url(), options,
|
|
@@ -937,7 +954,11 @@ void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
|
|
request_->initiator(), is_main_frame_navigation,
|
|
force_ignore_site_for_cookies);
|
|
|
|
- CookieOptions options = CreateCookieOptions(same_site_context);
|
|
+ bool is_in_nontrivial_first_party_set =
|
|
+ first_party_set_metadata_.frame_entry().has_value();
|
|
+ CookieOptions options = CreateCookieOptions(
|
|
+ same_site_context, first_party_set_metadata_.context(),
|
|
+ request_->isolation_info(), is_in_nontrivial_first_party_set);
|
|
|
|
// Set all cookies, without waiting for them to be set. Any subsequent
|
|
// read will see the combined result of all cookie operation.
|
|
diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc
|
|
index cd44f7ecda273880f148577648dee0380381beb9..ab310b74a255834f558828d1ba4a830f09ccebcf 100644
|
|
--- a/services/network/cookie_access_delegate_impl.cc
|
|
+++ b/services/network/cookie_access_delegate_impl.cc
|
|
@@ -64,11 +64,12 @@ absl::optional<net::FirstPartySetMetadata>
|
|
CookieAccessDelegateImpl::ComputeFirstPartySetMetadataMaybeAsync(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
if (!first_party_sets_access_delegate_)
|
|
return {net::FirstPartySetMetadata()};
|
|
return first_party_sets_access_delegate_->ComputeMetadata(
|
|
- site, top_frame_site, std::move(callback));
|
|
+ site, top_frame_site, party_context, std::move(callback));
|
|
}
|
|
|
|
absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
|
|
diff --git a/services/network/cookie_access_delegate_impl.h b/services/network/cookie_access_delegate_impl.h
|
|
index 4ef1746b383cfbf7ad007cb6ae7e331408ab75fe..50c3a309db86e5f044e2bfc429ca82fc6586d084 100644
|
|
--- a/services/network/cookie_access_delegate_impl.h
|
|
+++ b/services/network/cookie_access_delegate_impl.h
|
|
@@ -5,7 +5,10 @@
|
|
#ifndef SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
|
|
#define SERVICES_NETWORK_COOKIE_ACCESS_DELEGATE_IMPL_H_
|
|
|
|
+#include <set>
|
|
+
|
|
#include "base/component_export.h"
|
|
+#include "base/containers/flat_map.h"
|
|
#include "base/containers/flat_set.h"
|
|
#include "base/functional/callback_forward.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
@@ -56,6 +59,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) CookieAccessDelegateImpl
|
|
ComputeFirstPartySetMetadataMaybeAsync(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback)
|
|
const override;
|
|
[[nodiscard]] absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
|
|
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.cc b/services/network/first_party_sets/first_party_sets_access_delegate.cc
|
|
index 08120524ead3ca40a8a167bf8d9991af871426df..9f2e736f056bf2d2b8c04264be6052fabc769d26 100644
|
|
--- a/services/network/first_party_sets/first_party_sets_access_delegate.cc
|
|
+++ b/services/network/first_party_sets/first_party_sets_access_delegate.cc
|
|
@@ -69,6 +69,7 @@ absl::optional<net::FirstPartySetMetadata>
|
|
FirstPartySetsAccessDelegate::ComputeMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
@@ -85,12 +86,12 @@ FirstPartySetsAccessDelegate::ComputeMetadata(
|
|
EnqueuePendingQuery(base::BindOnce(
|
|
&FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke,
|
|
base::Unretained(this), site, base::OptionalFromPtr(top_frame_site),
|
|
- std::move(callback)));
|
|
+ party_context, std::move(callback)));
|
|
return absl::nullopt;
|
|
}
|
|
|
|
- return manager_->ComputeMetadata(site, top_frame_site, *context_config(),
|
|
- std::move(callback));
|
|
+ return manager_->ComputeMetadata(site, top_frame_site, party_context,
|
|
+ *context_config(), std::move(callback));
|
|
}
|
|
|
|
absl::optional<FirstPartySetsAccessDelegate::EntriesResult>
|
|
@@ -148,6 +149,7 @@ FirstPartySetsAccessDelegate::GetCacheFilterMatchInfo(
|
|
void FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite> top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
CHECK(context_config());
|
|
@@ -162,7 +164,8 @@ void FirstPartySetsAccessDelegate::ComputeMetadataAndInvoke(
|
|
|
|
absl::optional<net::FirstPartySetMetadata> sync_result =
|
|
manager_->ComputeMetadata(site, base::OptionalToPtr(top_frame_site),
|
|
- *context_config(), std::move(callbacks.first));
|
|
+ party_context, *context_config(),
|
|
+ std::move(callbacks.first));
|
|
|
|
if (sync_result.has_value())
|
|
std::move(callbacks.second).Run(std::move(sync_result.value()));
|
|
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.h b/services/network/first_party_sets/first_party_sets_access_delegate.h
|
|
index cb2399650853758378306ffe34ae14688ca06f72..67df37ef7dfc344bff9bb569fdc58c29967aeb22 100644
|
|
--- a/services/network/first_party_sets/first_party_sets_access_delegate.h
|
|
+++ b/services/network/first_party_sets/first_party_sets_access_delegate.h
|
|
@@ -62,6 +62,7 @@ class FirstPartySetsAccessDelegate
|
|
[[nodiscard]] absl::optional<net::FirstPartySetMetadata> ComputeMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
|
|
|
|
// Calls FirstPartySetsManager::FindEntries either asynchronously or
|
|
@@ -91,6 +92,7 @@ class FirstPartySetsAccessDelegate
|
|
void ComputeMetadataAndInvoke(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite> top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const;
|
|
|
|
// Same as `FindEntries`, but plumbs the result into the callback. Must only
|
|
diff --git a/services/network/first_party_sets/first_party_sets_manager.cc b/services/network/first_party_sets/first_party_sets_manager.cc
|
|
index 68306f7e32db4455366be68e8dd6434797bc6e3e..d89cd3f6fd38a17f9aa7d09d168496518b1e716a 100644
|
|
--- a/services/network/first_party_sets/first_party_sets_manager.cc
|
|
+++ b/services/network/first_party_sets/first_party_sets_manager.cc
|
|
@@ -15,6 +15,7 @@
|
|
#include "base/feature_list.h"
|
|
#include "base/metrics/histogram_functions.h"
|
|
#include "base/metrics/histogram_macros.h"
|
|
+#include "base/ranges/algorithm.h"
|
|
#include "base/sequence_checker.h"
|
|
#include "base/time/time.h"
|
|
#include "base/timer/elapsed_timer.h"
|
|
@@ -24,6 +25,7 @@
|
|
#include "net/first_party_sets/first_party_set_entry.h"
|
|
#include "net/first_party_sets/first_party_set_metadata.h"
|
|
#include "net/first_party_sets/global_first_party_sets.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
|
namespace network {
|
|
@@ -48,6 +50,7 @@ absl::optional<net::FirstPartySetMetadata>
|
|
FirstPartySetsManager::ComputeMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& fps_context_config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
@@ -59,16 +62,19 @@ FirstPartySetsManager::ComputeMetadata(
|
|
EnqueuePendingQuery(base::BindOnce(
|
|
&FirstPartySetsManager::ComputeMetadataAndInvoke,
|
|
weak_factory_.GetWeakPtr(), site, base::OptionalFromPtr(top_frame_site),
|
|
- fps_context_config.Clone(), std::move(callback), base::ElapsedTimer()));
|
|
+ party_context, fps_context_config.Clone(), std::move(callback),
|
|
+ base::ElapsedTimer()));
|
|
return absl::nullopt;
|
|
}
|
|
|
|
- return ComputeMetadataInternal(site, top_frame_site, fps_context_config);
|
|
+ return ComputeMetadataInternal(site, top_frame_site, party_context,
|
|
+ fps_context_config);
|
|
}
|
|
|
|
void FirstPartySetsManager::ComputeMetadataAndInvoke(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite> top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& fps_context_config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback,
|
|
base::ElapsedTimer timer) const {
|
|
@@ -78,18 +84,21 @@ void FirstPartySetsManager::ComputeMetadataAndInvoke(
|
|
UMA_HISTOGRAM_TIMES("Cookie.FirstPartySets.EnqueueingDelay.ComputeMetadata2",
|
|
timer.Elapsed());
|
|
|
|
- std::move(callback).Run(ComputeMetadataInternal(
|
|
- site, base::OptionalToPtr(top_frame_site), fps_context_config));
|
|
+ std::move(callback).Run(
|
|
+ ComputeMetadataInternal(site, base::OptionalToPtr(top_frame_site),
|
|
+ party_context, fps_context_config));
|
|
}
|
|
|
|
net::FirstPartySetMetadata FirstPartySetsManager::ComputeMetadataInternal(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& fps_context_config) const {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
CHECK(sets_.has_value());
|
|
|
|
- return sets_->ComputeMetadata(site, top_frame_site, fps_context_config);
|
|
+ return sets_->ComputeMetadata(site, top_frame_site, party_context,
|
|
+ fps_context_config);
|
|
}
|
|
|
|
absl::optional<net::FirstPartySetEntry> FirstPartySetsManager::FindEntry(
|
|
diff --git a/services/network/first_party_sets/first_party_sets_manager.h b/services/network/first_party_sets/first_party_sets_manager.h
|
|
index 9754dd5f6b0087c6630285b1f592e43cda4ba8d6..b04a98f42fc96a5f2e85cd1bc8ea841fb170e4f2 100644
|
|
--- a/services/network/first_party_sets/first_party_sets_manager.h
|
|
+++ b/services/network/first_party_sets/first_party_sets_manager.h
|
|
@@ -15,6 +15,7 @@
|
|
#include "base/functional/callback.h"
|
|
#include "base/sequence_checker.h"
|
|
#include "base/thread_annotations.h"
|
|
+#include "base/time/time.h"
|
|
#include "base/timer/elapsed_timer.h"
|
|
#include "net/base/schemeful_site.h"
|
|
#include "net/first_party_sets/first_party_set_entry.h"
|
|
@@ -52,6 +53,7 @@ class FirstPartySetsManager {
|
|
[[nodiscard]] absl::optional<net::FirstPartySetMetadata> ComputeMetadata(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& fps_context_config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback);
|
|
|
|
@@ -84,6 +86,7 @@ class FirstPartySetsManager {
|
|
void ComputeMetadataAndInvoke(
|
|
const net::SchemefulSite& site,
|
|
const absl::optional<net::SchemefulSite> top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& fps_context_config,
|
|
base::OnceCallback<void(net::FirstPartySetMetadata)> callback,
|
|
base::ElapsedTimer timer) const;
|
|
@@ -93,6 +96,7 @@ class FirstPartySetsManager {
|
|
net::FirstPartySetMetadata ComputeMetadataInternal(
|
|
const net::SchemefulSite& site,
|
|
const net::SchemefulSite* top_frame_site,
|
|
+ const std::set<net::SchemefulSite>& party_context,
|
|
const net::FirstPartySetsContextConfig& fps_context_config) const;
|
|
|
|
// Returns `site`'s entry, or `nullopt` if `site` has no entry.
|
|
diff --git a/services/network/network_service_network_delegate.cc b/services/network/network_service_network_delegate.cc
|
|
index d8133af94ca8dc20974e8e6600933ce115106530..80acabb2b079a48cab2a76f8e1faad1db7e7710e 100644
|
|
--- a/services/network/network_service_network_delegate.cc
|
|
+++ b/services/network/network_service_network_delegate.cc
|
|
@@ -18,6 +18,7 @@
|
|
#include "net/base/load_flags.h"
|
|
#include "net/base/net_errors.h"
|
|
#include "net/cookies/cookie_setting_override.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "net/url_request/clear_site_data.h"
|
|
#include "net/url_request/referrer_policy.h"
|
|
#include "net/url_request/url_request.h"
|
|
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.cc b/services/network/public/cpp/cookie_manager_mojom_traits.cc
|
|
index 5269c91580bc8d9cf93c3323f7b96ac748cd5972..2505b01a13c62f49ce73a539d5d452ea6ae340bd 100644
|
|
--- a/services/network/public/cpp/cookie_manager_mojom_traits.cc
|
|
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.cc
|
|
@@ -586,6 +586,17 @@ bool StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions>::
|
|
else
|
|
cookie_options->unset_return_excluded_cookies();
|
|
|
|
+ net::SamePartyContext same_party_context;
|
|
+ if (!mojo_options.ReadSamePartyContext(&same_party_context))
|
|
+ return false;
|
|
+ cookie_options->set_same_party_context(same_party_context);
|
|
+
|
|
+ cookie_options->set_full_party_context_size(
|
|
+ mojo_options.full_party_context_size());
|
|
+
|
|
+ cookie_options->set_is_in_nontrivial_first_party_set(
|
|
+ mojo_options.is_in_nontrivial_first_party_set());
|
|
+
|
|
return true;
|
|
}
|
|
|
|
diff --git a/services/network/public/cpp/cookie_manager_mojom_traits.h b/services/network/public/cpp/cookie_manager_mojom_traits.h
|
|
index 5531222e359de032cb45b28e3451b5622a731069..d562b702b0f5a87017268e80d5941585609ccc3b 100644
|
|
--- a/services/network/public/cpp/cookie_manager_mojom_traits.h
|
|
+++ b/services/network/public/cpp/cookie_manager_mojom_traits.h
|
|
@@ -16,6 +16,8 @@
|
|
#include "net/cookies/cookie_inclusion_status.h"
|
|
#include "net/cookies/cookie_options.h"
|
|
#include "net/cookies/cookie_partition_key_collection.h"
|
|
+#include "net/first_party_sets/first_party_set_entry.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "services/network/public/cpp/cookie_manager_shared_mojom_traits.h"
|
|
#include "services/network/public/mojom/cookie_manager.mojom-forward.h"
|
|
#include "services/network/public/mojom/cookie_manager.mojom.h"
|
|
@@ -194,6 +196,18 @@ struct StructTraits<network::mojom::CookieOptionsDataView, net::CookieOptions> {
|
|
return o.return_excluded_cookies();
|
|
}
|
|
|
|
+ static net::SamePartyContext same_party_context(const net::CookieOptions& o) {
|
|
+ return o.same_party_context();
|
|
+ }
|
|
+
|
|
+ static uint32_t full_party_context_size(const net::CookieOptions& o) {
|
|
+ return o.full_party_context_size();
|
|
+ }
|
|
+
|
|
+ static bool is_in_nontrivial_first_party_set(const net::CookieOptions& o) {
|
|
+ return o.is_in_nontrivial_first_party_set();
|
|
+ }
|
|
+
|
|
static bool Read(network::mojom::CookieOptionsDataView mojo_options,
|
|
net::CookieOptions* cookie_options);
|
|
};
|
|
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.cc b/services/network/public/cpp/first_party_sets_mojom_traits.cc
|
|
index 0c20fd9b054b6bdf989adde7d9c03f4f784215d9..4d1e584278722eb449012ef4f2f8f2162223711f 100644
|
|
--- a/services/network/public/cpp/first_party_sets_mojom_traits.cc
|
|
+++ b/services/network/public/cpp/first_party_sets_mojom_traits.cc
|
|
@@ -18,6 +18,7 @@
|
|
#include "net/first_party_sets/first_party_sets_cache_filter.h"
|
|
#include "net/first_party_sets/first_party_sets_context_config.h"
|
|
#include "net/first_party_sets/global_first_party_sets.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "services/network/public/cpp/schemeful_site_mojom_traits.h"
|
|
#include "services/network/public/mojom/first_party_sets.mojom-shared.h"
|
|
|
|
@@ -83,10 +84,55 @@ bool StructTraits<network::mojom::FirstPartySetEntryDataView,
|
|
return true;
|
|
}
|
|
|
|
+bool EnumTraits<network::mojom::SamePartyCookieContextType,
|
|
+ net::SamePartyContext::Type>::
|
|
+ FromMojom(network::mojom::SamePartyCookieContextType context_type,
|
|
+ net::SamePartyContext::Type* out) {
|
|
+ switch (context_type) {
|
|
+ case network::mojom::SamePartyCookieContextType::kCrossParty:
|
|
+ *out = net::SamePartyContext::Type::kCrossParty;
|
|
+ return true;
|
|
+ case network::mojom::SamePartyCookieContextType::kSameParty:
|
|
+ *out = net::SamePartyContext::Type::kSameParty;
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+network::mojom::SamePartyCookieContextType
|
|
+EnumTraits<network::mojom::SamePartyCookieContextType,
|
|
+ net::SamePartyContext::Type>::ToMojom(net::SamePartyContext::Type
|
|
+ context_type) {
|
|
+ switch (context_type) {
|
|
+ case net::SamePartyContext::Type::kCrossParty:
|
|
+ return network::mojom::SamePartyCookieContextType::kCrossParty;
|
|
+ case net::SamePartyContext::Type::kSameParty:
|
|
+ return network::mojom::SamePartyCookieContextType::kSameParty;
|
|
+ }
|
|
+ NOTREACHED();
|
|
+ return network::mojom::SamePartyCookieContextType::kCrossParty;
|
|
+}
|
|
+
|
|
+bool StructTraits<network::mojom::SamePartyContextDataView,
|
|
+ net::SamePartyContext>::
|
|
+ Read(network::mojom::SamePartyContextDataView context,
|
|
+ net::SamePartyContext* out) {
|
|
+ net::SamePartyContext::Type context_type;
|
|
+ if (!context.ReadContextType(&context_type))
|
|
+ return false;
|
|
+
|
|
+ *out = net::SamePartyContext(context_type);
|
|
+ return true;
|
|
+}
|
|
+
|
|
bool StructTraits<network::mojom::FirstPartySetMetadataDataView,
|
|
net::FirstPartySetMetadata>::
|
|
Read(network::mojom::FirstPartySetMetadataDataView metadata,
|
|
net::FirstPartySetMetadata* out_metadata) {
|
|
+ net::SamePartyContext context;
|
|
+ if (!metadata.ReadContext(&context))
|
|
+ return false;
|
|
+
|
|
absl::optional<net::FirstPartySetEntry> frame_entry;
|
|
if (!metadata.ReadFrameEntry(&frame_entry))
|
|
return false;
|
|
@@ -95,8 +141,9 @@ bool StructTraits<network::mojom::FirstPartySetMetadataDataView,
|
|
if (!metadata.ReadTopFrameEntry(&top_frame_entry))
|
|
return false;
|
|
|
|
- *out_metadata = net::FirstPartySetMetadata(
|
|
- base::OptionalToPtr(frame_entry), base::OptionalToPtr(top_frame_entry));
|
|
+ *out_metadata =
|
|
+ net::FirstPartySetMetadata(context, base::OptionalToPtr(frame_entry),
|
|
+ base::OptionalToPtr(top_frame_entry));
|
|
|
|
return true;
|
|
}
|
|
diff --git a/services/network/public/cpp/first_party_sets_mojom_traits.h b/services/network/public/cpp/first_party_sets_mojom_traits.h
|
|
index b255f56ead022bb237296e7560c73f692a7d7ee3..644aab23aef7fb37c573add9e4180b743c755a12 100644
|
|
--- a/services/network/public/cpp/first_party_sets_mojom_traits.h
|
|
+++ b/services/network/public/cpp/first_party_sets_mojom_traits.h
|
|
@@ -16,6 +16,7 @@
|
|
#include "net/first_party_sets/first_party_sets_cache_filter.h"
|
|
#include "net/first_party_sets/first_party_sets_context_config.h"
|
|
#include "net/first_party_sets/global_first_party_sets.h"
|
|
+#include "net/first_party_sets/same_party_context.h"
|
|
#include "services/network/public/mojom/first_party_sets.mojom-shared.h"
|
|
|
|
namespace mojo {
|
|
@@ -61,10 +62,38 @@ struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
net::FirstPartySetEntry* out);
|
|
};
|
|
|
|
+template <>
|
|
+struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
+ EnumTraits<network::mojom::SamePartyCookieContextType,
|
|
+ net::SamePartyContext::Type> {
|
|
+ static network::mojom::SamePartyCookieContextType ToMojom(
|
|
+ net::SamePartyContext::Type context_type);
|
|
+
|
|
+ static bool FromMojom(network::mojom::SamePartyCookieContextType context_type,
|
|
+ net::SamePartyContext::Type* out);
|
|
+};
|
|
+
|
|
+template <>
|
|
+struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
+ StructTraits<network::mojom::SamePartyContextDataView,
|
|
+ net::SamePartyContext> {
|
|
+ static net::SamePartyContext::Type context_type(
|
|
+ const net::SamePartyContext& s) {
|
|
+ return s.context_type();
|
|
+ }
|
|
+
|
|
+ static bool Read(network::mojom::SamePartyContextDataView bundle,
|
|
+ net::SamePartyContext* out);
|
|
+};
|
|
+
|
|
template <>
|
|
struct COMPONENT_EXPORT(FIRST_PARTY_SETS_MOJOM_TRAITS)
|
|
StructTraits<network::mojom::FirstPartySetMetadataDataView,
|
|
net::FirstPartySetMetadata> {
|
|
+ static net::SamePartyContext context(const net::FirstPartySetMetadata& m) {
|
|
+ return m.context();
|
|
+ }
|
|
+
|
|
static absl::optional<net::FirstPartySetEntry> frame_entry(
|
|
const net::FirstPartySetMetadata& m) {
|
|
return m.frame_entry();
|
|
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
|
|
index 311985f787a8577715609fcd389c3de04f25e310..32dd3b3924964d087121b5d4256c83951160baf1 100644
|
|
--- a/services/network/public/mojom/BUILD.gn
|
|
+++ b/services/network/public/mojom/BUILD.gn
|
|
@@ -1019,6 +1019,14 @@ mojom("mojom_first_party_sets") {
|
|
mojom = "network.mojom.FirstPartySetEntry"
|
|
cpp = "::net::FirstPartySetEntry"
|
|
},
|
|
+ {
|
|
+ mojom = "network.mojom.SamePartyCookieContextType"
|
|
+ cpp = "::net::SamePartyContext::Type"
|
|
+ },
|
|
+ {
|
|
+ mojom = "network.mojom.SamePartyContext"
|
|
+ cpp = "::net::SamePartyContext"
|
|
+ },
|
|
{
|
|
mojom = "network.mojom.FirstPartySetMetadata"
|
|
cpp = "::net::FirstPartySetMetadata"
|
|
diff --git a/services/network/public/mojom/cookie_manager.mojom b/services/network/public/mojom/cookie_manager.mojom
|
|
index 3e2e95956b691efe49b99a1509daea55d96fb8b9..563394f5d34f3314ca2208e46913bfd69bef6c58 100644
|
|
--- a/services/network/public/mojom/cookie_manager.mojom
|
|
+++ b/services/network/public/mojom/cookie_manager.mojom
|
|
@@ -183,6 +183,12 @@ struct CookieOptions {
|
|
CookieSameSiteContext same_site_cookie_context;
|
|
bool update_access_time = true;
|
|
bool return_excluded_cookies = false;
|
|
+ SamePartyContext same_party_context;
|
|
+ // The size of the isolation_info.party_context plus the top-frame site for
|
|
+ // logging purposes.
|
|
+ uint32 full_party_context_size = 0;
|
|
+ // Whether the site is a member of a nontrivial First-Party Set.
|
|
+ bool is_in_nontrivial_first_party_set = false;
|
|
};
|
|
|
|
// See net/cookies/canonical_cookie.{h,cc} for documentation.
|
|
diff --git a/services/network/public/mojom/first_party_sets.mojom b/services/network/public/mojom/first_party_sets.mojom
|
|
index 0ea745cd2450c2d92002c3a0113295b0d4bbd40e..150fed986ded1c82ca3b965c0218193dc938d7a1 100644
|
|
--- a/services/network/public/mojom/first_party_sets.mojom
|
|
+++ b/services/network/public/mojom/first_party_sets.mojom
|
|
@@ -27,9 +27,25 @@ struct FirstPartySetEntry {
|
|
SiteIndex? site_index;
|
|
};
|
|
|
|
+// Computed for every cookie access attempt but is only relevant for SameParty
|
|
+// cookies.
|
|
+enum SamePartyCookieContextType {
|
|
+ // The opposite to kSameParty. Should be the default value.
|
|
+ kCrossParty,
|
|
+ // If the request URL is in the same First-Party Sets as the top-frame site
|
|
+ // and each member of the isolation_info.party_context.
|
|
+ kSameParty,
|
|
+};
|
|
+
|
|
+// Keep defaults in here in sync with net/cookies/same_party_context.cc.
|
|
+struct SamePartyContext {
|
|
+ SamePartyCookieContextType context_type = kCrossParty;
|
|
+};
|
|
+
|
|
// This struct must match the class fields defined in
|
|
// //net/first_party_sets/first_party_set_metadata.h.
|
|
struct FirstPartySetMetadata {
|
|
+ SamePartyContext context;
|
|
// absl::nullopt indicates that the frame's site is not associated with any
|
|
// First-Party Set.
|
|
FirstPartySetEntry? frame_entry;
|
|
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
|
|
index cc22ed62613a567e44708758a75de2cac18ee284..1a1eca338ff8cd7e1b1b247cfadaee16f37e5628 100644
|
|
--- a/services/network/restricted_cookie_manager.cc
|
|
+++ b/services/network/restricted_cookie_manager.cc
|
|
@@ -56,11 +56,17 @@ BASE_FEATURE(kIncreaseCoookieAccesCacheSize,
|
|
// adding a user-perceptible delay.
|
|
constexpr base::TimeDelta kCookiesAccessedTimeout = base::Milliseconds(100);
|
|
|
|
+// The `force_ignore_top_frame_party` param being false prevents `document.cookie`
|
|
+// access for same-party scripts embedded in an extension frame.
|
|
+const bool kForceIgnoreTopFrameParty = false;
|
|
+
|
|
net::CookieOptions MakeOptionsForSet(
|
|
mojom::RestrictedCookieManagerRole role,
|
|
const GURL& url,
|
|
const net::SiteForCookies& site_for_cookies,
|
|
- const CookieSettings& cookie_settings) {
|
|
+ const net::IsolationInfo& isolation_info,
|
|
+ const CookieSettings& cookie_settings,
|
|
+ const net::FirstPartySetMetadata& first_party_set_metadata) {
|
|
net::CookieOptions options;
|
|
bool force_ignore_site_for_cookies =
|
|
cookie_settings.ShouldIgnoreSameSiteRestrictions(url, site_for_cookies);
|
|
@@ -76,6 +82,14 @@ net::CookieOptions MakeOptionsForSet(
|
|
net::cookie_util::ComputeSameSiteContextForSubresource(
|
|
url, site_for_cookies, force_ignore_site_for_cookies));
|
|
}
|
|
+ options.set_same_party_context(first_party_set_metadata.context());
|
|
+ if (isolation_info.party_context().has_value()) {
|
|
+ // Count the top-frame site since it's not in the party_context.
|
|
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
|
|
+ 1);
|
|
+ }
|
|
+ options.set_is_in_nontrivial_first_party_set(
|
|
+ first_party_set_metadata.frame_entry().has_value());
|
|
|
|
return options;
|
|
}
|
|
@@ -84,7 +98,9 @@ net::CookieOptions MakeOptionsForGet(
|
|
mojom::RestrictedCookieManagerRole role,
|
|
const GURL& url,
|
|
const net::SiteForCookies& site_for_cookies,
|
|
- const CookieSettings& cookie_settings) {
|
|
+ const net::IsolationInfo& isolation_info,
|
|
+ const CookieSettings& cookie_settings,
|
|
+ const net::FirstPartySetMetadata& first_party_set_metadata) {
|
|
// TODO(https://crbug.com/925311): Wire initiator here.
|
|
net::CookieOptions options;
|
|
bool force_ignore_site_for_cookies =
|
|
@@ -102,6 +118,14 @@ net::CookieOptions MakeOptionsForGet(
|
|
net::cookie_util::ComputeSameSiteContextForSubresource(
|
|
url, site_for_cookies, force_ignore_site_for_cookies));
|
|
}
|
|
+ options.set_same_party_context(first_party_set_metadata.context());
|
|
+ if (isolation_info.party_context().has_value()) {
|
|
+ // Count the top-frame site since it's not in the party_context.
|
|
+ options.set_full_party_context_size(isolation_info.party_context()->size() +
|
|
+ 1);
|
|
+ }
|
|
+ options.set_is_in_nontrivial_first_party_set(
|
|
+ first_party_set_metadata.frame_entry().has_value());
|
|
|
|
return options;
|
|
}
|
|
@@ -123,7 +147,8 @@ void RestrictedCookieManager::ComputeFirstPartySetMetadata(
|
|
absl::optional<net::FirstPartySetMetadata> metadata =
|
|
net::cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
|
|
/*request_site=*/net::SchemefulSite(origin), isolation_info,
|
|
- cookie_store->cookie_access_delegate(), std::move(callbacks.first));
|
|
+ cookie_store->cookie_access_delegate(), kForceIgnoreTopFrameParty,
|
|
+ std::move(callbacks.first));
|
|
if (metadata.has_value())
|
|
std::move(callbacks.second).Run(std::move(metadata.value()));
|
|
}
|
|
@@ -216,7 +241,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
bool has_storage_access,
|
|
const absl::optional<net::CookiePartitionKey>& cookie_partition_key,
|
|
net::CookieOptions options,
|
|
- mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener)
|
|
+ mojo::PendingRemote<mojom::CookieChangeListener> mojo_listener,
|
|
+ bool same_party_attribute_enabled)
|
|
: cookie_store_(cookie_store),
|
|
restricted_cookie_manager_(restricted_cookie_manager),
|
|
url_(url),
|
|
@@ -224,7 +250,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
top_frame_origin_(top_frame_origin),
|
|
has_storage_access_(has_storage_access),
|
|
options_(options),
|
|
- mojo_listener_(std::move(mojo_listener)) {
|
|
+ mojo_listener_(std::move(mojo_listener)),
|
|
+ same_party_attribute_enabled_(same_party_attribute_enabled) {
|
|
// TODO(pwnall): add a constructor w/options to net::CookieChangeDispatcher.
|
|
cookie_store_subscription_ =
|
|
cookie_store->GetChangeDispatcher().AddCallbackForUrl(
|
|
@@ -260,11 +287,16 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
|
|
// CookieChangeDispatcher doesn't check for inclusion against `options_`, so
|
|
// we need to double-check that.
|
|
+ net::CookieSamePartyStatus same_party_status =
|
|
+ net::cookie_util::GetSamePartyStatus(change.cookie, options_,
|
|
+ same_party_attribute_enabled_);
|
|
+
|
|
if (!change.cookie
|
|
.IncludeForRequestURL(
|
|
url_, options_,
|
|
net::CookieAccessParams{change.access_result.access_semantics,
|
|
- delegate_treats_url_as_trustworthy})
|
|
+ delegate_treats_url_as_trustworthy,
|
|
+ same_party_status})
|
|
.status.IsInclude()) {
|
|
return;
|
|
}
|
|
@@ -315,6 +347,8 @@ class RestrictedCookieManager::Listener : public base::LinkNode<Listener> {
|
|
|
|
mojo::Remote<mojom::CookieChangeListener> mojo_listener_;
|
|
|
|
+ bool same_party_attribute_enabled_;
|
|
+
|
|
SEQUENCE_CHECKER(sequence_checker_);
|
|
};
|
|
|
|
@@ -341,6 +375,8 @@ RestrictedCookieManager::RestrictedCookieManager(
|
|
cookie_partition_key_collection_(
|
|
net::CookiePartitionKeyCollection::FromOptional(
|
|
cookie_partition_key_)),
|
|
+ same_party_attribute_enabled_(base::FeatureList::IsEnabled(
|
|
+ net::features::kSamePartyAttributeEnabled)),
|
|
receiver_(this),
|
|
metrics_updater_(metrics_updater),
|
|
cookies_access_timer_(
|
|
@@ -451,7 +487,8 @@ void RestrictedCookieManager::GetAllForUrl(
|
|
// TODO(morlovich): Try to validate site_for_cookies as well.
|
|
|
|
net::CookieOptions net_options =
|
|
- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
|
|
+ MakeOptionsForGet(role_, url, site_for_cookies, isolation_info_,
|
|
+ cookie_settings(), first_party_set_metadata_);
|
|
// TODO(https://crbug.com/977040): remove set_return_excluded_cookies() once
|
|
// removing deprecation warnings.
|
|
net_options.set_return_excluded_cookies();
|
|
@@ -705,7 +742,8 @@ void RestrictedCookieManager::SetCanonicalCookie(
|
|
|
|
net::CanonicalCookie cookie_copy = *sanitized_cookie;
|
|
net::CookieOptions options =
|
|
- MakeOptionsForSet(role_, url, site_for_cookies, cookie_settings());
|
|
+ MakeOptionsForSet(role_, url, site_for_cookies, isolation_info_,
|
|
+ cookie_settings(), first_party_set_metadata_);
|
|
|
|
net::CookieAccessResult cookie_access_result(status);
|
|
cookie_store_->SetCanonicalCookieAsync(
|
|
@@ -757,11 +795,12 @@ void RestrictedCookieManager::AddChangeListener(
|
|
}
|
|
|
|
net::CookieOptions net_options =
|
|
- MakeOptionsForGet(role_, url, site_for_cookies, cookie_settings());
|
|
+ MakeOptionsForGet(role_, url, site_for_cookies, isolation_info_,
|
|
+ cookie_settings(), first_party_set_metadata_);
|
|
auto listener = std::make_unique<Listener>(
|
|
cookie_store_, this, url, site_for_cookies, top_frame_origin,
|
|
has_storage_access, cookie_partition_key_, net_options,
|
|
- std::move(mojo_listener));
|
|
+ std::move(mojo_listener), same_party_attribute_enabled_);
|
|
|
|
listener->mojo_listener().set_disconnect_handler(
|
|
base::BindOnce(&RestrictedCookieManager::RemoveChangeListener,
|
|
diff --git a/services/network/restricted_cookie_manager.h b/services/network/restricted_cookie_manager.h
|
|
index be2749818c7af32f48da819b378c9afaa4933933..8086076904844fe208c4f3f72569e85fb485dec0 100644
|
|
--- a/services/network/restricted_cookie_manager.h
|
|
+++ b/services/network/restricted_cookie_manager.h
|
|
@@ -314,6 +314,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) RestrictedCookieManager
|
|
// update filtering.
|
|
CookieAccessesByURLAndSite recent_cookie_accesses_;
|
|
|
|
+ bool same_party_attribute_enabled_;
|
|
+
|
|
// This class can optionally bind its Receiver. If that's the case it's stored
|
|
// done with this variable.
|
|
mojo::Receiver<mojom::RestrictedCookieManager> receiver_;
|
|
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
|
|
index 4ad8c5476cbf00a4246ec524e5d95037b06a7151..2cb705fcd442334074edcf2265ae0ccbb26db183 100644
|
|
--- a/services/network/url_loader.cc
|
|
+++ b/services/network/url_loader.cc
|
|
@@ -287,6 +287,8 @@ bool ShouldNotifyAboutCookie(net::CookieInclusionStatus status) {
|
|
return status.IsInclude() || status.ShouldWarn() ||
|
|
status.HasExclusionReason(
|
|
net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES) ||
|
|
+ status.HasExclusionReason(
|
|
+ net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY) ||
|
|
status.HasExclusionReason(
|
|
net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII);
|
|
}
|
|
@@ -586,6 +588,9 @@ URLLoader::URLLoader(
|
|
DCHECK(!url_request_->isolation_info().IsEmpty());
|
|
}
|
|
|
|
+ if (ShouldForceIgnoreTopFramePartyForCookies())
|
|
+ url_request_->set_force_ignore_top_frame_party_for_cookies(true);
|
|
+
|
|
// When a service worker forwards a navigation request it uses the
|
|
// service worker's IsolationInfo. This causes the cookie code to fail
|
|
// to send SameSite=Lax cookies for main-frame navigations passed through
|
|
@@ -2689,6 +2694,36 @@ bool URLLoader::ShouldForceIgnoreSiteForCookies(
|
|
return false;
|
|
}
|
|
|
|
+bool URLLoader::ShouldForceIgnoreTopFramePartyForCookies() const {
|
|
+ const net::IsolationInfo& isolation_info = url_request_->isolation_info();
|
|
+ const absl::optional<url::Origin>& top_frame_origin =
|
|
+ isolation_info.top_frame_origin();
|
|
+
|
|
+ if (!top_frame_origin || top_frame_origin->opaque())
|
|
+ return false;
|
|
+
|
|
+ const absl::optional<std::set<net::SchemefulSite>>& party_context =
|
|
+ isolation_info.party_context();
|
|
+ if (!party_context)
|
|
+ return false;
|
|
+
|
|
+ // The top frame origin must have access to the request URL.
|
|
+ if (cors::OriginAccessList::AccessState::kAllowed !=
|
|
+ origin_access_list_->CheckAccessState(*top_frame_origin,
|
|
+ url_request_->url())) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // The top frame origin must have access to each site in the party_context.
|
|
+ return base::ranges::all_of(
|
|
+ *party_context,
|
|
+ [this, &top_frame_origin](const net::SchemefulSite& site) {
|
|
+ return origin_access_list_->CheckAccessState(*top_frame_origin,
|
|
+ site.GetURL()) ==
|
|
+ cors::OriginAccessList::AccessState::kAllowed;
|
|
+ });
|
|
+}
|
|
+
|
|
void URLLoader::SetRequestCredentials(const GURL& url) {
|
|
bool coep_allow_credentials = CoepAllowCredentials(url);
|
|
|
|
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
|
|
index 6970066e65c6e61a6fed1248127abd6550ddfec6..96d224b1634aff0791ac6b3799725e61ab11afca 100644
|
|
--- a/services/network/url_loader.h
|
|
+++ b/services/network/url_loader.h
|
|
@@ -548,6 +548,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
|
|
// Whether `force_ignore_site_for_cookies` should be set on net::URLRequest.
|
|
bool ShouldForceIgnoreSiteForCookies(const ResourceRequest& request);
|
|
|
|
+ // Whether `force_ignore_top_frame_party_for_cookies` should be set on
|
|
+ // net::URLRequest.
|
|
+ bool ShouldForceIgnoreTopFramePartyForCookies() const;
|
|
+
|
|
// Applies Private Network Access checks to the current request.
|
|
//
|
|
// Helper for `OnConnected()`.
|