Commit 0f741288 authored by Mihai Sardarescu's avatar Mihai Sardarescu Committed by Commit Bot

Update the CHROME_CONNECTED cookie using the cookie manager API.

This CL removes the hack to write the CHROME_CONNECTED cookie using
a WKWebView and instead uses the cookie manager API. This works well
as the Chrome iOS cookie manager is now backed by the WKHTTPCookieStore.

Bug: 1102794

Change-Id: Ida2d74372616ce8331eadbde507fb131e4afa0ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2323901
Commit-Queue: Mihai Sardarescu <msarda@chromium.org>
Reviewed-by: default avatarNohemi Fernandez <fernandex@chromium.org>
Cr-Commit-Position: refs/heads/master@{#794243}
parent e769f1ea
......@@ -19,6 +19,7 @@
#include "components/signin/ios/browser/active_state_manager.h"
#import "components/signin/ios/browser/manage_accounts_delegate.h"
#import "components/signin/public/identity_manager/identity_manager.h"
#include "net/cookies/cookie_access_result.h"
namespace content_settings {
class CookieSettings;
......@@ -33,18 +34,18 @@ class WebStatePolicyDecider;
class AccountReconcilor;
class PrefService;
@class AccountConsistencyNavigationDelegate;
@class WKWebView;
// Handles actions necessary for Account Consistency to work on iOS. This
// includes setting the Account Consistency cookie (informing Gaia that the
// Account Consistency is on).
//
// This is currently only used when WKWebView is enabled.
class AccountConsistencyService : public KeyedService,
public signin::IdentityManager::Observer,
public ActiveStateManager::Observer {
public:
// Name of the cookie that is managed by AccountConsistencyService and is used
// to inform Google web properties that the browser is connected and that
// Google authentication cookies are managed by |AccountReconcilor|).
static const char kChromeConnectedCookieName[];
// Name of the preference property that persists the domains that have a
// CHROME_CONNECTED cookie set by this service.
static const char kDomainsWithCookiePref[];
......@@ -125,17 +126,11 @@ class AccountConsistencyService : public KeyedService,
// Applies the pending CHROME_CONNECTED cookie requests one by one.
void ApplyCookieRequests();
void FinishedSetCookie(net::CookieAccessResult cookie_access_result);
// Called when the current CHROME_CONNECTED cookie request is done.
void FinishedApplyingCookieRequest(bool success);
// Returns the cached WKWebView if it exists, or creates one if necessary.
// Can return nil if the browser state is not active.
WKWebView* GetWKWebView();
// Actually creates a WKWebView. Virtual for testing.
virtual WKWebView* BuildWKWebView();
// Stops any page loading in the WKWebView currently in use and releases it.
void ResetWKWebView();
// Returns whether the CHROME_CONNECTED cookie should be added to |domain|.
// If the cookie is already on |domain|, this function will return false
// unless |force_update_if_too_old| is true. In this case, it will return true
......@@ -156,9 +151,8 @@ class AccountConsistencyService : public KeyedService,
// ActiveStateManager::Observer implementation.
void OnActive() override;
void OnInactive() override;
// Browser state associated with the service, used to create WKWebViews.
// Browser state associated with the service.
web::BrowserState* browser_state_;
// Used to update kDomainsWithCookiePref.
PrefService* prefs_;
......@@ -180,12 +174,6 @@ class AccountConsistencyService : public KeyedService,
// the time when the cookie was last updated.
std::map<std::string, base::Time> last_cookie_update_map_;
// Web view used to apply the CHROME_CONNECTED cookie requests.
__strong WKWebView* web_view_;
// Navigation delegate of |web_view_| that informs the service when a cookie
// request has been applied.
AccountConsistencyNavigationDelegate* navigation_delegate_;
// Handlers reacting on GAIA responses with the X-Chrome-Manage-Accounts
// header set.
std::map<web::WebState*, std::unique_ptr<web::WebStatePolicyDecider>>
......
......@@ -37,17 +37,6 @@ namespace {
// should be added again on a domain it was previously set.
const int kHoursThresholdToReAddCookie = 24;
// JavaScript template used to set (or delete) the CHROME_CONNECTED cookie.
// It takes 3 arguments: the domain of the cookie, its value and its expiration
// date. It also clears the legacy X-CHROME-CONNECTED cookie.
NSString* const kChromeConnectedCookieTemplate =
@"<html><script>domain=\"%@\";"
"document.cookie=\"X-CHROME-CONNECTED=; path=/; domain=\" + domain + \";"
" expires=Thu, 01-Jan-1970 00:00:01 GMT\";"
"document.cookie=\"CHROME_CONNECTED=%@; path=/; domain=\" + domain + \";"
" expires=\" + new Date(%f).toGMTString() + \"; secure;"
" samesite=lax;\"</script></html>";
// WebStatePolicyDecider that monitors the HTTP headers on Gaia responses,
// reacting on the X-Chrome-Manage-Accounts header and notifying its delegate.
// It also notifies the AccountConsistencyService of domains it should add the
......@@ -158,45 +147,8 @@ void AccountConsistencyHandler::WebStateDestroyed() {
account_consistency_service_->RemoveWebStateHandler(web_state());
}
// WKWebView navigation delegate that calls its callback every time a navigation
// has finished.
@interface AccountConsistencyNavigationDelegate : NSObject<WKNavigationDelegate>
// Designated initializer. |callback| will be called every time a navigation has
// finished. |callback| must not be empty.
- (instancetype)initWithCallback:(const base::RepeatingClosure&)callback
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
@implementation AccountConsistencyNavigationDelegate {
// Callback that will be called every time a navigation has finished.
base::RepeatingClosure _callback;
}
- (instancetype)initWithCallback:(const base::RepeatingClosure&)callback {
self = [super init];
if (self) {
DCHECK(!callback.is_null());
_callback = callback;
}
return self;
}
- (instancetype)init {
NOTREACHED();
return nil;
}
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView*)webView
didFinishNavigation:(WKNavigation*)navigation {
_callback.Run();
}
@end
const char AccountConsistencyService::kChromeConnectedCookieName[] =
"CHROME_CONNECTED";
const char AccountConsistencyService::kDomainsWithCookiePref[] =
"signin.domains_with_cookie";
......@@ -251,8 +203,6 @@ AccountConsistencyService::AccountConsistencyService(
}
AccountConsistencyService::~AccountConsistencyService() {
DCHECK(!web_view_);
DCHECK(!navigation_delegate_);
}
// static
......@@ -344,7 +294,6 @@ void AccountConsistencyService::LoadFromPrefs() {
void AccountConsistencyService::Shutdown() {
identity_manager_->RemoveObserver(this);
ActiveStateManager::FromBrowserState(browser_state_)->RemoveObserver(this);
ResetWKWebView();
web_state_handlers_.clear();
}
......@@ -365,10 +314,8 @@ void AccountConsistencyService::ApplyCookieRequests() {
applying_cookie_requests_ = true;
const GURL url("https://" + cookie_requests_.front().domain);
std::string cookie_value = "";
// Expiration date of the cookie in the JavaScript convention of time, a
// number of milliseconds since the epoch.
double expiration_date = 0;
std::string cookie_value;
base::Time expiration_date;
switch (cookie_requests_.front().request_type) {
case ADD_CHROME_CONNECTED_COOKIE:
cookie_value = signin::BuildMirrorRequestCookieIfPossible(
......@@ -382,22 +329,43 @@ void AccountConsistencyService::ApplyCookieRequests() {
return;
}
// Create expiration date of Now+2y to roughly follow the SAPISID cookie.
expiration_date =
(base::Time::Now() + base::TimeDelta::FromDays(730)).ToJsTime();
expiration_date = base::Time::Now() + base::TimeDelta::FromDays(730);
break;
case REMOVE_CHROME_CONNECTED_COOKIE:
// Nothing to do. Default values correspond to removing the cookie (no
// value, expiration date in the past).
// Default values correspond to removing the cookie (no value, expiration
// date in the past).
expiration_date = base::Time::UnixEpoch();
break;
}
NSString* html = [NSString
stringWithFormat:kChromeConnectedCookieTemplate,
base::SysUTF8ToNSString(url.host()),
base::SysUTF8ToNSString(cookie_value), expiration_date];
// Load an HTML string with embedded JavaScript that will set or remove the
// cookie. By setting the base URL to |url|, this effectively allows to modify
// cookies on the correct domain without having to do a network request.
[GetWKWebView() loadHTMLString:html baseURL:net::NSURLWithGURL(url)];
std::unique_ptr<net::CanonicalCookie> cookie =
net::CanonicalCookie::CreateSanitizedCookie(
url,
/*name=*/kChromeConnectedCookieName, cookie_value,
/*domain=*/url.host(),
/*path=*/std::string(),
/*creation_time=*/base::Time::Now(), expiration_date,
/*last_access_time=*/base::Time(),
/*secure=*/true,
/*httponly=*/false, net::CookieSameSite::LAX_MODE,
net::COOKIE_PRIORITY_DEFAULT);
net::CookieOptions options;
options.set_include_httponly();
options.set_same_site_cookie_context(
net::CookieOptions::SameSiteCookieContext::MakeInclusive());
network::mojom::CookieManager* cookie_manager =
browser_state_->GetCookieManager();
cookie_manager->SetCanonicalCookie(
*cookie, url, options,
base::BindOnce(&AccountConsistencyService::FinishedSetCookie,
base::Unretained(this)));
}
void AccountConsistencyService::FinishedSetCookie(
net::CookieAccessResult cookie_access_result) {
DCHECK(cookie_access_result.status.IsInclude());
FinishedApplyingCookieRequest(true);
}
void AccountConsistencyService::FinishedApplyingCookieRequest(bool success) {
......@@ -427,35 +395,6 @@ void AccountConsistencyService::FinishedApplyingCookieRequest(bool success) {
}
}
WKWebView* AccountConsistencyService::GetWKWebView() {
if (!ActiveStateManager::FromBrowserState(browser_state_)->IsActive()) {
// |browser_state_| is not active, WKWebView linked to this browser state
// should not exist or be created.
return nil;
}
if (!web_view_) {
web_view_ = BuildWKWebView();
navigation_delegate_ = [[AccountConsistencyNavigationDelegate alloc]
initWithCallback:base::BindRepeating(&AccountConsistencyService::
FinishedApplyingCookieRequest,
base::Unretained(this), true)];
[web_view_ setNavigationDelegate:navigation_delegate_];
}
return web_view_;
}
WKWebView* AccountConsistencyService::BuildWKWebView() {
return web::BuildWKWebView(CGRectZero, browser_state_);
}
void AccountConsistencyService::ResetWKWebView() {
[web_view_ setNavigationDelegate:nil];
[web_view_ stopLoading];
web_view_ = nil;
navigation_delegate_ = nil;
applying_cookie_requests_ = false;
}
void AccountConsistencyService::AddChromeConnectedCookies() {
DCHECK(!browser_state_->IsOffTheRecord());
// These cookie request are preventive and not a strong signal (unlike
......@@ -469,7 +408,6 @@ void AccountConsistencyService::AddChromeConnectedCookies() {
void AccountConsistencyService::OnBrowsingDataRemoved() {
// CHROME_CONNECTED cookies have been removed, update internal state
// accordingly.
ResetWKWebView();
for (auto& cookie_request : cookie_requests_) {
base::OnceClosure callback(std::move(cookie_request.callback));
if (!callback.is_null()) {
......@@ -510,9 +448,3 @@ void AccountConsistencyService::OnActive() {
// to apply.
ApplyCookieRequests();
}
void AccountConsistencyService::OnInactive() {
// |browser_state_| is now inactive. Stop using |web_view_| and don't create
// a new one until it is active.
ResetWKWebView();
}
......@@ -10,6 +10,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/test/bind_test_util.h"
#import "base/test/ios/wait_util.h"
#include "base/values.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
......@@ -49,6 +51,25 @@ NSURL* const kCountryGoogleUrl = [NSURL URLWithString:@"https://google.de/"];
const char* kGoogleDomain = "google.com";
// Youtube domain.
const char* kYoutubeDomain = "youtube.com";
// Google domain where the CHROME_CONNECTED cookie is set/removed.
const char* kCountryGoogleDomain = "google.de";
// Returns true if |cookies| contains a cookie with |name| and |domain|.
//
// Note: If |domain| is the empty string, then it returns true if any cookie
// with |name| is found.
bool ContainsCookie(const std::vector<net::CanonicalCookie>& cookies,
const std::string& name,
const std::string& domain) {
for (const auto& cookie : cookies) {
if (cookie.Name() ==
AccountConsistencyService::kChromeConnectedCookieName) {
if (domain.empty() || cookie.Domain() == domain)
return true;
}
}
return false;
}
// AccountConsistencyService specialization that fakes the creation of the
// WKWebView in order to mock it. This allows tests to intercept the calls to
......@@ -67,14 +88,6 @@ class FakeAccountConsistencyService : public AccountConsistencyService {
cookie_settings,
identity_manager) {}
private:
WKWebView* BuildWKWebView() override {
if (!mock_web_view_) {
mock_web_view_ = [OCMockObject niceMockForClass:[WKWebView class]];
}
return mock_web_view_;
}
id mock_web_view_;
};
// Mock AccountReconcilor to catch call to OnReceivedManageAccountsResponse.
......@@ -130,7 +143,6 @@ class AccountConsistencyServiceTest : public PlatformTest {
public:
void OnRemoveChromeConnectedCookieFinished() {
EXPECT_FALSE(remove_cookie_callback_called_);
EXPECT_EQ(0, web_view_load_expection_count_);
remove_cookie_callback_called_ = true;
}
......@@ -142,7 +154,6 @@ class AccountConsistencyServiceTest : public PlatformTest {
content_settings::CookieSettings::RegisterProfilePrefs(prefs_.registry());
HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry());
web_view_load_expection_count_ = 0;
signin_client_.reset(
new TestSigninClient(&prefs_, &test_url_loader_factory_));
identity_test_env_.reset(new signin::IdentityTestEnvironment(
......@@ -160,8 +171,6 @@ class AccountConsistencyServiceTest : public PlatformTest {
}
void TearDown() override {
EXPECT_EQ(0, web_view_load_expection_count_);
EXPECT_OCMOCK_VERIFY(GetMockWKWebView());
account_consistency_service_->Shutdown();
settings_map_->ShutdownOnUIThread();
ActiveStateManager::FromBrowserState(&browser_state_)->SetActive(false);
......@@ -169,25 +178,6 @@ class AccountConsistencyServiceTest : public PlatformTest {
PlatformTest::TearDown();
}
// Adds an expectation for |url| to be loaded in the web view of
// |account_consistency_service_|.
// |continue_navigation| controls whether navigation will continue or be
// stopped on page load.
void AddPageLoadedExpectation(NSURL* url, bool continue_navigation) {
++web_view_load_expection_count_;
void (^continueBlock)(NSInvocation*) = ^(NSInvocation* invocation) {
--web_view_load_expection_count_;
if (!continue_navigation)
return;
__unsafe_unretained WKWebView* web_view = nil;
[invocation getArgument:&web_view atIndex:0];
[GetNavigationDelegate() webView:web_view didFinishNavigation:nil];
};
[static_cast<WKWebView*>([[GetMockWKWebView() expect] andDo:continueBlock])
loadHTMLString:[OCMArg any]
baseURL:url];
}
void ResetAccountConsistencyService() {
if (account_consistency_service_) {
account_consistency_service_->Shutdown();
......@@ -197,28 +187,26 @@ class AccountConsistencyServiceTest : public PlatformTest {
identity_test_env_->identity_manager()));
}
void WaitUntilAllCookieRequestsAreApplied() {
// Spinning the runloop is needed to ensure that the cookie manager requests
// are executed.
base::RunLoop().RunUntilIdle();
if (ActiveStateManager::FromBrowserState(&browser_state_)->IsActive())
EXPECT_TRUE(account_consistency_service_->cookie_requests_.empty());
}
void SignIn() {
signin::MakePrimaryAccountAvailable(identity_test_env_->identity_manager(),
"user@gmail.com");
EXPECT_EQ(0, web_view_load_expection_count_);
WaitUntilAllCookieRequestsAreApplied();
}
void SignOutAndSimulateGaiaCookieManagerServiceLogout() {
signin::ClearPrimaryAccount(identity_test_env_->identity_manager(),
signin::ClearPrimaryAccountPolicy::DEFAULT);
SimulateGaiaCookieManagerServiceLogout(true);
}
id GetWKWebView() { return account_consistency_service_->GetWKWebView(); }
id GetMockWKWebView() {
// Should use BuildWKWebView() to always have the mock instance, even when
// the |account_consistency_service_| is inactive.
return account_consistency_service_->BuildWKWebView();
}
id GetNavigationDelegate() {
return account_consistency_service_->navigation_delegate_;
SimulateGaiaCookieManagerServiceLogout();
WaitUntilAllCookieRequestsAreApplied();
}
bool ShouldAddCookieToDomain(const std::string& domain,
......@@ -227,21 +215,53 @@ class AccountConsistencyServiceTest : public PlatformTest {
domain, should_check_last_update_time);
}
void CheckDomainHasCookie(const std::string& domain) {
std::vector<net::CanonicalCookie> GetCookiesInCookieJar() {
std::vector<net::CanonicalCookie> cookies_out;
base::RunLoop run_loop;
network::mojom::CookieManager* cookie_manager =
browser_state_.GetCookieManager();
cookie_manager->GetAllCookies(base::BindOnce(base::BindLambdaForTesting(
[&run_loop,
&cookies_out](const std::vector<net::CanonicalCookie>& cookies) {
cookies_out = cookies;
run_loop.Quit();
})));
run_loop.Run();
return cookies_out;
}
void CheckDomainHasChromeConnectedCookie(const std::string& domain) {
EXPECT_TRUE(ContainsCookie(
GetCookiesInCookieJar(),
AccountConsistencyService::kChromeConnectedCookieName, "." + domain));
EXPECT_GE(
account_consistency_service_->last_cookie_update_map_.count(domain),
1u);
}
void SimulateGaiaCookieManagerServiceLogout(
bool expect_remove_cookie_callback) {
// Simulate the action of the action GaiaCookieManagerService to cleanup
// the cookies once the sign-out is done.
remove_cookie_callback_called_ = false;
account_consistency_service_->RemoveChromeConnectedCookies(base::BindOnce(
&AccountConsistencyServiceTest::OnRemoveChromeConnectedCookieFinished,
base::Unretained(this)));
EXPECT_EQ(expect_remove_cookie_callback, remove_cookie_callback_called_);
void CheckNoChromeConnectedCookieForDomain(const std::string& domain) {
EXPECT_FALSE(ContainsCookie(
GetCookiesInCookieJar(),
AccountConsistencyService::kChromeConnectedCookieName, "." + domain));
EXPECT_EQ(0U, account_consistency_service_->last_cookie_update_map_.count(
domain));
}
void CheckNoChromeConnectedCookies() {
EXPECT_FALSE(
ContainsCookie(GetCookiesInCookieJar(),
AccountConsistencyService::kChromeConnectedCookieName,
/*domain=*/std::string()));
}
// Simulate the action of the action GaiaCookieManagerService to cleanup
// the cookies once the sign-out is done.
void SimulateGaiaCookieManagerServiceLogout() {
base::RunLoop run_loop;
account_consistency_service_->RemoveChromeConnectedCookies(
run_loop.QuitClosure());
run_loop.Run();
}
// Creates test threads, necessary for ActiveStateManager that needs a UI
......@@ -261,27 +281,29 @@ class AccountConsistencyServiceTest : public PlatformTest {
scoped_refptr<HostContentSettingsMap> settings_map_;
scoped_refptr<content_settings::CookieSettings> cookie_settings_;
bool remove_cookie_callback_called_;
int web_view_load_expection_count_;
};
// Tests whether the WKWebView is actually stopped when the browser state is
// inactive.
TEST_F(AccountConsistencyServiceTest, OnInactive) {
[[GetMockWKWebView() expect] stopLoading];
// Loads the webview.
EXPECT_TRUE(GetWKWebView());
ActiveStateManager::FromBrowserState(&browser_state_)->SetActive(false);
// Tests that main domains are added to the internal map when cookies are set in
// reaction to signin.
TEST_F(AccountConsistencyServiceTest, SigninAddCookieOnMainDomains) {
SignIn();
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
const base::DictionaryValue* dict =
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref);
EXPECT_EQ(2u, dict->size());
EXPECT_TRUE(dict->GetBooleanWithoutPathExpansion("google.com", nullptr));
EXPECT_TRUE(dict->GetBooleanWithoutPathExpansion("youtube.com", nullptr));
}
// Tests that cookies that are added during SignIn and subsequent navigations
// are correctly removed during the SignOut.
TEST_F(AccountConsistencyServiceTest, SignInSignOut) {
// Check that main Google domains are added.
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
SignIn();
// Check that other Google domains are added on navigation.
AddPageLoadedExpectation(kCountryGoogleUrl, true /* continue_navigation */);
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
CheckNoChromeConnectedCookieForDomain(kCountryGoogleDomain);
id delegate =
[OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
......@@ -291,23 +313,26 @@ TEST_F(AccountConsistencyServiceTest, SignInSignOut) {
statusCode:200
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
web_view_load_expection_count_ = 1;
account_consistency_service_->SetWebStateHandler(&web_state_, delegate);
EXPECT_TRUE(
web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
web_state_.WebStateDestroyed();
EXPECT_EQ(0, web_view_load_expection_count_);
// Check that all domains are removed.
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kCountryGoogleUrl, true /* continue_navigation */);
// Check that cookies was also added for |kCountryGoogleDomain|.
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
CheckDomainHasChromeConnectedCookie(kCountryGoogleDomain);
SignOutAndSimulateGaiaCookieManagerServiceLogout();
CheckNoChromeConnectedCookies();
}
// Tests that signing out with no domains known, still call the callback.
TEST_F(AccountConsistencyServiceTest, SignOutWithoutDomains) {
CheckNoChromeConnectedCookies();
SignOutAndSimulateGaiaCookieManagerServiceLogout();
CheckNoChromeConnectedCookies();
}
// Tests that pending cookie requests are correctly applied when the browser
......@@ -315,27 +340,13 @@ TEST_F(AccountConsistencyServiceTest, SignOutWithoutDomains) {
TEST_F(AccountConsistencyServiceTest, ApplyOnActive) {
// No request is made until the browser state is active, then a WKWebView and
// its navigation delegate are created, and the requests are processed.
[[GetMockWKWebView() expect] setNavigationDelegate:[OCMArg isNotNil]];
ActiveStateManager::FromBrowserState(&browser_state_)->SetActive(false);
SignIn();
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
ActiveStateManager::FromBrowserState(&browser_state_)->SetActive(true);
}
CheckNoChromeConnectedCookies();
// Tests that cookie request being processed is correctly cancelled when the
// browser state becomes inactives and correctly re-started later when the
// browser state becomes active.
TEST_F(AccountConsistencyServiceTest, CancelOnInactiveReApplyOnActive) {
// The first request starts to get applied and get cancelled as the browser
// state becomes inactive. It is resumed after the browser state becomes
// active again.
AddPageLoadedExpectation(kGoogleUrl, false /* continue_navigation */);
SignIn();
ActiveStateManager::FromBrowserState(&browser_state_)->SetActive(false);
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
ActiveStateManager::FromBrowserState(&browser_state_)->SetActive(true);
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
}
// Tests that the X-Chrome-Manage-Accounts header is ignored unless it comes
......@@ -408,42 +419,30 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsDefault) {
EXPECT_OCMOCK_VERIFY(delegate);
}
// Tests that domains with cookie are added to the prefs only after the request
// has been applied.
TEST_F(AccountConsistencyServiceTest, DomainsWithCookiePrefsOnApplied) {
// Second request is not completely applied. Ensure prefs reflect that.
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, false /* continue_navigation */);
SignIn();
const base::DictionaryValue* dict =
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref);
EXPECT_EQ(1u, dict->size());
EXPECT_TRUE(dict->GetBooleanWithoutPathExpansion("google.com", nullptr));
EXPECT_FALSE(dict->GetBooleanWithoutPathExpansion("youtube.com", nullptr));
}
// Tests that domains with cookie are correctly loaded from the prefs on service
// startup.
TEST_F(AccountConsistencyServiceTest, DomainsWithCookieLoadedFromPrefs) {
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
SignIn();
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
ResetAccountConsistencyService();
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
SignOutAndSimulateGaiaCookieManagerServiceLogout();
CheckNoChromeConnectedCookies();
}
// Tests that domains with cookie are cleared when browsing data is removed.
TEST_F(AccountConsistencyServiceTest, DomainsClearedOnBrowsingDataRemoved) {
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
SignIn();
const base::DictionaryValue* dict =
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref);
EXPECT_EQ(2u, dict->size());
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
EXPECT_EQ(
2u,
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref)
->size());
// Sets Response to get IdentityManager::Observer::OnAccountsInCookieUpdated
// through GaiaCookieManagerService::OnCookieChange.
......@@ -456,36 +455,20 @@ TEST_F(AccountConsistencyServiceTest, DomainsClearedOnBrowsingDataRemoved) {
// AccountsCookieMutator::ForceTriggerOnCookieChange and finally
// IdentityManager::Observer::OnAccountsInCookieUpdated is called.
account_consistency_service_->OnBrowsingDataRemoved();
EXPECT_EQ(
0u,
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref)
->size());
run_loop.Run();
dict =
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref);
EXPECT_EQ(0u, dict->size());
}
// Tests that remove cookie call back is called when the signout is interrupted
// by removing the browser data.
TEST_F(AccountConsistencyServiceTest, DomainsClearedOnBrowsingDataRemoved2) {
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
SignIn();
AddPageLoadedExpectation(kGoogleUrl, false /* continue_navigation */);
SimulateGaiaCookieManagerServiceLogout(false);
// Sets Response to get IdentityManager::Observer::OnAccountsInCookieUpdated
// through GaiaCookieManagerService::OnCookieChange.
signin::SetListAccountsResponseNoAccounts(&test_url_loader_factory_);
base::RunLoop run_loop;
identity_test_env_->identity_manager_observer()
->SetOnAccountsInCookieUpdatedCallback(run_loop.QuitClosure());
// OnBrowsingDataRemoved triggers
// AccountsCookieMutator::ForceTriggerOnCookieChange and finally
// IdentityManager::Observer::OnAccountsInCookieUpdated is called.
account_consistency_service_->OnBrowsingDataRemoved();
run_loop.Run();
EXPECT_TRUE(remove_cookie_callback_called_);
// AccountConsistency service is supposed to rebuild the CHROME_CONNECTED
// cookies when browsing data is removed.
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
EXPECT_EQ(
2u,
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref)
->size());
}
// Tests that cookie requests are correctly processed or ignored when the update
......@@ -494,15 +477,16 @@ TEST_F(AccountConsistencyServiceTest, ShouldAddCookieDontCheckUpdateTime) {
EXPECT_TRUE(ShouldAddCookieToDomain(kGoogleDomain, false));
EXPECT_TRUE(ShouldAddCookieToDomain(kYoutubeDomain, false));
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
SignIn();
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
EXPECT_FALSE(ShouldAddCookieToDomain(kGoogleDomain, false));
EXPECT_FALSE(ShouldAddCookieToDomain(kYoutubeDomain, false));
ResetAccountConsistencyService();
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
EXPECT_FALSE(ShouldAddCookieToDomain(kGoogleDomain, false));
EXPECT_FALSE(ShouldAddCookieToDomain(kYoutubeDomain, false));
}
......@@ -513,26 +497,17 @@ TEST_F(AccountConsistencyServiceTest, ShouldAddCookieCheckUpdateTime) {
EXPECT_TRUE(ShouldAddCookieToDomain(kGoogleDomain, true));
EXPECT_TRUE(ShouldAddCookieToDomain(kYoutubeDomain, true));
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
SignIn();
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
EXPECT_FALSE(ShouldAddCookieToDomain(kGoogleDomain, true));
EXPECT_FALSE(ShouldAddCookieToDomain(kYoutubeDomain, true));
ResetAccountConsistencyService();
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
EXPECT_TRUE(ShouldAddCookieToDomain(kGoogleDomain, true));
EXPECT_TRUE(ShouldAddCookieToDomain(kYoutubeDomain, true));
}
// Tests that main domains are added to the internal map when cookies are set in
// reaction to signin.
TEST_F(AccountConsistencyServiceTest, SigninAddCookieOnMainDomains) {
AddPageLoadedExpectation(kGoogleUrl, true /* continue_navigation */);
AddPageLoadedExpectation(kYoutubeUrl, true /* continue_navigation */);
SignIn();
CheckDomainHasCookie(kGoogleDomain);
CheckDomainHasCookie(kYoutubeDomain);
}
......@@ -10,6 +10,7 @@
#include "base/bind_helpers.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "components/signin/ios/browser/account_consistency_service.h"
#include "ios/chrome/browser/signin/feature_flags.h"
#include "ios/net/cookies/system_cookie_util.h"
#include "ios/web/common/features.h"
......@@ -20,13 +21,6 @@
#error "This file requires ARC support."
#endif
namespace {
// Name of the cookie that is managed by AccountConsistencyService and is used
// to inform Google web properties that the browser is connected and that Google
// authentication cookies are managed by |AccountReconcilor|).
const char kChromeConnectedCookieName[] = "CHROME_CONNECTED";
}
@interface GaiaAuthFetcherIOSURLSessionDelegate
: NSObject <NSURLSessionTaskDelegate>
......@@ -159,8 +153,10 @@ void GaiaAuthFetcherIOSNSURLSessionBridge::FetchPendingRequestWithCookies(
// |CHROME_CONNECTED| cookie is attached to all web requests to Google web
// properties. Requests initiated from the browser services (e.g.
// GaiaCookieManagerService) must not include this cookie.
if (cookie_with_access_result.cookie.Name() == kChromeConnectedCookieName)
if (cookie_with_access_result.cookie.Name() ==
AccountConsistencyService::kChromeConnectedCookieName) {
continue;
}
[http_cookies addObject:net::SystemCookieFromCanonicalCookie(
cookie_with_access_result.cookie)];
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment