xref: /aosp_15_r20/external/cronet/net/base/isolation_info_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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