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}),
__anonc5d6f88f0202(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,CreateForInternalRequest)451 TEST_P(IsolationInfoTest, CreateForInternalRequest) {
452 IsolationInfo isolation_info =
453 IsolationInfo::CreateForInternalRequest(kOrigin1);
454 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
455 EXPECT_EQ(kOrigin1, isolation_info.top_frame_origin());
456 EXPECT_EQ(kOrigin1, isolation_info.frame_origin());
457 switch (NetworkIsolationKey::GetMode()) {
458 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
459 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
460 EXPECT_EQ("https://foo.test https://foo.test",
461 isolation_info.network_isolation_key().ToCacheKeyString());
462 break;
463 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
464 EXPECT_EQ("https://foo.test _0",
465 isolation_info.network_isolation_key().ToCacheKeyString());
466 break;
467 }
468
469 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
470 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
471 EXPECT_TRUE(
472 isolation_info.site_for_cookies().IsFirstParty(kOrigin1.GetURL()));
473 EXPECT_FALSE(isolation_info.nonce());
474
475 DuplicateAndCompare(isolation_info);
476
477 IsolationInfo redirected_isolation_info =
478 isolation_info.CreateForRedirect(kOrigin3);
479 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
480 }
481
482 // Test that in the UpdateNothing case, the SiteForCookies does not have to
483 // match the frame origin, unlike in the HTTP/HTTPS case.
TEST_P(IsolationInfoTest,CustomSchemeRequestTypeOther)484 TEST_P(IsolationInfoTest, CustomSchemeRequestTypeOther) {
485 // Have to register the scheme, or url::Origin::Create() will return an
486 // opaque origin.
487 url::ScopedSchemeRegistryForTests scoped_registry;
488 url::AddStandardScheme("foo", url::SCHEME_WITH_HOST);
489
490 const GURL kCustomOriginUrl = GURL("foo://a.foo.com");
491 const url::Origin kCustomOrigin = url::Origin::Create(kCustomOriginUrl);
492
493 IsolationInfo isolation_info = IsolationInfo::Create(
494 IsolationInfo::RequestType::kOther, kCustomOrigin, kOrigin1,
495 SiteForCookies::FromOrigin(kCustomOrigin));
496 EXPECT_EQ(IsolationInfo::RequestType::kOther, isolation_info.request_type());
497 EXPECT_EQ(kCustomOrigin, isolation_info.top_frame_origin());
498 EXPECT_EQ(kOrigin1, isolation_info.frame_origin());
499 switch (NetworkIsolationKey::GetMode()) {
500 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
501 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
502 EXPECT_EQ("foo://a.foo.com https://foo.test",
503 isolation_info.network_isolation_key().ToCacheKeyString());
504 break;
505 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
506 EXPECT_EQ("foo://a.foo.com _1",
507 isolation_info.network_isolation_key().ToCacheKeyString());
508 break;
509 }
510
511 EXPECT_TRUE(isolation_info.network_isolation_key().IsFullyPopulated());
512 EXPECT_FALSE(isolation_info.network_isolation_key().IsTransient());
513 EXPECT_TRUE(isolation_info.site_for_cookies().IsFirstParty(kCustomOriginUrl));
514 EXPECT_FALSE(isolation_info.nonce());
515
516 DuplicateAndCompare(isolation_info);
517
518 IsolationInfo redirected_isolation_info =
519 isolation_info.CreateForRedirect(kOrigin2);
520 EXPECT_TRUE(isolation_info.IsEqualForTesting(redirected_isolation_info));
521 }
522
523 // Success cases are covered by other tests, so only need a separate test to
524 // cover the failure cases.
TEST_P(IsolationInfoTest,CreateIfConsistentFails)525 TEST_P(IsolationInfoTest, CreateIfConsistentFails) {
526 // Main frames with inconsistent SiteForCookies.
527 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
528 IsolationInfo::RequestType::kMainFrame, kOrigin1, kOrigin1,
529 SiteForCookies::FromOrigin(kOrigin2)));
530 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
531 IsolationInfo::RequestType::kMainFrame, kOpaqueOrigin, kOpaqueOrigin,
532 SiteForCookies::FromOrigin(kOrigin1)));
533
534 // Sub frame with inconsistent SiteForCookies.
535 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
536 IsolationInfo::RequestType::kSubFrame, kOrigin1, kOrigin2,
537 SiteForCookies::FromOrigin(kOrigin2)));
538
539 // Sub resources with inconsistent SiteForCookies.
540 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
541 IsolationInfo::RequestType::kOther, kOrigin1, kOrigin2,
542 SiteForCookies::FromOrigin(kOrigin2)));
543
544 // Correctly have empty/non-empty origins:
545 EXPECT_TRUE(IsolationInfo::CreateIfConsistent(
546 IsolationInfo::RequestType::kOther, std::nullopt, std::nullopt,
547 SiteForCookies()));
548
549 // Incorrectly have empty/non-empty origins:
550 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
551 IsolationInfo::RequestType::kOther, std::nullopt, kOrigin1,
552 SiteForCookies()));
553 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
554 IsolationInfo::RequestType::kSubFrame, std::nullopt, kOrigin2,
555 SiteForCookies()));
556
557 // Empty frame origins are incorrect.
558 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
559 IsolationInfo::RequestType::kOther, kOrigin1, std::nullopt,
560 SiteForCookies()));
561 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
562 IsolationInfo::RequestType::kSubFrame, kOrigin1, std::nullopt,
563 SiteForCookies()));
564 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
565 IsolationInfo::RequestType::kMainFrame, kOrigin1, std::nullopt,
566 SiteForCookies::FromOrigin(kOrigin1)));
567 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
568 IsolationInfo::RequestType::kOther, kOrigin1, kOrigin2,
569 SiteForCookies::FromOrigin(kOrigin1)));
570
571 // No origins with non-null SiteForCookies.
572 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
573 IsolationInfo::RequestType::kOther, std::nullopt, std::nullopt,
574 SiteForCookies::FromOrigin(kOrigin1)));
575
576 // No origins with non-null nonce.
577 EXPECT_FALSE(IsolationInfo::CreateIfConsistent(
578 IsolationInfo::RequestType::kOther, std::nullopt, std::nullopt,
579 SiteForCookies(), kNonce1));
580 }
581
TEST_P(IsolationInfoTest,Serialization)582 TEST_P(IsolationInfoTest, Serialization) {
583 EXPECT_FALSE(IsolationInfo::Deserialize(""));
584 EXPECT_FALSE(IsolationInfo::Deserialize("garbage"));
585
586 const IsolationInfo kPositiveTestCases[] = {
587 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
588 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
589 // Null party context
590 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
591 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
592 // Empty party context
593 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
594 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
595 // Multiple party context entries.
596 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
597 kOrigin2, SiteForCookies::FromOrigin(kOrigin1)),
598 // Without SiteForCookies
599 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
600 kOrigin2, SiteForCookies()),
601 // Request type kOther
602 IsolationInfo::Create(IsolationInfo::RequestType::kOther, kOrigin1,
603 kOrigin1, SiteForCookies::FromOrigin(kOrigin1)),
604 // Request type kMainframe
605 IsolationInfo::Create(IsolationInfo::RequestType::kMainFrame, kOrigin1,
606 kOrigin1, SiteForCookies::FromOrigin(kOrigin1)),
607 };
608 for (const auto& info : kPositiveTestCases) {
609 auto rt = IsolationInfo::Deserialize(info.Serialize());
610 ASSERT_TRUE(rt);
611 EXPECT_TRUE(rt->IsEqualForTesting(info));
612 }
613
614 const IsolationInfo kNegativeTestCases[] = {
615 IsolationInfo::CreateTransient(),
616 // With nonce (i.e transient).
617 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
618 kOrigin2, SiteForCookies::FromOrigin(kOrigin1),
619 kNonce1),
620 };
621 for (const auto& info : kNegativeTestCases) {
622 EXPECT_TRUE(info.Serialize().empty());
623 }
624 const IsolationInfo kNegativeWhenTripleKeyEnabledTestCases[] = {
625 // With an opaque frame origin. When the NIK is triple-keyed, the opaque
626 // frame site will cause it to be considered transient and fail to
627 // serialize. When triple-keying is disabled, a boolean is used in place
628 // of the frame site, so the NIK won't be considered transient anymore.
629 // This will cause the IsolationInfo to be serialized, except that it
630 // doesn't serialize opaque origins with the nonce, so upon
631 // deserialization the recreated IsolationInfo will have a frame site
632 // with a different nonce (i.e. a different opaque origin).
633 IsolationInfo::Create(IsolationInfo::RequestType::kSubFrame, kOrigin1,
634 url::Origin(),
635 SiteForCookies::FromOrigin(kOrigin1)),
636 };
637 for (const auto& info : kNegativeWhenTripleKeyEnabledTestCases) {
638 switch (NetworkIsolationKey::GetMode()) {
639 case NetworkIsolationKey::Mode::kFrameSiteEnabled:
640 EXPECT_TRUE(info.Serialize().empty());
641 break;
642 case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
643 case NetworkIsolationKey::Mode::kFrameSiteWithSharedOpaqueEnabled:
644 auto rt = IsolationInfo::Deserialize(info.Serialize());
645 ASSERT_TRUE(rt);
646 // See comment above for why this check fails.
647 EXPECT_FALSE(rt->IsEqualForTesting(info));
648 EXPECT_TRUE(rt->frame_origin()->opaque());
649 EXPECT_NE(rt->frame_origin(), info.frame_origin());
650 break;
651 }
652 }
653 }
654
655 } // namespace
656
657 } // namespace net
658