0

Add interest group browser tests for Trusted KVv2 signals

Add same origin and cross origin for both trusted KVv2 bidding and scoring signals.

Bug: 337917489
Change-Id: Ic01927e432575ed1b5c4578d1807819cf2b5e5f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5930645
Commit-Queue: Tianyang Xu <xtlsheep@google.com>
Reviewed-by: Maks Orlovich <morlovich@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1372731}
This commit is contained in:
Tianyang Xu
2024-10-23 15:44:46 +00:00
committed by Chromium LUCI CQ
parent c87fb63b8a
commit ba04ed009c
2 changed files with 776 additions and 1 deletions
content
browser
test

@ -90,6 +90,7 @@
#include "content/public/test/test_frame_navigation_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/url_loader_monitor.h"
#include "content/services/auction_worklet/public/cpp/cbor_test_util.h"
#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
@ -104,6 +105,7 @@
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "net/third_party/quiche/src/quiche/oblivious_http/oblivious_http_gateway.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "services/network/public/cpp/features.h"
@ -948,6 +950,10 @@ class InterestGroupBrowserTest : public ContentBrowserTest {
dict.Set("trustedBiddingSignalsURL",
group.trusted_bidding_signals_url->spec());
}
if (group.trusted_bidding_signals_coordinator) {
dict.Set("trustedBiddingSignalsCoordinator",
group.trusted_bidding_signals_coordinator->Serialize());
}
if (group.user_bidding_signals) {
dict.Set("userBiddingSignals", JsonToValue(*group.user_bidding_signals));
}
@ -20959,7 +20965,7 @@ class InterestGroupBiddingAndAuctionServerBrowserTest
void ProvideKeys() {
// We use a URLLoaderInterceptor instead of the EmbeddedTestServer, since we
// need to set the URL for it in the constructor, before the
// EmbeddedTestServer starts. At that point we don't know the origin the
// EmbeddedTestServer starts. At that point we don't know the port the
// EmbeddedTestServer will be using.
url_loader_interceptor_ =
std::make_unique<URLLoaderInterceptor>(base::BindLambdaForTesting(
@ -26656,6 +26662,774 @@ IN_PROC_BROWSER_TEST_F(InterestGroupUseMainThreadInRendererTest,
}
#endif
class InterestGroupTrustedSignalsKVv2BrowserTest
: public InterestGroupBrowserTest {
public:
InterestGroupTrustedSignalsKVv2BrowserTest() {
feature_list_.InitWithFeaturesAndParameters(
{{blink::features::kFledgeBiddingAndAuctionServer,
{{"FledgeBiddingAndAuctionKeyURL", kKeyUrl.spec()}}},
{blink::features::kFledgeTrustedSignalsKVv2Support, {}},
{blink::features::kFledgePermitCrossOriginTrustedSignals, {}}},
{});
}
void SetUpOnMainThread() override {
embedded_https_test_server().RegisterRequestHandler(base::BindRepeating(
&InterestGroupTrustedSignalsKVv2BrowserTest::HandleTrustedKVv2Signals,
base::Unretained(this)));
InterestGroupBrowserTest::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
InterestGroupBrowserTest::TearDownOnMainThread();
url_loader_interceptor_.reset();
}
void ProvideKeys() {
// We use a URLLoaderInterceptor instead of the EmbeddedTestServer, since we
// need to set the URL for it in the constructor, before the
// EmbeddedTestServer starts. At that point we don't know the port the
// EmbeddedTestServer will be using.
url_loader_interceptor_ =
std::make_unique<URLLoaderInterceptor>(base::BindLambdaForTesting(
[&](URLLoaderInterceptor::RequestParams* params) -> bool {
if (params->url_request.url != kKeyUrl) {
return false;
}
std::string headers =
"HTTP/1.1 200 OK\nContent-Type: application/json\n\n";
const uint8_t kTestPublicKey[] = {
0xa1, 0x5f, 0x40, 0x65, 0x86, 0xfa, 0xc4, 0x7b,
0x99, 0x59, 0x70, 0xf1, 0x85, 0xd9, 0xd8, 0x91,
0xc7, 0x4d, 0xcf, 0x1e, 0xb9, 0x1a, 0x7d, 0x50,
0xa5, 0x8b, 0x01, 0x68, 0x3e, 0x60, 0x05, 0x2d,
};
base::Value::Dict key;
key.Set("key", base::Base64Encode(kTestPublicKey));
key.Set("id", "AA");
base::Value::List keys;
keys.Append(std::move(key));
base::Value::Dict outer;
outer.Set("keys", std::move(keys));
std::string json_output;
JSONStringValueSerializer serializer(&json_output);
serializer.Serialize(outer);
URLLoaderInterceptor::WriteResponse(headers, json_output,
params->client.get());
return true;
}));
}
void TestTrustedKVv2BiddingSignalsCrossOrigin(bool expect_success,
bool add_cors_header,
bool attest_signals_origin);
void TestTrustedKVv2ScoringSignalsCrossOrigin(bool expect_success,
bool add_cors_header,
bool add_script_header,
bool attest_signals_origin);
protected:
std::unique_ptr<net::test_server::HttpResponse> HandleTrustedKVv2Signals(
const net::test_server::HttpRequest& request) {
if (!base::StartsWith(request.relative_url,
"/trusted_kvv2_bidding_signals") &&
!base::StartsWith(request.relative_url,
"/trusted_kvv2_scoring_signals")) {
return nullptr;
}
const char kBiddingBase[] =
R"([
{
"id": 0,
"dataVersion": 100,
"keyGroupOutputs": [
{
"tags": [
"interestGroupNames"
],
"keyValues": {
"group": {
"value": "{\"priorityVector\":{\"foo\":1}}"
}
}
},
{
"tags": [
"keys"
],
"keyValues": {
"key1": {
"value": "1"
},
"key2": {
"value": "\"2\""
}
}
}
]
}
])";
const char kScoringBase[] =
R"([
{
"id": 0,
"dataVersion": 100,
"keyGroupOutputs": [
{
"tags": [
"renderUrls"
],
"keyValues": {
"https://bar.test/": {
"value": "1"
}
}
},
{
"tags": [
"adComponentRenderUrls"
],
"keyValues": {
"https://barsub.test/": {
"value": "2"
},
"https://foosub.test/": {
"value": "\"3\""
}
}
}
]
}
])";
const uint8_t kTestPrivateKey[] = {
0xff, 0x1f, 0x47, 0xb1, 0x68, 0xb6, 0xb9, 0xea, 0x65, 0xf7, 0x97,
0x4f, 0xf2, 0x2e, 0xf2, 0x36, 0x94, 0xe2, 0xf6, 0xb6, 0x8d, 0x66,
0xf3, 0xa7, 0x64, 0x14, 0x28, 0xd4, 0x45, 0x35, 0x01, 0x8f,
};
base::AutoLock auto_lock(lock_);
// Handle CORS preflight request.
if (request.method == net::test_server::METHOD_OPTIONS) {
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
response->set_code(net::HTTP_OK);
response->AddCustomHeader("Access-Control-Allow-Origin",
access_control_allow_origin_header_);
response->AddCustomHeader("Access-Control-Allow-Methods", "POST");
response->AddCustomHeader("Access-Control-Allow-Headers", "*");
return response;
}
// Decrypt the request.
auto response_key_config = quiche::ObliviousHttpHeaderKeyConfig::Create(
0xAA, EVP_HPKE_DHKEM_X25519_HKDF_SHA256, EVP_HPKE_HKDF_SHA256,
EVP_HPKE_AES_256_GCM);
CHECK(response_key_config.ok()) << response_key_config.status();
auto ohttp_gateway =
quiche::ObliviousHttpGateway::Create(
std::string(reinterpret_cast<const char*>(&kTestPrivateKey[0]),
sizeof(kTestPrivateKey)),
response_key_config.value())
.value();
auto received_request = ohttp_gateway.DecryptObliviousHttpRequest(
request.content, "message/ad-auction-trusted-signals-request");
CHECK(received_request.ok()) << received_request.status();
cbor::Value::MapValue compression_group;
compression_group.try_emplace(cbor::Value("compressionGroupId"),
cbor::Value(0));
compression_group.try_emplace(cbor::Value("ttlMs"), cbor::Value(100));
if (base::StartsWith(request.relative_url,
"/trusted_kvv2_bidding_signals")) {
compression_group.try_emplace(
cbor::Value("content"),
cbor::Value(auction_worklet::test::ToCborVector(kBiddingBase)));
} else {
compression_group.try_emplace(
cbor::Value("content"),
cbor::Value(auction_worklet::test::ToCborVector(kScoringBase)));
}
cbor::Value::ArrayValue compression_groups;
compression_groups.emplace_back(std::move(compression_group));
cbor::Value::MapValue body_map;
body_map.try_emplace(cbor::Value("compressionGroups"),
cbor::Value(std::move(compression_groups)));
cbor::Value body_value(std::move(body_map));
std::optional<std::vector<uint8_t>> maybe_body_bytes =
cbor::Writer::Write(body_value);
std::string response_body = auction_worklet::test::CreateKVv2ResponseBody(
base::as_string_view(maybe_body_bytes.value()));
auto response_context =
std::move(received_request).value().ReleaseContext();
// Encrypt the response body.
auto maybe_response = ohttp_gateway.CreateObliviousHttpResponse(
response_body, response_context,
"message/ad-auction-trusted-signals-response");
EXPECT_TRUE(maybe_response.ok()) << maybe_response.status();
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
response->set_content_type("message/ad-auction-trusted-signals-response");
response->set_content(maybe_response->EncapsulateAndSerialize());
response->AddCustomHeader("Ad-Auction-Allowed", "true");
if (!access_control_allow_origin_header_.empty()) {
response->AddCustomHeader("Access-Control-Allow-Origin",
access_control_allow_origin_header_);
}
return response;
}
void SetAccessControlAllowOriginHeader(std::string header) {
base::AutoLock auto_lock(lock_);
access_control_allow_origin_header_ = header;
}
const GURL kKeyUrl =
GURL("https://example.test/interest_group/b_and_a_keys.json");
std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_;
base::test::ScopedFeatureList feature_list_;
base::Lock lock_;
std::string access_control_allow_origin_header_ GUARDED_BY(lock_);
};
void InterestGroupTrustedSignalsKVv2BrowserTest::
TestTrustedKVv2BiddingSignalsCrossOrigin(bool expect_success,
bool add_cors_header,
bool attest_signals_origin) {
const char kPublisher[] = "a.test";
const char kBidder[] = "b.test";
const char kSeller[] = "c.test";
const char kBidderSignals[] = "d.test";
GURL test_url =
embedded_https_test_server().GetURL(kPublisher, "/page_with_iframe.html");
GURL ad_url =
embedded_https_test_server().GetURL(kBidder, "/echo?render_cars");
GURL bidder_url = embedded_https_test_server().GetURL(kBidder, "/echo");
GURL bidder_script_url = embedded_https_test_server().GetURL(
kBidder, "/interest_group/bidding_logic_trusted_kvv2_bidding_signals.js");
GURL bidder_signals_url = embedded_https_test_server().GetURL(
kBidderSignals, "/trusted_kvv2_bidding_signals");
GURL seller_script_url = embedded_https_test_server().GetURL(
kSeller, "/interest_group/decision_logic.js");
url::Origin bidder_origin = url::Origin::Create(bidder_script_url);
url::Origin seller_origin = url::Origin::Create(seller_script_url);
ProvideKeys();
if (add_cors_header) {
SetAccessControlAllowOriginHeader(
url::Origin::Create(bidder_script_url).Serialize());
}
if (attest_signals_origin) {
content_browser_client_->AddToAllowList(
{url::Origin::Create(bidder_signals_url)});
}
// Navigate to bidder site, and add an interest group.
ASSERT_TRUE(NavigateToURL(shell(), bidder_url));
WebContentsConsoleObserver console_observer(shell()->web_contents());
if (!attest_signals_origin) {
console_observer.SetPattern(
"joinAdInterestGroup of interest group with owner 'https://b.test:*' "
"blocked because it lacks attestation of cross-origin trusted signals "
"origin 'https://d.test:*' or that origin is disallowed by user "
"preferences");
}
auto ig =
blink::TestInterestGroupBuilder(
/*owner=*/bidder_origin,
/*name=*/"group")
.SetBiddingUrl(bidder_script_url)
.SetTrustedBiddingSignalsUrl(bidder_signals_url)
.SetTrustedBiddingSignalsKeys({{"key1", "key2"}})
.SetAds(/*ads=*/{{{ad_url, R"({"ad":"metadata","here":[1,2]})"}}})
.SetTrustedBiddingSignalsCoordinator(url::Origin::Create(
GURL("https://publickeyservice.gcp.privacysandboxservices.com")))
.SetExecutionMode(
blink::InterestGroup::ExecutionMode::kGroupedByOriginMode)
.Build();
if (attest_signals_origin) {
EXPECT_EQ(kSuccess, JoinInterestGroupAndVerify(ig));
} else {
// Can't actually tell the join failed, but it won't verify.
EXPECT_EQ(kSuccess, JoinInterestGroup(ig));
EXPECT_TRUE(console_observer.Wait());
// Auction will fail w/o an IG available.
}
// Register a bidder script that only bids if
// `crossOriginTrustedBiddingSignals` is successfully fetched.
const char kBidScriptTemplate[] = R"(
function generateBid(
interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
browserSignals, directFromSellerSignals,
crossOriginTrustedBiddingSignals) {
if ('dataVersion' in browserSignals) {
throw 'Unexpected dataVersion in browserSignals.';
}
if (browserSignals.crossOriginDataVersion !== 100) {
throw 'Unexpected crossOriginDataVersion: ' +
browserSignals.crossOriginDataVersion;
}
if (trustedBiddingSignals !== null) {
throw 'Unexpected trustedBiddingSignals found.';
}
if (crossOriginTrustedBiddingSignals[$1].key1 !== 1 ||
crossOriginTrustedBiddingSignals[$1].key2 !== '2') {
throw 'Unexpected crossOriginTrustedBiddingSignals: ' +
JSON.stringify(crossOriginTrustedBiddingSignals);
}
return {
bid: 1,
render: interestGroup.ads[0].renderURL,
};
})";
network_responder_->RegisterNetworkResponse(
bidder_script_url.path(),
JsReplace(kBidScriptTemplate, url::Origin::Create(bidder_signals_url)),
"application/javascript");
// Navigate to publisher.
ASSERT_TRUE(
NavigateToURL(shell(), embedded_https_test_server().GetURL(
kPublisher, "/page_with_iframe.html")));
std::string auction_config = JsReplace(
R"({
seller: $1,
decisionLogicURL: $2,
interestGroupBuyers: [$3],
})",
seller_origin, seller_script_url, bidder_origin);
if (expect_success) {
EXPECT_EQ(ad_url, RunAuctionAndWaitForUrl(auction_config));
} else {
EXPECT_EQ(nullptr, RunAuctionAndWait(auction_config));
}
}
void InterestGroupTrustedSignalsKVv2BrowserTest::
TestTrustedKVv2ScoringSignalsCrossOrigin(bool expect_success,
bool add_cors_header,
bool add_script_header,
bool attest_signals_origin) {
const char kPublisher[] = "a.test";
const char kBidder[] = "b.test";
const char kSeller[] = "c.test";
const char kSellerSignals[] = "d.test";
GURL test_url =
embedded_https_test_server().GetURL(kPublisher, "/page_with_iframe.html");
GURL ad_url = GURL("https://bar.test/");
GURL bidder_url = embedded_https_test_server().GetURL(kBidder, "/echo");
GURL bidder_script_url = embedded_https_test_server().GetURL(
kBidder, "/interest_group/bidding_logic.js");
GURL seller_script_url = embedded_https_test_server().GetURL(
kSeller,
"/interest_group/decision_logic_trusted_kvv2_scoring_signals.js");
GURL seller_signals_url = embedded_https_test_server().GetURL(
kSellerSignals, "/trusted_kvv2_scoring_signals");
url::Origin bidder_origin = url::Origin::Create(bidder_script_url);
url::Origin seller_origin = url::Origin::Create(seller_script_url);
ProvideKeys();
if (add_cors_header) {
SetAccessControlAllowOriginHeader(
url::Origin::Create(seller_script_url).Serialize());
}
if (attest_signals_origin) {
content_browser_client_->AddToAllowList(
{url::Origin::Create(seller_signals_url)});
}
// Navigate to bidder site, and add an interest group.
ASSERT_TRUE(NavigateToURL(shell(), bidder_url));
EXPECT_EQ(
kSuccess,
JoinInterestGroupAndVerify(
blink::TestInterestGroupBuilder(
/*owner=*/bidder_origin,
/*name=*/"group")
.SetBiddingUrl(bidder_script_url)
.SetAds({{{ad_url, /*metadata=*/std::nullopt}}})
.SetAdComponents(
{{{GURL("https://barsub.test/"), /*metadata=*/std::nullopt},
{GURL("https://foosub.test/"), /*metadata=*/std::nullopt}}})
.Build()));
const char kBidderScript[] = R"(
function generateBid(interestGroup, auctionSignals, perBuyerSignals,
trustedBiddingSignals, browserSignals) {
const ad = interestGroup.ads[0];
let result = {'ad': ad, 'bid': 1, 'render': ad.renderURL};
if (interestGroup.adComponents && interestGroup.adComponents[0])
result.adComponents =
[interestGroup.adComponents[0].renderURL,
interestGroup.adComponents[1].renderURL];
return result;
})";
network_responder_->RegisterNetworkResponse(
bidder_script_url.path(), kBidderScript, "application/javascript");
// Navigate to publisher.
ASSERT_TRUE(NavigateToURL(shell(), test_url));
WebContentsConsoleObserver console_observer(shell()->web_contents());
if (!attest_signals_origin) {
console_observer.SetPattern(
"Worklet error: runAdAuction() auction with seller 'https://c.test:*' "
"failed because it lacks attestation of cross-origin trusted signals "
"origin 'https://d.test:*' or that origin is disallowed by user "
"preferences");
}
// Register a seller script that only score if `trustedScoringSignals` is
// successfully fetched.
const char kSellerScriptTemplate[] = R"(
function scoreAd(
adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals,
directFromSellerSignals, crossOriginTrustedScoringSignals) {
if ('dataVersion' in browserSignals) {
throw 'Unexpected dataVersion in browserSignals.';
}
if (browserSignals.crossOriginDataVersion !== 100) {
throw 'Unexpected crossOriginDataVersion: ' +
browserSignals.crossOriginDataVersion;
}
if (trustedScoringSignals !== null) {
throw 'Unexpected trustedScoringSignals found.';
}
if (crossOriginTrustedScoringSignals[$1].renderURL[browserSignals.renderURL] !== 1 ||
crossOriginTrustedScoringSignals[$1].adComponentRenderURLs[browserSignals.adComponents[0]] !== 2 ||
crossOriginTrustedScoringSignals[$1].adComponentRenderURLs[browserSignals.adComponents[1]] !== '3') {
throw 'Unexpected crossOriginTrustedScoringSignals: ' +
JSON.stringify(crossOriginTrustedScoringSignals);
}
return bid;
}
)";
NetworkResponder::ResponseHeaders extra_js_headers;
if (add_script_header) {
extra_js_headers.emplace_back(
std::string("Ad-Auction-Allow-Trusted-Scoring-Signals-From"),
base::StringPrintf(
"\"%s\"",
url::Origin::Create(seller_signals_url).Serialize().c_str()));
}
network_responder_->RegisterNetworkResponse(
seller_script_url.path(),
JsReplace(kSellerScriptTemplate, url::Origin::Create(seller_signals_url)),
"application/javascript", std::move(extra_js_headers));
std::string auction_config = JsReplace(R"({
seller: $1,
decisionLogicURL: $2,
trustedScoringSignalsURL: $3,
interestGroupBuyers: [$4],
trustedScoringSignalsCoordinator:
"https://publickeyservice.gcp.privacysandboxservices.com"
})",
seller_origin, seller_script_url,
seller_signals_url, bidder_origin);
if (expect_success) {
EXPECT_EQ(ad_url, RunAuctionAndWaitForUrl(auction_config));
} else {
EXPECT_EQ(nullptr, RunAuctionAndWait(auction_config));
}
if (!attest_signals_origin) {
EXPECT_TRUE(console_observer.Wait());
}
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2BiddingSignals) {
const char kPublisher[] = "a.test";
const char kBidder[] = "b.test";
const char kSeller[] = "c.test";
const char kBidderSignals[] = "b.test";
GURL test_url =
embedded_https_test_server().GetURL(kPublisher, "/page_with_iframe.html");
GURL ad_url =
embedded_https_test_server().GetURL(kBidder, "/echo?render_cars");
GURL bidder_url = embedded_https_test_server().GetURL(kBidder, "/echo");
GURL bidder_script_url = embedded_https_test_server().GetURL(
kBidder, "/interest_group/bidding_logic_trusted_kvv2_bidding_signals.js");
GURL bidder_signals_url = embedded_https_test_server().GetURL(
kBidderSignals, "/trusted_kvv2_bidding_signals");
GURL seller_script_url = embedded_https_test_server().GetURL(
kSeller, "/interest_group/decision_logic.js");
url::Origin bidder_origin = url::Origin::Create(bidder_script_url);
url::Origin seller_origin = url::Origin::Create(seller_script_url);
ProvideKeys();
// Navigate to bidder site, and add an interest group.
ASSERT_TRUE(NavigateToURL(shell(), bidder_url));
EXPECT_EQ(
kSuccess,
JoinInterestGroupAndVerify(
blink::TestInterestGroupBuilder(
/*owner=*/bidder_origin,
/*name=*/"group")
.SetBiddingUrl(bidder_script_url)
.SetTrustedBiddingSignalsUrl(bidder_signals_url)
.SetTrustedBiddingSignalsKeys({{"key1", "key2"}})
.SetAds(/*ads=*/{{{ad_url, R"({"ad":"metadata","here":[1,2]})"}}})
.SetTrustedBiddingSignalsCoordinator(url::Origin::Create(GURL(
"https://publickeyservice.gcp.privacysandboxservices.com")))
.SetExecutionMode(
blink::InterestGroup::ExecutionMode::kGroupedByOriginMode)
.Build()));
// Register a bidder script that only bids if `trustedBiddingSignals` is
// successfully fetched.
const char kBidderScript[] = R"(
function generateBid(
interestGroup, auctionSignals, perBuyerSignals, trustedBiddingSignals,
browserSignals, directFromSellerSignals,
crossOriginTrustedBiddingSignals) {
if ('crossOriginDataVersion' in browserSignals) {
throw 'Unexpected crossOriginDataVersion in browserSignals.';
}
if (browserSignals.dataVersion !== 100) {
throw 'Unexpected dataVersion: ' + browserSignals.dataVersion;
}
if (crossOriginTrustedBiddingSignals !== null) {
throw 'Unexpected crossOriginTrustedBiddingSignals found.';
}
if (trustedBiddingSignals.key1 !== 1 ||
trustedBiddingSignals.key2 !== '2') {
throw 'Unexpected trustedBiddingSignals: ' +
JSON.stringify(trustedBiddingSignals);
}
return {
bid: 1,
render: interestGroup.ads[0].renderURL,
};
})";
network_responder_->RegisterNetworkResponse(
bidder_script_url.path(), kBidderScript, "application/javascript");
// Navigate to publisher.
ASSERT_TRUE(
NavigateToURL(shell(), embedded_https_test_server().GetURL(
kPublisher, "/page_with_iframe.html")));
std::string auction_config = JsReplace(
R"({
seller: $1,
decisionLogicURL: $2,
interestGroupBuyers: [$3],
})",
seller_origin, seller_script_url, bidder_origin);
EXPECT_EQ(ad_url, RunAuctionAndWaitForUrl(auction_config));
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2ScoringSignals) {
const char kPublisher[] = "a.test";
const char kBidder[] = "b.test";
const char kSeller[] = "c.test";
const char kSellerSignals[] = "c.test";
GURL test_url =
embedded_https_test_server().GetURL(kPublisher, "/page_with_iframe.html");
GURL ad_url = GURL("https://bar.test/");
GURL bidder_url = embedded_https_test_server().GetURL(kBidder, "/echo");
GURL bidder_script_url = embedded_https_test_server().GetURL(
kBidder, "/interest_group/bidding_logic.js");
GURL seller_script_url = embedded_https_test_server().GetURL(
kSeller,
"/interest_group/decision_logic_trusted_kvv2_scoring_signals.js");
GURL seller_signals_url = embedded_https_test_server().GetURL(
kSellerSignals, "/trusted_kvv2_scoring_signals");
url::Origin bidder_origin = url::Origin::Create(bidder_script_url);
url::Origin seller_origin = url::Origin::Create(seller_script_url);
ProvideKeys();
// Navigate to bidder site, and add an interest group.
ASSERT_TRUE(NavigateToURL(shell(), bidder_url));
EXPECT_EQ(
kSuccess,
JoinInterestGroupAndVerify(
blink::TestInterestGroupBuilder(
/*owner=*/bidder_origin,
/*name=*/"group")
.SetBiddingUrl(bidder_script_url)
.SetAds({{{ad_url, /*metadata=*/std::nullopt}}})
.SetAdComponents(
{{{GURL("https://barsub.test/"), /*metadata=*/std::nullopt},
{GURL("https://foosub.test/"), /*metadata=*/std::nullopt}}})
.Build()));
const char kBidderScript[] = R"(
function generateBid(interestGroup, auctionSignals, perBuyerSignals,
trustedBiddingSignals, browserSignals) {
const ad = interestGroup.ads[0];
let result = {'ad': ad, 'bid': 1, 'render': ad.renderURL};
if (interestGroup.adComponents && interestGroup.adComponents[0])
result.adComponents =
[interestGroup.adComponents[0].renderURL,
interestGroup.adComponents[1].renderURL];
return result;
})";
network_responder_->RegisterNetworkResponse(
bidder_script_url.path(), kBidderScript, "application/javascript");
// Navigate to publisher.
ASSERT_TRUE(NavigateToURL(shell(), test_url));
// Register a seller script that only score if `trustedScoringSignals` is
// successfully fetched.
const char kSellerScript[] = R"(
function scoreAd(
adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals,
directFromSellerSignals, crossOriginTrustedScoringSignals) {
if ('crossOriginDataVersion' in browserSignals) {
throw 'Unexpected crossOriginDataVersion in browserSignals.';
}
if (browserSignals.dataVersion !== 100) {
throw 'Unexpected dataVersion: ' + browserSignals.dataVersion;
}
if (crossOriginTrustedScoringSignals !== null) {
throw 'Unexpected crossOriginTrustedScoringSignals found.';
}
if (trustedScoringSignals.renderURL[browserSignals.renderURL] !== 1 ||
trustedScoringSignals.adComponentRenderURLs[browserSignals.adComponents[0]] !== 2 ||
trustedScoringSignals.adComponentRenderURLs[browserSignals.adComponents[1]] !== '3') {
throw 'Unexpected trustedScoringSignals: ' + JSON.stringify(trustedScoringSignals);
}
return bid;
}
)";
network_responder_->RegisterNetworkResponse(
seller_script_url.path(), kSellerScript, "application/javascript");
std::string auction_config = JsReplace(R"({
seller: $1,
decisionLogicURL: $2,
trustedScoringSignalsURL: $3,
interestGroupBuyers: [$4],
trustedScoringSignalsCoordinator:
"https://publickeyservice.gcp.privacysandboxservices.com"
})",
seller_origin, seller_script_url,
seller_signals_url, bidder_origin);
EXPECT_EQ(ad_url, RunAuctionAndWaitForUrl(auction_config));
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2BiddingSignalsCrossOriginSuccess) {
TestTrustedKVv2BiddingSignalsCrossOrigin(/*expect_success=*/true,
/*add_cors_header=*/true,
/*attest_signals_origin=*/true);
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2BiddingSignalsCrossOriginNoCors) {
TestTrustedKVv2BiddingSignalsCrossOrigin(/*expect_success=*/false,
/*add_cors_header=*/false,
/*attest_signals_origin=*/true);
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2BiddingSignalsCrossOriginNoAttestation) {
TestTrustedKVv2BiddingSignalsCrossOrigin(/*expect_success=*/false,
/*add_cors_header=*/true,
/*attest_signals_origin=*/false);
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2ScoringSignalsCrossOriginSuccess) {
TestTrustedKVv2ScoringSignalsCrossOrigin(/*expect_success=*/true,
/*add_cors_header=*/true,
/*add_script_header=*/true,
/*attest_signals_origin=*/true);
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2ScoringSignalsCrossOriginNoCors) {
TestTrustedKVv2ScoringSignalsCrossOrigin(/*expect_success=*/false,
/*add_cors_header=*/false,
/*add_script_header=*/true,
/*attest_signals_origin=*/true);
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2ScoringSignalsCrossOriginNoscriptHeader) {
TestTrustedKVv2ScoringSignalsCrossOrigin(/*expect_success=*/false,
/*add_cors_header=*/true,
/*add_script_header=*/false,
/*attest_signals_origin=*/true);
}
IN_PROC_BROWSER_TEST_F(InterestGroupTrustedSignalsKVv2BrowserTest,
TrustedKVv2ScoringSignalsCrossOriginNoAttestation) {
TestTrustedKVv2ScoringSignalsCrossOrigin(/*expect_success=*/false,
/*add_cors_header=*/true,
/*add_script_header=*/true,
/*attest_signals_origin=*/false);
}
} // namespace
} // namespace content

@ -1845,6 +1845,7 @@ test("content_browsertests") {
"//content/public/gpu",
"//content/public/renderer",
"//content/renderer:for_content_tests",
"//content/services/auction_worklet/public/cpp:test_support",
"//content/services/auction_worklet/public/mojom:for_content_tests",
"//content/shell:content_browsertests_mojom",
"//content/shell:content_shell_lib",