• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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