1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/test/bind.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_destroyer.h"
#include "components/content_settings/core/common/content_settings.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/test/extension_test_message_listener.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/default_handlers.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#if BUILDFLAG(IS_ANDROID)
#else
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/ui_test_utils.h"
#endif
namespace extensions {
using ContextType = extensions::browser_test_util::ContextType;
namespace {
enum class SameSiteCookieSemantics {
kModern,
kLegacy,
};
} // namespace
#if !BUILDFLAG(IS_ANDROID)
// This test cannot be run by a Service Worked-based extension
// because it uses the Document object.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ReadFromDocument) {
ASSERT_TRUE(RunExtensionTest("cookies/read_from_doc")) << message_;
}
#endif
class CookiesApiTest : public ExtensionApiTest,
public testing::WithParamInterface<
std::tuple<ContextType, SameSiteCookieSemantics>> {
public:
CookiesApiTest() : ExtensionApiTest(std::get<0>(GetParam())) {}
~CookiesApiTest() override = default;
CookiesApiTest(const CookiesApiTest&) = delete;
CookiesApiTest& operator=(const CookiesApiTest&) = delete;
void SetUpOnMainThread() override {
ExtensionApiTest::SetUpOnMainThread();
// If SameSite access semantics is "legacy", add content settings to allow
// legacy access for all sites.
if (!AreSameSiteCookieSemanticsModern()) {
profile()
->GetDefaultStoragePartition()
->GetNetworkContext()
->GetCookieManager(
cookie_manager_remote_.BindNewPipeAndPassReceiver());
cookie_manager_remote_->SetContentSettings(
ContentSettingsType::LEGACY_COOKIE_ACCESS,
{ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
base::Value(ContentSetting::CONTENT_SETTING_ALLOW),
content_settings::ProviderType::kNone, false /* incognito */)},
base::NullCallback());
cookie_manager_remote_.FlushForTesting();
}
net::test_server::RegisterDefaultHandlers(embedded_test_server());
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(StartEmbeddedTestServer());
}
protected:
bool RunTest(const char* extension_name,
bool allow_in_incognito = false,
const char* custom_arg = nullptr) {
return RunExtensionTest(extension_name, {.custom_arg = custom_arg},
{.allow_in_incognito = allow_in_incognito});
}
ContextType GetContextType() { return std::get<0>(GetParam()); }
bool AreSameSiteCookieSemanticsModern() {
return std::get<1>(GetParam()) == SameSiteCookieSemantics::kModern;
}
private:
mojo::Remote<network::mojom::CookieManager> cookie_manager_remote_;
};
// Android extension API tests only support service worker.
#if !BUILDFLAG(IS_ANDROID)
INSTANTIATE_TEST_SUITE_P(
EventPage,
CookiesApiTest,
::testing::Combine(::testing::Values(ContextType::kEventPage),
::testing::Values(SameSiteCookieSemantics::kLegacy,
SameSiteCookieSemantics::kModern)));
#endif
INSTANTIATE_TEST_SUITE_P(
ServiceWorker,
CookiesApiTest,
::testing::Combine(::testing::Values(ContextType::kServiceWorker),
::testing::Values(SameSiteCookieSemantics::kLegacy,
SameSiteCookieSemantics::kModern)));
#if !BUILDFLAG(IS_ANDROID)
// A test suite that only runs with MV3 extensions.
using CookiesApiMV3Test = CookiesApiTest;
INSTANTIATE_TEST_SUITE_P(
ServiceWorker,
CookiesApiMV3Test,
::testing::Combine(::testing::Values(ContextType::kServiceWorker),
::testing::Values(SameSiteCookieSemantics::kLegacy,
SameSiteCookieSemantics::kModern)));
#endif
// TODO(crbug.com/40839864): Flaky on Windows.
// TODO(crbug.com/371423073): Flaky on desktop Android.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
#define MAYBE_Cookies DISABLED_Cookies
#else
#define MAYBE_Cookies Cookies
#endif
IN_PROC_BROWSER_TEST_P(CookiesApiTest, MAYBE_Cookies) {
ASSERT_TRUE(RunTest("cookies/api", /*allow_in_incognito=*/false,
AreSameSiteCookieSemanticsModern() ? "true" : "false"))
<< message_;
}
IN_PROC_BROWSER_TEST_P(CookiesApiTest, CookiesEvents) {
ASSERT_TRUE(RunTest("cookies/events")) << message_;
}
IN_PROC_BROWSER_TEST_P(CookiesApiTest, CookiesNoPermission) {
ASSERT_TRUE(RunTest("cookies/no_permission")) << message_;
}
IN_PROC_BROWSER_TEST_P(CookiesApiTest, CookiesEventsSpanningAsync) {
// This version of the test creates the OTR page *after* the JavaScript test
// code has registered the cookie listener. This tests the cookie API code
// that listens for the new profile creation.
//
// The test sends us message with the string "listening" once it's registered
// its listener. We force a reply to synchronize with the JS so the test
// always runs the same way.
ExtensionTestMessageListener listener("listening", ReplyBehavior::kWillReply);
listener.SetOnSatisfied(
base::BindLambdaForTesting([this, &listener](const std::string&) {
PlatformOpenURLOffTheRecord(profile(), GURL("chrome://newtab/"));
listener.Reply("ok");
}));
ASSERT_TRUE(RunTest("cookies/events_spanning",
/*allow_in_incognito=*/true))
<< message_;
}
IN_PROC_BROWSER_TEST_P(CookiesApiTest, CookiesEventsObservePrimaryOTROnly) {
// In addition to above, this test makes sure that CookiesEventRouter
// does not observe a non-primary OTR profile, which leads to CHECK
// failure (crbug.com/6527130).
ExtensionTestMessageListener listener("listening", ReplyBehavior::kWillReply);
listener.SetOnSatisfied(
base::BindLambdaForTesting([this, &listener](const std::string&) {
PlatformOpenURLOffTheRecord(profile(), GURL("chrome://newtab/"));
listener.Reply("ok");
}));
ASSERT_TRUE(RunTest("cookies/events_spanning",
/*allow_in_incognito=*/true))
<< message_;
{
auto* second_profile = profile()->GetOffTheRecordProfile(
Profile::OTRProfileID::CreateUniqueForTesting(),
/*create_if_needed=*/true);
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(second_profile);
}
}
#if !BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/371423073): Enable this test on desktop android.
IN_PROC_BROWSER_TEST_P(CookiesApiTest, CookiesEventsSpanning) {
// We need to initialize an incognito mode window in order have an initialized
// incognito cookie store. Otherwise, the chrome.cookies.set operation is just
// ignored and we won't be notified about a newly set cookie for which we want
// to test whether the storeId is set correctly.
PlatformOpenURLOffTheRecord(profile(), GURL("chrome://newtab/"));
ASSERT_TRUE(RunTest("cookies/events_spanning",
/*allow_in_incognito=*/true))
<< message_;
}
// TODO(crbug.com/371423073): Enable this test on desktop android after the
// tabs and webNavigation APIs are enabled.
IN_PROC_BROWSER_TEST_P(CookiesApiMV3Test, TestGetPartitionKey) {
// Before running test, set up a top-level site (a.com) that embeds a
// cross-site (b.com). To test the cookies.getPartitionKey() api.
const std::string default_response = "/defaultresponse";
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("a.com", default_response)));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
// Inject two iframes and navigate one to a cross-site with host permissions
// (b.com) and the other to a cross-site (c.com) with no host permissions.
const GURL cross_site_url =
embedded_test_server()->GetURL("b.com", default_response);
const GURL no_host_permissions_url =
embedded_test_server()->GetURL("c.com", default_response);
std::string script =
"var f = document.createElement('iframe');\n"
"f.src = '" +
cross_site_url.spec() +
"';\n"
"document.body.appendChild(f);\n"
"var noHostFrame = document.createElement('iframe');\n"
"noHostFrame.src = '" +
no_host_permissions_url.spec() +
"';\n"
"document.body.appendChild(noHostFrame);\n";
EXPECT_TRUE(ExecJs(contents, script));
EXPECT_TRUE(WaitForLoadStop(contents));
ASSERT_TRUE(RunTest("cookies/get_partition_key")) << message_;
}
#endif // !BUILDFLAG(IS_ANDROID)
} // namespace extensions
|