blob: 6c44d0dddd71b90f41f820b9abb13f1c54709d9f [file]
// 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