• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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/device_bound_sessions/cookie_craving.h"
6 
7 #include "base/strings/string_util.h"
8 #include "base/unguessable_token.h"
9 #include "net/cookies/canonical_cookie.h"
10 #include "net/cookies/cookie_constants.h"
11 #include "net/cookies/cookie_partition_key.h"
12 #include "net/device_bound_sessions/proto/storage.pb.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace net::device_bound_sessions {
17 
18 // Default values for tests.
19 constexpr char kUrlString[] = "https://www.example.test/foo";
20 constexpr char kName[] = "name";
21 const base::Time kCreationTime = base::Time::Now();
22 
23 // Helper to Create() and unwrap a CookieCraving, expecting it to be valid.
CreateValidCookieCraving(const GURL & url,const std::string & name,const std::string & attributes,base::Time creation_time=kCreationTime,std::optional<CookiePartitionKey> cookie_partition_key=std::nullopt)24 CookieCraving CreateValidCookieCraving(
25     const GURL& url,
26     const std::string& name,
27     const std::string& attributes,
28     base::Time creation_time = kCreationTime,
29     std::optional<CookiePartitionKey> cookie_partition_key = std::nullopt) {
30   std::optional<CookieCraving> maybe_cc = CookieCraving::Create(
31       url, name, attributes, creation_time, cookie_partition_key);
32   EXPECT_TRUE(maybe_cc);
33   EXPECT_TRUE(maybe_cc->IsValid());
34   return std::move(*maybe_cc);
35 }
36 
37 // Helper to create and unwrap a CanonicalCookie.
CreateCanonicalCookie(const GURL & url,const std::string & cookie_line,base::Time creation_time=kCreationTime,std::optional<CookiePartitionKey> cookie_partition_key=std::nullopt)38 CanonicalCookie CreateCanonicalCookie(
39     const GURL& url,
40     const std::string& cookie_line,
41     base::Time creation_time = kCreationTime,
42     std::optional<CookiePartitionKey> cookie_partition_key = std::nullopt) {
43   std::unique_ptr<CanonicalCookie> canonical_cookie =
44       CanonicalCookie::CreateForTesting(url, cookie_line, creation_time,
45                                         /*server_time=*/std::nullopt,
46                                         cookie_partition_key);
47   EXPECT_TRUE(canonical_cookie);
48   EXPECT_TRUE(canonical_cookie->IsCanonical());
49   return *canonical_cookie;
50 }
51 
TEST(CookieCravingTest,CreateBasic)52 TEST(CookieCravingTest, CreateBasic) {
53   // Default cookie.
54   CookieCraving cc = CreateValidCookieCraving(GURL(kUrlString), kName, "");
55   EXPECT_EQ(cc.Name(), kName);
56   EXPECT_EQ(cc.Domain(), "www.example.test");
57   EXPECT_EQ(cc.Path(), "/");
58   EXPECT_EQ(cc.CreationDate(), kCreationTime);
59   EXPECT_FALSE(cc.SecureAttribute());
60   EXPECT_FALSE(cc.IsHttpOnly());
61   EXPECT_EQ(cc.SameSite(), CookieSameSite::UNSPECIFIED);
62   EXPECT_EQ(cc.PartitionKey(), std::nullopt);
63   EXPECT_EQ(cc.SourceScheme(), CookieSourceScheme::kSecure);
64   EXPECT_EQ(cc.SourcePort(), 443);
65 
66   // Non-default attributes.
67   cc = CreateValidCookieCraving(
68       GURL(kUrlString), kName,
69       "Secure; HttpOnly; Path=/foo; Domain=example.test; SameSite=Lax");
70   EXPECT_EQ(cc.Name(), kName);
71   EXPECT_EQ(cc.Domain(), ".example.test");
72   EXPECT_EQ(cc.Path(), "/foo");
73   EXPECT_EQ(cc.CreationDate(), kCreationTime);
74   EXPECT_TRUE(cc.SecureAttribute());
75   EXPECT_TRUE(cc.IsHttpOnly());
76   EXPECT_EQ(cc.SameSite(), CookieSameSite::LAX_MODE);
77   EXPECT_EQ(cc.PartitionKey(), std::nullopt);
78   EXPECT_EQ(cc.SourceScheme(), CookieSourceScheme::kSecure);
79   EXPECT_EQ(cc.SourcePort(), 443);
80 
81   // Normalize whitespace.
82   cc = CreateValidCookieCraving(
83       GURL(kUrlString), "     name    ",
84       "  Secure;HttpOnly;Path = /foo;   Domain= example.test; SameSite =Lax  ");
85   EXPECT_EQ(cc.Name(), "name");
86   EXPECT_EQ(cc.Domain(), ".example.test");
87   EXPECT_EQ(cc.Path(), "/foo");
88   EXPECT_EQ(cc.CreationDate(), kCreationTime);
89   EXPECT_TRUE(cc.SecureAttribute());
90   EXPECT_TRUE(cc.IsHttpOnly());
91   EXPECT_EQ(cc.SameSite(), CookieSameSite::LAX_MODE);
92   EXPECT_EQ(cc.PartitionKey(), std::nullopt);
93   EXPECT_EQ(cc.SourceScheme(), CookieSourceScheme::kSecure);
94   EXPECT_EQ(cc.SourcePort(), 443);
95 }
96 
TEST(CookieCravingTest,CreateWithPartitionKey)97 TEST(CookieCravingTest, CreateWithPartitionKey) {
98   // The site of the partition key is not checked in Create(), so these two
99   // should behave the same.
100   const CookiePartitionKey kSameSitePartitionKey =
101       CookiePartitionKey::FromURLForTesting(GURL("https://auth.example.test"));
102   const CookiePartitionKey kCrossSitePartitionKey =
103       CookiePartitionKey::FromURLForTesting(GURL("https://www.other.test"));
104   // A key with a nonce might be used for a fenced frame or anonymous iframe.
105   const CookiePartitionKey kNoncedPartitionKey =
106       CookiePartitionKey::FromURLForTesting(
107           GURL("https://www.anonymous-iframe.test"),
108           CookiePartitionKey::AncestorChainBit::kCrossSite,
109           base::UnguessableToken::Create());
110 
111   for (const CookiePartitionKey& partition_key :
112        {kSameSitePartitionKey, kCrossSitePartitionKey, kNoncedPartitionKey}) {
113     // Partitioned cookies must be set with Secure. The __Host- prefix is not
114     // required.
115     CookieCraving cc =
116         CreateValidCookieCraving(GURL(kUrlString), kName, "Secure; Partitioned",
117                                  kCreationTime, partition_key);
118     EXPECT_TRUE(cc.SecureAttribute());
119     EXPECT_TRUE(cc.IsPartitioned());
120     EXPECT_EQ(cc.PartitionKey(), partition_key);
121   }
122 
123   // If a cookie is not set with a Partitioned attribute, the partition key
124   // should be ignored and cleared (if it's a normal partition key).
125   for (const CookiePartitionKey& partition_key :
126        {kSameSitePartitionKey, kCrossSitePartitionKey}) {
127     CookieCraving cc = CreateValidCookieCraving(
128         GURL(kUrlString), kName, "Secure", kCreationTime, partition_key);
129     EXPECT_TRUE(cc.SecureAttribute());
130     EXPECT_FALSE(cc.IsPartitioned());
131     EXPECT_EQ(cc.PartitionKey(), std::nullopt);
132   }
133 
134   // For nonced partition keys, the Partitioned attribute is not explicitly
135   // required in order for the cookie to be considered partitioned.
136   CookieCraving cc = CreateValidCookieCraving(
137       GURL(kUrlString), kName, "Secure", kCreationTime, kNoncedPartitionKey);
138   EXPECT_TRUE(cc.SecureAttribute());
139   EXPECT_TRUE(cc.IsPartitioned());
140   EXPECT_EQ(cc.PartitionKey(), kNoncedPartitionKey);
141 
142   // The Secure attribute is also not required for a nonced partition key.
143   cc = CreateValidCookieCraving(GURL(kUrlString), kName, "", kCreationTime,
144                                 kNoncedPartitionKey);
145   EXPECT_FALSE(cc.SecureAttribute());
146   EXPECT_TRUE(cc.IsPartitioned());
147   EXPECT_EQ(cc.PartitionKey(), kNoncedPartitionKey);
148 }
149 
TEST(CookieCravingTest,CreateWithPrefix)150 TEST(CookieCravingTest, CreateWithPrefix) {
151   // Valid __Host- cookie.
152   CookieCraving cc = CreateValidCookieCraving(GURL(kUrlString), "__Host-blah",
153                                               "Secure; Path=/");
154   EXPECT_EQ(cc.Domain(), "www.example.test");
155   EXPECT_EQ(cc.Path(), "/");
156   EXPECT_TRUE(cc.SecureAttribute());
157 
158   // Valid __Secure- cookie.
159   cc = CreateValidCookieCraving(GURL(kUrlString), "__Secure-blah",
160                                 "Secure; Path=/foo; Domain=example.test");
161   EXPECT_TRUE(cc.SecureAttribute());
162 }
163 
164 // Test various strange inputs that should still be valid.
TEST(CookieCravingTest,CreateStrange)165 TEST(CookieCravingTest, CreateStrange) {
166   const char* kStrangeNames[] = {
167       // Empty name is permitted.
168       "",
169       // Leading and trailing whitespace should get trimmed.
170       "   name     ",
171       // Internal whitespace is allowed.
172       "n a m e",
173       // Trim leading and trailing whitespace while preserving internal
174       // whitespace.
175       "   n a m e   ",
176   };
177   for (const char* name : kStrangeNames) {
178     CookieCraving cc = CreateValidCookieCraving(GURL(kUrlString), name, "");
179     EXPECT_EQ(cc.Name(), base::TrimWhitespaceASCII(name, base::TRIM_ALL));
180   }
181 
182   const char* kStrangeAttributesLines[] = {
183       // Capitalization.
184       "SECURE; PATH=/; SAMESITE=LAX",
185       // Leading semicolon.
186       "; Secure; Path=/; SameSite=Lax",
187       // Empty except for semicolons.
188       ";;;",
189       // Extra whitespace.
190       "     Secure;     Path=/;     SameSite=Lax     ",
191       // No whitespace.
192       "Secure;Path=/;SameSite=Lax",
193       // Domain attribute with leading dot.
194       "Domain=.example.test",
195       // Different path from the URL is allowed.
196       "Path=/different",
197       // Path not beginning with '/' is allowed. (It's just ignored.)
198       "Path=noslash",
199       // Attributes with extraneous values.
200       "Secure=true; HttpOnly=yes; Partitioned=absolutely",
201       // Unknown attributes or attribute values.
202       "Fake=totally; SameSite=SuperStrict",
203   };
204   for (const char* attributes : kStrangeAttributesLines) {
205     CreateValidCookieCraving(GURL(kUrlString), kName, attributes);
206   }
207 }
208 
209 // Another strange/maybe unexpected case is that Create() does not check the
210 // secureness of the URL against the cookie's Secure attribute. (This is
211 // documented in the method comment.)
TEST(CookieCravingTest,CreateSecureFromInsecureUrl)212 TEST(CookieCravingTest, CreateSecureFromInsecureUrl) {
213   CookieCraving cc =
214       CreateValidCookieCraving(GURL("http://insecure.test"), kName, "Secure");
215   EXPECT_TRUE(cc.SecureAttribute());
216   EXPECT_EQ(cc.SourceScheme(), CookieSourceScheme::kNonSecure);
217 }
218 
219 // Test inputs that should result in a failure to parse the cookie line.
TEST(CookieCravingTest,CreateFailParse)220 TEST(CookieCravingTest, CreateFailParse) {
221   const struct {
222     const char* name;
223     const char* attributes;
224   } kParseFailInputs[] = {
225       // Invalid characters in name.
226       {"blah\nsomething", "Secure; Path=/"},
227       {"blah=something", "Secure; Path=/"},
228       {"blah;something", "Secure; Path=/"},
229       // Truncated lines are blocked.
230       {"name", "Secure;\n Path=/"},
231   };
232   for (const auto& input : kParseFailInputs) {
233     std::optional<CookieCraving> cc =
234         CookieCraving::Create(GURL(kUrlString), input.name, input.attributes,
235                               kCreationTime, std::nullopt);
236     EXPECT_FALSE(cc);
237   }
238 }
239 
240 // Test cases where the Create() params are not valid.
TEST(CookieCravingTest,CreateFailInvalidParams)241 TEST(CookieCravingTest, CreateFailInvalidParams) {
242   // Invalid URL.
243   std::optional<CookieCraving> cc =
244       CookieCraving::Create(GURL(), kName, "", kCreationTime, std::nullopt);
245   EXPECT_FALSE(cc);
246 
247   // Null creation time.
248   cc = CookieCraving::Create(GURL(kUrlString), kName, "", base::Time(),
249                              std::nullopt);
250   EXPECT_FALSE(cc);
251 }
252 
TEST(CookieCravingTest,CreateFailBadDomain)253 TEST(CookieCravingTest, CreateFailBadDomain) {
254   // URL does not match domain.
255   std::optional<CookieCraving> cc =
256       CookieCraving::Create(GURL(kUrlString), kName, "Domain=other.test",
257                             kCreationTime, std::nullopt);
258   EXPECT_FALSE(cc);
259 
260   // Public suffix is not allowed to be Domain attribute.
261   cc = CookieCraving::Create(GURL(kUrlString), kName, "Domain=test",
262                              kCreationTime, std::nullopt);
263   EXPECT_FALSE(cc);
264 
265   // IP addresses cannot set suffixes as the Domain attribute.
266   cc = CookieCraving::Create(GURL("http://1.2.3.4"), kName, "Domain=2.3.4",
267                              kCreationTime, std::nullopt);
268   EXPECT_FALSE(cc);
269 }
270 
TEST(CookieCravingTest,CreateFailBadPartitioned)271 TEST(CookieCravingTest, CreateFailBadPartitioned) {
272   const CookiePartitionKey kPartitionKey =
273       CookiePartitionKey::FromURLForTesting(GURL("https://example.test"));
274 
275   // Not Secure.
276   std::optional<CookieCraving> cc = CookieCraving::Create(
277       GURL(kUrlString), kName, "Partitioned", kCreationTime, kPartitionKey);
278   EXPECT_FALSE(cc);
279 
280   // The URL scheme is not cryptographic.
281   cc = CookieCraving::Create(GURL("http://example.test"), kName,
282                              "Secure; Partitioned", kCreationTime,
283                              kPartitionKey);
284   EXPECT_FALSE(cc);
285 }
286 
TEST(CookieCravingTest,CreateFailInvalidPrefix)287 TEST(CookieCravingTest, CreateFailInvalidPrefix) {
288   // __Host- with insecure URL.
289   std::optional<CookieCraving> cc =
290       CookieCraving::Create(GURL("http://insecure.test"), "__Host-blah",
291                             "Secure; Path=/", kCreationTime, std::nullopt);
292   EXPECT_FALSE(cc);
293 
294   // __Host- with non-Secure cookie.
295   cc = CookieCraving::Create(GURL(kUrlString), "__Host-blah", "Path=/",
296                              kCreationTime, std::nullopt);
297   EXPECT_FALSE(cc);
298 
299   // __Host- with Domain attribute value.
300   cc = CookieCraving::Create(GURL(kUrlString), "__Host-blah",
301                              "Secure; Path=/; Domain=example.test",
302                              kCreationTime, std::nullopt);
303   EXPECT_FALSE(cc);
304 
305   // __Host- with non-root path.
306   cc = CookieCraving::Create(GURL(kUrlString), "__Host-blah",
307                              "Secure; Path=/foo", kCreationTime, std::nullopt);
308   EXPECT_FALSE(cc);
309 
310   // __Secure- with non-Secure cookie.
311   cc = CookieCraving::Create(GURL(kUrlString), "__Secure-blah", "",
312                              kCreationTime, std::nullopt);
313   EXPECT_FALSE(cc);
314 
315   // Prefixes are checked case-insensitively, so these CookieCravings are also
316   // invalid for not satisfying the prefix requirements.
317   // Missing Secure.
318   cc = CookieCraving::Create(GURL(kUrlString), "__host-blah", "Path=/",
319                              kCreationTime, std::nullopt);
320   EXPECT_FALSE(cc);
321   // Specifies Domain.
322   cc = CookieCraving::Create(GURL(kUrlString), "__HOST-blah",
323                              "Secure; Path=/; Domain=example.test",
324                              kCreationTime, std::nullopt);
325   EXPECT_FALSE(cc);
326   // Missing Secure.
327   cc = CookieCraving::Create(GURL(kUrlString), "__SeCuRe-blah", "",
328                              kCreationTime, std::nullopt);
329   EXPECT_FALSE(cc);
330 }
331 
332 // Valid cases were tested as part of the successful Create() tests above, so
333 // this only tests the invalid cases.
TEST(CookieCravingTest,IsNotValid)334 TEST(CookieCravingTest, IsNotValid) {
335   const struct {
336     const char* name;
337     const char* domain;
338     const char* path;
339     bool secure;
340     base::Time creation = kCreationTime;
341   } kTestCases[] = {
342       // Invalid name.
343       {" name", "www.example.test", "/", true},
344       {";", "www.example.test", "/", true},
345       {"=", "www.example.test", "/", true},
346       {"na\nme", "www.example.test", "/", true},
347       // Empty domain.
348       {"name", "", "/", true},
349       // Non-canonical domain.
350       {"name", "ExAmPlE.test", "/", true},
351       // Empty path.
352       {"name", "www.example.test", "", true},
353       // Path not beginning with slash.
354       {"name", "www.example.test", "noslash", true},
355       // Invalid __Host- prefix.
356       {"__Host-name", ".example.test", "/", true},
357       {"__Host-name", "www.example.test", "/", false},
358       {"__Host-name", "www.example.test", "/foo", false},
359       // Invalid __Secure- prefix.
360       {"__Secure-name", "www.example.test", "/", false},
361       // Invalid __Host- prefix (case insensitive).
362       {"__HOST-name", ".example.test", "/", true},
363       {"__HoSt-name", "www.example.test", "/", false},
364       {"__host-name", "www.example.test", "/foo", false},
365       // Invalid __Secure- prefix (case insensitive).
366       {"__secure-name", "www.example.test", "/", false},
367       // Null creation date.
368       {"name", "www.example.test", "/", true, base::Time()},
369   };
370 
371   for (const auto& test_case : kTestCases) {
372     CookieCraving cc = CookieCraving::CreateUnsafeForTesting(
373         test_case.name, test_case.domain, test_case.path, test_case.creation,
374         test_case.secure,
375         /*httponly=*/false, CookieSameSite::LAX_MODE,
376         /*partition_key=*/std::nullopt, CookieSourceScheme::kSecure, 443);
377     SCOPED_TRACE(cc.DebugString());
378     EXPECT_FALSE(cc.IsValid());
379   }
380 
381   // Additionally, Partitioned requires the Secure attribute.
382   CookieCraving cc = CookieCraving::CreateUnsafeForTesting(
383       "name", "www.example.test", "/", kCreationTime, /*secure=*/false,
384       /*httponly=*/false, CookieSameSite::LAX_MODE,
385       CookiePartitionKey::FromURLForTesting(GURL("https://example.test")),
386       CookieSourceScheme::kSecure, 443);
387   EXPECT_FALSE(cc.IsValid());
388 }
389 
TEST(CookieCravingTest,IsSatisfiedBy)390 TEST(CookieCravingTest, IsSatisfiedBy) {
391   // Default case with no attributes.
392   CanonicalCookie canonical_cookie =
393       CreateCanonicalCookie(GURL(kUrlString), "name=somevalue");
394   CookieCraving cookie_craving =
395       CreateValidCookieCraving(GURL(kUrlString), "name", "");
396   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
397 
398   // With attributes.
399   canonical_cookie =
400       CreateCanonicalCookie(GURL(kUrlString),
401                             "name=somevalue; Domain=example.test; Path=/; "
402                             "Secure; HttpOnly; SameSite=Lax");
403   cookie_craving = CreateValidCookieCraving(
404       GURL(kUrlString), "name",
405       "Domain=example.test; Path=/; Secure; HttpOnly; SameSite=Lax");
406   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
407 
408   // The URL may differ as long as the cookie attributes match.
409   canonical_cookie = CreateCanonicalCookie(
410       GURL(kUrlString), "name=somevalue; Domain=example.test");
411   cookie_craving = CreateValidCookieCraving(
412       GURL("https://subdomain.example.test"), "name", "Domain=example.test");
413   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
414 
415   // Creation time is not required to match.
416   canonical_cookie = CreateCanonicalCookie(
417       GURL(kUrlString), "name=somevalue; Domain=example.test", kCreationTime);
418   cookie_craving =
419       CreateValidCookieCraving(GURL(kUrlString), "name", "Domain=example.test",
420                                kCreationTime + base::Hours(1));
421   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
422 
423   // Source scheme and port (and indeed source host) are not required to match.
424   canonical_cookie = CreateCanonicalCookie(
425       GURL(kUrlString), "name=somevalue; Domain=example.test");
426   cookie_craving =
427       CreateValidCookieCraving(GURL("http://subdomain.example.test:8080"),
428                                "name", "Domain=example.test");
429   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
430 }
431 
TEST(CookieCravingTest,IsNotSatisfiedBy)432 TEST(CookieCravingTest, IsNotSatisfiedBy) {
433   // Name does not match.
434   CanonicalCookie canonical_cookie =
435       CreateCanonicalCookie(GURL(kUrlString), "realname=somevalue");
436   CookieCraving cookie_craving =
437       CreateValidCookieCraving(GURL(kUrlString), "fakename", "");
438   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
439 
440   // Domain does not match.
441   canonical_cookie = CreateCanonicalCookie(
442       GURL(kUrlString), "name=somevalue; Domain=example.test");
443   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name",
444                                             "Domain=www.example.test");
445   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
446 
447   // Host cookie vs domain cookie.
448   canonical_cookie = CreateCanonicalCookie(GURL(kUrlString), "name=somevalue");
449   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name",
450                                             "Domain=www.example.test");
451   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
452 
453   // Domain cookie vs host cookie.
454   canonical_cookie = CreateCanonicalCookie(
455       GURL(kUrlString), "name=somevalue; Domain=www.example.test");
456   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name", "");
457   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
458 
459   // Path does not match.
460   canonical_cookie = CreateCanonicalCookie(
461       GURL(kUrlString), "name=somevalue; Domain=example.test; Path=/");
462   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name",
463                                             "Domain=example.test; Path=/foo");
464   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
465 
466   // Secure vs non-Secure.
467   canonical_cookie = CreateCanonicalCookie(
468       GURL(kUrlString), "name=somevalue; Secure; Domain=example.test; Path=/");
469   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name",
470                                             "Domain=example.test; Path=/foo");
471   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
472 
473   // Non-Secure vs Secure.
474   canonical_cookie = CreateCanonicalCookie(
475       GURL(kUrlString), "name=somevalue; Domain=example.test; Path=/");
476   cookie_craving = CreateValidCookieCraving(
477       GURL(kUrlString), "name", "Secure; Domain=example.test; Path=/foo");
478   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
479 
480   // HttpOnly vs non-HttpOnly.
481   canonical_cookie = CreateCanonicalCookie(
482       GURL(kUrlString),
483       "name=somevalue; HttpOnly; Domain=example.test; Path=/");
484   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name",
485                                             "Domain=example.test; Path=/foo");
486   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
487 
488   // Non-HttpOnly vs HttpOnly.
489   canonical_cookie = CreateCanonicalCookie(
490       GURL(kUrlString), "name=somevalue; Domain=example.test; Path=/");
491   cookie_craving = CreateValidCookieCraving(
492       GURL(kUrlString), "name", "HttpOnly; Domain=example.test; Path=/foo");
493   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
494 
495   // SameSite does not match.
496   canonical_cookie =
497       CreateCanonicalCookie(GURL(kUrlString), "name=somevalue; SameSite=Lax");
498   cookie_craving =
499       CreateValidCookieCraving(GURL(kUrlString), "name", "SameSite=Strict");
500   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
501 
502   // SameSite vs unspecified SameSite. (Note that the SameSite attribute value
503   // is compared, not the effective SameSite enforcement mode.)
504   canonical_cookie =
505       CreateCanonicalCookie(GURL(kUrlString), "name=somevalue; SameSite=Lax");
506   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name", "");
507   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
508 }
509 
TEST(CookieCravingTest,IsSatisfiedByWithPartitionKey)510 TEST(CookieCravingTest, IsSatisfiedByWithPartitionKey) {
511   const CookiePartitionKey kPartitionKey =
512       CookiePartitionKey::FromURLForTesting(GURL("https://example.test"));
513   const CookiePartitionKey kOtherPartitionKey =
514       CookiePartitionKey::FromURLForTesting(GURL("https://other.test"));
515 
516   const base::UnguessableToken kNonce = base::UnguessableToken::Create();
517   const CookiePartitionKey kNoncedPartitionKey =
518       CookiePartitionKey::FromURLForTesting(
519           GURL("https://example.test"),
520           CookiePartitionKey::AncestorChainBit::kCrossSite, kNonce);
521 
522   // Partition keys match.
523   CanonicalCookie canonical_cookie = CreateCanonicalCookie(
524       GURL(kUrlString), "name=somevalue; Secure; Partitioned", kCreationTime,
525       kPartitionKey);
526   CookieCraving cookie_craving =
527       CreateValidCookieCraving(GURL(kUrlString), "name", "Secure; Partitioned",
528                                kCreationTime, kPartitionKey);
529   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
530 
531   // Cookie line doesn't specified Partitioned so key gets cleared for both.
532   canonical_cookie = CreateCanonicalCookie(
533       GURL(kUrlString), "name=somevalue; Secure", kCreationTime, kPartitionKey);
534   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name", "Secure",
535                                             kCreationTime, kOtherPartitionKey);
536   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
537 
538   // Without partition key for the CookieCraving, but cookie line doesn't
539   // specify Partitioned so they are equivalent.
540   canonical_cookie = CreateCanonicalCookie(
541       GURL(kUrlString), "name=somevalue; Secure", kCreationTime, kPartitionKey);
542   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name", "Secure");
543   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
544 
545   // Without partition key for the CanonicalCookie, but cookie line doesn't
546   // specify Partitioned so they are equivalent.
547   canonical_cookie =
548       CreateCanonicalCookie(GURL(kUrlString), "name=somevalue; Secure");
549   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name", "Secure",
550                                             kCreationTime, kPartitionKey);
551   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
552 
553   // Identical nonced partition keys.
554   canonical_cookie =
555       CreateCanonicalCookie(GURL(kUrlString), "name=somevalue; Secure",
556                             kCreationTime, kNoncedPartitionKey);
557   cookie_craving = CreateValidCookieCraving(GURL(kUrlString), "name", "Secure",
558                                             kCreationTime, kNoncedPartitionKey);
559   EXPECT_TRUE(cookie_craving.IsSatisfiedBy(canonical_cookie));
560 }
561 
TEST(CookieCravingTest,IsNotSatisfiedByWithPartitionKey)562 TEST(CookieCravingTest, IsNotSatisfiedByWithPartitionKey) {
563   const CookiePartitionKey kPartitionKey =
564       CookiePartitionKey::FromURLForTesting(GURL("https://example.test"));
565   const CookiePartitionKey kOtherPartitionKey =
566       CookiePartitionKey::FromURLForTesting(GURL("https://other.test"));
567 
568   const base::UnguessableToken kNonce = base::UnguessableToken::Create();
569   const base::UnguessableToken kOtherNonce = base::UnguessableToken::Create();
570   const CookiePartitionKey kNoncedPartitionKey =
571       CookiePartitionKey::FromURLForTesting(
572           GURL("https://example.test"),
573           CookiePartitionKey::AncestorChainBit::kCrossSite, kNonce);
574   const CookiePartitionKey kOtherNoncedPartitionKey =
575       CookiePartitionKey::FromURLForTesting(
576           GURL("https://example.test"),
577           CookiePartitionKey::AncestorChainBit::kCrossSite, kOtherNonce);
578 
579   // Partition keys do not match.
580   CanonicalCookie canonical_cookie = CreateCanonicalCookie(
581       GURL(kUrlString), "name=somevalue; Secure; Partitioned", kCreationTime,
582       kPartitionKey);
583   CookieCraving cookie_craving =
584       CreateValidCookieCraving(GURL(kUrlString), "name", "Secure; Partitioned",
585                                kCreationTime, kOtherPartitionKey);
586   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
587 
588   // Nonced partition keys do not match.
589   canonical_cookie = CreateCanonicalCookie(
590       GURL(kUrlString), "name=somevalue; Secure; Partitioned", kCreationTime,
591       kNoncedPartitionKey);
592   cookie_craving =
593       CreateValidCookieCraving(GURL(kUrlString), "name", "Secure; Partitioned",
594                                kCreationTime, kOtherNoncedPartitionKey);
595   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
596 
597   // Nonced partition key vs regular partition key.
598   canonical_cookie = CreateCanonicalCookie(
599       GURL(kUrlString), "name=somevalue; Secure; Partitioned", kCreationTime,
600       kNoncedPartitionKey);
601   cookie_craving =
602       CreateValidCookieCraving(GURL(kUrlString), "name", "Secure; Partitioned",
603                                kCreationTime, kPartitionKey);
604   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
605 
606   // Regular partition key vs nonced partition key.
607   canonical_cookie = CreateCanonicalCookie(
608       GURL(kUrlString), "name=somevalue; Secure; Partitioned", kCreationTime,
609       kPartitionKey);
610   cookie_craving =
611       CreateValidCookieCraving(GURL(kUrlString), "name", "Secure; Partitioned",
612                                kCreationTime, kNoncedPartitionKey);
613   EXPECT_FALSE(cookie_craving.IsSatisfiedBy(canonical_cookie));
614 }
615 
TEST(CookieCravingTest,BasicCookieToFromProto)616 TEST(CookieCravingTest, BasicCookieToFromProto) {
617   // Default cookie.
618   CookieCraving cc = CreateValidCookieCraving(GURL(kUrlString), kName, "");
619 
620   proto::CookieCraving proto = cc.ToProto();
621   EXPECT_EQ(proto.name(), kName);
622   EXPECT_EQ(proto.domain(), "www.example.test");
623   EXPECT_EQ(proto.path(), "/");
624   EXPECT_EQ(proto.creation_time(),
625             kCreationTime.ToDeltaSinceWindowsEpoch().InMicroseconds());
626   EXPECT_FALSE(proto.secure());
627   EXPECT_FALSE(proto.httponly());
628   EXPECT_EQ(proto.same_site(),
629             proto::CookieSameSite::COOKIE_SAME_SITE_UNSPECIFIED);
630   EXPECT_FALSE(proto.has_serialized_partition_key());
631   EXPECT_EQ(proto.source_scheme(), proto::CookieSourceScheme::SECURE);
632   EXPECT_EQ(proto.source_port(), 443);
633 
634   std::optional<CookieCraving> restored_cc =
635       CookieCraving::CreateFromProto(proto);
636   ASSERT_TRUE(restored_cc.has_value());
637   EXPECT_TRUE(restored_cc->IsEqualForTesting(cc));
638 
639   // Non-default attributes.
640   cc = CreateValidCookieCraving(
641       GURL(kUrlString), kName,
642       "Secure; HttpOnly; Path=/foo; Domain=example.test; SameSite=Lax");
643 
644   proto = cc.ToProto();
645   EXPECT_EQ(proto.name(), kName);
646   EXPECT_EQ(proto.domain(), ".example.test");
647   EXPECT_EQ(proto.path(), "/foo");
648   EXPECT_EQ(proto.creation_time(),
649             kCreationTime.ToDeltaSinceWindowsEpoch().InMicroseconds());
650   EXPECT_TRUE(proto.secure());
651   EXPECT_TRUE(proto.httponly());
652   EXPECT_EQ(proto.same_site(), proto::CookieSameSite::LAX_MODE);
653   EXPECT_FALSE(proto.has_serialized_partition_key());
654   EXPECT_EQ(proto.source_scheme(), proto::CookieSourceScheme::SECURE);
655   EXPECT_EQ(proto.source_port(), 443);
656 
657   restored_cc = CookieCraving::CreateFromProto(proto);
658   ASSERT_TRUE(restored_cc.has_value());
659   EXPECT_TRUE(restored_cc->IsEqualForTesting(cc));
660 }
661 
TEST(CookieCravingTest,PartitionedCookieToFromProto)662 TEST(CookieCravingTest, PartitionedCookieToFromProto) {
663   const CookiePartitionKey kSameSitePartitionKey =
664       CookiePartitionKey::FromURLForTesting(GURL("https://auth.example.test"));
665   const CookiePartitionKey kCrossSitePartitionKey =
666       CookiePartitionKey::FromURLForTesting(GURL("https://www.other.test"));
667 
668   for (const CookiePartitionKey& partition_key :
669        {kSameSitePartitionKey, kCrossSitePartitionKey}) {
670     // Partitioned cookies must be set with Secure. The __Host- prefix is not
671     // required.
672     CookieCraving cc =
673         CreateValidCookieCraving(GURL(kUrlString), kName, "Secure; Partitioned",
674                                  kCreationTime, partition_key);
675     EXPECT_EQ(cc.PartitionKey(), partition_key);
676     base::expected<net::CookiePartitionKey::SerializedCookiePartitionKey,
677                    std::string>
678         serialized_partition_key =
679             net::CookiePartitionKey::Serialize(partition_key);
680     CHECK(serialized_partition_key.has_value());
681 
682     proto::CookieCraving proto = cc.ToProto();
683     EXPECT_TRUE(proto.secure());
684     ASSERT_TRUE(proto.has_serialized_partition_key());
685     EXPECT_EQ(proto.serialized_partition_key().top_level_site(),
686               serialized_partition_key->TopLevelSite());
687     EXPECT_EQ(proto.serialized_partition_key().has_cross_site_ancestor(),
688               serialized_partition_key->has_cross_site_ancestor());
689 
690     std::optional<CookieCraving> restored_cc =
691         CookieCraving::CreateFromProto(proto);
692     ASSERT_TRUE(restored_cc.has_value());
693     EXPECT_TRUE(restored_cc->IsEqualForTesting(cc));
694   }
695 }
696 
TEST(CookieCravingTest,FailCreateFromInvalidProto)697 TEST(CookieCravingTest, FailCreateFromInvalidProto) {
698   // Empty proto.
699   proto::CookieCraving proto;
700   std::optional<CookieCraving> cc = CookieCraving::CreateFromProto(proto);
701   EXPECT_FALSE(cc.has_value());
702 
703   cc = CreateValidCookieCraving(
704       GURL(kUrlString), kName,
705       "Secure; HttpOnly; Path=/foo; Domain=example.test; SameSite=Lax");
706   proto = cc->ToProto();
707 
708   // Missing parameters.
709   {
710     proto::CookieCraving p(proto);
711     p.clear_name();
712     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
713     EXPECT_FALSE(c.has_value());
714   }
715   {
716     proto::CookieCraving p(proto);
717     p.clear_domain();
718     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
719     EXPECT_FALSE(c.has_value());
720   }
721   {
722     proto::CookieCraving p(proto);
723     p.clear_path();
724     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
725     EXPECT_FALSE(c.has_value());
726   }
727   {
728     proto::CookieCraving p(proto);
729     p.clear_secure();
730     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
731     EXPECT_FALSE(c.has_value());
732   }
733   {
734     proto::CookieCraving p(proto);
735     p.clear_httponly();
736     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
737     EXPECT_FALSE(c.has_value());
738   }
739   {
740     proto::CookieCraving p(proto);
741     p.clear_source_port();
742     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
743     EXPECT_FALSE(c.has_value());
744   }
745   {
746     proto::CookieCraving p(proto);
747     p.clear_creation_time();
748     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
749     EXPECT_FALSE(c.has_value());
750   }
751   {
752     proto::CookieCraving p(proto);
753     p.clear_same_site();
754     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
755     EXPECT_FALSE(c.has_value());
756   }
757   {
758     proto::CookieCraving p(proto);
759     p.clear_source_scheme();
760     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
761     EXPECT_FALSE(c.has_value());
762   }
763   // Malformed serialized partition key.
764   {
765     proto::CookieCraving p(proto);
766     p.mutable_serialized_partition_key()->set_top_level_site("");
767     p.mutable_serialized_partition_key()->set_has_cross_site_ancestor(false);
768     std::optional<CookieCraving> c = CookieCraving::CreateFromProto(p);
769     EXPECT_FALSE(c.has_value());
770   }
771 }
772 
773 }  // namespace net::device_bound_sessions
774