| // Copyright 2020 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 "chrome/browser/signin/signin_manager.h" |
| |
| #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "components/signin/public/identity_manager/identity_test_environment.h" |
| #include "components/signin/public/identity_manager/identity_test_utils.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::Mock; |
| |
| namespace signin { |
| namespace { |
| const char kTestEmail[] = "me@gmail.com"; |
| const char kTestEmail2[] = "me2@gmail.com"; |
| |
| class FakeIdentityManagerObserver : public IdentityManager::Observer { |
| public: |
| explicit FakeIdentityManagerObserver(IdentityManager* identity_manager) |
| : identity_manager_(identity_manager) {} |
| ~FakeIdentityManagerObserver() override = default; |
| |
| void OnPrimaryAccountChanged( |
| const PrimaryAccountChangeEvent& event) override { |
| auto current_state = event.GetCurrentState(); |
| EXPECT_EQ( |
| current_state.primary_account, |
| identity_manager_->GetPrimaryAccountInfo(current_state.consent_level)); |
| events_.push_back(event); |
| } |
| |
| const std::vector<PrimaryAccountChangeEvent>& events() const { |
| return events_; |
| } |
| |
| void Reset() { events_.clear(); } |
| |
| private: |
| IdentityManager* identity_manager_; |
| std::vector<PrimaryAccountChangeEvent> events_; |
| }; |
| } // namespace |
| |
| class SigninManagerTest : public testing::Test { |
| public: |
| SigninManagerTest() |
| : identity_test_env_(/*test_url_loader_factory=*/nullptr, |
| /*pref_service=*/nullptr, |
| signin::AccountConsistencyMethod::kDice, |
| /*test_signin_client=*/nullptr), |
| observer_(identity_test_env_.identity_manager()) {} |
| |
| void SetUp() override { |
| testing::Test::SetUp(); |
| RecreateSigninManager(); |
| identity_manager()->AddObserver(&observer_); |
| } |
| |
| void TearDown() override { identity_manager()->RemoveObserver(&observer_); } |
| |
| void RecreateSigninManager() { |
| signin_manger_ = std::make_unique<SigninManager>(identity_manager()); |
| } |
| |
| AccountInfo GetAccountInfo(const std::string& email) { |
| AccountInfo account_info; |
| account_info.gaia = GetTestGaiaIdForEmail(email); |
| account_info.account_id = |
| identity_manager()->PickAccountIdForAccount(account_info.gaia, email); |
| account_info.email = email; |
| return account_info; |
| } |
| |
| void ExpectUnconsentedPrimaryAccountSetEvent( |
| const CoreAccountInfo& expected_primary_account) { |
| EXPECT_EQ(1U, observer().events().size()); |
| auto event = observer().events()[0]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, |
| event.GetEventTypeFor(ConsentLevel::kNotRequired)); |
| EXPECT_TRUE(event.GetPreviousState().primary_account.IsEmpty()); |
| EXPECT_EQ(expected_primary_account, |
| event.GetCurrentState().primary_account); |
| observer().Reset(); |
| } |
| |
| void ExpectUnconsentedPrimaryAccountClearedEvent( |
| const CoreAccountInfo& expected_cleared_account) { |
| EXPECT_EQ(1U, observer().events().size()); |
| auto event = observer().events()[0]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, |
| event.GetEventTypeFor(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(expected_cleared_account, |
| event.GetPreviousState().primary_account); |
| EXPECT_TRUE(event.GetCurrentState().primary_account.IsEmpty()); |
| observer().Reset(); |
| } |
| |
| void ExpectSyncPrimaryAccountSetEvent( |
| const CoreAccountInfo& expected_primary_account) { |
| EXPECT_EQ(1U, observer().events().size()); |
| auto event = observer().events()[0]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, |
| event.GetEventTypeFor(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_TRUE(event.GetPreviousState().primary_account.IsEmpty()); |
| EXPECT_EQ(expected_primary_account, |
| event.GetCurrentState().primary_account); |
| observer().Reset(); |
| } |
| |
| IdentityManager* identity_manager() { |
| return identity_test_env_.identity_manager(); |
| } |
| |
| IdentityTestEnvironment* identity_test_env() { return &identity_test_env_; } |
| |
| AccountInfo MakeAccountAvailableWithCookies(const std::string& email) { |
| AccountInfo account = GetAccountInfo(kTestEmail); |
| identity_test_env_.MakeAccountAvailableWithCookies(account.email, |
| account.gaia); |
| EXPECT_FALSE(account.IsEmpty()); |
| EXPECT_TRUE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| return account; |
| } |
| |
| AccountInfo MakeSyncAccountAvailableWithCookies(const std::string& email) { |
| AccountInfo account = identity_test_env_.MakePrimaryAccountAvailable(email); |
| identity_test_env_.SetCookieAccounts({{account.email, account.gaia}}); |
| EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| EXPECT_EQ(account, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken()); |
| return account; |
| } |
| |
| FakeIdentityManagerObserver& observer() { return observer_; } |
| |
| content::BrowserTaskEnvironment task_environment_; |
| IdentityTestEnvironment identity_test_env_; |
| std::unique_ptr<SigninManager> signin_manger_; |
| FakeIdentityManagerObserver observer_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SigninManagerTest); |
| }; |
| |
| TEST_F( |
| SigninManagerTest, |
| UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithValidTokenWhenNoSyncConsent) { |
| // Add an unconsented primary account, incl. proper cookies. |
| AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); |
| ExpectUnconsentedPrimaryAccountSetEvent(account); |
| EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| } |
| |
| TEST_F( |
| SigninManagerTest, |
| UnconsentedPrimaryAccountUpdatedOnItsAccountRefreshTokenUpdateWithInvalidTokenWhenNoSyncConsent) { |
| // Prerequisite: add an unconsented primary account, incl. proper cookies. |
| AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); |
| ExpectUnconsentedPrimaryAccountSetEvent(account); |
| |
| // Invalid token. |
| SetInvalidRefreshTokenForAccount(identity_manager(), account.account_id); |
| ExpectUnconsentedPrimaryAccountClearedEvent(account); |
| EXPECT_FALSE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| |
| // Update with a valid token. |
| UpdatePersistentErrorOfRefreshTokenForAccount( |
| identity_manager(), account.account_id, |
| GoogleServiceAuthError::AuthErrorNone()); |
| ExpectUnconsentedPrimaryAccountSetEvent(account); |
| EXPECT_EQ( |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired), |
| account); |
| } |
| |
| TEST_F( |
| SigninManagerTest, |
| UnconsentedPrimaryAccountRemovedOnItsAccountRefreshTokenRemovalWhenNoSyncConsent) { |
| // Prerequisite: Add an unconsented primary account, incl. proper cookies. |
| AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); |
| ExpectUnconsentedPrimaryAccountSetEvent(account); |
| |
| // With no refresh token, there is no unconsented primary account any more. |
| identity_test_env()->RemoveRefreshTokenForAccount(account.account_id); |
| ExpectUnconsentedPrimaryAccountClearedEvent(account); |
| EXPECT_FALSE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| } |
| |
| TEST_F(SigninManagerTest, UnconsentedPrimaryAccountNotChangedOnSignout) { |
| // Set a primary account at sync consent level. |
| AccountInfo account = MakeSyncAccountAvailableWithCookies(kTestEmail); |
| EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| EXPECT_EQ(account, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync)); |
| EXPECT_TRUE(identity_manager()->HasPrimaryAccountWithRefreshToken()); |
| |
| // Verify the primary account changed event. |
| ExpectSyncPrimaryAccountSetEvent(account); |
| |
| // Tests that sync primary account is cleared, but unconsented account is not. |
| identity_test_env()->RevokeSyncConsent(); |
| EXPECT_EQ(account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| |
| EXPECT_EQ(1U, observer().events().size()); |
| auto event = observer().events()[0]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kNone, |
| event.GetEventTypeFor(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_EQ(account, event.GetPreviousState().primary_account); |
| EXPECT_EQ(account, event.GetCurrentState().primary_account); |
| } |
| |
| TEST_F(SigninManagerTest, |
| UnconsentedPrimaryAccountTokenRevokedWithStaleCookies) { |
| // Prerequisite: add an unconsented primary account, incl. proper cookies. |
| AccountInfo account = MakeAccountAvailableWithCookies(kTestEmail); |
| ExpectUnconsentedPrimaryAccountSetEvent(account); |
| |
| // Make the cookies stale and remove the account. |
| // Removing the refresh token for the unconsented primary account is |
| // sufficient to clear it. |
| identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false); |
| identity_test_env()->RemoveRefreshTokenForAccount(account.account_id); |
| ASSERT_FALSE(identity_manager()->GetAccountsInCookieJar().accounts_are_fresh); |
| |
| // Unconsented account was removed. |
| EXPECT_FALSE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| ExpectUnconsentedPrimaryAccountClearedEvent(account); |
| } |
| |
| TEST_F(SigninManagerTest, |
| UnconsentedPrimaryAccountTokenRevokedWithStaleCookiesMultipleAccounts) { |
| // Add two accounts with cookies. |
| AccountInfo main_account = |
| identity_test_env()->MakeAccountAvailable(kTestEmail); |
| AccountInfo secondary_account = |
| identity_test_env()->MakeAccountAvailable(kTestEmail2); |
| identity_test_env()->SetCookieAccounts( |
| {{main_account.email, main_account.gaia}, |
| {secondary_account.email, secondary_account.gaia}}); |
| |
| EXPECT_TRUE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| ExpectUnconsentedPrimaryAccountSetEvent(main_account); |
| |
| // Make the cookies stale and remove the main account. |
| identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false); |
| identity_test_env()->RemoveRefreshTokenForAccount(main_account.account_id); |
| ASSERT_FALSE(identity_manager()->GetAccountsInCookieJar().accounts_are_fresh); |
| |
| // Unconsented account was removed. |
| EXPECT_FALSE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| ExpectUnconsentedPrimaryAccountClearedEvent(main_account); |
| } |
| |
| TEST_F(SigninManagerTest, UnconsentedPrimaryAccountDuringLoad) { |
| // Pre-requisite: Add two accounts with cookies. |
| AccountInfo main_account = |
| identity_test_env()->MakeAccountAvailable(kTestEmail); |
| AccountInfo secondary_account = |
| identity_test_env()->MakeAccountAvailable(kTestEmail2); |
| identity_test_env()->SetCookieAccounts( |
| {{main_account.email, main_account.gaia}, |
| {secondary_account.email, secondary_account.gaia}}); |
| ASSERT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| ASSERT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| ExpectUnconsentedPrimaryAccountSetEvent(main_account); |
| |
| // Set the token service in "loading" mode. |
| identity_test_env()->ResetToAccountsNotYetLoadedFromDiskState(); |
| RecreateSigninManager(); |
| |
| // Unconsented primary account is available while tokens are not loaded. |
| EXPECT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| EXPECT_TRUE(observer().events().empty()); |
| |
| // Revoking an unrelated token doesn't change the unconsented primary account. |
| identity_test_env()->RemoveRefreshTokenForAccount( |
| secondary_account.account_id); |
| EXPECT_EQ(main_account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| EXPECT_TRUE(observer().events().empty()); |
| |
| // Revoke the unconsented primary account while tokens are not loaded. |
| identity_test_env()->RemoveRefreshTokenForAccount(main_account.account_id); |
| EXPECT_FALSE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| ExpectUnconsentedPrimaryAccountClearedEvent(main_account); |
| |
| // Finish the token load. |
| identity_test_env()->ReloadAccountsFromDisk(); |
| EXPECT_FALSE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| EXPECT_TRUE(observer().events().empty()); |
| } |
| |
| TEST_F(SigninManagerTest, |
| UnconsentedPrimaryAccountUpdatedOnSyncConsentRevoked) { |
| AccountInfo first_account = |
| identity_test_env()->MakeAccountAvailable(kTestEmail); |
| AccountInfo second_account = |
| identity_test_env()->MakeAccountAvailable(kTestEmail2); |
| identity_test_env()->SetCookieAccounts( |
| {{first_account.email, first_account.gaia}, |
| {second_account.email, second_account.gaia}}); |
| ASSERT_EQ(first_account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| ExpectUnconsentedPrimaryAccountSetEvent(first_account); |
| |
| // Set the sync primary account to the second account in cookies. |
| // The unconsented primary account should be updated. |
| identity_test_env()->SetPrimaryAccount(second_account.email); |
| EXPECT_EQ(second_account, |
| identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSync)); |
| EXPECT_EQ(1U, observer().events().size()); |
| auto event = observer().events()[0]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_EQ(first_account, event.GetPreviousState().primary_account); |
| EXPECT_EQ(second_account, event.GetCurrentState().primary_account); |
| observer().Reset(); |
| |
| // Clear primary account but do not delete the account. The unconsented |
| // primary account should be updated to be the first account in cookies. |
| identity_test_env()->RevokeSyncConsent(); |
| // Primary account is cleared, but unconsented account is not. |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount()); |
| EXPECT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSync)); |
| EXPECT_TRUE( |
| identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(first_account, identity_manager()->GetPrimaryAccountInfo( |
| ConsentLevel::kNotRequired)); |
| |
| EXPECT_EQ(2U, observer().events().size()); |
| event = observer().events()[0]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kNone, |
| event.GetEventTypeFor(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(second_account, event.GetPreviousState().primary_account); |
| EXPECT_EQ(second_account, event.GetCurrentState().primary_account); |
| |
| event = observer().events()[1]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kNone, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kSet, |
| event.GetEventTypeFor(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(second_account, event.GetPreviousState().primary_account); |
| EXPECT_EQ(first_account, event.GetCurrentState().primary_account); |
| } |
| |
| TEST_F(SigninManagerTest, ClearPrimaryAccountAndSignOut) { |
| AccountInfo account = MakeSyncAccountAvailableWithCookies(kTestEmail); |
| ExpectSyncPrimaryAccountSetEvent(account); |
| |
| identity_test_env()->ClearPrimaryAccount(); |
| |
| EXPECT_EQ(1U, observer().events().size()); |
| auto event = observer().events()[0]; |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, |
| event.GetEventTypeFor(ConsentLevel::kNotRequired)); |
| EXPECT_EQ(PrimaryAccountChangeEvent::Type::kCleared, |
| event.GetEventTypeFor(ConsentLevel::kSync)); |
| EXPECT_EQ(account, event.GetPreviousState().primary_account); |
| EXPECT_TRUE(event.GetCurrentState().primary_account.IsEmpty()); |
| } |
| |
| } // namespace signin |