1 // Copyright 2019 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/base/network_isolation_key.h"
11
12 #include <optional>
13
14 #include "base/test/scoped_feature_list.h"
15 #include "base/unguessable_token.h"
16 #include "base/values.h"
17 #include "net/base/features.h"
18 #include "net/base/schemeful_site.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "url/gurl.h"
21 #include "url/url_util.h"
22
23 namespace net {
24
25 namespace {
26 const char kDataUrl[] = "data:text/html,<body>Hello World</body>";
27
TEST(NetworkIsolationKeyTest,EmptyKey)28 TEST(NetworkIsolationKeyTest, EmptyKey) {
29 NetworkIsolationKey key;
30 EXPECT_FALSE(key.IsFullyPopulated());
31 EXPECT_EQ(std::nullopt, key.ToCacheKeyString());
32 EXPECT_TRUE(key.IsTransient());
33 EXPECT_EQ("null null", key.ToDebugString());
34 }
35
TEST(NetworkIsolationKeyTest,NonEmptySameSiteKey)36 TEST(NetworkIsolationKeyTest, NonEmptySameSiteKey) {
37 SchemefulSite site1 = SchemefulSite(GURL("http://a.test/"));
38 NetworkIsolationKey key(site1, site1);
39 EXPECT_TRUE(key.IsFullyPopulated());
40 EXPECT_EQ(site1.Serialize() + " " + site1.Serialize(),
41 key.ToCacheKeyString());
42 EXPECT_EQ(site1.GetDebugString() + " " + site1.GetDebugString(),
43 key.ToDebugString());
44 EXPECT_FALSE(key.IsTransient());
45 }
46
TEST(NetworkIsolationKeyTest,NonEmptyCrossSiteKey)47 TEST(NetworkIsolationKeyTest, NonEmptyCrossSiteKey) {
48 SchemefulSite site1 = SchemefulSite(GURL("http://a.test/"));
49 SchemefulSite site2 = SchemefulSite(GURL("http://b.test/"));
50 NetworkIsolationKey key(site1, site2);
51 EXPECT_TRUE(key.IsFullyPopulated());
52 EXPECT_EQ(site1.Serialize() + " " + site2.Serialize(),
53 key.ToCacheKeyString());
54 EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString(),
55 key.ToDebugString());
56 EXPECT_FALSE(key.IsTransient());
57 }
58
TEST(NetworkIsolationKeyTest,KeyWithNonce)59 TEST(NetworkIsolationKeyTest, KeyWithNonce) {
60 SchemefulSite site1 = SchemefulSite(GURL("http://a.test/"));
61 SchemefulSite site2 = SchemefulSite(GURL("http://b.test/"));
62 base::UnguessableToken nonce = base::UnguessableToken::Create();
63 NetworkIsolationKey key(site1, site2, nonce);
64 EXPECT_TRUE(key.IsFullyPopulated());
65 EXPECT_EQ(std::nullopt, key.ToCacheKeyString());
66 EXPECT_TRUE(key.IsTransient());
67 EXPECT_EQ(site1.GetDebugString() + " " + site2.GetDebugString() +
68 " (with nonce " + nonce.ToString() + ")",
69 key.ToDebugString());
70
71 // Create another NetworkIsolationKey with the same input parameters, and
72 // check that it is equal.
73 NetworkIsolationKey same_key(site1, site2, nonce);
74 EXPECT_EQ(key, same_key);
75
76 // Create another NetworkIsolationKey with a different nonce and check that
77 // it's different.
78 base::UnguessableToken nonce2 = base::UnguessableToken::Create();
79 NetworkIsolationKey key2(site1, site2, nonce2);
80 EXPECT_NE(key, key2);
81 EXPECT_NE(key.ToDebugString(), key2.ToDebugString());
82 }
83
TEST(NetworkIsolationKeyTest,OpaqueOriginKey)84 TEST(NetworkIsolationKeyTest, OpaqueOriginKey) {
85 SchemefulSite site_data = SchemefulSite(GURL(kDataUrl));
86 NetworkIsolationKey key(site_data, site_data);
87 EXPECT_TRUE(key.IsFullyPopulated());
88 EXPECT_EQ(std::nullopt, key.ToCacheKeyString());
89 EXPECT_TRUE(key.IsTransient());
90 EXPECT_EQ(site_data.GetDebugString() + " " + site_data.GetDebugString(),
91 key.ToDebugString());
92
93 // Create another site with an opaque origin, and make sure it's different and
94 // has a different debug string.
95 SchemefulSite other_site = SchemefulSite(GURL(kDataUrl));
96 NetworkIsolationKey other_key(other_site, other_site);
97 EXPECT_NE(key, other_key);
98 EXPECT_NE(key.ToDebugString(), other_key.ToDebugString());
99 EXPECT_EQ(other_site.GetDebugString() + " " + other_site.GetDebugString(),
100 other_key.ToDebugString());
101 }
102
TEST(NetworkIsolationKeyTest,OpaqueOriginTopLevelSiteKey)103 TEST(NetworkIsolationKeyTest, OpaqueOriginTopLevelSiteKey) {
104 SchemefulSite site1 = SchemefulSite(GURL("http://a.test/"));
105 SchemefulSite site_data = SchemefulSite(GURL(kDataUrl));
106 NetworkIsolationKey key(site_data, site1);
107 EXPECT_TRUE(key.IsFullyPopulated());
108 EXPECT_EQ(std::nullopt, key.ToCacheKeyString());
109 EXPECT_TRUE(key.IsTransient());
110 EXPECT_EQ(site_data.GetDebugString() + " " + site1.GetDebugString(),
111 key.ToDebugString());
112
113 // Create another site with an opaque origin, and make sure it's different and
114 // has a different debug string.
115 SchemefulSite other_site = SchemefulSite(GURL(kDataUrl));
116 NetworkIsolationKey other_key(other_site, site1);
117 EXPECT_NE(key, other_key);
118 EXPECT_NE(key.ToDebugString(), other_key.ToDebugString());
119 EXPECT_EQ(other_site.GetDebugString() + " " + site1.GetDebugString(),
120 other_key.ToDebugString());
121 }
122
TEST(NetworkIsolationKeyTest,OpaqueOriginIframeKey)123 TEST(NetworkIsolationKeyTest, OpaqueOriginIframeKey) {
124 SchemefulSite site1 = SchemefulSite(GURL("http://a.test/"));
125 SchemefulSite site_data = SchemefulSite(GURL(kDataUrl));
126 NetworkIsolationKey key(site1, site_data);
127 EXPECT_TRUE(key.IsFullyPopulated());
128 EXPECT_EQ(std::nullopt, key.ToCacheKeyString());
129 EXPECT_TRUE(key.IsTransient());
130 EXPECT_EQ(site1.GetDebugString() + " " + site_data.GetDebugString(),
131 key.ToDebugString());
132
133 // Create another site with an opaque origin iframe, and make sure it's
134 // different and has a different debug string when the frame site is in use.
135 SchemefulSite other_site = SchemefulSite(GURL(kDataUrl));
136 NetworkIsolationKey other_key(site1, other_site);
137 EXPECT_NE(key, other_key);
138 EXPECT_NE(key.ToDebugString(), other_key.ToDebugString());
139 EXPECT_EQ(site1.GetDebugString() + " " + other_site.GetDebugString(),
140 other_key.ToDebugString());
141 }
142
TEST(NetworkIsolationKeyTest,Operators)143 TEST(NetworkIsolationKeyTest, Operators) {
144 base::UnguessableToken nonce1 = base::UnguessableToken::Create();
145 base::UnguessableToken nonce2 = base::UnguessableToken::Create();
146 if (nonce2 < nonce1)
147 std::swap(nonce1, nonce2);
148 // These are in ascending order.
149 const NetworkIsolationKey kKeys[] = {
150 NetworkIsolationKey(),
151 // Site with unique origins are still sorted by scheme, so data is before
152 // file, and file before http.
153 NetworkIsolationKey(SchemefulSite(GURL(kDataUrl)),
154 SchemefulSite(GURL(kDataUrl))),
155 NetworkIsolationKey(SchemefulSite(GURL("file:///foo")),
156 SchemefulSite(GURL("file:///foo"))),
157 NetworkIsolationKey(SchemefulSite(GURL("http://a.test/")),
158 SchemefulSite(GURL("http://a.test/"))),
159 NetworkIsolationKey(SchemefulSite(GURL("http://b.test/")),
160 SchemefulSite(GURL("http://b.test/"))),
161 NetworkIsolationKey(SchemefulSite(GURL("https://a.test/")),
162 SchemefulSite(GURL("https://a.test/"))),
163 NetworkIsolationKey(SchemefulSite(GURL("https://a.test/")),
164 SchemefulSite(GURL("https://a.test/")), nonce1),
165 NetworkIsolationKey(SchemefulSite(GURL("https://a.test/")),
166 SchemefulSite(GURL("https://a.test/")), nonce2),
167 };
168
169 for (size_t first = 0; first < std::size(kKeys); ++first) {
170 NetworkIsolationKey key1 = kKeys[first];
171 SCOPED_TRACE(key1.ToDebugString());
172
173 EXPECT_TRUE(key1 == key1);
174 EXPECT_FALSE(key1 != key1);
175 EXPECT_FALSE(key1 < key1);
176
177 // Make sure that copying a key doesn't change the results of any operation.
178 // This check is a bit more interesting with unique origins.
179 NetworkIsolationKey key1_copy = key1;
180 EXPECT_TRUE(key1 == key1_copy);
181 EXPECT_FALSE(key1 < key1_copy);
182 EXPECT_FALSE(key1_copy < key1);
183
184 for (size_t second = first + 1; second < std::size(kKeys); ++second) {
185 NetworkIsolationKey key2 = kKeys[second];
186 SCOPED_TRACE(key2.ToDebugString());
187
188 EXPECT_TRUE(key1 < key2);
189 EXPECT_FALSE(key2 < key1);
190 EXPECT_FALSE(key1 == key2);
191 EXPECT_FALSE(key2 == key1);
192 }
193 }
194 }
195
TEST(NetworkIsolationKeyTest,UniqueOriginOperators)196 TEST(NetworkIsolationKeyTest, UniqueOriginOperators) {
197 const auto kSite1 = SchemefulSite(GURL(kDataUrl));
198 const auto kSite2 = SchemefulSite(GURL(kDataUrl));
199 NetworkIsolationKey key1(kSite1, kSite1);
200 NetworkIsolationKey key2(kSite2, kSite2);
201
202 EXPECT_TRUE(key1 == key1);
203 EXPECT_TRUE(key2 == key2);
204
205 // Creating copies shouldn't affect comparison result.
206 EXPECT_TRUE(NetworkIsolationKey(key1) == NetworkIsolationKey(key1));
207 EXPECT_TRUE(NetworkIsolationKey(key2) == NetworkIsolationKey(key2));
208
209 EXPECT_FALSE(key1 == key2);
210 EXPECT_FALSE(key2 == key1);
211
212 // Order of Nonces isn't predictable, but they should have an ordering.
213 EXPECT_TRUE(key1 < key2 || key2 < key1);
214 EXPECT_TRUE(!(key1 < key2) || !(key2 < key1));
215 }
216
TEST(NetworkIsolationKeyTest,OpaqueSiteKeyBoth)217 TEST(NetworkIsolationKeyTest, OpaqueSiteKeyBoth) {
218 SchemefulSite site_data_1 = SchemefulSite(GURL(kDataUrl));
219 SchemefulSite site_data_2 = SchemefulSite(GURL(kDataUrl));
220 SchemefulSite site_data_3 = SchemefulSite(GURL(kDataUrl));
221
222 NetworkIsolationKey key1(site_data_1, site_data_2);
223 NetworkIsolationKey key2(site_data_1, site_data_2);
224 NetworkIsolationKey key3(site_data_1, site_data_3);
225
226 // All the keys should be fully populated and transient.
227 EXPECT_TRUE(key1.IsFullyPopulated());
228 EXPECT_TRUE(key2.IsFullyPopulated());
229 EXPECT_TRUE(key3.IsFullyPopulated());
230 EXPECT_TRUE(key1.IsTransient());
231 EXPECT_TRUE(key2.IsTransient());
232 EXPECT_TRUE(key3.IsTransient());
233
234 // Test the equality/comparisons of the various keys
235 EXPECT_TRUE(key1 == key2);
236 EXPECT_FALSE(key1 < key2 || key2 < key1);
237 EXPECT_FALSE(key1 == key3);
238 EXPECT_TRUE(key1 < key3 || key3 < key1);
239 EXPECT_NE(key1.ToDebugString(), key3.ToDebugString());
240
241 // Test the ToString and ToDebugString
242 EXPECT_EQ(key1.ToDebugString(), key2.ToDebugString());
243 EXPECT_EQ(std::nullopt, key1.ToCacheKeyString());
244 EXPECT_EQ(std::nullopt, key2.ToCacheKeyString());
245 EXPECT_EQ(std::nullopt, key3.ToCacheKeyString());
246 }
247
248 // Make sure that the logic to extract the registerable domain from an origin
249 // does not affect the host when using a non-standard scheme.
TEST(NetworkIsolationKeyTest,NonStandardScheme)250 TEST(NetworkIsolationKeyTest, NonStandardScheme) {
251 // Have to register the scheme, or SchemefulSite() will return an opaque
252 // origin.
253 url::ScopedSchemeRegistryForTests scoped_registry;
254 url::AddStandardScheme("foo", url::SCHEME_WITH_HOST);
255
256 SchemefulSite site = SchemefulSite(GURL("foo://a.foo.com"));
257 NetworkIsolationKey key(site, site);
258 EXPECT_FALSE(key.GetTopFrameSite()->opaque());
259 EXPECT_EQ("foo://a.foo.com foo://a.foo.com", key.ToCacheKeyString());
260 }
261
TEST(NetworkIsolationKeyTest,CreateWithNewFrameSite)262 TEST(NetworkIsolationKeyTest, CreateWithNewFrameSite) {
263 SchemefulSite site_a = SchemefulSite(GURL("http://a.com"));
264 SchemefulSite site_b = SchemefulSite(GURL("http://b.com"));
265 SchemefulSite site_c = SchemefulSite(GURL("http://c.com"));
266
267 NetworkIsolationKey key(site_a, site_b);
268 NetworkIsolationKey key_c = key.CreateWithNewFrameSite(site_c);
269 EXPECT_EQ(site_c, key_c.GetFrameSiteForTesting());
270 EXPECT_NE(key_c, key);
271 EXPECT_EQ(site_a, key_c.GetTopFrameSite());
272
273 // Ensure that `CreateWithNewFrameSite()` preserves the nonce if one exists.
274 base::UnguessableToken nonce = base::UnguessableToken::Create();
275 NetworkIsolationKey key_with_nonce(site_a, site_b, nonce);
276 NetworkIsolationKey key_with_nonce_c =
277 key_with_nonce.CreateWithNewFrameSite(site_c);
278 EXPECT_EQ(key_with_nonce.GetNonce(), key_with_nonce_c.GetNonce());
279 EXPECT_TRUE(key_with_nonce_c.IsTransient());
280 }
281
TEST(NetworkIsolationKeyTest,CreateTransientForTesting)282 TEST(NetworkIsolationKeyTest, CreateTransientForTesting) {
283 NetworkIsolationKey transient_key =
284 NetworkIsolationKey::CreateTransientForTesting();
285 EXPECT_TRUE(transient_key.IsFullyPopulated());
286 EXPECT_TRUE(transient_key.IsTransient());
287 EXPECT_FALSE(transient_key.IsEmpty());
288 EXPECT_EQ(transient_key, transient_key);
289
290 // Make sure that subsequent calls don't return the same NIK.
291 for (int i = 0; i < 1000; ++i) {
292 EXPECT_NE(transient_key, NetworkIsolationKey::CreateTransientForTesting());
293 }
294 }
295
296 } // namespace
297
298 } // namespace net
299