• 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/session.h"
6 
7 #include "base/test/bind.h"
8 #include "net/cookies/cookie_constants.h"
9 #include "net/cookies/cookie_inclusion_status.h"
10 #include "net/cookies/cookie_util.h"
11 #include "net/device_bound_sessions/proto/storage.pb.h"
12 #include "net/test/test_with_task_environment.h"
13 #include "net/url_request/url_request_context_builder.h"
14 #include "net/url_request/url_request_test_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace net::device_bound_sessions {
18 
19 namespace {
20 
21 class SessionTest : public TestWithTaskEnvironment {
22  protected:
SessionTest()23   SessionTest() : context_(CreateTestURLRequestContextBuilder()->Build()) {}
24 
25   std::unique_ptr<URLRequestContext> context_;
26 };
27 
28 class FakeDelegate : public URLRequest::Delegate {
OnReadCompleted(URLRequest * request,int bytes_read)29   void OnReadCompleted(URLRequest* request, int bytes_read) override {}
30 };
31 
32 constexpr net::NetworkTrafficAnnotationTag kDummyAnnotation =
33     net::DefineNetworkTrafficAnnotation("dbsc_registration", "");
34 constexpr char kSessionId[] = "SessionId";
35 constexpr char kUrlString[] = "https://example.test/index.html";
36 const GURL kTestUrl(kUrlString);
37 
CreateValidParams()38 SessionParams CreateValidParams() {
39   SessionParams::Scope scope;
40   std::vector<SessionParams::Credential> cookie_credentials(
41       {SessionParams::Credential{"test_cookie",
42                                  "Secure; Domain=example.test"}});
43   SessionParams params{kSessionId, kUrlString, std::move(scope),
44                        std::move(cookie_credentials)};
45   return params;
46 }
47 
TEST_F(SessionTest,ValidService)48 TEST_F(SessionTest, ValidService) {
49   auto session = Session::CreateIfValid(CreateValidParams(), kTestUrl);
50   EXPECT_TRUE(session);
51 }
52 
TEST_F(SessionTest,DefaultExpiry)53 TEST_F(SessionTest, DefaultExpiry) {
54   auto session = Session::CreateIfValid(CreateValidParams(), kTestUrl);
55   ASSERT_TRUE(session);
56   EXPECT_LT(base::Time::Now() + base::Days(399), session->expiry_date());
57 }
58 
TEST_F(SessionTest,InvalidServiceRefreshUrl)59 TEST_F(SessionTest, InvalidServiceRefreshUrl) {
60   auto params = CreateValidParams();
61   params.refresh_url = "";
62   EXPECT_FALSE(Session::CreateIfValid(params, kTestUrl));
63 }
64 
TEST_F(SessionTest,ToFromProto)65 TEST_F(SessionTest, ToFromProto) {
66   std::unique_ptr<Session> session =
67       Session::CreateIfValid(CreateValidParams(), kTestUrl);
68   ASSERT_TRUE(session);
69 
70   // Convert to proto and validate contents.
71   proto::Session sproto = session->ToProto();
72   EXPECT_EQ(Session::Id(sproto.id()), session->id());
73   EXPECT_EQ(sproto.refresh_url(), session->refresh_url().spec());
74   EXPECT_EQ(sproto.should_defer_when_expired(),
75             session->should_defer_when_expired());
76 
77   // Restore session from proto and validate contents.
78   std::unique_ptr<Session> restored = Session::CreateFromProto(sproto);
79   ASSERT_TRUE(restored);
80   EXPECT_TRUE(restored->IsEqualForTesting(*session));
81 }
82 
TEST_F(SessionTest,FailCreateFromInvalidProto)83 TEST_F(SessionTest, FailCreateFromInvalidProto) {
84   // Empty proto.
85   {
86     proto::Session sproto;
87     EXPECT_FALSE(Session::CreateFromProto(sproto));
88   }
89 
90   // Create a fully populated proto.
91   std::unique_ptr<Session> session =
92       Session::CreateIfValid(CreateValidParams(), kTestUrl);
93   ASSERT_TRUE(session);
94   proto::Session sproto = session->ToProto();
95 
96   // Missing fields.
97   {
98     proto::Session s(sproto);
99     s.clear_id();
100     EXPECT_FALSE(Session::CreateFromProto(s));
101   }
102   {
103     proto::Session s(sproto);
104     s.clear_refresh_url();
105     EXPECT_FALSE(Session::CreateFromProto(s));
106   }
107   {
108     proto::Session s(sproto);
109     s.clear_should_defer_when_expired();
110     EXPECT_FALSE(Session::CreateFromProto(s));
111   }
112   {
113     proto::Session s(sproto);
114     s.clear_expiry_time();
115     EXPECT_FALSE(Session::CreateFromProto(s));
116   }
117   {
118     proto::Session s(sproto);
119     s.clear_session_inclusion_rules();
120     EXPECT_FALSE(Session::CreateFromProto(s));
121   }
122 
123   // Empty id.
124   {
125     proto::Session s(sproto);
126     s.set_id("");
127     EXPECT_FALSE(Session::CreateFromProto(s));
128   }
129   // Invalid refresh URL.
130   {
131     proto::Session s(sproto);
132     s.set_refresh_url("blank");
133     EXPECT_FALSE(Session::CreateFromProto(s));
134   }
135 
136   // Expired
137   {
138     proto::Session s(sproto);
139     base::Time expiry_date = base::Time::Now() - base::Days(1);
140     s.set_expiry_time(expiry_date.ToDeltaSinceWindowsEpoch().InMicroseconds());
141     EXPECT_FALSE(Session::CreateFromProto(s));
142   }
143 }
144 
TEST_F(SessionTest,DeferredSession)145 TEST_F(SessionTest, DeferredSession) {
146   auto params = CreateValidParams();
147   auto session = Session::CreateIfValid(params, kTestUrl);
148   ASSERT_TRUE(session);
149   net::TestDelegate delegate;
150   std::unique_ptr<URLRequest> request =
151       context_->CreateRequest(kTestUrl, IDLE, &delegate, kDummyAnnotation);
152   request->set_site_for_cookies(SiteForCookies::FromUrl(kTestUrl));
153 
154   bool is_deferred = session->ShouldDeferRequest(request.get());
155   EXPECT_TRUE(is_deferred);
156 }
157 
TEST_F(SessionTest,NotDeferredAsExcluded)158 TEST_F(SessionTest, NotDeferredAsExcluded) {
159   auto params = CreateValidParams();
160   SessionParams::Scope::Specification spec;
161   spec.type = SessionParams::Scope::Specification::Type::kExclude;
162   spec.domain = "example.test";
163   spec.path = "/index.html";
164   params.scope.specifications.push_back(spec);
165   auto session = Session::CreateIfValid(params, kTestUrl);
166   ASSERT_TRUE(session);
167   net::TestDelegate delegate;
168   std::unique_ptr<URLRequest> request =
169       context_->CreateRequest(kTestUrl, IDLE, &delegate, kDummyAnnotation);
170   request->set_site_for_cookies(SiteForCookies::FromUrl(kTestUrl));
171 
172   bool is_deferred = session->ShouldDeferRequest(request.get());
173   EXPECT_FALSE(is_deferred);
174 }
175 
TEST_F(SessionTest,NotDeferredSubdomain)176 TEST_F(SessionTest, NotDeferredSubdomain) {
177   const char subdomain[] = "https://test.example.test/index.html";
178   const GURL url_subdomain(subdomain);
179   auto params = CreateValidParams();
180   auto session = Session::CreateIfValid(params, kTestUrl);
181   ASSERT_TRUE(session);
182   net::TestDelegate delegate;
183   std::unique_ptr<URLRequest> request =
184       context_->CreateRequest(url_subdomain, IDLE, &delegate, kDummyAnnotation);
185   request->set_site_for_cookies(SiteForCookies::FromUrl(url_subdomain));
186 
187   bool is_deferred = session->ShouldDeferRequest(request.get());
188   EXPECT_FALSE(is_deferred);
189 }
190 
TEST_F(SessionTest,DeferredIncludedSubdomain)191 TEST_F(SessionTest, DeferredIncludedSubdomain) {
192   // Unless include site is specified, only same origin will be
193   // matched even if the spec adds an include for a different
194   // origin.
195   const char subdomain[] = "https://test.example.test/index.html";
196   const GURL url_subdomain(subdomain);
197   auto params = CreateValidParams();
198   SessionParams::Scope::Specification spec;
199   spec.type = SessionParams::Scope::Specification::Type::kInclude;
200   spec.domain = "test.example.test";
201   spec.path = "/index.html";
202   params.scope.specifications.push_back(spec);
203   auto session = Session::CreateIfValid(params, kTestUrl);
204   ASSERT_TRUE(session);
205   net::TestDelegate delegate;
206   std::unique_ptr<URLRequest> request =
207       context_->CreateRequest(url_subdomain, IDLE, &delegate, kDummyAnnotation);
208   request->set_site_for_cookies(SiteForCookies::FromUrl(url_subdomain));
209   ASSERT_TRUE(session->ShouldDeferRequest(request.get()));
210 }
211 
TEST_F(SessionTest,NotDeferredWithCookieSession)212 TEST_F(SessionTest, NotDeferredWithCookieSession) {
213   auto params = CreateValidParams();
214   auto session = Session::CreateIfValid(params, kTestUrl);
215   ASSERT_TRUE(session);
216   net::TestDelegate delegate;
217   std::unique_ptr<URLRequest> request =
218       context_->CreateRequest(kTestUrl, IDLE, &delegate, kDummyAnnotation);
219   request->set_site_for_cookies(SiteForCookies::FromUrl(kTestUrl));
220   bool is_deferred = session->ShouldDeferRequest(request.get());
221   EXPECT_TRUE(is_deferred);
222 
223   CookieInclusionStatus status;
224   auto source = CookieSourceType::kHTTP;
225   auto cookie = CanonicalCookie::Create(
226       kTestUrl, "test_cookie=v;Secure; Domain=example.test", base::Time::Now(),
227       std::nullopt, std::nullopt, source, &status);
228   ASSERT_TRUE(cookie);
229   CookieAccessResult access_result;
230   request->set_maybe_sent_cookies({{*cookie.get(), access_result}});
231   EXPECT_FALSE(session->ShouldDeferRequest(request.get()));
232 }
233 
TEST_F(SessionTest,NotDeferredInsecure)234 TEST_F(SessionTest, NotDeferredInsecure) {
235   const char insecure_url[] = "http://example.test/index.html";
236   const GURL test_insecure_url(insecure_url);
237   auto params = CreateValidParams();
238   auto session = Session::CreateIfValid(params, kTestUrl);
239   ASSERT_TRUE(session);
240   net::TestDelegate delegate;
241   std::unique_ptr<URLRequest> request = context_->CreateRequest(
242       test_insecure_url, IDLE, &delegate, kDummyAnnotation);
243   request->set_site_for_cookies(SiteForCookies::FromUrl(kTestUrl));
244 
245   bool is_deferred = session->ShouldDeferRequest(request.get());
246   EXPECT_FALSE(is_deferred);
247 }
248 
249 class InsecureDelegate : public CookieAccessDelegate {
250  public:
ShouldTreatUrlAsTrustworthy(const GURL & url) const251   bool ShouldTreatUrlAsTrustworthy(const GURL& url) const override {
252     return true;
253   }
GetAccessSemantics(const CanonicalCookie & cookie) const254   CookieAccessSemantics GetAccessSemantics(
255       const CanonicalCookie& cookie) const override {
256     return CookieAccessSemantics::UNKNOWN;
257   }
258 
GetAccessForLegacyCookieScope(const CanonicalCookie & cookie) const259   CookieLegacyScope GetAccessForLegacyCookieScope(
260       const CanonicalCookie& cookie) const override {
261     return CookieLegacyScope::UNKNOWN;
262   }
263   // Returns whether a cookie should be attached regardless of its SameSite
264   // value vs the request context.
ShouldIgnoreSameSiteRestrictions(const GURL & url,const SiteForCookies & site_for_cookies) const265   bool ShouldIgnoreSameSiteRestrictions(
266       const GURL& url,
267       const SiteForCookies& site_for_cookies) const override {
268     return true;
269   }
270   [[nodiscard]] std::optional<
271       std::pair<FirstPartySetMetadata, FirstPartySetsCacheFilter::MatchInfo>>
ComputeFirstPartySetMetadataMaybeAsync(const net::SchemefulSite & site,const net::SchemefulSite * top_frame_site,base::OnceCallback<void (FirstPartySetMetadata,FirstPartySetsCacheFilter::MatchInfo)> callback) const272   ComputeFirstPartySetMetadataMaybeAsync(
273       const net::SchemefulSite& site,
274       const net::SchemefulSite* top_frame_site,
275       base::OnceCallback<void(FirstPartySetMetadata,
276                               FirstPartySetsCacheFilter::MatchInfo)> callback)
277       const override {
278     return std::nullopt;
279   }
280   [[nodiscard]] std::optional<
281       base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>>
FindFirstPartySetEntries(const base::flat_set<net::SchemefulSite> & sites,base::OnceCallback<void (base::flat_map<net::SchemefulSite,net::FirstPartySetEntry>)> callback) const282   FindFirstPartySetEntries(
283       const base::flat_set<net::SchemefulSite>& sites,
284       base::OnceCallback<
285           void(base::flat_map<net::SchemefulSite, net::FirstPartySetEntry>)>
286           callback) const override {
287     return std::nullopt;
288   }
289 };
290 
TEST_F(SessionTest,NotDeferredNotSameSite)291 TEST_F(SessionTest, NotDeferredNotSameSite) {
292   auto params = CreateValidParams();
293   auto session = Session::CreateIfValid(params, kTestUrl);
294   ASSERT_TRUE(session);
295   net::TestDelegate delegate;
296   std::unique_ptr<URLRequest> request =
297       context_->CreateRequest(kTestUrl, IDLE, &delegate, kDummyAnnotation);
298 
299   bool is_deferred = session->ShouldDeferRequest(request.get());
300   EXPECT_FALSE(is_deferred);
301 }
302 
TEST_F(SessionTest,DeferredNotSameSiteDelegate)303 TEST_F(SessionTest, DeferredNotSameSiteDelegate) {
304   context_->cookie_store()->SetCookieAccessDelegate(
305       std::make_unique<InsecureDelegate>());
306   auto params = CreateValidParams();
307   auto session = Session::CreateIfValid(params, kTestUrl);
308   ASSERT_TRUE(session);
309   net::TestDelegate delegate;
310   std::unique_ptr<URLRequest> request =
311       context_->CreateRequest(kTestUrl, IDLE, &delegate, kDummyAnnotation);
312 
313   bool is_deferred = session->ShouldDeferRequest(request.get());
314   EXPECT_TRUE(is_deferred);
315 }
316 
TEST_F(SessionTest,NotDeferredIncludedSubdomainHostCraving)317 TEST_F(SessionTest, NotDeferredIncludedSubdomainHostCraving) {
318   // Unless include site is specified, only same origin will be
319   // matched even if the spec adds an include for a different
320   // origin.
321   const char subdomain[] = "https://test.example.test/index.html";
322   const GURL url_subdomain(subdomain);
323   auto params = CreateValidParams();
324   SessionParams::Scope::Specification spec;
325   spec.type = SessionParams::Scope::Specification::Type::kInclude;
326   spec.domain = "test.example.test";
327   spec.path = "/index.html";
328   params.scope.specifications.push_back(spec);
329   std::vector<SessionParams::Credential> cookie_credentials(
330       {SessionParams::Credential{"test_cookie", "Secure;"}});
331   params.credentials = std::move(cookie_credentials);
332   auto session = Session::CreateIfValid(params, kTestUrl);
333   ASSERT_TRUE(session);
334   net::TestDelegate delegate;
335   std::unique_ptr<URLRequest> request =
336       context_->CreateRequest(url_subdomain, IDLE, &delegate, kDummyAnnotation);
337   request->set_site_for_cookies(SiteForCookies::FromUrl(url_subdomain));
338   ASSERT_FALSE(session->ShouldDeferRequest(request.get()));
339 }
340 
TEST_F(SessionTest,CreationDate)341 TEST_F(SessionTest, CreationDate) {
342   auto session = Session::CreateIfValid(CreateValidParams(), kTestUrl);
343   ASSERT_TRUE(session);
344   // Make sure it's set to a plausible value.
345   EXPECT_LT(base::Time::Now() - base::Days(1), session->creation_date());
346 }
347 
348 }  // namespace
349 
350 }  // namespace net::device_bound_sessions
351