restricted_cookie_manager_unittest.cc 108 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/network/restricted_cookie_manager.h"
  5. #include <set>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/run_loop.h"
  10. #include "base/test/bind.h"
  11. #include "base/test/scoped_feature_list.h"
  12. #include "base/test/task_environment.h"
  13. #include "base/time/time.h"
  14. #include "mojo/public/cpp/bindings/pending_remote.h"
  15. #include "mojo/public/cpp/bindings/receiver.h"
  16. #include "mojo/public/cpp/bindings/receiver_set.h"
  17. #include "mojo/public/cpp/bindings/remote.h"
  18. #include "mojo/public/cpp/system/functions.h"
  19. #include "net/base/features.h"
  20. #include "net/base/isolation_info.h"
  21. #include "net/base/network_isolation_key.h"
  22. #include "net/base/schemeful_site.h"
  23. #include "net/cookies/canonical_cookie_test_helpers.h"
  24. #include "net/cookies/cookie_constants.h"
  25. #include "net/cookies/cookie_inclusion_status.h"
  26. #include "net/cookies/cookie_monster.h"
  27. #include "net/cookies/cookie_partition_key.h"
  28. #include "net/cookies/cookie_store.h"
  29. #include "net/cookies/cookie_store_test_callbacks.h"
  30. #include "net/cookies/cookie_util.h"
  31. #include "net/cookies/first_party_set_metadata.h"
  32. #include "net/cookies/same_party_context.h"
  33. #include "net/cookies/site_for_cookies.h"
  34. #include "net/cookies/test_cookie_access_delegate.h"
  35. #include "services/network/cookie_access_delegate_impl.h"
  36. #include "services/network/cookie_settings.h"
  37. #include "services/network/first_party_sets/first_party_sets_access_delegate.h"
  38. #include "services/network/public/mojom/cookie_access_observer.mojom.h"
  39. #include "services/network/public/mojom/cookie_manager.mojom.h"
  40. #include "services/network/public/mojom/first_party_sets.mojom.h"
  41. #include "services/network/test/test_network_context_client.h"
  42. #include "testing/gmock/include/gmock/gmock-matchers.h"
  43. #include "testing/gtest/include/gtest/gtest.h"
  44. #include "url/origin.h"
  45. #include "url/url_util.h"
  46. namespace net {
  47. bool operator==(const net::SiteForCookies& a, const net::SiteForCookies& b) {
  48. return a.IsEquivalent(b);
  49. }
  50. } // namespace net
  51. namespace network {
  52. namespace {
  53. net::FirstPartySetMetadata ComputeFirstPartySetMetadataSync(
  54. const url::Origin& origin,
  55. const net::CookieStore* cookie_store,
  56. const net::IsolationInfo& isolation_info) {
  57. base::RunLoop run_loop;
  58. net::FirstPartySetMetadata first_party_set_metadata;
  59. RestrictedCookieManager::ComputeFirstPartySetMetadata(
  60. origin, cookie_store, isolation_info,
  61. base::BindLambdaForTesting([&](net::FirstPartySetMetadata metadata) {
  62. first_party_set_metadata = std::move(metadata);
  63. run_loop.Quit();
  64. }));
  65. run_loop.Run();
  66. return first_party_set_metadata;
  67. }
  68. } // namespace
  69. class RecordingCookieObserver : public network::mojom::CookieAccessObserver {
  70. public:
  71. struct CookieOp {
  72. mojom::CookieAccessDetails::Type type;
  73. GURL url;
  74. net::SiteForCookies site_for_cookies;
  75. mojom::CookieOrLinePtr cookie_or_line;
  76. net::CookieInclusionStatus status;
  77. friend void PrintTo(const CookieOp& op, std::ostream* os) {
  78. *os << "{type=" << op.type << ", url=" << op.url
  79. << ", site_for_cookies=" << op.site_for_cookies.RepresentativeUrl()
  80. << ", cookie_or_line=(" << CookieOrLineToString(op.cookie_or_line)
  81. << ", " << static_cast<int>(op.cookie_or_line->which()) << ")"
  82. << ", status=" << op.status.GetDebugString() << "}";
  83. }
  84. static std::string CookieOrLineToString(
  85. const mojom::CookieOrLinePtr& cookie_or_line) {
  86. switch (cookie_or_line->which()) {
  87. case mojom::CookieOrLine::Tag::kCookie:
  88. return net::CanonicalCookie::BuildCookieLine(
  89. {cookie_or_line->get_cookie()});
  90. case mojom::CookieOrLine::Tag::kCookieString:
  91. return cookie_or_line->get_cookie_string();
  92. }
  93. }
  94. };
  95. RecordingCookieObserver() : run_loop_(std::make_unique<base::RunLoop>()) {}
  96. ~RecordingCookieObserver() override = default;
  97. std::vector<CookieOp>& recorded_activity() { return recorded_activity_; }
  98. mojo::PendingRemote<mojom::CookieAccessObserver> GetRemote() {
  99. mojo::PendingRemote<mojom::CookieAccessObserver> remote;
  100. receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
  101. return remote;
  102. }
  103. void WaitForCallback() {
  104. run_loop_->Run();
  105. run_loop_ = std::make_unique<base::RunLoop>();
  106. }
  107. void OnCookiesAccessed(mojom::CookieAccessDetailsPtr details) override {
  108. for (const auto& cookie_and_access_result : details->cookie_list) {
  109. CookieOp op;
  110. op.type = details->type;
  111. op.url = details->url;
  112. op.site_for_cookies = details->site_for_cookies;
  113. op.cookie_or_line = std::move(cookie_and_access_result->cookie_or_line);
  114. op.status = cookie_and_access_result->access_result.status;
  115. recorded_activity_.push_back(std::move(op));
  116. }
  117. run_loop_->QuitClosure().Run();
  118. }
  119. void Clone(
  120. mojo::PendingReceiver<mojom::CookieAccessObserver> observer) override {
  121. receivers_.Add(this, std::move(observer));
  122. }
  123. private:
  124. std::vector<CookieOp> recorded_activity_;
  125. mojo::ReceiverSet<mojom::CookieAccessObserver> receivers_;
  126. std::unique_ptr<base::RunLoop> run_loop_;
  127. };
  128. // Synchronous proxies to a wrapped RestrictedCookieManager's methods.
  129. class RestrictedCookieManagerSync {
  130. public:
  131. // Caller must guarantee that |*cookie_service| outlives the
  132. // SynchronousCookieManager.
  133. explicit RestrictedCookieManagerSync(
  134. mojom::RestrictedCookieManager* cookie_service)
  135. : cookie_service_(cookie_service) {}
  136. RestrictedCookieManagerSync(const RestrictedCookieManagerSync&) = delete;
  137. RestrictedCookieManagerSync& operator=(const RestrictedCookieManagerSync&) =
  138. delete;
  139. ~RestrictedCookieManagerSync() = default;
  140. // Wraps GetAllForUrl() but discards CookieAccessResult from returned cookies.
  141. std::vector<net::CanonicalCookie> GetAllForUrl(
  142. const GURL& url,
  143. const net::SiteForCookies& site_for_cookies,
  144. const url::Origin& top_frame_origin,
  145. mojom::CookieManagerGetOptionsPtr options,
  146. bool partitioned_cookies_runtime_feature_enabled) {
  147. base::RunLoop run_loop;
  148. std::vector<net::CanonicalCookie> result;
  149. cookie_service_->GetAllForUrl(
  150. url, site_for_cookies, top_frame_origin, std::move(options),
  151. partitioned_cookies_runtime_feature_enabled,
  152. base::BindLambdaForTesting(
  153. [&run_loop, &result](const std::vector<net::CookieWithAccessResult>&
  154. backend_result) {
  155. result = net::cookie_util::StripAccessResults(backend_result);
  156. run_loop.Quit();
  157. }));
  158. run_loop.Run();
  159. return result;
  160. }
  161. bool SetCanonicalCookie(const net::CanonicalCookie& cookie,
  162. const GURL& url,
  163. const net::SiteForCookies& site_for_cookies,
  164. const url::Origin& top_frame_origin,
  165. absl::optional<net::CookieInclusionStatus>
  166. cookie_inclusion_status = absl::nullopt) {
  167. base::RunLoop run_loop;
  168. bool result = false;
  169. net::CookieInclusionStatus status;
  170. if (cookie_inclusion_status.has_value()) {
  171. status = cookie_inclusion_status.value();
  172. }
  173. cookie_service_->SetCanonicalCookie(
  174. cookie, url, site_for_cookies, top_frame_origin, status,
  175. base::BindLambdaForTesting([&run_loop, &result](bool backend_result) {
  176. result = backend_result;
  177. run_loop.Quit();
  178. }));
  179. run_loop.Run();
  180. return result;
  181. }
  182. void SetCookieFromString(const GURL& url,
  183. const net::SiteForCookies& site_for_cookies,
  184. const url::Origin& top_frame_origin,
  185. const std::string& cookie,
  186. bool partitioned_cookies_runtime_feature_enabled) {
  187. base::RunLoop run_loop;
  188. cookie_service_->SetCookieFromString(
  189. url, site_for_cookies, top_frame_origin, cookie,
  190. partitioned_cookies_runtime_feature_enabled,
  191. base::BindLambdaForTesting(
  192. [&run_loop](bool site_for_cookies_ok, bool top_frame_origin_ok) {
  193. run_loop.Quit();
  194. }));
  195. run_loop.Run();
  196. }
  197. void AddChangeListener(
  198. const GURL& url,
  199. const net::SiteForCookies& site_for_cookies,
  200. const url::Origin& top_frame_origin,
  201. mojo::PendingRemote<mojom::CookieChangeListener> listener) {
  202. base::RunLoop run_loop;
  203. cookie_service_->AddChangeListener(url, site_for_cookies, top_frame_origin,
  204. std::move(listener),
  205. run_loop.QuitClosure());
  206. run_loop.Run();
  207. }
  208. private:
  209. raw_ptr<mojom::RestrictedCookieManager> cookie_service_;
  210. };
  211. namespace {
  212. // Stashes the cookie changes it receives, for testing.
  213. class TestCookieChangeListener : public network::mojom::CookieChangeListener {
  214. public:
  215. explicit TestCookieChangeListener(
  216. mojo::PendingReceiver<network::mojom::CookieChangeListener> receiver)
  217. : receiver_(this, std::move(receiver)) {}
  218. ~TestCookieChangeListener() override = default;
  219. // Spin in a run loop until a change is received.
  220. void WaitForChange() {
  221. base::RunLoop loop;
  222. run_loop_ = &loop;
  223. loop.Run();
  224. run_loop_ = nullptr;
  225. }
  226. // Changes received by this listener.
  227. const std::vector<net::CookieChangeInfo>& observed_changes() const {
  228. return observed_changes_;
  229. }
  230. // network::mojom::CookieChangeListener
  231. void OnCookieChange(const net::CookieChangeInfo& change) override {
  232. observed_changes_.emplace_back(change);
  233. if (run_loop_) // Set in WaitForChange().
  234. run_loop_->Quit();
  235. }
  236. private:
  237. std::vector<net::CookieChangeInfo> observed_changes_;
  238. mojo::Receiver<network::mojom::CookieChangeListener> receiver_;
  239. // If not null, will be stopped when a cookie change notification is received.
  240. raw_ptr<base::RunLoop> run_loop_ = nullptr;
  241. };
  242. } // namespace
  243. class RestrictedCookieManagerTest
  244. : public testing::TestWithParam<mojom::RestrictedCookieManagerRole> {
  245. public:
  246. RestrictedCookieManagerTest()
  247. : cookie_monster_(/*store=*/nullptr,
  248. /*net_log=*/nullptr,
  249. kFirstPartySetsEnabled),
  250. isolation_info_(kDefaultIsolationInfo),
  251. service_(std::make_unique<RestrictedCookieManager>(
  252. GetParam(),
  253. &cookie_monster_,
  254. cookie_settings_,
  255. kDefaultOrigin,
  256. isolation_info_,
  257. recording_client_.GetRemote(),
  258. kFirstPartySetsEnabled,
  259. ComputeFirstPartySetMetadataSync(kDefaultOrigin,
  260. &cookie_monster_,
  261. isolation_info_))),
  262. receiver_(service_.get(),
  263. service_remote_.BindNewPipeAndPassReceiver()) {
  264. sync_service_ =
  265. std::make_unique<RestrictedCookieManagerSync>(service_remote_.get());
  266. }
  267. ~RestrictedCookieManagerTest() override = default;
  268. void SetUp() override {
  269. mojo::SetDefaultProcessErrorHandler(base::BindRepeating(
  270. &RestrictedCookieManagerTest::OnBadMessage, base::Unretained(this)));
  271. }
  272. void TearDown() override {
  273. mojo::SetDefaultProcessErrorHandler(base::NullCallback());
  274. }
  275. // Set a canonical cookie directly into the store.
  276. // Default to be a cross-site, cross-party cookie context.
  277. bool SetCanonicalCookie(
  278. const net::CanonicalCookie& cookie,
  279. std::string source_scheme,
  280. bool can_modify_httponly,
  281. const net::CookieOptions::SameSiteCookieContext::ContextType
  282. same_site_cookie_context_type = net::CookieOptions::
  283. SameSiteCookieContext::ContextType::CROSS_SITE,
  284. const net::SamePartyContext::Type same_party_context_type =
  285. net::SamePartyContext::Type::kCrossParty) {
  286. net::ResultSavingCookieCallback<net::CookieAccessResult> callback;
  287. net::CookieOptions options;
  288. if (can_modify_httponly)
  289. options.set_include_httponly();
  290. net::CookieOptions::SameSiteCookieContext same_site_cookie_context(
  291. same_site_cookie_context_type, same_site_cookie_context_type);
  292. options.set_same_site_cookie_context(same_site_cookie_context);
  293. options.set_same_party_context(
  294. net::SamePartyContext(same_party_context_type));
  295. cookie_monster_.SetCanonicalCookieAsync(
  296. std::make_unique<net::CanonicalCookie>(cookie),
  297. net::cookie_util::SimulatedCookieSource(cookie, source_scheme), options,
  298. callback.MakeCallback());
  299. callback.WaitUntilDone();
  300. return callback.result().status.IsInclude();
  301. }
  302. // Simplified helper for SetCanonicalCookie.
  303. //
  304. // Creates a CanonicalCookie that is secure (unless overriden), not http-only,
  305. // and has SameSite=None. Crashes if the creation fails.
  306. void SetSessionCookie(const char* name,
  307. const char* value,
  308. const char* domain,
  309. const char* path,
  310. bool secure = true) {
  311. ASSERT_TRUE(SetCanonicalCookie(
  312. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  313. name, value, domain, path, base::Time(), base::Time(), base::Time(),
  314. base::Time(),
  315. /*secure=*/secure,
  316. /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
  317. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  318. "https", /*can_modify_httponly=*/true));
  319. }
  320. // Like above, but makes an http-only cookie.
  321. void SetHttpOnlySessionCookie(const char* name,
  322. const char* value,
  323. const char* domain,
  324. const char* path) {
  325. CHECK(SetCanonicalCookie(
  326. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  327. name, value, domain, path, base::Time(), base::Time(), base::Time(),
  328. base::Time(),
  329. /*secure=*/true,
  330. /*httponly=*/true, net::CookieSameSite::NO_RESTRICTION,
  331. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  332. "https", /*can_modify_httponly=*/true));
  333. }
  334. std::unique_ptr<TestCookieChangeListener> CreateCookieChangeListener(
  335. const GURL& url,
  336. const net::SiteForCookies& site_for_cookies,
  337. const url::Origin& top_frame_origin) {
  338. mojo::PendingRemote<network::mojom::CookieChangeListener> listener_remote;
  339. mojo::PendingReceiver<network::mojom::CookieChangeListener> receiver =
  340. listener_remote.InitWithNewPipeAndPassReceiver();
  341. sync_service_->AddChangeListener(url, site_for_cookies, top_frame_origin,
  342. std::move(listener_remote));
  343. return std::make_unique<TestCookieChangeListener>(std::move(receiver));
  344. }
  345. void ExpectBadMessage() { expecting_bad_message_ = true; }
  346. bool received_bad_message() { return received_bad_message_; }
  347. mojom::RestrictedCookieManager* backend() { return service_remote_.get(); }
  348. protected:
  349. void OnBadMessage(const std::string& reason) {
  350. EXPECT_TRUE(expecting_bad_message_) << "Unexpected bad message: " << reason;
  351. received_bad_message_ = true;
  352. }
  353. std::vector<RecordingCookieObserver::CookieOp>& recorded_activity() {
  354. return recording_client_.recorded_activity();
  355. }
  356. void WaitForCallback() { return recording_client_.WaitForCallback(); }
  357. const GURL kDefaultUrl{"https://example.com/"};
  358. const GURL kDefaultUrlWithPath{"https://example.com/test/"};
  359. const GURL kOtherUrl{"https://notexample.com/"};
  360. const GURL kOtherUrlWithPath{"https://notexample.com/test/"};
  361. const url::Origin kDefaultOrigin = url::Origin::Create(kDefaultUrl);
  362. const url::Origin kOtherOrigin = url::Origin::Create(kOtherUrl);
  363. const net::SiteForCookies kDefaultSiteForCookies =
  364. net::SiteForCookies::FromUrl(kDefaultUrl);
  365. const net::SiteForCookies kOtherSiteForCookies =
  366. net::SiteForCookies::FromUrl(kOtherUrl);
  367. const net::IsolationInfo kDefaultIsolationInfo =
  368. net::IsolationInfo::CreateForInternalRequest(kDefaultOrigin);
  369. // IsolationInfo that replaces the default SiteForCookies with a blank one.
  370. const net::IsolationInfo kOtherIsolationInfo =
  371. net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
  372. kDefaultOrigin,
  373. kDefaultOrigin,
  374. net::SiteForCookies());
  375. const bool kFirstPartySetsEnabled = true;
  376. base::test::SingleThreadTaskEnvironment task_environment_{
  377. base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
  378. net::CookieMonster cookie_monster_;
  379. CookieSettings cookie_settings_;
  380. net::IsolationInfo isolation_info_;
  381. RecordingCookieObserver recording_client_;
  382. std::unique_ptr<RestrictedCookieManager> service_;
  383. mojo::Remote<mojom::RestrictedCookieManager> service_remote_;
  384. mojo::Receiver<mojom::RestrictedCookieManager> receiver_;
  385. std::unique_ptr<RestrictedCookieManagerSync> sync_service_;
  386. bool expecting_bad_message_ = false;
  387. bool received_bad_message_ = false;
  388. };
  389. namespace {
  390. mojom::FirstPartySetsAccessDelegateParamsPtr
  391. CreateFirstPartySetsAccessDelegateParams() {
  392. auto params = mojom::FirstPartySetsAccessDelegateParams::New();
  393. params->enabled = true;
  394. return params;
  395. }
  396. } // namespace
  397. class SamePartyEnabledRestrictedCookieManagerTest
  398. : public RestrictedCookieManagerTest {
  399. public:
  400. SamePartyEnabledRestrictedCookieManagerTest()
  401. : first_party_sets_manager_(/*enabled=*/true),
  402. first_party_sets_access_delegate_(
  403. first_party_sets_access_delegate_remote_
  404. .BindNewPipeAndPassReceiver(),
  405. CreateFirstPartySetsAccessDelegateParams(),
  406. &first_party_sets_manager_) {
  407. network::mojom::PublicFirstPartySetsPtr public_sets =
  408. network::mojom::PublicFirstPartySets::New();
  409. public_sets->sets = {
  410. {net::SchemefulSite(GURL("https://example.com")),
  411. net::FirstPartySetEntry(
  412. net::SchemefulSite(GURL("https://example.com")),
  413. net::SiteType::kPrimary, absl::nullopt)},
  414. {net::SchemefulSite(GURL("https://member1.com")),
  415. net::FirstPartySetEntry(
  416. net::SchemefulSite(GURL("https://example.com")),
  417. net::SiteType::kAssociated, 0)},
  418. };
  419. first_party_sets_manager_.SetCompleteSets(std::move(public_sets));
  420. first_party_sets_access_delegate_remote_->NotifyReady(
  421. mojom::FirstPartySetsReadyEvent::New());
  422. auto cookie_access_delegate = std::make_unique<CookieAccessDelegateImpl>(
  423. mojom::CookieAccessDelegateType::USE_CONTENT_SETTINGS,
  424. &first_party_sets_access_delegate_, &cookie_settings_);
  425. cookie_monster_.SetCookieAccessDelegate(std::move(cookie_access_delegate));
  426. }
  427. ~SamePartyEnabledRestrictedCookieManagerTest() override = default;
  428. // Set a canonical cookie directly into the store, has both SameSite=lax and
  429. // SameParty.
  430. void SetSamePartyCookie(const char* name,
  431. const char* value,
  432. const char* domain,
  433. const char* path,
  434. bool secure = true) {
  435. CHECK(SetCanonicalCookie(
  436. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  437. name, value, domain, path, base::Time(), base::Time(), base::Time(),
  438. base::Time(),
  439. /*secure=*/secure,
  440. /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
  441. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/true),
  442. "https", /*can_modify_httponly=*/true,
  443. net::CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX,
  444. net::SamePartyContext::Type::kSameParty));
  445. }
  446. private:
  447. base::test::ScopedFeatureList feature_list_;
  448. FirstPartySetsManager first_party_sets_manager_;
  449. mojo::Remote<mojom::FirstPartySetsAccessDelegate>
  450. first_party_sets_access_delegate_remote_;
  451. FirstPartySetsAccessDelegate first_party_sets_access_delegate_;
  452. };
  453. INSTANTIATE_TEST_SUITE_P(
  454. SameParty,
  455. SamePartyEnabledRestrictedCookieManagerTest,
  456. testing::Values(mojom::RestrictedCookieManagerRole::SCRIPT,
  457. mojom::RestrictedCookieManagerRole::NETWORK));
  458. namespace {
  459. using testing::ElementsAre;
  460. using testing::IsEmpty;
  461. using testing::Not;
  462. using testing::UnorderedElementsAre;
  463. MATCHER_P5(MatchesCookieOp,
  464. type,
  465. url,
  466. site_for_cookies,
  467. cookie_or_line,
  468. status,
  469. "") {
  470. return testing::ExplainMatchResult(
  471. testing::AllOf(
  472. testing::Field(&RecordingCookieObserver::CookieOp::type, type),
  473. testing::Field(&RecordingCookieObserver::CookieOp::url, url),
  474. testing::Field(&RecordingCookieObserver::CookieOp::site_for_cookies,
  475. site_for_cookies),
  476. testing::Field(&RecordingCookieObserver::CookieOp::cookie_or_line,
  477. cookie_or_line),
  478. testing::Field(&RecordingCookieObserver::CookieOp::status, status)),
  479. arg, result_listener);
  480. }
  481. MATCHER_P2(CookieOrLine, string, type, "") {
  482. return type == arg->which() &&
  483. testing::ExplainMatchResult(
  484. string,
  485. RecordingCookieObserver::CookieOp::CookieOrLineToString(arg),
  486. result_listener);
  487. }
  488. } // anonymous namespace
  489. // Test the case when `origin` differs from `isolation_info.frame_origin`.
  490. // RestrictedCookieManager only works for the bound origin and doesn't care
  491. // about the IsolationInfo's frame_origin. Technically this should only happen
  492. // when role == mojom::RestrictedCookieManagerRole::NETWORK. Otherwise, it
  493. // should trigger a CHECK in the RestrictedCookieManager constructor (which is
  494. // bypassed here due to constructing it properly, then using an origin
  495. // override).
  496. TEST_P(RestrictedCookieManagerTest,
  497. GetAllForUrlFromMismatchingIsolationInfoFrameOrigin) {
  498. service_->OverrideOriginForTesting(kOtherOrigin);
  499. // Override isolation_info to make it explicit that its frame_origin is
  500. // different from the origin.
  501. service_->OverrideIsolationInfoForTesting(kDefaultIsolationInfo);
  502. SetSessionCookie("new-name", "new-value", kOtherUrl.host().c_str(), "/");
  503. // Fetch cookies from the wrong origin (IsolationInfo's frame_origin) should
  504. // result in a bad message.
  505. {
  506. auto options = mojom::CookieManagerGetOptions::New();
  507. options->name = "new-name";
  508. options->match_type = mojom::CookieMatchType::EQUALS;
  509. ExpectBadMessage();
  510. std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
  511. kDefaultUrl, kDefaultSiteForCookies, kDefaultOrigin, std::move(options),
  512. /*partitioned_cookies_runtime_feature_enabled=*/false);
  513. EXPECT_TRUE(received_bad_message());
  514. }
  515. // Fetch cookies from the correct origin value which RestrictedCookieManager
  516. // is bound to should work.
  517. {
  518. auto options = mojom::CookieManagerGetOptions::New();
  519. options->name = "new-name";
  520. options->match_type = mojom::CookieMatchType::EQUALS;
  521. std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
  522. kOtherUrl, kDefaultSiteForCookies, kDefaultOrigin, std::move(options),
  523. /*partitioned_cookies_runtime_feature_enabled=*/false);
  524. ASSERT_THAT(cookies, testing::SizeIs(1));
  525. EXPECT_EQ("new-name", cookies[0].Name());
  526. EXPECT_EQ("new-value", cookies[0].Value());
  527. }
  528. }
  529. TEST_P(RestrictedCookieManagerTest, GetAllForUrlBlankFilter) {
  530. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  531. SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
  532. SetSessionCookie("other-cookie-name", "other-cookie-value", "not-example.com",
  533. "/");
  534. auto options = mojom::CookieManagerGetOptions::New();
  535. options->name = "";
  536. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  537. EXPECT_THAT(
  538. sync_service_->GetAllForUrl(
  539. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  540. std::move(options),
  541. /*partitioned_cookies_runtime_feature_enabled=*/false),
  542. UnorderedElementsAre(
  543. net::MatchesCookieNameValue("cookie-name", "cookie-value"),
  544. net::MatchesCookieNameValue("cookie-name-2", "cookie-value-2")));
  545. // Can also use the document.cookie-style API to get the same info.
  546. std::string cookies_out;
  547. EXPECT_TRUE(backend()->GetCookiesString(
  548. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  549. /*partitioned_cookies_runtime_feature_enabled=*/false, &cookies_out));
  550. EXPECT_EQ("cookie-name=cookie-value; cookie-name-2=cookie-value-2",
  551. cookies_out);
  552. }
  553. TEST_P(RestrictedCookieManagerTest, GetAllForUrlEmptyFilter) {
  554. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  555. auto options = mojom::CookieManagerGetOptions::New();
  556. options->name = "";
  557. options->match_type = mojom::CookieMatchType::EQUALS;
  558. EXPECT_THAT(sync_service_->GetAllForUrl(
  559. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  560. std::move(options),
  561. /*partitioned_cookies_runtime_feature_enabled=*/false),
  562. IsEmpty());
  563. }
  564. TEST_P(RestrictedCookieManagerTest, GetAllForUrlEqualsMatch) {
  565. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  566. SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
  567. auto options = mojom::CookieManagerGetOptions::New();
  568. options->name = "cookie-name";
  569. options->match_type = mojom::CookieMatchType::EQUALS;
  570. EXPECT_THAT(
  571. sync_service_->GetAllForUrl(
  572. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  573. std::move(options),
  574. /*partitioned_cookies_runtime_feature_enabled=*/false),
  575. ElementsAre(net::MatchesCookieNameValue("cookie-name", "cookie-value")));
  576. }
  577. TEST_P(RestrictedCookieManagerTest, GetAllForUrlStartsWithMatch) {
  578. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  579. SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
  580. SetSessionCookie("cookie-name-2b", "cookie-value-2b", "example.com", "/");
  581. SetSessionCookie("cookie-name-3b", "cookie-value-3b", "example.com", "/");
  582. auto options = mojom::CookieManagerGetOptions::New();
  583. options->name = "cookie-name-2";
  584. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  585. EXPECT_THAT(
  586. sync_service_->GetAllForUrl(
  587. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  588. std::move(options),
  589. /*partitioned_cookies_runtime_feature_enabled=*/false),
  590. UnorderedElementsAre(
  591. net::MatchesCookieNameValue("cookie-name-2", "cookie-value-2"),
  592. net::MatchesCookieNameValue("cookie-name-2b", "cookie-value-2b")));
  593. }
  594. TEST_P(RestrictedCookieManagerTest, GetAllForUrlHttpOnly) {
  595. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  596. SetHttpOnlySessionCookie("cookie-name-http", "cookie-value-2", "example.com",
  597. "/");
  598. auto options = mojom::CookieManagerGetOptions::New();
  599. options->name = "cookie-name";
  600. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  601. std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
  602. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  603. std::move(options),
  604. /*partitioned_cookies_runtime_feature_enabled=*/false);
  605. if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) {
  606. EXPECT_THAT(cookies, UnorderedElementsAre(net::MatchesCookieNameValue(
  607. "cookie-name", "cookie-value")));
  608. } else {
  609. EXPECT_THAT(
  610. cookies,
  611. UnorderedElementsAre(
  612. net::MatchesCookieNameValue("cookie-name", "cookie-value"),
  613. net::MatchesCookieNameValue("cookie-name-http", "cookie-value-2")));
  614. }
  615. }
  616. TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromWrongOrigin) {
  617. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  618. SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
  619. SetSessionCookie("other-cookie-name", "other-cookie-value", "notexample.com",
  620. "/");
  621. auto options = mojom::CookieManagerGetOptions::New();
  622. options->name = "";
  623. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  624. ExpectBadMessage();
  625. EXPECT_THAT(sync_service_->GetAllForUrl(
  626. kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  627. std::move(options),
  628. /*partitioned_cookies_runtime_feature_enabled=*/false),
  629. IsEmpty());
  630. EXPECT_TRUE(received_bad_message());
  631. }
  632. TEST_P(RestrictedCookieManagerTest, GetAllForUrlFromOpaqueOrigin) {
  633. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  634. url::Origin opaque_origin;
  635. ASSERT_TRUE(opaque_origin.opaque());
  636. service_->OverrideOriginForTesting(opaque_origin);
  637. auto options = mojom::CookieManagerGetOptions::New();
  638. options->name = "";
  639. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  640. ExpectBadMessage();
  641. EXPECT_THAT(sync_service_->GetAllForUrl(
  642. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  643. std::move(options),
  644. /*partitioned_cookies_runtime_feature_enabled=*/false),
  645. IsEmpty());
  646. EXPECT_TRUE(received_bad_message());
  647. }
  648. TEST_P(RestrictedCookieManagerTest, GetCookieStringFromWrongOrigin) {
  649. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  650. SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
  651. SetSessionCookie("other-cookie-name", "other-cookie-value", "notexample.com",
  652. "/");
  653. ExpectBadMessage();
  654. std::string cookies_out;
  655. EXPECT_TRUE(backend()->GetCookiesString(
  656. kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  657. /*partitioned_cookies_runtime_feature_enabled=*/false, &cookies_out));
  658. EXPECT_TRUE(received_bad_message());
  659. EXPECT_THAT(cookies_out, IsEmpty());
  660. }
  661. TEST_P(RestrictedCookieManagerTest, GetAllForUrlPolicy) {
  662. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  663. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  664. // With default policy, should be able to get all cookies, even third-party.
  665. {
  666. auto options = mojom::CookieManagerGetOptions::New();
  667. options->name = "cookie-name";
  668. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  669. EXPECT_THAT(sync_service_->GetAllForUrl(
  670. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  671. std::move(options),
  672. /*partitioned_cookies_runtime_feature_enabled=*/false),
  673. ElementsAre(net::MatchesCookieNameValue("cookie-name",
  674. "cookie-value")));
  675. }
  676. WaitForCallback();
  677. EXPECT_THAT(recorded_activity(),
  678. ElementsAre(MatchesCookieOp(
  679. mojom::CookieAccessDetails::Type::kRead,
  680. "https://example.com/test/", net::SiteForCookies(),
  681. CookieOrLine("cookie-name=cookie-value",
  682. mojom::CookieOrLine::Tag::kCookie),
  683. net::IsInclude())));
  684. // Disabing getting third-party cookies works correctly.
  685. cookie_settings_.set_block_third_party_cookies(true);
  686. {
  687. auto options = mojom::CookieManagerGetOptions::New();
  688. options->name = "cookie-name";
  689. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  690. EXPECT_THAT(sync_service_->GetAllForUrl(
  691. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  692. std::move(options),
  693. /*partitioned_cookies_runtime_feature_enabled=*/false),
  694. IsEmpty());
  695. }
  696. WaitForCallback();
  697. EXPECT_THAT(
  698. recorded_activity(),
  699. ElementsAre(
  700. testing::_,
  701. MatchesCookieOp(
  702. mojom::CookieAccessDetails::Type::kRead,
  703. "https://example.com/test/", net::SiteForCookies(),
  704. CookieOrLine("cookie-name=cookie-value",
  705. mojom::CookieOrLine::Tag::kCookie),
  706. net::CookieInclusionStatus::MakeFromReasonsForTesting(
  707. {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES},
  708. {}))));
  709. }
  710. TEST_P(RestrictedCookieManagerTest, FilteredCookieAccessEvents) {
  711. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  712. const char* kCookieName = "cookie-name";
  713. const char* kCookieValue = "cookie-value";
  714. const char* kCookieSite = "example.com";
  715. std::string cookie_name_field =
  716. std::string(kCookieName) + std::string("=") + std::string(kCookieValue);
  717. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  718. SetSessionCookie(kCookieName, kCookieValue, kCookieSite, "/");
  719. // With default policy, should be able to get all cookies, even third-party.
  720. {
  721. auto options = mojom::CookieManagerGetOptions::New();
  722. options->name = kCookieName;
  723. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  724. EXPECT_THAT(
  725. sync_service_->GetAllForUrl(
  726. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  727. std::move(options),
  728. /*partitioned_cookies_runtime_feature_enabled=*/false),
  729. ElementsAre(net::MatchesCookieNameValue(kCookieName, kCookieValue)));
  730. WaitForCallback();
  731. EXPECT_THAT(
  732. recorded_activity(),
  733. ElementsAre(MatchesCookieOp(
  734. mojom::CookieAccessDetails::Type::kRead, kDefaultUrlWithPath,
  735. net::SiteForCookies(),
  736. CookieOrLine(cookie_name_field, mojom::CookieOrLine::Tag::kCookie),
  737. net::CookieInclusionStatus())));
  738. }
  739. {
  740. auto options = mojom::CookieManagerGetOptions::New();
  741. options->name = kCookieName;
  742. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  743. EXPECT_THAT(
  744. sync_service_->GetAllForUrl(
  745. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  746. std::move(options),
  747. /*partitioned_cookies_runtime_feature_enabled=*/false),
  748. ElementsAre(net::MatchesCookieNameValue(kCookieName, kCookieValue)));
  749. // A second cookie access should not generate a notification.
  750. EXPECT_THAT(
  751. recorded_activity(),
  752. ElementsAre(MatchesCookieOp(
  753. mojom::CookieAccessDetails::Type::kRead, kDefaultUrlWithPath,
  754. net::SiteForCookies(),
  755. CookieOrLine(cookie_name_field, mojom::CookieOrLine::Tag::kCookie),
  756. net::CookieInclusionStatus())));
  757. }
  758. // Change the cookie with a new value so that a cookie access
  759. // event is possible, then block the cookie access.
  760. const char* kNewCookieValue = "new-cookie-value";
  761. cookie_name_field = std::string(kCookieName) + std::string("=") +
  762. std::string(kNewCookieValue);
  763. SetSessionCookie(kCookieName, kNewCookieValue, kCookieSite, "/");
  764. cookie_settings_.set_block_third_party_cookies(true);
  765. {
  766. auto options = mojom::CookieManagerGetOptions::New();
  767. options->name = kCookieName;
  768. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  769. EXPECT_THAT(sync_service_->GetAllForUrl(
  770. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  771. std::move(options),
  772. /*partitioned_cookies_runtime_feature_enabled=*/false),
  773. IsEmpty());
  774. WaitForCallback();
  775. // A change in access result (allowed -> blocked) should generate a new
  776. // notification.
  777. EXPECT_EQ(recorded_activity().size(), 2ul);
  778. }
  779. // Allow the cookie access.
  780. cookie_settings_.set_block_third_party_cookies(false);
  781. {
  782. auto options = mojom::CookieManagerGetOptions::New();
  783. options->name = kCookieName;
  784. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  785. EXPECT_THAT(
  786. sync_service_->GetAllForUrl(
  787. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  788. std::move(options),
  789. /*partitioned_cookies_runtime_feature_enabled=*/false),
  790. ElementsAre(net::MatchesCookieNameValue(kCookieName, kNewCookieValue)));
  791. WaitForCallback();
  792. // A change in access result (blocked -> allowed) should generate a new
  793. // notification.
  794. EXPECT_THAT(recorded_activity(),
  795. ElementsAre(testing::_, testing::_,
  796. MatchesCookieOp(
  797. mojom::CookieAccessDetails::Type::kRead,
  798. kDefaultUrlWithPath, net::SiteForCookies(),
  799. CookieOrLine(cookie_name_field,
  800. mojom::CookieOrLine::Tag::kCookie),
  801. net::CookieInclusionStatus())));
  802. }
  803. }
  804. TEST_P(RestrictedCookieManagerTest, GetAllForUrlPolicyWarnActual) {
  805. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  806. // Activate legacy semantics to be able to inject a bad cookie.
  807. auto cookie_access_delegate =
  808. std::make_unique<net::TestCookieAccessDelegate>();
  809. cookie_access_delegate->SetExpectationForCookieDomain(
  810. "example.com", net::CookieAccessSemantics::LEGACY);
  811. cookie_monster_.SetCookieAccessDelegate(std::move(cookie_access_delegate));
  812. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/",
  813. /*secure=*/false);
  814. // Now test get using (default) nonlegacy semantics.
  815. cookie_monster_.SetCookieAccessDelegate(nullptr);
  816. {
  817. auto options = mojom::CookieManagerGetOptions::New();
  818. options->name = "cookie-name";
  819. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  820. EXPECT_THAT(sync_service_->GetAllForUrl(
  821. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  822. std::move(options),
  823. /*partitioned_cookies_runtime_feature_enabled=*/false),
  824. IsEmpty());
  825. }
  826. WaitForCallback();
  827. EXPECT_THAT(recorded_activity(),
  828. ElementsAre(MatchesCookieOp(
  829. mojom::CookieAccessDetails::Type::kRead,
  830. "https://example.com/test/", net::SiteForCookies(),
  831. CookieOrLine("cookie-name=cookie-value",
  832. mojom::CookieOrLine::Tag::kCookie),
  833. net::HasExactlyExclusionReasonsForTesting(
  834. std::vector<net::CookieInclusionStatus::ExclusionReason>{
  835. net::CookieInclusionStatus::
  836. EXCLUDE_SAMESITE_NONE_INSECURE}))));
  837. }
  838. TEST_P(SamePartyEnabledRestrictedCookieManagerTest, GetAllForUrlSameParty) {
  839. SetSamePartyCookie("cookie-name", "cookie-value", "example.com", "/");
  840. // Same Party
  841. {
  842. auto options = mojom::CookieManagerGetOptions::New();
  843. options->name = "cookie-name";
  844. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  845. EXPECT_THAT(sync_service_->GetAllForUrl(
  846. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  847. std::move(options),
  848. /*partitioned_cookies_runtime_feature_enabled=*/false),
  849. ElementsAre(net::MatchesCookieNameValue("cookie-name",
  850. "cookie-value")));
  851. WaitForCallback();
  852. }
  853. // Same Party. `party_context` contains fps site.
  854. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  855. net::IsolationInfo::RequestType::kOther, kDefaultOrigin, kDefaultOrigin,
  856. net::SiteForCookies(),
  857. std::set<net::SchemefulSite>{
  858. net::SchemefulSite(GURL("https://member1.com"))}));
  859. {
  860. auto options = mojom::CookieManagerGetOptions::New();
  861. options->name = "cookie-name";
  862. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  863. EXPECT_THAT(sync_service_->GetAllForUrl(
  864. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  865. std::move(options),
  866. /*partitioned_cookies_runtime_feature_enabled=*/false),
  867. ElementsAre(net::MatchesCookieNameValue("cookie-name",
  868. "cookie-value")));
  869. WaitForCallback();
  870. }
  871. {
  872. // Should still be blocked when third-party cookie blocking is enabled.
  873. cookie_settings_.set_block_third_party_cookies(true);
  874. auto options = mojom::CookieManagerGetOptions::New();
  875. options->name = "cookie-name";
  876. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  877. EXPECT_THAT(sync_service_->GetAllForUrl(
  878. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  879. std::move(options),
  880. /*partitioned_cookies_runtime_feature_enabled=*/false),
  881. IsEmpty());
  882. WaitForCallback();
  883. // This checks that the cookie access is not double-reported due the
  884. // warning reason and EXCLUDE_USER_PREFERENCES.
  885. std::vector<net::CookieInclusionStatus::WarningReason> expected_warnings = {
  886. net::CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY,
  887. };
  888. EXPECT_THAT(
  889. recorded_activity(),
  890. ElementsAre(
  891. testing::_, testing::_,
  892. MatchesCookieOp(
  893. mojom::CookieAccessDetails::Type::kRead, kDefaultUrlWithPath,
  894. net::SiteForCookies(),
  895. CookieOrLine("cookie-name=cookie-value",
  896. mojom::CookieOrLine::Tag::kCookie),
  897. net::CookieInclusionStatus::MakeFromReasonsForTesting(
  898. {net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES},
  899. expected_warnings))));
  900. cookie_settings_.set_block_third_party_cookies(false);
  901. }
  902. // Cross Party
  903. {
  904. // `party_context` contains cross-party site.
  905. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  906. net::IsolationInfo::RequestType::kOther, kDefaultOrigin, kDefaultOrigin,
  907. net::SiteForCookies(),
  908. std::set<net::SchemefulSite>{
  909. net::SchemefulSite(GURL("https://nonexample.com"))}));
  910. auto options = mojom::CookieManagerGetOptions::New();
  911. options->name = "cookie-name";
  912. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  913. EXPECT_THAT(sync_service_->GetAllForUrl(
  914. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  915. std::move(options),
  916. /*partitioned_cookies_runtime_feature_enabled=*/false),
  917. IsEmpty());
  918. WaitForCallback();
  919. EXPECT_THAT(
  920. recorded_activity(),
  921. ElementsAre(
  922. testing::_, testing::_, testing::_,
  923. MatchesCookieOp(
  924. testing::_ /* type */, testing::_ /* url */,
  925. testing::_ /* site_for_cookies */,
  926. testing::_ /* cookie_or_line */,
  927. net::HasExactlyExclusionReasonsForTesting(
  928. std::vector<net::CookieInclusionStatus::ExclusionReason>{
  929. net::CookieInclusionStatus::
  930. EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT}))));
  931. }
  932. }
  933. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookie) {
  934. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  935. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  936. "new-name", "new-value", "example.com", "/", base::Time(),
  937. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  938. /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
  939. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  940. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin));
  941. auto options = mojom::CookieManagerGetOptions::New();
  942. options->name = "new-name";
  943. options->match_type = mojom::CookieMatchType::EQUALS;
  944. EXPECT_THAT(
  945. sync_service_->GetAllForUrl(
  946. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  947. std::move(options),
  948. /*partitioned_cookies_runtime_feature_enabled=*/false),
  949. ElementsAre(net::MatchesCookieNameValue("new-name", "new-value")));
  950. }
  951. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieHttpOnly) {
  952. EXPECT_EQ(GetParam() == mojom::RestrictedCookieManagerRole::NETWORK,
  953. sync_service_->SetCanonicalCookie(
  954. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  955. "new-name", "new-value", "example.com", "/", base::Time(),
  956. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  957. /*httponly=*/true, net::CookieSameSite::NO_RESTRICTION,
  958. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  959. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin));
  960. auto options = mojom::CookieManagerGetOptions::New();
  961. options->name = "new-name";
  962. options->match_type = mojom::CookieMatchType::EQUALS;
  963. std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
  964. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  965. std::move(options),
  966. /*partitioned_cookies_runtime_feature_enabled=*/false);
  967. if (GetParam() == mojom::RestrictedCookieManagerRole::SCRIPT) {
  968. EXPECT_THAT(cookies, IsEmpty());
  969. } else {
  970. EXPECT_THAT(cookies, ElementsAre(net::MatchesCookieNameValue("new-name",
  971. "new-value")));
  972. }
  973. }
  974. TEST_P(RestrictedCookieManagerTest, SetCookieFromString) {
  975. bool site_for_cookies_ok = false;
  976. bool top_frame_origin_ok = false;
  977. EXPECT_TRUE(backend()->SetCookieFromString(
  978. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  979. "new-name=new-value;path=/",
  980. /*partitioned_cookies_runtime_feature_enabled=*/false,
  981. &site_for_cookies_ok, &top_frame_origin_ok));
  982. EXPECT_TRUE(site_for_cookies_ok);
  983. EXPECT_TRUE(top_frame_origin_ok);
  984. auto options = mojom::CookieManagerGetOptions::New();
  985. options->name = "new-name";
  986. options->match_type = mojom::CookieMatchType::EQUALS;
  987. EXPECT_THAT(
  988. sync_service_->GetAllForUrl(
  989. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  990. std::move(options),
  991. /*partitioned_cookies_runtime_feature_enabled=*/false),
  992. ElementsAre(net::MatchesCookieNameValue("new-name", "new-value")));
  993. }
  994. TEST_P(RestrictedCookieManagerTest, BadSetCookieFromString) {
  995. bool site_for_cookies_ok = true;
  996. bool top_frame_origin_ok = true;
  997. // Purposely set an invalid cookie to return early before the DCHECK fails.
  998. EXPECT_TRUE(backend()->SetCookieFromString(
  999. kDefaultUrlWithPath, net::SiteForCookies(),
  1000. url::Origin::Create(GURL("https://not-example.com")),
  1001. "__Host-invalid=host_prefix_with_domain; Domain=example.com",
  1002. /*partitioned_cookies_runtime_feature_enabled=*/false,
  1003. &site_for_cookies_ok, &top_frame_origin_ok));
  1004. EXPECT_FALSE(site_for_cookies_ok);
  1005. EXPECT_FALSE(top_frame_origin_ok);
  1006. }
  1007. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieFromWrongOrigin) {
  1008. ExpectBadMessage();
  1009. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1010. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1011. "new-name", "new-value", "not-example.com", "/", base::Time(),
  1012. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  1013. /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
  1014. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1015. kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin));
  1016. ASSERT_TRUE(received_bad_message());
  1017. }
  1018. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieFromOpaqueOrigin) {
  1019. url::Origin opaque_origin;
  1020. ASSERT_TRUE(opaque_origin.opaque());
  1021. service_->OverrideOriginForTesting(opaque_origin);
  1022. ExpectBadMessage();
  1023. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1024. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1025. "new-name", "new-value", "not-example.com", "/", base::Time(),
  1026. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  1027. /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
  1028. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1029. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin));
  1030. ASSERT_TRUE(received_bad_message());
  1031. }
  1032. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieWithMismatchingDomain) {
  1033. ExpectBadMessage();
  1034. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1035. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1036. "new-name", "new-value", "not-example.com", "/", base::Time(),
  1037. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  1038. /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
  1039. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1040. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin));
  1041. ASSERT_TRUE(received_bad_message());
  1042. }
  1043. TEST_P(RestrictedCookieManagerTest, SetCookieFromStringWrongOrigin) {
  1044. ExpectBadMessage();
  1045. bool site_for_cookies_ok = false;
  1046. bool top_frame_origin_ok = false;
  1047. EXPECT_TRUE(backend()->SetCookieFromString(
  1048. kOtherUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  1049. "new-name=new-value;path=/",
  1050. /*partitioned_cookies_runtime_feature_enabled=*/false,
  1051. &site_for_cookies_ok, &top_frame_origin_ok));
  1052. ASSERT_TRUE(received_bad_message());
  1053. }
  1054. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookiePolicy) {
  1055. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1056. {
  1057. // With default settings object, setting a third-party cookie is OK.
  1058. auto cookie = net::CanonicalCookie::Create(
  1059. kDefaultUrl, "A=B; SameSite=none; Secure", base::Time::Now(),
  1060. absl::nullopt /* server_time */,
  1061. absl::nullopt /* cookie_partition_key */);
  1062. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1063. *cookie, kDefaultUrl, net::SiteForCookies(), kDefaultOrigin));
  1064. }
  1065. WaitForCallback();
  1066. EXPECT_THAT(recorded_activity(),
  1067. ElementsAre(MatchesCookieOp(
  1068. mojom::CookieAccessDetails::Type::kChange,
  1069. "https://example.com/", net::SiteForCookies(),
  1070. CookieOrLine("A=B", mojom::CookieOrLine::Tag::kCookie),
  1071. net::IsInclude())));
  1072. {
  1073. // Not if third-party cookies are disabled, though.
  1074. cookie_settings_.set_block_third_party_cookies(true);
  1075. auto cookie = net::CanonicalCookie::Create(
  1076. kDefaultUrl, "A2=B2; SameSite=none; Secure", base::Time::Now(),
  1077. absl::nullopt /* server_time */,
  1078. absl::nullopt /* cookie_partition_key */);
  1079. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1080. *cookie, kDefaultUrl, net::SiteForCookies(), kDefaultOrigin));
  1081. }
  1082. WaitForCallback();
  1083. EXPECT_THAT(
  1084. recorded_activity(),
  1085. ElementsAre(
  1086. testing::_,
  1087. MatchesCookieOp(
  1088. mojom::CookieAccessDetails::Type::kChange, "https://example.com/",
  1089. net::SiteForCookies(),
  1090. CookieOrLine("A2=B2", mojom::CookieOrLine::Tag::kCookie),
  1091. net::HasExactlyExclusionReasonsForTesting(
  1092. std::vector<net::CookieInclusionStatus::ExclusionReason>{
  1093. net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES}))));
  1094. // Read back, in first-party context
  1095. auto options = mojom::CookieManagerGetOptions::New();
  1096. options->name = "A";
  1097. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1098. service_->OverrideIsolationInfoForTesting(kDefaultIsolationInfo);
  1099. EXPECT_THAT(sync_service_->GetAllForUrl(
  1100. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  1101. std::move(options),
  1102. /*partitioned_cookies_runtime_feature_enabled=*/false),
  1103. ElementsAre(net::MatchesCookieNameValue("A", "B")));
  1104. WaitForCallback();
  1105. EXPECT_THAT(
  1106. recorded_activity(),
  1107. ElementsAre(
  1108. testing::_, testing::_,
  1109. MatchesCookieOp(
  1110. mojom::CookieAccessDetails::Type::kRead,
  1111. "https://example.com/test/",
  1112. net::SiteForCookies::FromUrl(GURL("https://example.com/")),
  1113. CookieOrLine("A=B", mojom::CookieOrLine::Tag::kCookie),
  1114. net::IsInclude())));
  1115. }
  1116. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookiePolicyWarnActual) {
  1117. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1118. auto cookie = net::CanonicalCookie::Create(
  1119. kDefaultUrl, "A=B", base::Time::Now(), absl::nullopt /* server_time */,
  1120. absl::nullopt /* cookie_partition_key */);
  1121. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1122. *cookie, kDefaultUrl, net::SiteForCookies(), kDefaultOrigin));
  1123. EXPECT_THAT(recorded_activity(),
  1124. ElementsAre(MatchesCookieOp(
  1125. mojom::CookieAccessDetails::Type::kChange,
  1126. "https://example.com/", net::SiteForCookies(),
  1127. CookieOrLine("A=B", mojom::CookieOrLine::Tag::kCookie),
  1128. net::HasExactlyExclusionReasonsForTesting(
  1129. std::vector<net::CookieInclusionStatus::ExclusionReason>{
  1130. net::CookieInclusionStatus::
  1131. EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}))));
  1132. }
  1133. TEST_P(SamePartyEnabledRestrictedCookieManagerTest,
  1134. SetCookieFromString_SameParty_ReportsInvalid) {
  1135. // Invalid. Should be reported.
  1136. sync_service_->SetCookieFromString(
  1137. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin,
  1138. "name=value;SameParty",
  1139. /*partitioned_cookies_runtime_feature_enabled=*/false);
  1140. WaitForCallback();
  1141. EXPECT_THAT(
  1142. recorded_activity(),
  1143. ElementsAre(MatchesCookieOp(
  1144. mojom::CookieAccessDetails::Type::kChange, kDefaultUrlWithPath,
  1145. net::SiteForCookies(),
  1146. CookieOrLine("name=value;SameParty",
  1147. mojom::CookieOrLine::Tag::kCookieString),
  1148. net::HasExactlyExclusionReasonsForTesting(
  1149. std::vector<net::CookieInclusionStatus::ExclusionReason>{
  1150. net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY}))));
  1151. }
  1152. TEST_P(SamePartyEnabledRestrictedCookieManagerTest,
  1153. SetCanonicalCookieSameParty) {
  1154. // Same Party. `party_context` contains fps site.
  1155. {
  1156. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  1157. net::IsolationInfo::RequestType::kOther, kDefaultOrigin,
  1158. url::Origin::Create(GURL("https://member1.com")), net::SiteForCookies(),
  1159. std::set<net::SchemefulSite>{
  1160. net::SchemefulSite(GURL("https://member1.com"))}));
  1161. // Need to override origin as well since the access is from member1.com.
  1162. service_->OverrideOriginForTesting(
  1163. url::Origin::Create(GURL("https://member1.com")));
  1164. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1165. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1166. "new-name", "new-value", "member1.com", "/", base::Time(),
  1167. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  1168. /*httponly=*/false, net::CookieSameSite::LAX_MODE,
  1169. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/true),
  1170. GURL("https://member1.com/test/"), net::SiteForCookies(),
  1171. kDefaultOrigin));
  1172. auto options = mojom::CookieManagerGetOptions::New();
  1173. options->name = "new-name";
  1174. options->match_type = mojom::CookieMatchType::EQUALS;
  1175. EXPECT_THAT(
  1176. sync_service_->GetAllForUrl(
  1177. GURL("https://member1.com/test/"), net::SiteForCookies(),
  1178. kDefaultOrigin, std::move(options),
  1179. /*partitioned_cookies_runtime_feature_enabled=*/false),
  1180. ElementsAre(net::MatchesCookieNameValue("new-name", "new-value")));
  1181. }
  1182. // Cross Party
  1183. {
  1184. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  1185. net::IsolationInfo::RequestType::kOther, kDefaultOrigin, kDefaultOrigin,
  1186. net::SiteForCookies(),
  1187. std::set<net::SchemefulSite>{
  1188. net::SchemefulSite(GURL("https://not-example.com"))}));
  1189. // Need to restore the origin value since the previous Same Party test case
  1190. // changed it to member1.com.
  1191. service_->OverrideOriginForTesting(kDefaultOrigin);
  1192. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1193. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1194. "new-name", "new-value", "example.com", "/", base::Time(),
  1195. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  1196. /*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
  1197. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/true),
  1198. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin));
  1199. EXPECT_THAT(
  1200. recorded_activity(),
  1201. ElementsAre(
  1202. testing::_, testing::_,
  1203. MatchesCookieOp(
  1204. mojom::CookieAccessDetails::Type::kChange,
  1205. "https://example.com/test/", net::SiteForCookies(),
  1206. CookieOrLine("new-name=new-value",
  1207. mojom::CookieOrLine::Tag::kCookie),
  1208. net::HasExactlyExclusionReasonsForTesting(
  1209. std::vector<net::CookieInclusionStatus::ExclusionReason>{
  1210. net::CookieInclusionStatus::
  1211. EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT}))));
  1212. }
  1213. }
  1214. TEST_P(RestrictedCookieManagerTest, SetCanonicalCookieWithInclusionStatus) {
  1215. ExpectBadMessage();
  1216. net::CookieInclusionStatus status_exclude(
  1217. net::CookieInclusionStatus::ExclusionReason::EXCLUDE_USER_PREFERENCES);
  1218. // In this instance cookie should be OK but due to the status having
  1219. // an exclusion reason, the result should be false and a BadMessage should
  1220. // be received.
  1221. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1222. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1223. "new-name", "new-value", "example.com", "/", base::Time(),
  1224. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  1225. /*httponly=*/false, net::CookieSameSite::LAX_MODE,
  1226. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1227. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  1228. status_exclude));
  1229. ASSERT_TRUE(received_bad_message());
  1230. // In this instance the cookie should be OK and the status only
  1231. // has a warning so the result should be true.
  1232. net::CookieInclusionStatus status_warning(
  1233. net::CookieInclusionStatus::WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE);
  1234. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1235. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1236. "new-name", "new-value", "example.com", "/", base::Time(),
  1237. base::Time(), base::Time(), base::Time(), /*secure=*/true,
  1238. /*httponly=*/false, net::CookieSameSite::LAX_MODE,
  1239. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1240. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin,
  1241. status_warning));
  1242. WaitForCallback();
  1243. EXPECT_THAT(
  1244. recorded_activity(),
  1245. ElementsAre(MatchesCookieOp(
  1246. mojom::CookieAccessDetails::Type::kChange, kDefaultUrlWithPath,
  1247. kDefaultSiteForCookies,
  1248. CookieOrLine("new-name=new-value", mojom::CookieOrLine::Tag::kCookie),
  1249. net::CookieInclusionStatus::MakeFromReasonsForTesting(
  1250. {}, {net::CookieInclusionStatus::
  1251. WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE}))));
  1252. }
  1253. TEST_P(RestrictedCookieManagerTest, CookiesEnabledFor) {
  1254. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1255. // Default, third-party access is OK.
  1256. bool result = false;
  1257. EXPECT_TRUE(backend()->CookiesEnabledFor(kDefaultUrl, net::SiteForCookies(),
  1258. kDefaultOrigin, &result));
  1259. EXPECT_TRUE(result);
  1260. // Third-party cookies disabled.
  1261. cookie_settings_.set_block_third_party_cookies(true);
  1262. EXPECT_TRUE(backend()->CookiesEnabledFor(kDefaultUrl, net::SiteForCookies(),
  1263. kDefaultOrigin, &result));
  1264. EXPECT_FALSE(result);
  1265. // First-party ones still OK.
  1266. service_->OverrideIsolationInfoForTesting(kDefaultIsolationInfo);
  1267. EXPECT_TRUE(backend()->CookiesEnabledFor(kDefaultUrl, kDefaultSiteForCookies,
  1268. kDefaultOrigin, &result));
  1269. EXPECT_TRUE(result);
  1270. }
  1271. // Test that special chrome:// scheme always attaches SameSite cookies when the
  1272. // requested origin is secure.
  1273. TEST_P(RestrictedCookieManagerTest, SameSiteCookiesSpecialScheme) {
  1274. url::ScopedSchemeRegistryForTests scoped_registry;
  1275. cookie_settings_.set_secure_origin_cookies_allowed_schemes({"chrome"});
  1276. url::AddStandardScheme("chrome", url::SchemeType::SCHEME_WITH_HOST);
  1277. GURL extension_url("chrome-extension://abcdefghijklmnopqrstuvwxyz");
  1278. GURL chrome_url("chrome://whatever");
  1279. GURL http_url("http://example.com/test");
  1280. GURL https_url("https://example.com/test");
  1281. auto http_origin = url::Origin::Create(http_url);
  1282. auto https_origin = url::Origin::Create(https_url);
  1283. auto chrome_origin = url::Origin::Create(chrome_url);
  1284. net::SiteForCookies chrome_site_for_cookies =
  1285. net::SiteForCookies::FromUrl(chrome_url);
  1286. // Test if site_for_cookies is chrome, then SameSite cookies can be
  1287. // set and gotten if the origin is secure.
  1288. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  1289. net::IsolationInfo::RequestType::kOther, chrome_origin, https_origin,
  1290. chrome_site_for_cookies));
  1291. service_->OverrideOriginForTesting(https_origin);
  1292. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1293. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1294. "strict-cookie", "1", "example.com", "/", base::Time(), base::Time(),
  1295. base::Time(), base::Time(), /*secure=*/false,
  1296. /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
  1297. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1298. https_url, chrome_site_for_cookies, chrome_origin));
  1299. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1300. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1301. "lax-cookie", "1", "example.com", "/", base::Time(), base::Time(),
  1302. base::Time(), base::Time(), /*secure=*/false,
  1303. /*httponly=*/false, net::CookieSameSite::LAX_MODE,
  1304. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1305. https_url, chrome_site_for_cookies, chrome_origin));
  1306. auto options = mojom::CookieManagerGetOptions::New();
  1307. options->name = "";
  1308. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1309. EXPECT_THAT(
  1310. sync_service_->GetAllForUrl(
  1311. https_url, chrome_site_for_cookies, chrome_origin, std::move(options),
  1312. /*partitioned_cookies_runtime_feature_enabled=*/false),
  1313. testing::SizeIs(2));
  1314. // Test if site_for_cookies is chrome, then SameSite cookies cannot be
  1315. // set and gotten if the origin is not secure.
  1316. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  1317. net::IsolationInfo::RequestType::kOther, chrome_origin, http_origin,
  1318. chrome_site_for_cookies));
  1319. service_->OverrideOriginForTesting(http_origin);
  1320. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1321. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1322. "strict-cookie", "2", "example.com", "/", base::Time(), base::Time(),
  1323. base::Time(), base::Time(), /*secure=*/false,
  1324. /*httponly=*/false, net::CookieSameSite::STRICT_MODE,
  1325. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1326. http_url, chrome_site_for_cookies, chrome_origin));
  1327. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1328. *net::CanonicalCookie::CreateUnsafeCookieForTesting(
  1329. "lax-cookie", "2", "example.com", "/", base::Time(), base::Time(),
  1330. base::Time(), base::Time(), /*secure=*/false,
  1331. /*httponly=*/false, net::CookieSameSite::LAX_MODE,
  1332. net::COOKIE_PRIORITY_DEFAULT, /*same_party=*/false),
  1333. http_url, chrome_site_for_cookies, chrome_origin));
  1334. options = mojom::CookieManagerGetOptions::New();
  1335. options->name = "";
  1336. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1337. EXPECT_THAT(
  1338. sync_service_->GetAllForUrl(
  1339. http_url, chrome_site_for_cookies, chrome_origin, std::move(options),
  1340. /*partitioned_cookies_runtime_feature_enabled=*/false),
  1341. IsEmpty());
  1342. }
  1343. TEST_P(RestrictedCookieManagerTest, ChangeDispatch) {
  1344. auto listener = CreateCookieChangeListener(
  1345. kDefaultUrlWithPath, kDefaultSiteForCookies, kDefaultOrigin);
  1346. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  1347. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  1348. listener->WaitForChange();
  1349. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1350. EXPECT_EQ(net::CookieChangeCause::INSERTED,
  1351. listener->observed_changes()[0].cause);
  1352. EXPECT_THAT(listener->observed_changes()[0].cookie,
  1353. net::MatchesCookieNameValue("cookie-name", "cookie-value"));
  1354. }
  1355. TEST_P(RestrictedCookieManagerTest, ChangeSettings) {
  1356. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1357. auto listener = CreateCookieChangeListener(
  1358. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin);
  1359. EXPECT_THAT(listener->observed_changes(), IsEmpty());
  1360. cookie_settings_.set_block_third_party_cookies(true);
  1361. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  1362. base::RunLoop().RunUntilIdle();
  1363. EXPECT_THAT(listener->observed_changes(), IsEmpty());
  1364. }
  1365. TEST_P(RestrictedCookieManagerTest, AddChangeListenerFromWrongOrigin) {
  1366. mojo::PendingRemote<network::mojom::CookieChangeListener> bad_listener_remote;
  1367. mojo::PendingReceiver<network::mojom::CookieChangeListener> bad_receiver =
  1368. bad_listener_remote.InitWithNewPipeAndPassReceiver();
  1369. ExpectBadMessage();
  1370. sync_service_->AddChangeListener(kOtherUrlWithPath, kDefaultSiteForCookies,
  1371. kDefaultOrigin,
  1372. std::move(bad_listener_remote));
  1373. EXPECT_TRUE(received_bad_message());
  1374. TestCookieChangeListener bad_listener(std::move(bad_receiver));
  1375. mojo::PendingRemote<network::mojom::CookieChangeListener>
  1376. good_listener_remote;
  1377. mojo::PendingReceiver<network::mojom::CookieChangeListener> good_receiver =
  1378. good_listener_remote.InitWithNewPipeAndPassReceiver();
  1379. sync_service_->AddChangeListener(kDefaultUrlWithPath, kDefaultSiteForCookies,
  1380. kDefaultOrigin,
  1381. std::move(good_listener_remote));
  1382. TestCookieChangeListener good_listener(std::move(good_receiver));
  1383. ASSERT_THAT(bad_listener.observed_changes(), IsEmpty());
  1384. ASSERT_THAT(good_listener.observed_changes(), IsEmpty());
  1385. SetSessionCookie("other-cookie-name", "other-cookie-value", "not-example.com",
  1386. "/");
  1387. SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
  1388. good_listener.WaitForChange();
  1389. EXPECT_THAT(bad_listener.observed_changes(), IsEmpty());
  1390. ASSERT_THAT(good_listener.observed_changes(), testing::SizeIs(1));
  1391. EXPECT_EQ(net::CookieChangeCause::INSERTED,
  1392. good_listener.observed_changes()[0].cause);
  1393. EXPECT_THAT(good_listener.observed_changes()[0].cookie,
  1394. net::MatchesCookieNameValue("cookie-name", "cookie-value"));
  1395. }
  1396. TEST_P(RestrictedCookieManagerTest, AddChangeListenerFromOpaqueOrigin) {
  1397. url::Origin opaque_origin;
  1398. ASSERT_TRUE(opaque_origin.opaque());
  1399. service_->OverrideOriginForTesting(opaque_origin);
  1400. mojo::PendingRemote<network::mojom::CookieChangeListener> bad_listener_remote;
  1401. mojo::PendingReceiver<network::mojom::CookieChangeListener> bad_receiver =
  1402. bad_listener_remote.InitWithNewPipeAndPassReceiver();
  1403. ExpectBadMessage();
  1404. sync_service_->AddChangeListener(kDefaultUrlWithPath, kDefaultSiteForCookies,
  1405. kDefaultOrigin,
  1406. std::move(bad_listener_remote));
  1407. EXPECT_TRUE(received_bad_message());
  1408. TestCookieChangeListener bad_listener(std::move(bad_receiver));
  1409. ASSERT_THAT(bad_listener.observed_changes(), IsEmpty());
  1410. }
  1411. TEST_P(SamePartyEnabledRestrictedCookieManagerTest,
  1412. AddChangeListenerSameParty) {
  1413. // Same Party. `party_context` contains fps site.
  1414. {
  1415. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  1416. net::IsolationInfo::RequestType::kOther, kDefaultOrigin, kDefaultOrigin,
  1417. net::SiteForCookies(),
  1418. std::set<net::SchemefulSite>{
  1419. net::SchemefulSite(GURL("https://member1.com"))}));
  1420. auto listener = CreateCookieChangeListener(
  1421. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin);
  1422. ASSERT_THAT(listener->observed_changes(), IsEmpty());
  1423. SetSamePartyCookie("cookie-name", "cookie-value", "example.com", "/");
  1424. listener->WaitForChange();
  1425. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1426. EXPECT_EQ(net::CookieChangeCause::INSERTED,
  1427. listener->observed_changes()[0].cause);
  1428. EXPECT_THAT(listener->observed_changes()[0].cookie,
  1429. net::MatchesCookieNameValue("cookie-name", "cookie-value"));
  1430. }
  1431. // Cross Party.
  1432. {
  1433. service_->OverrideIsolationInfoForTesting(net::IsolationInfo::Create(
  1434. net::IsolationInfo::RequestType::kOther, kDefaultOrigin, kDefaultOrigin,
  1435. net::SiteForCookies(),
  1436. std::set<net::SchemefulSite>{
  1437. net::SchemefulSite(GURL("https://not-example.com"))}));
  1438. auto listener = CreateCookieChangeListener(
  1439. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin);
  1440. EXPECT_THAT(listener->observed_changes(), IsEmpty());
  1441. SetSamePartyCookie("cookie-name", "cookie-value", "example.com", "/");
  1442. EXPECT_THAT(listener->observed_changes(), IsEmpty());
  1443. }
  1444. }
  1445. // Test that the Change listener receives the access semantics, and that they
  1446. // are taken into account when deciding when to dispatch the change.
  1447. TEST_P(RestrictedCookieManagerTest, ChangeNotificationIncludesAccessSemantics) {
  1448. auto cookie_access_delegate =
  1449. std::make_unique<net::TestCookieAccessDelegate>();
  1450. cookie_access_delegate->SetExpectationForCookieDomain(
  1451. "example.com", net::CookieAccessSemantics::LEGACY);
  1452. cookie_monster_.SetCookieAccessDelegate(std::move(cookie_access_delegate));
  1453. // Use a cross-site site_for_cookies.
  1454. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1455. auto listener = CreateCookieChangeListener(
  1456. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin);
  1457. ASSERT_THAT(listener->observed_changes(), IsEmpty());
  1458. auto cookie = net::CanonicalCookie::Create(
  1459. kDefaultUrl, "cookie_with_no_samesite=unspecified", base::Time::Now(),
  1460. absl::nullopt, absl::nullopt /* cookie_partition_key */);
  1461. // Set cookie directly into the CookieMonster, using all-inclusive options.
  1462. net::ResultSavingCookieCallback<net::CookieAccessResult> callback;
  1463. cookie_monster_.SetCanonicalCookieAsync(
  1464. std::move(cookie), kDefaultUrl, net::CookieOptions::MakeAllInclusive(),
  1465. callback.MakeCallback());
  1466. callback.WaitUntilDone();
  1467. ASSERT_TRUE(callback.result().status.IsInclude());
  1468. // The listener only receives the change because the cookie is legacy.
  1469. listener->WaitForChange();
  1470. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1471. EXPECT_EQ(net::CookieAccessSemantics::LEGACY,
  1472. listener->observed_changes()[0].access_result.access_semantics);
  1473. }
  1474. TEST_P(RestrictedCookieManagerTest, NoChangeNotificationForNonlegacyCookie) {
  1475. auto cookie_access_delegate =
  1476. std::make_unique<net::TestCookieAccessDelegate>();
  1477. cookie_access_delegate->SetExpectationForCookieDomain(
  1478. "example.com", net::CookieAccessSemantics::NONLEGACY);
  1479. cookie_monster_.SetCookieAccessDelegate(std::move(cookie_access_delegate));
  1480. // Use a cross-site site_for_cookies.
  1481. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1482. auto listener = CreateCookieChangeListener(
  1483. kDefaultUrlWithPath, net::SiteForCookies(), kDefaultOrigin);
  1484. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  1485. auto unspecified_cookie = net::CanonicalCookie::Create(
  1486. kDefaultUrl, "cookie_with_no_samesite=unspecified", base::Time::Now(),
  1487. absl::nullopt, absl::nullopt /* cookie_partition_key */);
  1488. auto samesite_none_cookie = net::CanonicalCookie::Create(
  1489. kDefaultUrl, "samesite_none_cookie=none; SameSite=None; Secure",
  1490. base::Time::Now(), absl::nullopt,
  1491. absl::nullopt /* cookie_partition_key */);
  1492. // Set cookies directly into the CookieMonster, using all-inclusive options.
  1493. net::ResultSavingCookieCallback<net::CookieAccessResult> callback1;
  1494. cookie_monster_.SetCanonicalCookieAsync(
  1495. std::move(unspecified_cookie), kDefaultUrl,
  1496. net::CookieOptions::MakeAllInclusive(), callback1.MakeCallback());
  1497. callback1.WaitUntilDone();
  1498. ASSERT_TRUE(callback1.result().status.IsInclude());
  1499. // Listener doesn't receive notification because cookie is not included for
  1500. // request URL for being unspecified and treated as lax.
  1501. base::RunLoop().RunUntilIdle();
  1502. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  1503. net::ResultSavingCookieCallback<net::CookieAccessResult> callback2;
  1504. cookie_monster_.SetCanonicalCookieAsync(
  1505. std::move(samesite_none_cookie), kDefaultUrl,
  1506. net::CookieOptions::MakeAllInclusive(), callback2.MakeCallback());
  1507. callback2.WaitUntilDone();
  1508. ASSERT_TRUE(callback2.result().status.IsInclude());
  1509. // Listener only receives notification about the SameSite=None cookie.
  1510. listener->WaitForChange();
  1511. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1512. EXPECT_EQ("samesite_none_cookie",
  1513. listener->observed_changes()[0].cookie.Name());
  1514. EXPECT_EQ(net::CookieAccessSemantics::NONLEGACY,
  1515. listener->observed_changes()[0].access_result.access_semantics);
  1516. }
  1517. INSTANTIATE_TEST_SUITE_P(
  1518. All,
  1519. RestrictedCookieManagerTest,
  1520. ::testing::Values(mojom::RestrictedCookieManagerRole::SCRIPT,
  1521. mojom::RestrictedCookieManagerRole::NETWORK));
  1522. class PartitionedCookiesRestrictedCookieManagerTest
  1523. : public RestrictedCookieManagerTest {
  1524. public:
  1525. PartitionedCookiesRestrictedCookieManagerTest() {
  1526. feature_list_.InitAndEnableFeature(net::features::kPartitionedCookies);
  1527. }
  1528. ~PartitionedCookiesRestrictedCookieManagerTest() override = default;
  1529. private:
  1530. base::test::ScopedFeatureList feature_list_;
  1531. };
  1532. // Test Partitioned cookie behavior when feature is disabled.
  1533. TEST_P(RestrictedCookieManagerTest, PartitionedCookies) {
  1534. const GURL kCookieURL("https://example.com");
  1535. const GURL kTopFrameURL("https://foo.com");
  1536. const net::SiteForCookies kSiteForCookies =
  1537. net::SiteForCookies::FromUrl(kTopFrameURL);
  1538. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  1539. const net::IsolationInfo kIsolationInfo =
  1540. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  1541. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  1542. // Set partitioned_cookies_runtime_feature_enabled to true to make sure it
  1543. // does not override the net feature.
  1544. sync_service_->SetCookieFromString(
  1545. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  1546. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  1547. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1548. { // Test request from the same top-level site.
  1549. auto options = mojom::CookieManagerGetOptions::New();
  1550. options->name = "";
  1551. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1552. net::CookieList cookies = sync_service_->GetAllForUrl(
  1553. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  1554. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1555. ASSERT_EQ(1u, cookies.size());
  1556. EXPECT_FALSE(cookies[0].IsPartitioned());
  1557. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1558. auto listener = CreateCookieChangeListener(kCookieURL, kSiteForCookies,
  1559. kTopFrameOrigin);
  1560. // Update partitioned cookie Max-Age: None -> 7200.
  1561. EXPECT_TRUE(SetCanonicalCookie(
  1562. *net::CanonicalCookie::Create(
  1563. kCookieURL,
  1564. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned; "
  1565. "Max-Age=7200",
  1566. base::Time::Now(), absl::nullopt /* server_time */,
  1567. net::CookiePartitionKey::FromNetworkIsolationKey(
  1568. kIsolationInfo.network_isolation_key())),
  1569. "https", false /* can_modify_httponly */));
  1570. // If Partitioned cookies are disabled, the change listener should see the
  1571. // change to the cookie on this top-level site.
  1572. listener->WaitForChange();
  1573. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1574. }
  1575. { // Test request from another top-level site.
  1576. const GURL kOtherTopFrameURL("https://bar.com");
  1577. const net::SiteForCookies kOtherSiteForCookies =
  1578. net::SiteForCookies::FromUrl(kOtherTopFrameURL);
  1579. const url::Origin kOtherTopFrameOrigin =
  1580. url::Origin::Create(kOtherTopFrameURL);
  1581. const net::IsolationInfo kOtherIsolationInfo =
  1582. net::IsolationInfo::CreateForInternalRequest(kOtherTopFrameOrigin);
  1583. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1584. auto options = mojom::CookieManagerGetOptions::New();
  1585. options->name = "";
  1586. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1587. net::CookieList cookies = sync_service_->GetAllForUrl(
  1588. kCookieURL, kOtherSiteForCookies, kOtherTopFrameOrigin,
  1589. std::move(options),
  1590. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1591. ASSERT_EQ(1u, cookies.size());
  1592. EXPECT_FALSE(cookies[0].IsPartitioned());
  1593. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1594. auto listener = CreateCookieChangeListener(kCookieURL, kOtherSiteForCookies,
  1595. kOtherTopFrameOrigin);
  1596. // Update partitioned cookie Max-Age: 7200 -> 3600.
  1597. EXPECT_TRUE(SetCanonicalCookie(
  1598. *net::CanonicalCookie::Create(
  1599. kCookieURL,
  1600. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned; "
  1601. "Max-Age=3600",
  1602. base::Time::Now(), absl::nullopt /* server_time */,
  1603. net::CookiePartitionKey::FromNetworkIsolationKey(
  1604. kIsolationInfo.network_isolation_key())),
  1605. "https", false /* can_modify_httponly */));
  1606. // If Partitioned cookies are disabled, the change listener should see the
  1607. // change to the cookie on the other top-level site as well.
  1608. listener->WaitForChange();
  1609. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1610. }
  1611. }
  1612. TEST_P(RestrictedCookieManagerTest, PartitionKeyFromScript) {
  1613. const GURL kCookieURL("https://example.com");
  1614. const GURL kTopFrameURL("https://foo.com");
  1615. const net::SiteForCookies kSiteForCookies =
  1616. net::SiteForCookies::FromUrl(kTopFrameURL);
  1617. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  1618. const net::IsolationInfo kIsolationInfo =
  1619. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  1620. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  1621. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1622. *net::CanonicalCookie::Create(
  1623. kCookieURL,
  1624. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  1625. base::Time::Now(), absl::nullopt /* server_time */,
  1626. net::CookiePartitionKey::FromScript()),
  1627. kCookieURL, kSiteForCookies, kTopFrameOrigin));
  1628. auto options = mojom::CookieManagerGetOptions::New();
  1629. options->name = "";
  1630. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1631. net::CookieList cookies = sync_service_->GetAllForUrl(
  1632. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  1633. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1634. ASSERT_EQ(1u, cookies.size());
  1635. EXPECT_FALSE(cookies[0].IsPartitioned());
  1636. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1637. }
  1638. // Test Partitioned cookie behavior when feature is enabled.
  1639. TEST_P(PartitionedCookiesRestrictedCookieManagerTest, PartitionedCookies) {
  1640. const GURL kCookieURL("https://example.com");
  1641. const GURL kTopFrameURL("https://sub.foo.com");
  1642. const net::SiteForCookies kSiteForCookies =
  1643. net::SiteForCookies::FromUrl(kTopFrameURL);
  1644. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  1645. const net::IsolationInfo kIsolationInfo =
  1646. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  1647. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  1648. sync_service_->SetCookieFromString(
  1649. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  1650. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  1651. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1652. { // Test request from the same top-level site.
  1653. auto options = mojom::CookieManagerGetOptions::New();
  1654. options->name = "";
  1655. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1656. net::CookieList cookies = sync_service_->GetAllForUrl(
  1657. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  1658. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1659. ASSERT_EQ(1u, cookies.size());
  1660. EXPECT_TRUE(cookies[0].IsPartitioned());
  1661. EXPECT_EQ(
  1662. net::CookiePartitionKey::FromURLForTesting(GURL("https://foo.com")),
  1663. cookies[0].PartitionKey());
  1664. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1665. auto listener = CreateCookieChangeListener(kCookieURL, kSiteForCookies,
  1666. kTopFrameOrigin);
  1667. // Update partitioned cookie Max-Age: None -> 7200.
  1668. EXPECT_TRUE(SetCanonicalCookie(
  1669. *net::CanonicalCookie::Create(
  1670. kCookieURL,
  1671. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned; "
  1672. "Max-Age=7200",
  1673. base::Time::Now(), absl::nullopt /* server_time */,
  1674. net::CookiePartitionKey::FromNetworkIsolationKey(
  1675. kIsolationInfo.network_isolation_key())),
  1676. "https", false /* can_modify_httponly */));
  1677. // If Partitioned cookies are enabled, the change listener should see the
  1678. // change to the cookie on this top-level site.
  1679. listener->WaitForChange();
  1680. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1681. }
  1682. { // Test request from another top-level site.
  1683. const GURL kOtherTopFrameURL("https://foo.bar.com");
  1684. const net::SiteForCookies kOtherSiteForCookies =
  1685. net::SiteForCookies::FromUrl(kOtherTopFrameURL);
  1686. const url::Origin kOtherTopFrameOrigin =
  1687. url::Origin::Create(kOtherTopFrameURL);
  1688. const net::IsolationInfo kOtherIsolationInfo =
  1689. net::IsolationInfo::CreateForInternalRequest(kOtherTopFrameOrigin);
  1690. service_->OverrideIsolationInfoForTesting(kOtherIsolationInfo);
  1691. auto options = mojom::CookieManagerGetOptions::New();
  1692. options->name = "";
  1693. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1694. net::CookieList cookies = sync_service_->GetAllForUrl(
  1695. kCookieURL, kOtherSiteForCookies, kOtherTopFrameOrigin,
  1696. std::move(options),
  1697. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1698. ASSERT_EQ(0u, cookies.size());
  1699. auto listener = CreateCookieChangeListener(kCookieURL, kOtherSiteForCookies,
  1700. kOtherTopFrameOrigin);
  1701. // Set a new listener with the original IsolationInfo, we wait for this
  1702. // listener to receive an event to verify that the second listener was
  1703. // either called or skipped.
  1704. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  1705. auto second_listener = CreateCookieChangeListener(
  1706. kCookieURL, kSiteForCookies, kTopFrameOrigin);
  1707. // Update partitioned cookie Max-Age: 7200 -> 3600.
  1708. EXPECT_TRUE(SetCanonicalCookie(
  1709. *net::CanonicalCookie::Create(
  1710. kCookieURL,
  1711. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned; "
  1712. "Max-Age=3600",
  1713. base::Time::Now(), absl::nullopt /* server_time */,
  1714. net::CookiePartitionKey::FromNetworkIsolationKey(
  1715. kIsolationInfo.network_isolation_key())),
  1716. "https", false /* can_modify_httponly */));
  1717. // If Partitioned cookies are enabled, the listener should not see cookie
  1718. // change events on this top-level site.
  1719. second_listener->WaitForChange();
  1720. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  1721. }
  1722. { // Test that a cookie cannot be set with a different partition key than
  1723. // RestrictedCookieManager's.
  1724. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  1725. ExpectBadMessage();
  1726. EXPECT_FALSE(sync_service_->SetCanonicalCookie(
  1727. *net::CanonicalCookie::Create(
  1728. kCookieURL,
  1729. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  1730. base::Time::Now(), absl::nullopt /* server_time */,
  1731. net::CookiePartitionKey::FromURLForTesting(
  1732. GURL("https://foo.bar.com"))),
  1733. kCookieURL, kSiteForCookies, kTopFrameOrigin));
  1734. }
  1735. }
  1736. TEST_P(PartitionedCookiesRestrictedCookieManagerTest, PartitionKeyFromScript) {
  1737. const GURL kCookieURL("https://example.com");
  1738. const GURL kTopFrameURL("https://foo.com");
  1739. const net::SiteForCookies kSiteForCookies =
  1740. net::SiteForCookies::FromUrl(kTopFrameURL);
  1741. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  1742. const net::IsolationInfo kIsolationInfo =
  1743. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  1744. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  1745. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1746. *net::CanonicalCookie::Create(
  1747. kCookieURL,
  1748. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  1749. base::Time::Now(), absl::nullopt /* server_time */,
  1750. net::CookiePartitionKey::FromScript()),
  1751. kCookieURL, kSiteForCookies, kTopFrameOrigin));
  1752. auto options = mojom::CookieManagerGetOptions::New();
  1753. options->name = "";
  1754. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1755. net::CookieList cookies = sync_service_->GetAllForUrl(
  1756. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  1757. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1758. ASSERT_EQ(1u, cookies.size());
  1759. EXPECT_TRUE(cookies[0].IsPartitioned());
  1760. EXPECT_EQ(cookies[0].PartitionKey().value(),
  1761. net::CookiePartitionKey::FromURLForTesting(kTopFrameURL));
  1762. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1763. }
  1764. // Tests the interaction between First-Party Sets and partitioned cookies in
  1765. // RestrictedCookieManager. When FPS are enabled, RestrictedCookieManager
  1766. // should use the same cookie partition key for all sites in
  1767. TEST_P(PartitionedCookiesRestrictedCookieManagerTest,
  1768. PartitionedCookiesAndFirstPartySets) {
  1769. const GURL kOwnerURL("https://owner.com");
  1770. const net::SchemefulSite kOwnerSite(kOwnerURL);
  1771. const url::Origin kOwnerOrigin = url::Origin::Create(kOwnerURL);
  1772. const net::IsolationInfo kOwnerIsolationInfo =
  1773. net::IsolationInfo::CreateForInternalRequest(kOwnerOrigin);
  1774. const net::SiteForCookies kOwnerSiteForCookies =
  1775. net::SiteForCookies::FromUrl(kOwnerURL);
  1776. const GURL kMemberURL("https://member.com");
  1777. const net::SchemefulSite kMemberSite(kMemberURL);
  1778. const url::Origin kMemberOrigin = url::Origin::Create(kMemberURL);
  1779. const net::IsolationInfo kMemberIsolationInfo =
  1780. net::IsolationInfo::CreateForInternalRequest(kMemberOrigin);
  1781. const net::SiteForCookies kMemberSiteForCookies =
  1782. net::SiteForCookies::FromUrl(kMemberURL);
  1783. const GURL kNonMemberURL("https://nonmember.com");
  1784. const url::Origin kNonMemberOrigin = url::Origin::Create(kNonMemberURL);
  1785. const net::IsolationInfo kNonMemberIsolationInfo =
  1786. net::IsolationInfo::CreateForInternalRequest(kNonMemberOrigin);
  1787. const net::SiteForCookies kNonMemberSiteForCookies =
  1788. net::SiteForCookies::FromUrl(kNonMemberURL);
  1789. const GURL kCookieURL("https://example.com");
  1790. auto cookie_access_delegate =
  1791. std::make_unique<net::TestCookieAccessDelegate>();
  1792. cookie_access_delegate->SetFirstPartySets({
  1793. {kOwnerSite, net::FirstPartySetEntry(kOwnerSite, net::SiteType::kPrimary,
  1794. absl::nullopt)},
  1795. {kMemberSite,
  1796. net::FirstPartySetEntry(kOwnerSite, net::SiteType::kAssociated, 0)},
  1797. });
  1798. cookie_monster_.SetCookieAccessDelegate(std::move(cookie_access_delegate));
  1799. // Set https://example.com cookie when the top-frame site is the owner
  1800. // of the set.
  1801. service_->OverrideIsolationInfoForTesting(kOwnerIsolationInfo);
  1802. sync_service_->SetCookieFromString(
  1803. kCookieURL, kOwnerSiteForCookies, kOwnerOrigin,
  1804. "__Host-foo=0; Secure; SameSite=None; Path=/; Partitioned",
  1805. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1806. {
  1807. // Check that its partition key is the set's owner site.
  1808. auto options = mojom::CookieManagerGetOptions::New();
  1809. options->name = "";
  1810. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1811. net::CookieList cookies = sync_service_->GetAllForUrl(
  1812. kCookieURL, kOwnerSiteForCookies, kOwnerOrigin, std::move(options),
  1813. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1814. ASSERT_EQ(1u, cookies.size());
  1815. EXPECT_TRUE(cookies[0].IsPartitioned());
  1816. EXPECT_EQ(net::CookiePartitionKey::FromURLForTesting(kOwnerURL),
  1817. cookies[0].PartitionKey());
  1818. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1819. auto listener = CreateCookieChangeListener(kCookieURL, kOwnerSiteForCookies,
  1820. kOwnerOrigin);
  1821. // Update partitioned cookie Max-Age: None -> 7200.
  1822. sync_service_->SetCookieFromString(
  1823. kCookieURL, kOwnerSiteForCookies, kOwnerOrigin,
  1824. "__Host-foo=0; Secure; SameSite=None; Path=/; Partitioned; "
  1825. "Max-Age: 7200",
  1826. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1827. listener->WaitForChange();
  1828. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1829. }
  1830. {
  1831. // Check that cookie is available to https://example.com when the top-frame
  1832. // site is a site that is a member of the set but not the owner.
  1833. service_->OverrideIsolationInfoForTesting(kMemberIsolationInfo);
  1834. auto options = mojom::CookieManagerGetOptions::New();
  1835. options->name = "";
  1836. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1837. net::CookieList cookies = sync_service_->GetAllForUrl(
  1838. kCookieURL, kMemberSiteForCookies, kMemberOrigin, std::move(options),
  1839. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1840. ASSERT_EQ(1u, cookies.size());
  1841. EXPECT_TRUE(cookies[0].IsPartitioned());
  1842. EXPECT_EQ(net::CookiePartitionKey::FromURLForTesting(kOwnerURL),
  1843. cookies[0].PartitionKey());
  1844. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1845. auto listener = CreateCookieChangeListener(
  1846. kCookieURL, kMemberSiteForCookies, kMemberOrigin);
  1847. // Update partitioned cookie Max-Age: None -> 7200.
  1848. service_->OverrideIsolationInfoForTesting(kOwnerIsolationInfo);
  1849. sync_service_->SetCookieFromString(
  1850. kCookieURL, kOwnerSiteForCookies, kOwnerOrigin,
  1851. "__Host-foo=0; Secure; SameSite=None; Path=/; Partitioned; "
  1852. "Max-Age: 3600",
  1853. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1854. listener->WaitForChange();
  1855. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(1));
  1856. }
  1857. // Set https://example.com cookie when the top-frame site is a member of
  1858. // the set.
  1859. service_->OverrideIsolationInfoForTesting(kMemberIsolationInfo);
  1860. sync_service_->SetCookieFromString(
  1861. kCookieURL, kMemberSiteForCookies, kMemberOrigin,
  1862. "__Host-bar=1; Secure; SameSite=None; Path=/; Partitioned",
  1863. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1864. {
  1865. // Check that the new cookie's partition key is the set's owner site.
  1866. auto options = mojom::CookieManagerGetOptions::New();
  1867. options->name = "";
  1868. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1869. net::CookieList cookies = sync_service_->GetAllForUrl(
  1870. kCookieURL, kMemberSiteForCookies, kMemberOrigin, std::move(options),
  1871. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1872. ASSERT_EQ(2u, cookies.size());
  1873. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1874. EXPECT_EQ("__Host-bar", cookies[1].Name());
  1875. for (const auto& cookie : cookies) {
  1876. EXPECT_TRUE(cookie.IsPartitioned());
  1877. EXPECT_EQ(net::CookiePartitionKey::FromURLForTesting(kOwnerURL),
  1878. cookie.PartitionKey());
  1879. }
  1880. }
  1881. {
  1882. // Check that the owner site can also access both cookies.
  1883. service_->OverrideIsolationInfoForTesting(kOwnerIsolationInfo);
  1884. auto options = mojom::CookieManagerGetOptions::New();
  1885. options->name = "";
  1886. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1887. net::CookieList cookies = sync_service_->GetAllForUrl(
  1888. kCookieURL, kOwnerSiteForCookies, kOwnerOrigin, std::move(options),
  1889. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1890. ASSERT_EQ(2u, cookies.size());
  1891. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1892. EXPECT_EQ("__Host-bar", cookies[1].Name());
  1893. }
  1894. {
  1895. // Check that the cookies are not available to https://example.com when the
  1896. // top-frame site is not a member of the set.
  1897. service_->OverrideIsolationInfoForTesting(kNonMemberIsolationInfo);
  1898. auto options = mojom::CookieManagerGetOptions::New();
  1899. options->name = "";
  1900. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1901. net::CookieList cookies = sync_service_->GetAllForUrl(
  1902. kCookieURL, kNonMemberSiteForCookies, kNonMemberOrigin,
  1903. std::move(options),
  1904. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1905. ASSERT_EQ(0u, cookies.size());
  1906. auto listener = CreateCookieChangeListener(
  1907. kCookieURL, kNonMemberSiteForCookies, kNonMemberOrigin);
  1908. // Set a new listener with the original IsolationInfo, we wait for this
  1909. // listener to receive an event to verify that the second listener was
  1910. // either called or skipped.
  1911. service_->OverrideIsolationInfoForTesting(kOwnerIsolationInfo);
  1912. auto second_listener = CreateCookieChangeListener(
  1913. kCookieURL, kOwnerSiteForCookies, kOwnerOrigin);
  1914. // Update partitioned cookie __Host-bar's Max-Age: None -> 3600.
  1915. service_->OverrideIsolationInfoForTesting(kOwnerIsolationInfo);
  1916. sync_service_->SetCookieFromString(
  1917. kCookieURL, kOwnerSiteForCookies, kOwnerOrigin,
  1918. "__Host-bar=1; Secure; SameSite=None; Path=/; Partitioned; "
  1919. "Max-Age: 3600",
  1920. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1921. // The listener set on the non-member top-frame site should not be able to
  1922. // observe the change.
  1923. second_listener->WaitForChange();
  1924. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  1925. }
  1926. }
  1927. TEST_P(PartitionedCookiesRestrictedCookieManagerTest, PartitionKeyWithNonce) {
  1928. const GURL kCookieURL("https://example.com");
  1929. const GURL kTopFrameURL("https://foo.com");
  1930. const net::SiteForCookies kSiteForCookies =
  1931. net::SiteForCookies::FromUrl(kTopFrameURL);
  1932. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  1933. const base::UnguessableToken kNonce = base::UnguessableToken::Create();
  1934. const absl::optional<std::set<net::SchemefulSite>> kPartyContextEmpty =
  1935. std::set<net::SchemefulSite>();
  1936. const net::IsolationInfo kNoncedIsolationInfo = net::IsolationInfo::Create(
  1937. net::IsolationInfo::RequestType::kMainFrame, kTopFrameOrigin,
  1938. kTopFrameOrigin, kSiteForCookies, kPartyContextEmpty, &kNonce);
  1939. const absl::optional<net::CookiePartitionKey> kNoncedPartitionKey =
  1940. net::CookiePartitionKey::FromNetworkIsolationKey(
  1941. net::NetworkIsolationKey(net::SchemefulSite(kTopFrameURL),
  1942. net::SchemefulSite(kTopFrameURL), &kNonce));
  1943. const net::IsolationInfo kUnnoncedIsolationInfo =
  1944. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  1945. service_->OverrideIsolationInfoForTesting(kNoncedIsolationInfo);
  1946. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  1947. *net::CanonicalCookie::Create(
  1948. kCookieURL, "__Host-foo=bar; Secure; SameSite=None; Path=/;",
  1949. base::Time::Now(), absl::nullopt /* server_time */,
  1950. net::CookiePartitionKey::FromScript()),
  1951. kCookieURL, kSiteForCookies, kTopFrameOrigin));
  1952. {
  1953. auto options = mojom::CookieManagerGetOptions::New();
  1954. options->name = "";
  1955. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1956. net::CookieList cookies = sync_service_->GetAllForUrl(
  1957. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  1958. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1959. ASSERT_EQ(1u, cookies.size());
  1960. EXPECT_TRUE(cookies[0].IsPartitioned());
  1961. EXPECT_EQ(cookies[0].PartitionKey().value(), kNoncedPartitionKey);
  1962. EXPECT_EQ("__Host-foo", cookies[0].Name());
  1963. }
  1964. { // Test that an unnonced partition cannot see the cookies or observe
  1965. // changes to them.
  1966. service_->OverrideIsolationInfoForTesting(kUnnoncedIsolationInfo);
  1967. auto options = mojom::CookieManagerGetOptions::New();
  1968. options->name = "";
  1969. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  1970. net::CookieList cookies = sync_service_->GetAllForUrl(
  1971. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  1972. /*partitioned_cookies_runtime_feature_enabled=*/true);
  1973. ASSERT_EQ(0u, cookies.size());
  1974. auto listener = CreateCookieChangeListener(kCookieURL, kSiteForCookies,
  1975. kTopFrameOrigin);
  1976. service_->OverrideIsolationInfoForTesting(kNoncedIsolationInfo);
  1977. auto second_listener = CreateCookieChangeListener(
  1978. kCookieURL, kSiteForCookies, kTopFrameOrigin);
  1979. // Update partitioned cookie Max-Age: None -> 7200.
  1980. EXPECT_TRUE(SetCanonicalCookie(
  1981. *net::CanonicalCookie::Create(
  1982. kCookieURL,
  1983. "__Host-foo=bar; Secure; SameSite=None; Path=/; Max-Age=7200",
  1984. base::Time::Now(), absl::nullopt /* server_time */,
  1985. kNoncedPartitionKey),
  1986. "https", false /* can_modify_httponly */));
  1987. second_listener->WaitForChange();
  1988. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  1989. }
  1990. { // Test that the nonced partition cannot observe changes to the unnonced
  1991. // partition and unpartitioned cookies.
  1992. // Set an unpartitioned cookie.
  1993. service_->OverrideIsolationInfoForTesting(kUnnoncedIsolationInfo);
  1994. EXPECT_TRUE(SetCanonicalCookie(
  1995. *net::CanonicalCookie::Create(
  1996. kCookieURL,
  1997. "__Host-unpartitioned=123; Secure; SameSite=None; Path=/;",
  1998. base::Time::Now(), absl::nullopt /* server_time */, absl::nullopt),
  1999. "https", false /* can_modify_httponly */));
  2000. // Set a partitioned cookie in the unnonced partition.
  2001. EXPECT_TRUE(sync_service_->SetCanonicalCookie(
  2002. *net::CanonicalCookie::Create(
  2003. kCookieURL,
  2004. "__Host-bar=baz; Secure; SameSite=None; Path=/; Partitioned;",
  2005. base::Time::Now(), absl::nullopt /* server_time */,
  2006. net::CookiePartitionKey::FromScript()),
  2007. kCookieURL, kSiteForCookies, kTopFrameOrigin));
  2008. service_->OverrideIsolationInfoForTesting(kNoncedIsolationInfo);
  2009. auto options = mojom::CookieManagerGetOptions::New();
  2010. options->name = "";
  2011. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2012. // Should only be able to see the nonced partitioned cookie only.
  2013. net::CookieList cookies = sync_service_->GetAllForUrl(
  2014. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2015. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2016. ASSERT_EQ(1u, cookies.size());
  2017. ASSERT_EQ("__Host-foo", cookies[0].Name());
  2018. // Create a listener in the nonced partition.
  2019. auto listener = CreateCookieChangeListener(kCookieURL, kSiteForCookies,
  2020. kTopFrameOrigin);
  2021. // Create a second listener in an unnonced partition.
  2022. service_->OverrideIsolationInfoForTesting(kUnnoncedIsolationInfo);
  2023. auto second_listener = CreateCookieChangeListener(
  2024. kCookieURL, kSiteForCookies, kTopFrameOrigin);
  2025. // Update unpartitioned cookie Max-Age: None -> 7200.
  2026. EXPECT_TRUE(SetCanonicalCookie(
  2027. *net::CanonicalCookie::Create(
  2028. kCookieURL,
  2029. "__Host-unpartitioned=123; Secure; SameSite=None; Path=/; "
  2030. "Max-Age=7200",
  2031. base::Time::Now(), absl::nullopt /* server_time */, absl::nullopt),
  2032. "https", false /* can_modify_httponly */));
  2033. // Test that the nonced partition cannot observe the change.
  2034. second_listener->WaitForChange();
  2035. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  2036. // Update unnonced partitioned cookie Max-Age: None -> 7200.
  2037. EXPECT_TRUE(SetCanonicalCookie(
  2038. *net::CanonicalCookie::Create(
  2039. kCookieURL,
  2040. "__Host-bar=baz; Secure; SameSite=None; Path=/; Partitioned; "
  2041. "Max-Age=7200",
  2042. base::Time::Now(), absl::nullopt /* server_time */, absl::nullopt),
  2043. "https", false /* can_modify_httponly */));
  2044. // Test that the nonced partition cannot observe the change.
  2045. second_listener->WaitForChange();
  2046. ASSERT_THAT(listener->observed_changes(), testing::SizeIs(0));
  2047. }
  2048. }
  2049. TEST_P(PartitionedCookiesRestrictedCookieManagerTest, RuntimeEnabledFeature) {
  2050. const GURL kCookieURL("https://example.com");
  2051. const GURL kTopFrameURL("https://sub.foo.com");
  2052. const net::SiteForCookies kSiteForCookies =
  2053. net::SiteForCookies::FromUrl(kTopFrameURL);
  2054. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  2055. const net::IsolationInfo kIsolationInfo =
  2056. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  2057. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  2058. // Setting a partitioned cookie when the RuntimeEnabledFeature is disabled
  2059. // should result in an unpartitioned cookie.
  2060. sync_service_->SetCookieFromString(
  2061. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  2062. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  2063. /*partitioned_cookies_runtime_feature_enabled=*/false);
  2064. auto options = mojom::CookieManagerGetOptions::New();
  2065. options->name = "";
  2066. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2067. net::CookieList cookies = sync_service_->GetAllForUrl(
  2068. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2069. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2070. ASSERT_EQ(1u, cookies.size());
  2071. EXPECT_EQ("__Host-foo", cookies[0].Name());
  2072. EXPECT_FALSE(cookies[0].IsPartitioned());
  2073. // Should be able to access both partitioned and unpartitioned cookie when the
  2074. // RuntimeEnabledFeature is on.
  2075. sync_service_->SetCookieFromString(
  2076. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  2077. "__Host-bar=baz; Secure; SameSite=None; Path=/; Partitioned",
  2078. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2079. options = mojom::CookieManagerGetOptions::New();
  2080. options->name = "";
  2081. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2082. cookies = sync_service_->GetAllForUrl(
  2083. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2084. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2085. ASSERT_EQ(2u, cookies.size());
  2086. EXPECT_FALSE(cookies[0].IsPartitioned());
  2087. EXPECT_TRUE(cookies[1].IsPartitioned());
  2088. // Should only be able to read the unpartitioned cookie when the feature is
  2089. // off.
  2090. options = mojom::CookieManagerGetOptions::New();
  2091. options->name = "";
  2092. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2093. cookies = sync_service_->GetAllForUrl(
  2094. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2095. /*partitioned_cookies_runtime_feature_enabled=*/false);
  2096. ASSERT_EQ(1u, cookies.size());
  2097. EXPECT_EQ("__Host-foo", cookies[0].Name());
  2098. }
  2099. TEST_P(PartitionedCookiesRestrictedCookieManagerTest,
  2100. RuntimeEnabledFeature_NoncedPartitionKey) {
  2101. const GURL kCookieURL("https://example.com");
  2102. const GURL kTopFrameURL("https://sub.foo.com");
  2103. const net::SiteForCookies kSiteForCookies =
  2104. net::SiteForCookies::FromUrl(kTopFrameURL);
  2105. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  2106. const base::UnguessableToken kNonce = base::UnguessableToken::Create();
  2107. const net::IsolationInfo kNoncedIsolationInfo = net::IsolationInfo::Create(
  2108. net::IsolationInfo::RequestType::kOther, kTopFrameOrigin, kTopFrameOrigin,
  2109. net::SiteForCookies::FromOrigin(kTopFrameOrigin),
  2110. /*party_context=*/std::set<net::SchemefulSite>(), &kNonce);
  2111. service_->OverrideIsolationInfoForTesting(kNoncedIsolationInfo);
  2112. // Should be able to set and read a partitioned cookie with a nonce when the
  2113. // runtime enabled feature is off.
  2114. sync_service_->SetCookieFromString(
  2115. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  2116. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  2117. /*partitioned_cookies_runtime_feature_enabled=*/false);
  2118. auto options = mojom::CookieManagerGetOptions::New();
  2119. options->name = "";
  2120. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2121. net::CookieList cookies = sync_service_->GetAllForUrl(
  2122. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2123. /*partitioned_cookies_runtime_feature_enabled=*/false);
  2124. ASSERT_EQ(1u, cookies.size());
  2125. EXPECT_EQ("__Host-foo", cookies[0].Name());
  2126. EXPECT_TRUE(cookies[0].IsPartitioned());
  2127. }
  2128. TEST_P(PartitionedCookiesRestrictedCookieManagerTest,
  2129. RuntimeEnabledFeature_BypassOriginTrial) {
  2130. base::test::ScopedFeatureList feature_list;
  2131. feature_list.InitWithFeatures(
  2132. {net::features::kPartitionedCookies,
  2133. net::features::kPartitionedCookiesBypassOriginTrial},
  2134. {});
  2135. const GURL kCookieURL("https://example.com");
  2136. const GURL kTopFrameURL("https://sub.foo.com");
  2137. const net::SiteForCookies kSiteForCookies =
  2138. net::SiteForCookies::FromUrl(kTopFrameURL);
  2139. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  2140. const net::IsolationInfo kIsolationInfo =
  2141. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  2142. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  2143. // Setting a partitioned cookie when the RuntimeEnabledFeature is disabled but
  2144. // the "bypass origin trial" feature is enabled should result in a partitioned
  2145. // cookie.
  2146. sync_service_->SetCookieFromString(
  2147. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  2148. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  2149. /*partitioned_cookies_runtime_feature_enabled=*/false);
  2150. auto options = mojom::CookieManagerGetOptions::New();
  2151. options->name = "";
  2152. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2153. auto cookies = sync_service_->GetAllForUrl(
  2154. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2155. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2156. ASSERT_EQ(1u, cookies.size());
  2157. EXPECT_TRUE(cookies[0].IsPartitioned());
  2158. }
  2159. TEST_P(PartitionedCookiesRestrictedCookieManagerTest,
  2160. ConvertPartitionedCookiesToUnpartitioned) {
  2161. const GURL kCookieURL("https://example.com");
  2162. const GURL kTopFrameURL("https://sub.foo.com");
  2163. const net::SiteForCookies kSiteForCookies =
  2164. net::SiteForCookies::FromUrl(kTopFrameURL);
  2165. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  2166. const net::IsolationInfo kIsolationInfo =
  2167. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  2168. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  2169. sync_service_->SetCookieFromString(
  2170. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  2171. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  2172. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2173. auto options = mojom::CookieManagerGetOptions::New();
  2174. options->name = "";
  2175. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2176. auto cookies = sync_service_->GetAllForUrl(
  2177. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2178. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2179. ASSERT_EQ(1u, cookies.size());
  2180. EXPECT_TRUE(cookies[0].IsPartitioned());
  2181. service_->ConvertPartitionedCookiesToUnpartitioned(kCookieURL);
  2182. // The partitioned cookie should now be unpartitioned.
  2183. options = mojom::CookieManagerGetOptions::New();
  2184. options->name = "";
  2185. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2186. cookies = sync_service_->GetAllForUrl(
  2187. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2188. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2189. ASSERT_EQ(1u, cookies.size());
  2190. EXPECT_FALSE(cookies[0].IsPartitioned());
  2191. }
  2192. TEST_P(PartitionedCookiesRestrictedCookieManagerTest,
  2193. ConvertPartitionedCookiesToUnpartitioned_BypassOriginTrial) {
  2194. base::test::ScopedFeatureList feature_list;
  2195. feature_list.InitWithFeatures(
  2196. {net::features::kPartitionedCookies,
  2197. net::features::kPartitionedCookiesBypassOriginTrial},
  2198. {});
  2199. const GURL kCookieURL("https://example.com");
  2200. const GURL kTopFrameURL("https://sub.foo.com");
  2201. const net::SiteForCookies kSiteForCookies =
  2202. net::SiteForCookies::FromUrl(kTopFrameURL);
  2203. const url::Origin kTopFrameOrigin = url::Origin::Create(kTopFrameURL);
  2204. const net::IsolationInfo kIsolationInfo =
  2205. net::IsolationInfo::CreateForInternalRequest(kTopFrameOrigin);
  2206. service_->OverrideIsolationInfoForTesting(kIsolationInfo);
  2207. sync_service_->SetCookieFromString(
  2208. kCookieURL, kSiteForCookies, kTopFrameOrigin,
  2209. "__Host-foo=bar; Secure; SameSite=None; Path=/; Partitioned",
  2210. /*partitioned_cookies_runtime_feature_enabled=*/false);
  2211. auto options = mojom::CookieManagerGetOptions::New();
  2212. options->name = "";
  2213. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2214. auto cookies = sync_service_->GetAllForUrl(
  2215. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2216. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2217. ASSERT_EQ(1u, cookies.size());
  2218. EXPECT_TRUE(cookies[0].IsPartitioned());
  2219. service_->ConvertPartitionedCookiesToUnpartitioned(kCookieURL);
  2220. // The partitioned cookie should remain partitioned if the origin trial bypass
  2221. // is enabled.
  2222. options = mojom::CookieManagerGetOptions::New();
  2223. options->name = "";
  2224. options->match_type = mojom::CookieMatchType::STARTS_WITH;
  2225. cookies = sync_service_->GetAllForUrl(
  2226. kCookieURL, kSiteForCookies, kTopFrameOrigin, std::move(options),
  2227. /*partitioned_cookies_runtime_feature_enabled=*/true);
  2228. ASSERT_EQ(1u, cookies.size());
  2229. EXPECT_TRUE(cookies[0].IsPartitioned());
  2230. }
  2231. INSTANTIATE_TEST_SUITE_P(
  2232. PartitionedCookies,
  2233. PartitionedCookiesRestrictedCookieManagerTest,
  2234. ::testing::Values(mojom::RestrictedCookieManagerRole::SCRIPT,
  2235. mojom::RestrictedCookieManagerRole::NETWORK));
  2236. } // namespace network