From 65d84573da3d4cd643122ea29fe38e2dc11f650f Mon Sep 17 00:00:00 2001 From: cfredric Date: Tue, 8 Dec 2020 23:38:58 +0000 Subject: [PATCH] Add FirstPartySet-querying methods to PreloadedFirstPartySets. These methods will be called in later CLs by the implementation of the SameParty attribute. Bug: 1143756 Change-Id: Id256e2a3971dccd4339f167516275a8dbcb46167 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2576110 Reviewed-by: Eric Orth Reviewed-by: Lily Chen Commit-Queue: Chris Fredrickson Cr-Commit-Position: refs/heads/master@{#834945} --- .../preloaded_first_party_sets.cc | 23 ++ .../preloaded_first_party_sets.h | 17 +- .../preloaded_first_party_sets_unittest.cc | 265 ++++++++++++++++++ 3 files changed, 303 insertions(+), 2 deletions(-) diff --git a/services/network/first_party_sets/preloaded_first_party_sets.cc b/services/network/first_party_sets/preloaded_first_party_sets.cc index f6f9df55cfe8c3..b740707165f471 100644 --- a/services/network/first_party_sets/preloaded_first_party_sets.cc +++ b/services/network/first_party_sets/preloaded_first_party_sets.cc @@ -79,6 +79,29 @@ PreloadedFirstPartySets::ParseAndSet(base::StringPiece raw_sets) { return &sets_; } +bool PreloadedFirstPartySets::IsContextSamePartyWithSite( + const net::SchemefulSite& site, + const net::SchemefulSite& top_frame_site, + const std::set& party_context) const { + const auto it = sets_.find(site); + if (it == sets_.end()) + return false; + const net::SchemefulSite& site_owner = it->second; + const auto is_owned_by_site_owner = + [this, &site_owner](const net::SchemefulSite& context_site) { + const auto context_owner = sets_.find(context_site); + return context_owner != sets_.end() && + context_owner->second == site_owner; + }; + return is_owned_by_site_owner(top_frame_site) && + base::ranges::all_of(party_context, is_owned_by_site_owner); +} + +bool PreloadedFirstPartySets::IsInNontrivialFirstPartySet( + const net::SchemefulSite& site) const { + return base::Contains(sets_, site); +} + void PreloadedFirstPartySets::ApplyManuallySpecifiedSet() { if (!manually_specified_set_) return; diff --git a/services/network/first_party_sets/preloaded_first_party_sets.h b/services/network/first_party_sets/preloaded_first_party_sets.h index fec0ff20e0bcc7..31a0174afe5c45 100644 --- a/services/network/first_party_sets/preloaded_first_party_sets.h +++ b/services/network/first_party_sets/preloaded_first_party_sets.h @@ -7,12 +7,11 @@ #include #include +#include -#include "base/callback.h" #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "net/base/schemeful_site.h" -#include "services/network/first_party_sets/first_party_set_parser.h" namespace network { @@ -40,6 +39,20 @@ class PreloadedFirstPartySets { base::flat_map* ParseAndSet( base::StringPiece raw_sets); + // Returns whether the `site` is same-party with the `party_context` and + // `top_frame_site`. That is, is the `site`'s owner the same as the owners of + // every member of `party_context` and of `top_frame_site`? Note: if `site` is + // not a member of a First-Party Set (with more than one member), then this + // returns false. + bool IsContextSamePartyWithSite( + const net::SchemefulSite& site, + const net::SchemefulSite& top_frame_site, + const std::set& party_context) const; + + // Returns whether the `site` is a member of a non-trivial (i.e. + // non-singleton) First-Party Set. + bool IsInNontrivialFirstPartySet(const net::SchemefulSite& site) const; + int64_t size() const { return sets_.size(); } private: diff --git a/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc b/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc index c9e399a9708746..75409623a46e17 100644 --- a/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc +++ b/services/network/first_party_sets/preloaded_first_party_sets_unittest.cc @@ -9,11 +9,14 @@ #include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" using ::testing::IsEmpty; +using ::testing::Not; using ::testing::Pair; using ::testing::Pointee; using ::testing::UnorderedElementsAre; +using ::testing::Value; // Some of these tests overlap with FirstPartySetParser unittests, but // overlapping test coverage isn't the worst thing. @@ -459,4 +462,266 @@ TEST(PreloadedFirstPartySets, SetsManuallySpecified_PrunesInducedSingletons) { SerializesTo("https://example.test"))))); } +class PreloadedFirstPartySetsTest : public ::testing::Test { + public: + PreloadedFirstPartySetsTest() { + const std::string input = R"( + [ + { + "owner": "https://example.test", + "members": ["https://member1.test", "https://member3.test"] + }, + { + "owner": "https://foo.test", + "members": ["https://member2.test"] + } + ] + )"; + CHECK(base::JSONReader::Read(input)); + + CHECK(Value( + sets().ParseAndSet(input), + Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member1.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member3.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://foo.test"), + SerializesTo("https://foo.test")), + Pair(SerializesTo("https://member2.test"), + SerializesTo("https://foo.test")))))); + } + + PreloadedFirstPartySets& sets() { return sets_; } + + protected: + PreloadedFirstPartySets sets_; +}; + +TEST_F(PreloadedFirstPartySetsTest, IsContextSamePartyWithSite_EmptyContext) { + net::SchemefulSite top_frame(GURL("https://example.test")); + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, {})); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, {})); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, {})); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://nonmember.test")), {})); + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), + net::SchemefulSite(GURL("https://example.test")), {})); +} + +TEST_F(PreloadedFirstPartySetsTest, + IsContextSamePartyWithSite_ContextIsNonmember) { + net::SchemefulSite top_frame(GURL("https://example.test")); + std::set context({ + net::SchemefulSite(GURL("https://nonmember.test")), + }); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member1.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://foo.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member2.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context)); +} + +TEST_F(PreloadedFirstPartySetsTest, IsContextSamePartyWithSite_ContextIsOwner) { + net::SchemefulSite top_frame(GURL("https://example.test")); + std::set context( + {net::SchemefulSite(GURL("https://example.test"))}); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, context)); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member1.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://foo.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member2.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context)); +} + +TEST_F(PreloadedFirstPartySetsTest, + IsContextSamePartyWithSite_ContextIsMember) { + net::SchemefulSite top_frame(GURL("https://example.test")); + std::set context( + {net::SchemefulSite(GURL("https://member1.test"))}); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, context)); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member1.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://foo.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member2.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context)); +} + +TEST_F(PreloadedFirstPartySetsTest, + IsContextSamePartyWithSite_ContextIsOwnerAndMember) { + net::SchemefulSite top_frame(GURL("https://example.test")); + std::set context({ + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + }); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, context)); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member1.test")), top_frame, context)); + + EXPECT_TRUE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member3.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://foo.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member2.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context)); +} + +TEST_F(PreloadedFirstPartySetsTest, + IsContextSamePartyWithSite_ContextMixesParties) { + net::SchemefulSite top_frame(GURL("https://example.test")); + std::set context({ + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("https://foo.test")), + }); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member1.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://foo.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member2.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context)); +} + +TEST_F(PreloadedFirstPartySetsTest, + IsContextSamePartyWithSite_ContextMixesMembersAndNonmembers) { + net::SchemefulSite top_frame(GURL("https://example.test")); + std::set context({ + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("http://nonmember.test")), + }); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member1.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://foo.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member2.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context)); +} + +TEST_F(PreloadedFirstPartySetsTest, + IsContextSamePartyWithSite_ContextMixesSchemes) { + net::SchemefulSite top_frame(GURL("https://example.test")); + std::set context({ + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("http://example.test")), + }); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("http://example.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member1.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://foo.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://member2.test")), top_frame, context)); + + EXPECT_FALSE(sets().IsContextSamePartyWithSite( + net::SchemefulSite(GURL("https://nonmember.test")), top_frame, context)); +} + +TEST_F(PreloadedFirstPartySetsTest, IsInNontrivialFirstPartySet) { + EXPECT_TRUE(sets().IsInNontrivialFirstPartySet( + net::SchemefulSite(GURL("https://example.test")))); + + EXPECT_FALSE(sets().IsInNontrivialFirstPartySet( + net::SchemefulSite(GURL("http://example.test")))); + + EXPECT_TRUE(sets().IsInNontrivialFirstPartySet( + net::SchemefulSite(GURL("https://member1.test")))); + + EXPECT_FALSE(sets().IsInNontrivialFirstPartySet( + net::SchemefulSite(GURL("https://nonmember.test")))); +} + } // namespace network