first_party_sets_access_delegate_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. // Copyright 2022 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/first_party_sets/first_party_sets_access_delegate.h"
  5. #include <set>
  6. #include <string>
  7. #include "base/containers/flat_set.h"
  8. #include "base/test/task_environment.h"
  9. #include "base/test/test_future.h"
  10. #include "mojo/public/cpp/bindings/pending_receiver.h"
  11. #include "mojo/public/cpp/bindings/receiver.h"
  12. #include "mojo/public/cpp/bindings/remote.h"
  13. #include "net/base/schemeful_site.h"
  14. #include "net/cookies/first_party_set_entry.h"
  15. #include "net/cookies/first_party_set_metadata.h"
  16. #include "net/cookies/same_party_context.h"
  17. #include "services/network/public/mojom/first_party_sets.mojom.h"
  18. #include "services/network/public/mojom/first_party_sets_access_delegate.mojom.h"
  19. #include "testing/gmock/include/gmock/gmock-matchers.h"
  20. #include "testing/gmock/include/gmock/gmock.h"
  21. #include "testing/gtest/include/gtest/gtest.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. #include "url/gurl.h"
  24. using ::testing::_;
  25. using ::testing::IsEmpty;
  26. using ::testing::Optional;
  27. using ::testing::Pair;
  28. using ::testing::UnorderedElementsAre;
  29. using Type = net::SamePartyContext::Type;
  30. using OverrideSets =
  31. base::flat_map<net::SchemefulSite, absl::optional<net::FirstPartySetEntry>>;
  32. namespace network {
  33. namespace {
  34. const net::SchemefulSite kSet1Owner(GURL("https://set1owner.test"));
  35. const net::SchemefulSite kSet1Member1(GURL("https://set1member1.test"));
  36. const net::SchemefulSite kSet1Member2(GURL("https://set1member2.test"));
  37. const net::SchemefulSite kSet2Owner(GURL("https://set2owner.test"));
  38. const net::SchemefulSite kSet2Member1(GURL("https://set2member1.test"));
  39. const net::SchemefulSite kSet3Owner(GURL("https://set3owner.test"));
  40. const net::SchemefulSite kSet3Member1(GURL("https://set3member1.test"));
  41. mojom::FirstPartySetsAccessDelegateParamsPtr
  42. CreateFirstPartySetsAccessDelegateParams(bool enabled) {
  43. auto params = mojom::FirstPartySetsAccessDelegateParams::New();
  44. params->enabled = enabled;
  45. return params;
  46. }
  47. mojom::FirstPartySetsReadyEventPtr CreateFirstPartySetsReadyEvent(
  48. OverrideSets override_sets) {
  49. auto ready_event = mojom::FirstPartySetsReadyEvent::New();
  50. ready_event->customizations = std::move(override_sets);
  51. return ready_event;
  52. }
  53. mojom::PublicFirstPartySetsPtr CreatePublicFirstPartySets(
  54. FirstPartySetsAccessDelegate::FlattenedSets sets) {
  55. mojom::PublicFirstPartySetsPtr public_sets =
  56. mojom::PublicFirstPartySets::New();
  57. public_sets->sets = sets;
  58. return public_sets;
  59. }
  60. } // namespace
  61. // No-op FirstPartySetsAccessDelegate should just pass queries to
  62. // FirstPartySetsManager synchronously.
  63. class NoopFirstPartySetsAccessDelegateTest : public ::testing::Test {
  64. public:
  65. NoopFirstPartySetsAccessDelegateTest()
  66. : first_party_sets_manager_(/*enabled=*/true),
  67. delegate_(
  68. /*receiver=*/mojo::NullReceiver(),
  69. /*params=*/nullptr,
  70. &first_party_sets_manager_) {
  71. first_party_sets_manager_.SetCompleteSets(CreatePublicFirstPartySets({
  72. {kSet1Member1,
  73. net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)},
  74. {kSet1Member2,
  75. net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 1)},
  76. {kSet1Owner, net::FirstPartySetEntry(
  77. kSet1Owner, net::SiteType::kPrimary, absl::nullopt)},
  78. {kSet2Member1,
  79. net::FirstPartySetEntry(kSet2Owner, net::SiteType::kAssociated, 0)},
  80. {kSet2Owner, net::FirstPartySetEntry(
  81. kSet2Owner, net::SiteType::kPrimary, absl::nullopt)},
  82. }));
  83. }
  84. FirstPartySetsAccessDelegate& delegate() { return delegate_; }
  85. private:
  86. FirstPartySetsManager first_party_sets_manager_;
  87. FirstPartySetsAccessDelegate delegate_;
  88. };
  89. TEST_F(NoopFirstPartySetsAccessDelegateTest, IsEnabled) {
  90. EXPECT_TRUE(delegate().is_enabled());
  91. }
  92. TEST_F(NoopFirstPartySetsAccessDelegateTest, ComputeMetadata) {
  93. EXPECT_THAT(
  94. delegate()
  95. .ComputeMetadata(kSet1Member1, &kSet1Owner,
  96. {kSet1Member1, kSet1Owner}, base::NullCallback())
  97. ->context(),
  98. net::SamePartyContext(Type::kSameParty));
  99. }
  100. TEST_F(NoopFirstPartySetsAccessDelegateTest, FindOwners) {
  101. EXPECT_THAT(
  102. delegate().FindOwners({kSet1Member1, kSet2Member1}, base::NullCallback()),
  103. FirstPartySetsAccessDelegate::OwnersResult({
  104. {kSet1Member1,
  105. net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)},
  106. {kSet2Member1,
  107. net::FirstPartySetEntry(kSet2Owner, net::SiteType::kAssociated, 0)},
  108. }));
  109. }
  110. class FirstPartySetsAccessDelegateTest : public ::testing::Test {
  111. public:
  112. explicit FirstPartySetsAccessDelegateTest(bool enabled)
  113. : first_party_sets_manager_(/*enabled=*/true),
  114. delegate_(delegate_remote_.BindNewPipeAndPassReceiver(),
  115. CreateFirstPartySetsAccessDelegateParams(enabled),
  116. &first_party_sets_manager_) {
  117. first_party_sets_manager_.SetCompleteSets(CreatePublicFirstPartySets({
  118. {kSet1Member1,
  119. net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)},
  120. {kSet1Member2,
  121. net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 1)},
  122. {kSet1Owner, net::FirstPartySetEntry(
  123. kSet1Owner, net::SiteType::kPrimary, absl::nullopt)},
  124. {kSet2Member1,
  125. net::FirstPartySetEntry(kSet2Owner, net::SiteType::kAssociated, 0)},
  126. {kSet2Owner, net::FirstPartySetEntry(
  127. kSet2Owner, net::SiteType::kPrimary, absl::nullopt)},
  128. }));
  129. }
  130. net::FirstPartySetMetadata ComputeMetadataAndWait(
  131. const net::SchemefulSite& site,
  132. const net::SchemefulSite* top_frame_site,
  133. const std::set<net::SchemefulSite>& party_context) {
  134. base::test::TestFuture<net::FirstPartySetMetadata> future;
  135. absl::optional<net::FirstPartySetMetadata> result =
  136. delegate_.ComputeMetadata(site, top_frame_site, party_context,
  137. future.GetCallback());
  138. return result.has_value() ? std::move(result).value() : future.Take();
  139. }
  140. FirstPartySetsAccessDelegate::OwnersResult FindOwnersAndWait(
  141. const base::flat_set<net::SchemefulSite>& site) {
  142. base::test::TestFuture<FirstPartySetsAccessDelegate::OwnersResult> future;
  143. absl::optional<FirstPartySetsAccessDelegate::OwnersResult> result =
  144. delegate_.FindOwners(site, future.GetCallback());
  145. return result.has_value() ? result.value() : future.Get();
  146. }
  147. FirstPartySetsAccessDelegate& delegate() { return delegate_; }
  148. mojom::FirstPartySetsAccessDelegate* delegate_remote() {
  149. return delegate_remote_.get();
  150. }
  151. private:
  152. base::test::TaskEnvironment env_;
  153. FirstPartySetsManager first_party_sets_manager_;
  154. mojo::Remote<mojom::FirstPartySetsAccessDelegate> delegate_remote_;
  155. FirstPartySetsAccessDelegate delegate_;
  156. };
  157. // Since the FPSs is disabled for the context, none of the callbacks
  158. // should ever be called, and the return values should all be non-nullopt.
  159. class FirstPartySetsAccessDelegateDisabledTest
  160. : public FirstPartySetsAccessDelegateTest {
  161. public:
  162. FirstPartySetsAccessDelegateDisabledTest()
  163. : FirstPartySetsAccessDelegateTest(false) {}
  164. };
  165. TEST_F(FirstPartySetsAccessDelegateDisabledTest, ComputeMetadata) {
  166. // Same as the default ctor, but just to be explicit:
  167. net::FirstPartySetMetadata expected_metadata(net::SamePartyContext(),
  168. /*frame_entry=*/nullptr,
  169. /*top_frame_entry=*/nullptr);
  170. EXPECT_THAT(delegate().ComputeMetadata(
  171. kSet1Member1, &kSet1Member1, {kSet1Member1, kSet1Owner},
  172. base::BindOnce([](net::FirstPartySetMetadata) { FAIL(); })),
  173. Optional(std::ref(expected_metadata)));
  174. }
  175. TEST_F(FirstPartySetsAccessDelegateDisabledTest, FindOwners) {
  176. EXPECT_THAT(
  177. delegate().FindOwners(
  178. {kSet1Member1, kSet2Member1},
  179. base::BindOnce([](FirstPartySetsManager::OwnersResult) { FAIL(); })),
  180. Optional(IsEmpty()));
  181. }
  182. // Test fixture that allows precise control over when the instance gets FPS
  183. // data. Useful for testing async flows.
  184. class AsyncFirstPartySetsAccessDelegateTest
  185. : public FirstPartySetsAccessDelegateTest {
  186. public:
  187. AsyncFirstPartySetsAccessDelegateTest()
  188. : FirstPartySetsAccessDelegateTest(true) {}
  189. };
  190. TEST_F(AsyncFirstPartySetsAccessDelegateTest,
  191. QueryBeforeReady_ComputeMetadata) {
  192. base::test::TestFuture<net::FirstPartySetMetadata> future;
  193. {
  194. // Force deallocation to provoke a UAF if the impl just copies the pointer.
  195. net::SchemefulSite local_member1(kSet1Member1);
  196. EXPECT_FALSE(delegate().ComputeMetadata(
  197. kSet1Member1, &local_member1, {kSet1Member1}, future.GetCallback()));
  198. }
  199. delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New());
  200. net::FirstPartySetEntry entry(kSet1Owner, net::SiteType::kAssociated, 0);
  201. EXPECT_EQ(future.Get(),
  202. net::FirstPartySetMetadata(net::SamePartyContext(Type::kSameParty),
  203. &entry, &entry));
  204. }
  205. TEST_F(AsyncFirstPartySetsAccessDelegateTest, QueryBeforeReady_FindOwners) {
  206. base::test::TestFuture<FirstPartySetsAccessDelegate::OwnersResult> future;
  207. EXPECT_FALSE(delegate().FindOwners({kSet1Member1, kSet2Member1},
  208. future.GetCallback()));
  209. delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New());
  210. EXPECT_THAT(
  211. future.Get(),
  212. FirstPartySetsAccessDelegate::OwnersResult({
  213. {kSet1Member1,
  214. net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)},
  215. {kSet2Member1,
  216. net::FirstPartySetEntry(kSet2Owner, net::SiteType::kAssociated, 0)},
  217. }));
  218. }
  219. TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_ComputeMetadata) {
  220. delegate_remote()->NotifyReady(CreateFirstPartySetsReadyEvent({
  221. {kSet1Member1,
  222. {net::FirstPartySetEntry(kSet3Owner, net::SiteType::kAssociated, 0)}},
  223. {kSet3Owner,
  224. {net::FirstPartySetEntry(kSet3Owner, net::SiteType::kPrimary,
  225. absl::nullopt)}},
  226. }));
  227. net::FirstPartySetEntry primary_entry(kSet3Owner, net::SiteType::kPrimary,
  228. absl::nullopt);
  229. net::FirstPartySetEntry associated_entry(kSet3Owner,
  230. net::SiteType::kAssociated, 0);
  231. EXPECT_EQ(ComputeMetadataAndWait(kSet3Owner, &kSet1Member1, {kSet1Member1}),
  232. net::FirstPartySetMetadata(net::SamePartyContext(Type::kSameParty),
  233. &primary_entry, &associated_entry));
  234. }
  235. TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_FindOwners) {
  236. delegate_remote()->NotifyReady(CreateFirstPartySetsReadyEvent({
  237. {kSet3Owner,
  238. {net::FirstPartySetEntry(kSet3Owner, net::SiteType::kPrimary,
  239. absl::nullopt)}},
  240. }));
  241. EXPECT_THAT(FindOwnersAndWait({kSet3Owner}),
  242. UnorderedElementsAre(Pair(kSet3Owner, _)));
  243. }
  244. class SyncFirstPartySetsAccessDelegateTest
  245. : public AsyncFirstPartySetsAccessDelegateTest {
  246. public:
  247. SyncFirstPartySetsAccessDelegateTest() {
  248. delegate_remote()->NotifyReady(CreateFirstPartySetsReadyEvent({
  249. {kSet3Member1,
  250. {net::FirstPartySetEntry(kSet3Owner, net::SiteType::kAssociated, 0)}},
  251. {kSet3Owner,
  252. {net::FirstPartySetEntry(kSet3Owner, net::SiteType::kPrimary,
  253. absl::nullopt)}},
  254. }));
  255. }
  256. };
  257. TEST_F(SyncFirstPartySetsAccessDelegateTest, ComputeMetadata) {
  258. net::FirstPartySetEntry entry(kSet1Owner, net::SiteType::kAssociated, 0);
  259. EXPECT_EQ(ComputeMetadataAndWait(kSet1Member1, &kSet1Member1, {kSet1Member1}),
  260. net::FirstPartySetMetadata(net::SamePartyContext(Type::kSameParty),
  261. &entry, &entry));
  262. }
  263. TEST_F(SyncFirstPartySetsAccessDelegateTest, FindOwners) {
  264. EXPECT_THAT(
  265. FindOwnersAndWait({kSet1Member1, kSet2Member1, kSet3Member1}),
  266. FirstPartySetsAccessDelegate::OwnersResult({
  267. {kSet1Member1,
  268. net::FirstPartySetEntry(kSet1Owner, net::SiteType::kAssociated, 0)},
  269. {kSet2Member1,
  270. net::FirstPartySetEntry(kSet2Owner, net::SiteType::kAssociated, 0)},
  271. {kSet3Member1,
  272. net::FirstPartySetEntry(kSet3Owner, net::SiteType::kAssociated, 0)},
  273. }));
  274. }
  275. } // namespace network