1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/isolation_info.h"
6
7 #include <iostream>
8 #include <optional>
9
10 #include "base/strings/strcat.h"
11 #include "base/test/gtest_util.h"
12 #include "base/test/scoped_feature_list.h"
13 #include "base/unguessable_token.h"
14 #include "isolation_info.h"
15 #include "net/base/features.h"
16 #include "net/base/network_anonymization_key.h"
17 #include "net/base/network_isolation_key.h"
18 #include "net/base/schemeful_site.h"
19 #include "net/cookies/site_for_cookies.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "url/gurl.h"
22 #include "url/origin.h"
23 #include "url/url_util.h"
24
25 namespace net {
26
27 namespace {
28
29 class IsolationInfoTest
30 : public testing::Test,
31 public testing::WithParamInterface<NetworkIsolationKey::Mode> {
32 public:
SetUp()33 void SetUp() override {
34 switch (GetParam()) {
35 case net::NetworkIsolationKey::Mode::kFrameSiteEnabled:
36 scoped_feature_list_.InitWithFeatures(
37 {},
38 {net::features::kEnableCrossSiteFlagNetworkIsolationKey,
39 net::features::kEnableFrameSiteSharedOpaqueNetworkIsolationKey});
40 break;
41
42 case net::NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
43 scoped_feature_list_.InitWithFeatures(
44 {net::features::kEnableFrameSiteSharedOpaqueNetworkIsolationKey},
45 {
46 net::features::kEnableCrossSiteFlagNetworkIsolationKey,
47 });
48 break;
49
50 case net::NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
51 scoped_feature_list_.InitWithFeatures(
52 {net::features::kEnableCrossSiteFlagNetworkIsolationKey},
53 {net::features::kEnableFrameSiteSharedOpaqueNetworkIsolationKey});
54 break;
55 }
56 }
57
58 const url::Origin kOrigin1 = url::Origin::Create(GURL("https://a.foo.test"));
59 const url::Origin kSite1 = url::Origin::Create(GURL("https://foo.test"));
60 const url::Origin kOrigin2 = url::Origin::Create(GURL("https://b.bar.test"));
61 const url::Origin kSite2 = url::Origin::Create(GURL("https://bar.test"));
62 const url::Origin kOrigin3 = url::Origin::Create(GURL("https://c.baz.test"));
63 const url::Origin kOpaqueOrigin;
64
65 const base::UnguessableToken kNonce1 = base::UnguessableToken::Create();
66 const base::UnguessableToken kNonce2 = base::UnguessableToken::Create();
67
68 private:
69 base::test::ScopedFeatureList scoped_feature_list_;
70 };
71
72 INSTANTIATE_TEST_SUITE_P(
73 Tests,
74 IsolationInfoTest,
75 testing::ValuesIn(
76 {NetworkIsolationKey::Mode::kFrameSiteEnabled,
77 NetworkIsolationKey::Mode::kCrossSiteFlagEnabled,
78 NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled}),
__anoncedceff10202(const testing::TestParamInfo<NetworkIsolationKey::Mode>& info) 79 [](const testing::TestParamInfo<NetworkIsolationKey::Mode>& info) {
80 switch (info.param) {
81 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
82 return "FrameSiteEnabled";
83 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
84 return "CrossSiteFlagEnabled";
85 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
86 return "FrameSiteSharedOpaqueEnabled";
87 }
88 });
89
DuplicateAndCompare(const IsolationInfo & isolation_info)90 void DuplicateAndCompare(const IsolationInfo& isolation_info) {
91 std::optional<IsolationInfo> duplicate_isolation_info =
92 IsolationInfo::CreateIfConsistent(
93 isolation_info.request_type(), isolation_info.top_frame_origin(),
94 isolation_info.frame_origin(), isolation_info.site_for_cookies(),
95 isolation_info.nonce());
96
97 ASSERT_TRUE(duplicate_isolation_info);
98 EXPECT_TRUE(isolation_info.IsEqualForTesting(*duplicate_isolation_info));
99 }
100
TEST_P(IsolationInfoTest,DebugString)101 TEST_P(IsolationInfoTest, DebugString) {
102 IsolationInfo isolation_info = IsolationInfo::Create(
103 IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin2,
104 SiteForCookies::FromOrigin(kOrigin1), kNonce1);
105 std::vector<std::string> parts;
106 parts.push_back(
107 "request_type: kMainFrame; top_frame_origin: https://a.foo.test; ");
108 parts.push_back("frame_origin: https://b.bar.test; ");
109 parts.push_back("network_anonymization_key: ");
110 parts.push_back(isolation_info.network_anonymization_key().ToDebugString());
111 parts.push_back("; network_isolation_key: ");
112 parts.push_back(isolation_info.network_isolation_key().ToDebugString());
113 parts.push_back("; nonce: ");
114 parts.push_back(isolation_info.nonce().value().ToString());
115 parts.push_back(
116 "; site_for_cookies: SiteForCookies: {site=https://foo.test; "
117 "schemefully_same=true}");
118 EXPECT_EQ(isolation_info.DebugString(), base::StrCat(parts));
119 }
120
TEST_P(IsolationInfoTest,CreateNetworkAnonymizationKeyForIsolationInfo)121 TEST_P(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfo) {
122 IsolationInfo isolation_info = IsolationInfo::Create(
123 IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin2,
124 SiteForCookies::FromOrigin(kOrigin1), kNonce1);
125 NetworkAnonymizationKey nak =
126 isolation_info.CreateNetworkAnonymizationKeyForIsolationInfo(
127 kOrigin1, kOrigin2, kNonce1);
128
129 IsolationInfo same_site_isolation_info = IsolationInfo::Create(
130 IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
131 SiteForCookies::FromOrigin(kOrigin1), kNonce1);
132
133 // Top frame should be populated regardless of scheme.
134 EXPECT_EQ(nak.GetTopFrameSite(), SchemefulSite(kOrigin1));
135 EXPECT_EQ(isolation_info.top_frame_origin(), kOrigin1);
136 EXPECT_EQ(isolation_info.network_anonymization_key().GetTopFrameSite(),
137 SchemefulSite(kOrigin1));
138
139 // Nonce should be empty regardless of scheme
140 EXPECT_EQ(nak.GetNonce().value(), kNonce1);
141 EXPECT_EQ(isolation_info.network_anonymization_key().GetNonce().value(),
142 kNonce1);
143 EXPECT_EQ(isolation_info.nonce().value(), kNonce1);
144
145 // Triple-keyed IsolationInfo + double-keyed + cross site bit
146 // NetworkAnonymizationKey case.
147 EXPECT_EQ(isolation_info.frame_origin(), kOrigin2);
148 EXPECT_TRUE(isolation_info.network_anonymization_key().IsCrossSite());
149 EXPECT_TRUE(
150 same_site_isolation_info.network_anonymization_key().IsSameSite());
151 }
152
153 // A 2.5-keyed NAK created with two identical opaque origins should be
154 // same-site.
TEST_P(IsolationInfoTest,CreateNetworkAnonymizationKeyForIsolationInfoOpaque)155 TEST_P(IsolationInfoTest, CreateNetworkAnonymizationKeyForIsolationInfoOpaque) {
156 url::Origin opaque;
157 IsolationInfo isolation_info = IsolationInfo::Create(
158 IsolationInfo::RequestType::kMainFrame, opaque, opaque,
159 SiteForCookies::FromOrigin(opaque), kNonce1);
160 NetworkAnonymizationKey nak =
161 isolation_info.CreateNetworkAnonymizationKeyForIsolationInfo(
162 opaque, opaque, kNonce1);
163
164 EXPECT_TRUE(nak.IsSameSite());
165
166 url::Origin opaque2;
167 nak = isolation_info.CreateNetworkAnonymizationKeyForIsolationInfo(
168 opaque, opaque2, kNonce1);
169
170 EXPECT_TRUE(nak.IsCrossSite());
171 }
172
TEST_P(IsolationInfoTest,RequestTypeMainFrame)173 TEST_P(IsolationInfoTest, RequestTypeMainFrame) {
174 IsolationInfo isolation_info =
175 IsolationInfo::Create(IsolationInfo::RequestType::kMainFrame, kOrigin1,
176 kOrigin1, SiteForCookies::FromOrigin(kOrigin1));
177 EXPECT_EQ(IsolationInfo::RequestType::kMainFrame,
178 isolation_info.request_type());
179 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
180
181 EXPECT_EQ(kOrigin1, isolation_info.frame_origin());
182 switch (NetworkIsolationKey::GetMode()) {
183 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
184 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
185 EXPECT_EQ("https://foo.test https://foo.test",
186 isolation_info.network_isolation_key().ToCacheKeyString());
187 break;
188 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
189 EXPECT_EQ("https://foo.test _0",
190 isolation_info.network_isolation_key().ToCacheKeyString());
191 break;
192 }
193 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
194 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
195 EXPECT_TRUE(
196 isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL()));
197 EXPECT_FALSE(isolation_info.nonce().has_value());
198
199 DuplicateAndCompare(isolation_info);
200
201 IsolationInfo redirected_isolation_info =
202 isolation_info.CreateForRedirect(kOrigin3);
203 EXPECT_EQ(IsolationInfo::RequestType::kMainFrame,
204 redirected_isolation_info.request_type());
205 EXPECT_EQ(kOrigin3, redirected_isolation_info.top_frame_origin());
206 EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin());
207 EXPECT_TRUE(
208 redirected_isolation_info.network_isolation_key().IsFullyPopulated());
209 EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsTransient());
210 switch (NetworkIsolationKey::GetMode()) {
211 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
212 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
213 EXPECT_EQ(
214 "https://baz.test https://baz.test",
215 redirected_isolation_info.network_isolation_key().ToCacheKeyString());
216 break;
217 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
218 EXPECT_EQ(
219 "https://baz.test _0",
220 redirected_isolation_info.network_isolation_key().ToCacheKeyString());
221 break;
222 }
223
224 EXPECT_TRUE(redirected_isolation_info.site_for_cookies().IsFirstParty(
225 kOrigin3.GetURL()));
226 EXPECT_FALSE(redirected_isolation_info.nonce().has_value());
227 }
228
TEST_P(IsolationInfoTest,RequestTypeSubFrame)229 TEST_P(IsolationInfoTest, RequestTypeSubFrame) {
230 IsolationInfo isolation_info =
231 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
232 kOrigin2, SiteForCookies::FromOrigin(kOrigin1));
233 EXPECT_EQ(IsolationInfo::RequestType::kSubFrame,
234 isolation_info.request_type());
235 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
236 EXPECT_EQ(kOrigin2, isolation_info.frame_origin());
237 switch (NetworkIsolationKey::GetMode()) {
238 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
239 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
240 EXPECT_EQ("https://foo.test https://bar.test",
241 isolation_info.network_isolation_key().ToCacheKeyString());
242 break;
243 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
244 EXPECT_EQ("https://foo.test _1",
245 isolation_info.network_isolation_key().ToCacheKeyString());
246 break;
247 }
248 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
249 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
250 EXPECT_TRUE(
251 isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL()));
252 EXPECT_FALSE(isolation_info.nonce().has_value());
253
254 DuplicateAndCompare(isolation_info);
255
256 IsolationInfo redirected_isolation_info =
257 isolation_info.CreateForRedirect(kOrigin3);
258 EXPECT_EQ(IsolationInfo::RequestType::kSubFrame,
259 redirected_isolation_info.request_type());
260 EXPECT_EQ(kOrigin1, redirected_isolation_info.top_frame_origin());
261
262 EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin());
263 switch (NetworkIsolationKey::GetMode()) {
264 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
265 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
266 EXPECT_EQ(
267 "https://foo.test https://baz.test",
268 redirected_isolation_info.network_isolation_key().ToCacheKeyString());
269 break;
270 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
271 EXPECT_EQ(
272 "https://foo.test _1",
273 redirected_isolation_info.network_isolation_key().ToCacheKeyString());
274 break;
275 }
276
277 EXPECT_TRUE(
278 redirected_isolation_info.network_isolation_key().IsFullyPopulated());
279 EXPECT_FALSE(redirected_isolation_info.network_isolation_key().IsTransient());
280 EXPECT_TRUE(redirected_isolation_info.site_for_cookies().IsFirstParty(
281 kOrigin1.GetURL()));
282 EXPECT_FALSE(redirected_isolation_info.nonce().has_value());
283 }
284
TEST_P(IsolationInfoTest,RequestTypeMainFrameWithNonce)285 TEST_P(IsolationInfoTest, RequestTypeMainFrameWithNonce) {
286 IsolationInfo isolation_info = IsolationInfo::Create(
287 IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
288 SiteForCookies::FromOrigin(kOrigin1), kNonce1);
289 EXPECT_EQ(IsolationInfo::RequestType::kMainFrame,
290 isolation_info.request_type());
291 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
292 EXPECT_EQ(kOrigin1, isolation_info.frame_origin());
293 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
294 EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient());
295 EXPECT_EQ(std::nullopt,
296 isolation_info.network_isolation_key().ToCacheKeyString());
297 EXPECT_TRUE(
298 isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL()));
299 EXPECT_EQ(kNonce1, isolation_info.nonce().value());
300
301 DuplicateAndCompare(isolation_info);
302
303 IsolationInfo redirected_isolation_info =
304 isolation_info.CreateForRedirect(kOrigin3);
305 EXPECT_EQ(IsolationInfo::RequestType::kMainFrame,
306 redirected_isolation_info.request_type());
307 EXPECT_EQ(kOrigin3, redirected_isolation_info.top_frame_origin());
308 EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin());
309 EXPECT_TRUE(
310 redirected_isolation_info.network_isolation_key().IsFullyPopulated());
311 EXPECT_TRUE(redirected_isolation_info.network_isolation_key().IsTransient());
312 EXPECT_EQ(
313 std::nullopt,
314 redirected_isolation_info.network_isolation_key().ToCacheKeyString());
315 EXPECT_TRUE(redirected_isolation_info.site_for_cookies().IsFirstParty(
316 kOrigin3.GetURL()));
317 EXPECT_EQ(kNonce1, redirected_isolation_info.nonce().value());
318 }
319
TEST_P(IsolationInfoTest,RequestTypeSubFrameWithNonce)320 TEST_P(IsolationInfoTest, RequestTypeSubFrameWithNonce) {
321 IsolationInfo isolation_info = IsolationInfo::Create(
322 IsolationInfo::RequestType::kSubFrame, kOrigin1, kOrigin2,
323 SiteForCookies::FromOrigin(kOrigin1), kNonce1);
324 EXPECT_EQ(IsolationInfo::RequestType::kSubFrame,
325 isolation_info.request_type());
326 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
327 EXPECT_EQ(kOrigin2, isolation_info.frame_origin());
328 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
329 EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient());
330 EXPECT_EQ(std::nullopt,
331 isolation_info.network_isolation_key().ToCacheKeyString());
332 EXPECT_TRUE(
333 isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL()));
334 EXPECT_EQ(kNonce1, isolation_info.nonce().value());
335
336 DuplicateAndCompare(isolation_info);
337
338 IsolationInfo redirected_isolation_info =
339 isolation_info.CreateForRedirect(kOrigin3);
340 EXPECT_EQ(IsolationInfo::RequestType::kSubFrame,
341 redirected_isolation_info.request_type());
342 EXPECT_EQ(kOrigin1, redirected_isolation_info.top_frame_origin());
343 EXPECT_EQ(kOrigin3, redirected_isolation_info.frame_origin());
344 EXPECT_TRUE(
345 redirected_isolation_info.network_isolation_key().IsFullyPopulated());
346 EXPECT_TRUE(redirected_isolation_info.network_isolation_key().IsTransient());
347 EXPECT_EQ(
348 std::nullopt,
349 redirected_isolation_info.network_isolation_key().ToCacheKeyString());
350 EXPECT_TRUE(redirected_isolation_info.site_for_cookies().IsFirstParty(
351 kOrigin1.GetURL()));
352 EXPECT_EQ(kNonce1, redirected_isolation_info.nonce().value());
353 }
354
TEST_P(IsolationInfoTest,RequestTypeOther)355 TEST_P(IsolationInfoTest, RequestTypeOther) {
356 IsolationInfo isolation_info;
357 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
358 EXPECT_FALSE(isolation_info.top_frame_origin());
359 EXPECT_FALSE(isolation_info.frame_origin());
360 EXPECT_TRUE(isolation_info.network_isolation_key().IsEmpty());
361 EXPECT_TRUE(isolation_info.site_for_cookies().IsNull());
362 EXPECT_FALSE(isolation_info.nonce());
363
364 DuplicateAndCompare(isolation_info);
365
366 IsolationInfo redirected_isolation_info =
367 isolation_info.CreateForRedirect(kOrigin3);
368 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
369 }
370
TEST_P(IsolationInfoTest,RequestTypeOtherWithSiteForCookies)371 TEST_P(IsolationInfoTest, RequestTypeOtherWithSiteForCookies) {
372 IsolationInfo isolation_info =
373 IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin1,
374 kOrigin1, SiteForCookies::FromOrigin(kOrigin1));
375 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
376 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
377 EXPECT_EQ(kOrigin1, isolation_info.frame_origin());
378 switch (NetworkIsolationKey::GetMode()) {
379 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
380 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
381 EXPECT_EQ("https://foo.test https://foo.test",
382 isolation_info.network_isolation_key().ToCacheKeyString());
383 break;
384 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
385 EXPECT_EQ("https://foo.test _0",
386 isolation_info.network_isolation_key().ToCacheKeyString());
387 break;
388 }
389 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
390 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
391 EXPECT_TRUE(
392 isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL()));
393 EXPECT_FALSE(isolation_info.nonce());
394
395 DuplicateAndCompare(isolation_info);
396
397 IsolationInfo redirected_isolation_info =
398 isolation_info.CreateForRedirect(kOrigin3);
399 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
400 }
401
402 // Test case of a subresource for cross-site subframe (which has an empty
403 // site-for-cookies).
TEST_P(IsolationInfoTest,RequestTypeOtherWithEmptySiteForCookies)404 TEST_P(IsolationInfoTest, RequestTypeOtherWithEmptySiteForCookies) {
405 IsolationInfo isolation_info = IsolationInfo::Create(
406 IsolationInfo::RequestType::kOther, kOrigin1, kOrigin2, SiteForCookies());
407 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
408 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
409 EXPECT_EQ(kOrigin2, isolation_info.frame_origin());
410 switch (NetworkIsolationKey::GetMode()) {
411 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
412 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
413 EXPECT_EQ("https://foo.test https://bar.test",
414 isolation_info.network_isolation_key().ToCacheKeyString());
415 break;
416 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
417 EXPECT_EQ("https://foo.test _1",
418 isolation_info.network_isolation_key().ToCacheKeyString());
419 break;
420 }
421
422 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
423 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
424 EXPECT_TRUE(isolation_info.site_for_cookies().IsNull());
425 EXPECT_FALSE(isolation_info.nonce());
426
427 DuplicateAndCompare(isolation_info);
428
429 IsolationInfo redirected_isolation_info =
430 isolation_info.CreateForRedirect(kOrigin3);
431 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
432 }
433
TEST_P(IsolationInfoTest,CreateTransient)434 TEST_P(IsolationInfoTest, CreateTransient) {
435 IsolationInfo isolation_info = IsolationInfo::CreateTransient();
436 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
437 EXPECT_TRUE(isolation_info.top_frame_origin()->opaque());
438 EXPECT_TRUE(isolation_info.frame_origin()->opaque());
439 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
440 EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient());
441 EXPECT_TRUE(isolation_info.site_for_cookies().IsNull());
442 EXPECT_FALSE(isolation_info.nonce());
443
444 DuplicateAndCompare(isolation_info);
445
446 IsolationInfo redirected_isolation_info =
447 isolation_info.CreateForRedirect(kOrigin3);
448 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
449 }
450
TEST_P(IsolationInfoTest,CreateTransientWithNonce)451 TEST_P(IsolationInfoTest, CreateTransientWithNonce) {
452 IsolationInfo isolation_info =
453 IsolationInfo::CreateTransientWithNonce(kNonce1);
454 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
455 EXPECT_TRUE(isolation_info.top_frame_origin()->opaque());
456 EXPECT_TRUE(isolation_info.frame_origin()->opaque());
457 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
458 EXPECT_TRUE(isolation_info.network_isolation_key().IsTransient());
459 EXPECT_TRUE(isolation_info.site_for_cookies().IsNull());
460 ASSERT_TRUE(isolation_info.nonce().has_value());
461 EXPECT_EQ(isolation_info.nonce().value(), kNonce1);
462
463 DuplicateAndCompare(isolation_info);
464
465 IsolationInfo redirected_isolation_info =
466 isolation_info.CreateForRedirect(kOrigin3);
467 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
468
469 IsolationInfo new_info_same_nonce =
470 IsolationInfo::CreateTransientWithNonce(kNonce1);
471 ASSERT_TRUE(new_info_same_nonce.nonce().has_value());
472 EXPECT_EQ(new_info_same_nonce.nonce().value(), kNonce1);
473
474 // The new NIK is distinct from the first one because it uses a new opaque
475 // origin, even if the nonce is the same.
476 EXPECT_NE(isolation_info.network_isolation_key(),
477 new_info_same_nonce.network_isolation_key());
478 }
479
TEST_P(IsolationInfoTest,CreateForInternalRequest)480 TEST_P(IsolationInfoTest, CreateForInternalRequest) {
481 IsolationInfo isolation_info =
482 IsolationInfo::CreateForInternalRequest(kOrigin1);
483 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
484 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
485 EXPECT_EQ(kOrigin1, isolation_info.frame_origin());
486 switch (NetworkIsolationKey::GetMode()) {
487 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
488 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
489 EXPECT_EQ("https://foo.test https://foo.test",
490 isolation_info.network_isolation_key().ToCacheKeyString());
491 break;
492 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
493 EXPECT_EQ("https://foo.test _0",
494 isolation_info.network_isolation_key().ToCacheKeyString());
495 break;
496 }
497
498 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
499 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
500 EXPECT_TRUE(
501 isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL()));
502 EXPECT_FALSE(isolation_info.nonce());
503
504 DuplicateAndCompare(isolation_info);
505
506 IsolationInfo redirected_isolation_info =
507 isolation_info.CreateForRedirect(kOrigin3);
508 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
509 }
510
511 // Test that in the UpdateNothing case, the SiteForCookies does not have to
512 // match the frame origin, unlike in the HTTP/HTTPS case.
TEST_P(IsolationInfoTest,CustomSchemeRequestTypeOther)513 TEST_P(IsolationInfoTest, CustomSchemeRequestTypeOther) {
514 // Have to register the scheme, or url::Origin::Create() will return an
515 // opaque origin.
516 url::ScopedSchemeRegistryForTests scoped_registry;
517 url::AddStandardScheme("foo", url::SCHEME_WITH_HOST);
518
519 const GURL kCustomOriginUrl = GURL("foo://a.foo.com");
520 const url::Origin kCustomOrigin = url::Origin::Create(kCustomOriginUrl);
521
522 IsolationInfo isolation_info = IsolationInfo::Create(
523 IsolationInfo::RequestType::kOther, kCustomOrigin, kOrigin1,
524 SiteForCookies::FromOrigin(kCustomOrigin));
525 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
526 EXPECT_EQ(kCustomOrigin, isolation_info.top_frame_origin());
527 EXPECT_EQ(kOrigin1, isolation_info.frame_origin());
528 switch (NetworkIsolationKey::GetMode()) {
529 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
530 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
531 EXPECT_EQ("foo://a.foo.com https://foo.test",
532 isolation_info.network_isolation_key().ToCacheKeyString());
533 break;
534 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
535 EXPECT_EQ("foo://a.foo.com _1",
536 isolation_info.network_isolation_key().ToCacheKeyString());
537 break;
538 }
539
540 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
541 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
542 EXPECT_TRUE(isolation_info.site_for_cookies().IsFirstParty(kCustomOriginUrl));
543 EXPECT_FALSE(isolation_info.nonce());
544
545 DuplicateAndCompare(isolation_info);
546
547 IsolationInfo redirected_isolation_info =
548 isolation_info.CreateForRedirect(kOrigin2);
549 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
550 }
551
552 // Success cases are covered by other tests, so only need a separate test to
553 // cover the failure cases.
TEST_P(IsolationInfoTest,CreateIfConsistentFails)554 TEST_P(IsolationInfoTest, CreateIfConsistentFails) {
555 // Main frames with inconsistent SiteForCookies.
556 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
557 IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
558 SiteForCookies::FromOrigin(kOrigin2)));
559 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
560 IsolationInfo::RequestType::kMainFrame, kOpaqueOrigin, kOpaqueOrigin,
561 SiteForCookies::FromOrigin(kOrigin1)));
562
563 // Sub frame with inconsistent SiteForCookies.
564 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
565 IsolationInfo::RequestType::kSubFrame, kOrigin1, kOrigin2,
566 SiteForCookies::FromOrigin(kOrigin2)));
567
568 // Sub resources with inconsistent SiteForCookies.
569 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
570 IsolationInfo::RequestType::kOther, kOrigin1, kOrigin2,
571 SiteForCookies::FromOrigin(kOrigin2)));
572
573 // Correctly have empty/non-empty origins:
574 EXPECT_TRUE(IsolationInfo::CreateIfConsistent(
575 IsolationInfo::RequestType::kOther, std::nullopt, std::nullopt,
576 SiteForCookies()));
577
578 // Incorrectly have empty/non-empty origins:
579 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
580 IsolationInfo::RequestType::kOther, std::nullopt, kOrigin1,
581 SiteForCookies()));
582 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
583 IsolationInfo::RequestType::kSubFrame, std::nullopt, kOrigin2,
584 SiteForCookies()));
585
586 // Empty frame origins are incorrect.
587 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
588 IsolationInfo::RequestType::kOther, kOrigin1, std::nullopt,
589 SiteForCookies()));
590 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
591 IsolationInfo::RequestType::kSubFrame, kOrigin1, std::nullopt,
592 SiteForCookies()));
593 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
594 IsolationInfo::RequestType::kMainFrame, kOrigin1, std::nullopt,
595 SiteForCookies::FromOrigin(kOrigin1)));
596 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
597 IsolationInfo::RequestType::kOther, kOrigin1, kOrigin2,
598 SiteForCookies::FromOrigin(kOrigin1)));
599
600 // No origins with non-null SiteForCookies.
601 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
602 IsolationInfo::RequestType::kOther, std::nullopt, std::nullopt,
603 SiteForCookies::FromOrigin(kOrigin1)));
604
605 // No origins with non-null nonce.
606 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
607 IsolationInfo::RequestType::kOther, std::nullopt, std::nullopt,
608 SiteForCookies(), kNonce1));
609 }
610
TEST_P(IsolationInfoTest,Serialization)611 TEST_P(IsolationInfoTest, Serialization) {
612 EXPECT_FALSE(IsolationInfo::Deserialize(""));
613 EXPECT_FALSE(IsolationInfo::Deserialize("garbage"));
614
615 const IsolationInfo kPositiveTestCases[] = {
616 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
617 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
618 // Null party context
619 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
620 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
621 // Empty party context
622 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
623 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
624 // Multiple party context entries.
625 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
626 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
627 // Without SiteForCookies
628 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
629 kOrigin2, SiteForCookies()),
630 // Request type kOther
631 IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin1,
632 kOrigin1, SiteForCookies::FromOrigin(kOrigin1)),
633 // Request type kMainframe
634 IsolationInfo::Create(IsolationInfo::RequestType::kMainFrame, kOrigin1,
635 kOrigin1, SiteForCookies::FromOrigin(kOrigin1)),
636 };
637 for (const auto& info : kPositiveTestCases) {
638 auto rt = IsolationInfo::Deserialize(info.Serialize());
639 ASSERT_TRUE(rt);
640 EXPECT_TRUE(rt->IsEqualForTesting(info));
641 }
642
643 const IsolationInfo kNegativeTestCases[] = {
644 IsolationInfo::CreateTransient(),
645 // With nonce (i.e transient).
646 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
647 kOrigin2, SiteForCookies::FromOrigin(kOrigin1),
648 kNonce1),
649 };
650 for (const auto& info : kNegativeTestCases) {
651 EXPECT_TRUE(info.Serialize().empty());
652 }
653 const IsolationInfo kNegativeWhenTripleKeyEnabledTestCases[] = {
654 // With an opaque frame origin. When the NIK is triple-keyed, the opaque
655 // frame site will cause it to be considered transient and fail to
656 // serialize. When triple-keying is disabled, a boolean is used in place
657 // of the frame site, so the NIK won't be considered transient anymore.
658 // This will cause the IsolationInfo to be serialized, except that it
659 // doesn't serialize opaque origins with the nonce, so upon
660 // deserialization the recreated IsolationInfo will have a frame site
661 // with a different nonce (i.e. a different opaque origin).
662 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
663 url::Origin(),
664 SiteForCookies::FromOrigin(kOrigin1)),
665 };
666 for (const auto& info : kNegativeWhenTripleKeyEnabledTestCases) {
667 switch (NetworkIsolationKey::GetMode()) {
668 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
669 EXPECT_TRUE(info.Serialize().empty());
670 break;
671 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
672 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
673 auto rt = IsolationInfo::Deserialize(info.Serialize());
674 ASSERT_TRUE(rt);
675 // See comment above for why this check fails.
676 EXPECT_FALSE(rt->IsEqualForTesting(info));
677 EXPECT_TRUE(rt->frame_origin()->opaque());
678 EXPECT_NE(rt->frame_origin(), info.frame_origin());
679 break;
680 }
681 }
682 }
683
684 } // namespace
685
686 } // namespace net
687