blob: 97b61b54ffb2d0070cd3013914d50683a0c5fa2b [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/signin/core/browser/consistency_cookie_manager_base.h"
#include <memory>
#include <string>
#include <utility>
#include "base/callback.h"
#include "base/run_loop.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/account_reconcilor_factory.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/browser/ssl/cert_verifier_browser_test.h"
#include "chrome/browser/ssl/chrome_mock_cert_verifier.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/signin/core/browser/consistency_cookie_manager_base.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "google_apis/gaia/gaia_switches.h"
#include "google_apis/gaia/gaia_urls.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "net/cookies/canonical_cookie.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/default_handlers.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
const char kConsistencyCookieName[] = "CHROME_ID_CONSISTENCY_STATE";
// Subclass of ConsistencyCookieManagerBase allowing to manually control the
// value of the cookie.
class TestConsistencyCookieManager
: public signin::ConsistencyCookieManagerBase,
public network::mojom::CookieChangeListener {
public:
TestConsistencyCookieManager(SigninClient* client,
AccountReconcilor* reconcilor)
: signin::ConsistencyCookieManagerBase(client, reconcilor),
cookie_listener_binding_(this) {
// Listen to cookie changes.
network::mojom::CookieChangeListenerPtr listener_ptr;
cookie_listener_binding_.Bind(mojo::MakeRequest(&listener_ptr));
client->GetCookieManager()->AddCookieChangeListener(
GaiaUrls::GetInstance()->gaia_url(), kConsistencyCookieName,
std::move(listener_ptr));
// Subclasses have to call UpdateCookie() in the constructor.
UpdateCookie();
// Wait for the initial cookie to be set.
WaitForCookieChange();
}
// Sets a new value for the consistency cookie.
void SetValue(const std::string& value) {
value_ = value;
UpdateCookie();
WaitForCookieChange();
}
private:
// Waits until OnCookieChange is called.
void WaitForCookieChange() {
base::RunLoop loop;
run_loop_quit_closure_ = loop.QuitClosure();
loop.Run();
}
// CookieChangeListener:
void OnCookieChange(const net::CanonicalCookie& cookie,
network::mojom::CookieChangeCause cause) override {
ASSERT_EQ(kConsistencyCookieName, cookie.Name());
if (!run_loop_quit_closure_.is_null())
std::move(run_loop_quit_closure_).Run();
}
// ConsistencyCookieManagerBase:
std::string CalculateCookieValue() override { return value_; }
std::string value_ = "initial_value";
mojo::Binding<network::mojom::CookieChangeListener> cookie_listener_binding_;
base::OnceClosure run_loop_quit_closure_;
};
} // namespace
class ConsistencyCookieBrowserTest : public CertVerifierBrowserTest {
public:
ConsistencyCookieBrowserTest()
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
net::test_server::RegisterDefaultHandlers(&https_server_);
}
~ConsistencyCookieBrowserTest() override {}
// Updates the cookie through the consistency cookie manager and blocks until
// it completes.
void SetCookieValue(const std::string& cookie_value) {
consistency_cookie_manager_->SetValue(cookie_value);
}
// Checks the cookie both in HTTP and javascript.
void CheckCookieValue(const std::string& expected_cookie) {
// Check that the cookie is set in HTTP.
ui_test_utils::NavigateToURL(
browser(),
https_server_.GetURL(GaiaUrls::GetInstance()->gaia_url().host(),
"/echoheader?Cookie"));
std::string http_cookie =
content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
"document.body.innerText")
.ExtractString();
EXPECT_EQ(expected_cookie, http_cookie);
// Check that the cookie is available in javascript.
std::string javascript_cookie =
content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
"document.cookie")
.ExtractString();
EXPECT_EQ(expected_cookie, javascript_cookie);
}
private:
// CertVerifierBrowserTest:
void SetUp() override {
ASSERT_TRUE(https_server_.InitializeAndListen());
CertVerifierBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
CertVerifierBrowserTest::SetUpOnMainThread();
// Configure the embedded test server.
// DNS rule for the Gaia URL.
host_resolver()->AddRule(GaiaUrls::GetInstance()->gaia_url().host(),
https_server_.base_url().host());
// Whitelist all certs for the HTTPS server to prevent SSL errors.
auto cert = https_server_.GetCertificate();
net::CertVerifyResult verify_result;
verify_result.cert_status = 0;
verify_result.is_issued_by_known_root = true;
verify_result.verified_cert = cert;
mock_cert_verifier()->AddResultForCert(cert.get(), verify_result, net::OK);
// Start the server.
https_server_.StartAcceptingConnections();
Profile* profile = browser()->profile();
// Setup the CookieConsistencyCookieManager
AccountReconcilor* reconcilor =
AccountReconcilorFactory::GetForProfile(profile);
std::unique_ptr<TestConsistencyCookieManager> consistency_cookie_manager =
std::make_unique<TestConsistencyCookieManager>(
ChromeSigninClientFactory::GetForProfile(profile), reconcilor);
consistency_cookie_manager_ = consistency_cookie_manager.get();
reconcilor->SetConsistencyCookieManager(
std::move(consistency_cookie_manager));
}
net::EmbeddedTestServer https_server_;
TestConsistencyCookieManager* consistency_cookie_manager_;
};
// Tests that the ConsistencyCookieManager can set and change the cookie in HTTP
// and javascript.
IN_PROC_BROWSER_TEST_F(ConsistencyCookieBrowserTest, Basic) {
// Check the initial value.
CheckCookieValue(std::string(kConsistencyCookieName) + "=initial_value");
// Change the cookie.
SetCookieValue("new_value");
CheckCookieValue(std::string(kConsistencyCookieName) + "=new_value");
}