| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/signin/dice_web_signin_interceptor.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <tuple> |
| |
| #include "base/functional/callback.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/bind.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "build/buildflag.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/enterprise/browser_management/management_service_factory.h" |
| #include "chrome/browser/profiles/profile_attributes_entry.h" |
| #include "chrome/browser/profiles/profile_attributes_storage.h" |
| #include "chrome/browser/signin/chrome_signin_client_factory.h" |
| #include "chrome/browser/signin/chrome_signin_client_test_util.h" |
| #include "chrome/browser/signin/dice_web_signin_interceptor_factory.h" |
| #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" |
| #include "chrome/browser/signin/web_signin_interceptor.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/ui_features.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/browser_with_test_window_test.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chrome/test/base/testing_profile_manager.h" |
| #include "components/policy/core/browser/signin/profile_separation_policies.h" |
| #include "components/policy/core/common/management/scoped_management_service_override_for_testing.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/public/base/consent_level.h" |
| #include "components/signin/public/base/signin_metrics.h" |
| #include "components/signin/public/base/signin_pref_names.h" |
| #include "components/signin/public/base/signin_prefs.h" |
| #include "components/signin/public/base/signin_switches.h" |
| #include "components/signin/public/identity_manager/account_capabilities_test_mutator.h" |
| #include "components/signin/public/identity_manager/account_info.h" |
| #include "components/signin/public/identity_manager/identity_test_environment.h" |
| #include "components/signin/public/identity_manager/signin_constants.h" |
| #include "components/signin/public/identity_manager/tribool.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| using signin::constants::kNoHostedDomainFound; |
| |
| namespace { |
| |
| class MockDiceWebSigninInterceptorDelegate |
| : public WebSigninInterceptor::Delegate { |
| public: |
| base::WeakPtr<MockDiceWebSigninInterceptorDelegate> GetWeakPtr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| |
| bool IsSigninInterceptionSupported( |
| const content::WebContents& web_contents) override { |
| return true; |
| } |
| |
| MOCK_METHOD(std::unique_ptr<ScopedWebSigninInterceptionBubbleHandle>, |
| ShowSigninInterceptionBubble, |
| (content::WebContents * web_contents, |
| const WebSigninInterceptor::Delegate::BubbleParameters& |
| bubble_parameters, |
| base::OnceCallback<void(SigninInterceptionResult)> callback), |
| (override)); |
| MOCK_METHOD(std::unique_ptr<ScopedWebSigninInterceptionBubbleHandle>, |
| ShowOidcInterceptionDialog, |
| (content::WebContents*, |
| const WebSigninInterceptor::Delegate::BubbleParameters&, |
| signin::SigninChoiceWithConfirmAndRetryCallback, |
| base::OnceClosure, |
| base::RepeatingClosure), |
| (override)); |
| void ShowFirstRunExperienceInNewProfile( |
| Browser* browser, |
| const CoreAccountId& account_id, |
| WebSigninInterceptor::SigninInterceptionType interception_type) override { |
| } |
| |
| private: |
| base::WeakPtrFactory<MockDiceWebSigninInterceptorDelegate> weak_factory_{ |
| this}; |
| }; |
| |
| MATCHER_P(HasSameAccountIdAs, other, "") { |
| return arg.account_id == other.account_id; |
| } |
| |
| // Matches BubbleParameters fields excepting the color. This is useful in the |
| // test because the color is randomly generated. |
| testing::Matcher<const WebSigninInterceptor::Delegate::BubbleParameters&> |
| MatchBubbleParameters( |
| const WebSigninInterceptor::Delegate::BubbleParameters& parameters) { |
| return testing::AllOf( |
| testing::Field( |
| "interception_type", |
| &WebSigninInterceptor::Delegate::BubbleParameters::interception_type, |
| parameters.interception_type), |
| testing::Field("intercepted_account", |
| &WebSigninInterceptor::Delegate::BubbleParameters:: |
| intercepted_account, |
| HasSameAccountIdAs(parameters.intercepted_account)), |
| testing::Field( |
| "primary_account", |
| &WebSigninInterceptor::Delegate::BubbleParameters::primary_account, |
| HasSameAccountIdAs(parameters.primary_account)), |
| testing::Field("show_link_data_option", |
| &WebSigninInterceptor::Delegate::BubbleParameters:: |
| show_link_data_option, |
| parameters.show_link_data_option), |
| testing::Field("show_managed_disclaimer", |
| &WebSigninInterceptor::Delegate::BubbleParameters:: |
| show_managed_disclaimer, |
| parameters.show_managed_disclaimer)); |
| } |
| |
| void MakeValidAccountCapabilities(AccountInfo* info) { |
| AccountCapabilitiesTestMutator mutator(&info->capabilities); |
| mutator.set_is_subject_to_parental_controls(true); |
| } |
| |
| void MakeValidAccountInfoWithoutCapabilities( |
| AccountInfo* info, |
| const std::string& hosted_domain = kNoHostedDomainFound) { |
| if (info->IsValid()) { |
| return; |
| } |
| info->full_name = "fullname"; |
| info->given_name = "givenname"; |
| info->hosted_domain = hosted_domain; |
| info->locale = "en"; |
| info->picture_url = "https://example.com"; |
| DCHECK(info->IsValid()); |
| } |
| |
| // If the account info is valid, does nothing. Otherwise fills the extended |
| // fields with default values. |
| void MakeValidAccountInfo( |
| AccountInfo* info, |
| const std::string& hosted_domain = kNoHostedDomainFound) { |
| if (info->IsValid()) { |
| return; |
| } |
| MakeValidAccountInfoWithoutCapabilities(info, hosted_domain); |
| MakeValidAccountCapabilities(info); |
| } |
| |
| std::string ParamToTestSuffixForInterceptionAndSyncPromo( |
| const ::testing::TestParamInfo<bool> info) { |
| bool interception_enabled = info.param; |
| return interception_enabled ? "Intercept" : "NoIntercept"; |
| } |
| |
| } // namespace |
| |
| class DiceWebSigninInterceptorTest : public BrowserWithTestWindowTest { |
| public: |
| DiceWebSigninInterceptorTest() |
| : BrowserWithTestWindowTest( |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} |
| ~DiceWebSigninInterceptorTest() override = default; |
| |
| DiceWebSigninInterceptor* interceptor() { |
| return DiceWebSigninInterceptorFactory::GetForProfile(profile()); |
| } |
| |
| MockDiceWebSigninInterceptorDelegate* mock_delegate() { |
| return mock_delegate_.get(); |
| } |
| |
| content::WebContents* web_contents() { |
| return browser()->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| ProfileAttributesStorage* profile_attributes_storage() { |
| return profile_manager()->profile_attributes_storage(); |
| } |
| |
| signin::IdentityTestEnvironment* identity_test_env() { |
| return identity_test_env_profile_adaptor_->identity_test_env(); |
| } |
| |
| Profile* CreateTestingProfile(const std::string& name) { |
| return profile_manager()->CreateTestingProfile(name); |
| } |
| |
| // Helper function that calls MaybeInterceptWebSignin with parameters |
| // compatible with interception. |
| void MaybeIntercept(CoreAccountId account_id) { |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/true, |
| /*is_sync_signin=*/false); |
| } |
| |
| // Calls MaybeInterceptWebSignin and verifies the heuristic outcome, the |
| // histograms and whether the interception is in progress. |
| // This function only works if the interception decision can be made |
| // synchronously (GetHeuristicOutcome() returns a value). |
| void TestSynchronousInterception( |
| AccountInfo account_info, |
| bool is_new_account, |
| bool is_sync_signin, |
| SigninInterceptionHeuristicOutcome expected_outcome) { |
| ASSERT_EQ(interceptor()->GetHeuristicOutcome(is_new_account, is_sync_signin, |
| account_info.email), |
| expected_outcome); |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, is_new_account, |
| is_sync_signin); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", |
| expected_outcome, 1); |
| histogram_tester.ExpectUniqueTimeSample("Signin.Intercept.HeuristicLatency", |
| base::Milliseconds(0), 1); |
| |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| } |
| |
| // Calls MaybeInterceptWebSignin and verifies the heuristic outcome and the |
| // histograms. |
| // This function only works if the interception decision cannot be made |
| // synchronously (GetHeuristicOutcome() returns no value). |
| void TestAsynchronousInterception( |
| AccountInfo account_info, |
| bool is_new_account, |
| bool is_sync_signin, |
| SigninInterceptionHeuristicOutcome expected_outcome) { |
| ASSERT_EQ(interceptor()->GetHeuristicOutcome(is_new_account, is_sync_signin, |
| account_info.email), |
| std::nullopt); |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, is_new_account, |
| is_sync_signin); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", |
| expected_outcome, 1); |
| histogram_tester.ExpectUniqueTimeSample("Signin.Intercept.HeuristicLatency", |
| base::Milliseconds(0), 1); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| } |
| |
| protected: |
| // testing::Test: |
| void SetUp() override { |
| BrowserWithTestWindowTest::SetUp(); |
| |
| identity_test_env_profile_adaptor_ = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile()); |
| identity_test_env_profile_adaptor_->identity_test_env() |
| ->SetTestURLLoaderFactory(&test_url_loader_factory_); |
| |
| // Create the first tab so that web_contents() exists. |
| AddTab(browser(), GURL("http://foo/1")); |
| } |
| |
| private: |
| void TearDown() override { |
| identity_test_env_profile_adaptor_.reset(); |
| BrowserWithTestWindowTest::TearDown(); |
| } |
| |
| std::unique_ptr<KeyedService> BuildDiceWebSigninInterceptor( |
| content::BrowserContext* browser_context) { |
| Profile* input_profile = Profile::FromBrowserContext(browser_context); |
| CHECK_EQ(input_profile, profile()); |
| auto delegate = std::make_unique< |
| testing::StrictMock<MockDiceWebSigninInterceptorDelegate>>(); |
| mock_delegate_ = delegate->GetWeakPtr(); |
| return std::make_unique<DiceWebSigninInterceptor>(profile(), |
| std::move(delegate)); |
| } |
| |
| TestingProfile::TestingFactories GetTestingFactories() override { |
| TestingProfile::TestingFactories factories = |
| IdentityTestEnvironmentProfileAdaptor:: |
| GetIdentityTestEnvironmentFactories(); |
| factories.push_back( |
| {ChromeSigninClientFactory::GetInstance(), |
| base::BindRepeating(&BuildChromeSigninClientWithURLLoader, |
| &test_url_loader_factory_)}); |
| |
| factories.push_back( |
| {DiceWebSigninInterceptorFactory::GetInstance(), |
| base::BindRepeating( |
| &DiceWebSigninInterceptorTest::BuildDiceWebSigninInterceptor, |
| base::Unretained(this))}); |
| |
| return factories; |
| } |
| |
| // Force local machine to be unmanaged, so that variations in try bots and |
| // developer machines don't affect the tests. See https://crbug.com/1445255. |
| policy::ScopedManagementServiceOverrideForTesting platform_browser_mgmt_ = { |
| policy::ManagementServiceFactory::GetForPlatform(), |
| policy::EnterpriseManagementAuthority::NONE}; |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> |
| identity_test_env_profile_adaptor_; |
| base::WeakPtr<MockDiceWebSigninInterceptorDelegate> mock_delegate_; |
| }; |
| |
| TEST_F(DiceWebSigninInterceptorTest, ShouldShowProfileSwitchBubble) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| const std::string& email = account_info.email; |
| EXPECT_FALSE(interceptor()->ShouldShowProfileSwitchBubble( |
| email, profile_attributes_storage())); |
| |
| // Add another profile with no account. |
| CreateTestingProfile("Profile 1"); |
| EXPECT_FALSE(interceptor()->ShouldShowProfileSwitchBubble( |
| email, profile_attributes_storage())); |
| |
| // Add another profile with a different account. |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| std::string kOtherGaiaID = "SomeOtherGaiaID"; |
| ASSERT_NE(kOtherGaiaID, account_info.gaia); |
| entry->SetAuthInfo(kOtherGaiaID, u"alice@gmail.com", |
| /*is_consented_primary_account=*/true); |
| EXPECT_FALSE(interceptor()->ShouldShowProfileSwitchBubble( |
| email, profile_attributes_storage())); |
| |
| // Change the account to match. |
| entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| const ProfileAttributesEntry* switch_to_entry = |
| interceptor()->ShouldShowProfileSwitchBubble( |
| email, profile_attributes_storage()); |
| EXPECT_EQ(entry, switch_to_entry); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, NoBubbleWithSingleAccount) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Without Primary account. |
| EXPECT_FALSE(interceptor()->ShouldShowEnterpriseBubble(account_info)); |
| |
| // With UPA. |
| identity_test_env()->SetPrimaryAccount("bob@example.com", |
| signin::ConsentLevel::kSignin); |
| EXPECT_FALSE(interceptor()->ShouldShowEnterpriseBubble(account_info)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, ShouldShowEnterpriseBubble) { |
| // Setup 3 accounts in the profile: |
| // - primary account |
| // - other enterprise account that is not primary (should be ignored) |
| // - intercepted account. |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo other_account_info = |
| identity_test_env()->MakeAccountAvailable("dummy@example.com"); |
| MakeValidAccountInfo(&other_account_info); |
| other_account_info.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(other_account_info); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| ASSERT_EQ(identity_test_env()->identity_manager()->GetPrimaryAccountId( |
| signin::ConsentLevel::kSignin), |
| primary_account_info.account_id); |
| |
| // The primary account does not have full account info (empty domain). |
| ASSERT_TRUE(identity_test_env() |
| ->identity_manager() |
| ->FindExtendedAccountInfo(primary_account_info) |
| .hosted_domain.empty()); |
| EXPECT_FALSE(interceptor()->ShouldShowEnterpriseBubble(account_info)); |
| account_info.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| EXPECT_TRUE(interceptor()->ShouldShowEnterpriseBubble(account_info)); |
| |
| // The primary account has full info. |
| MakeValidAccountInfo(&primary_account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| // The intercepted account is enterprise. |
| EXPECT_TRUE(interceptor()->ShouldShowEnterpriseBubble(account_info)); |
| // Two consummer accounts. |
| account_info.hosted_domain = kNoHostedDomainFound; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| EXPECT_FALSE(interceptor()->ShouldShowEnterpriseBubble(account_info)); |
| // The primary account is enterprise. |
| primary_account_info.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| EXPECT_TRUE(interceptor()->ShouldShowEnterpriseBubble(account_info)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, ShouldEnforceEnterpriseProfileSeparation) { |
| profile()->GetPrefs()->SetBoolean( |
| prefs::kManagedAccountsSigninRestrictionScopeMachine, true); |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_strict"); |
| |
| // Setup 3 accounts in the profile: |
| // - primary account |
| // - other enterprise account that is not primary (should be ignored) |
| // - intercepted account. |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@gmail.com", signin::ConsentLevel::kSignin); |
| |
| AccountInfo other_account_info = |
| identity_test_env()->MakeAccountAvailable("dummy@example.com"); |
| MakeValidAccountInfo(&other_account_info); |
| other_account_info.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(other_account_info); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| ASSERT_EQ(identity_test_env()->identity_manager()->GetPrimaryAccountId( |
| signin::ConsentLevel::kSignin), |
| primary_account_info.account_id); |
| interceptor()->state_->new_account_interception_ = true; |
| // Consumer account not intercepted. |
| EXPECT_FALSE( |
| interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info)); |
| account_info.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| // Managed account intercepted. |
| EXPECT_TRUE( |
| interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| ShouldEnforceEnterpriseProfileSeparationWithoutUPA) { |
| profile()->GetPrefs()->SetBoolean( |
| prefs::kManagedAccountsSigninRestrictionScopeMachine, true); |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_strict"); |
| AccountInfo account_info_1 = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&account_info_1); |
| account_info_1.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_1); |
| |
| interceptor()->state_->new_account_interception_ = true; |
| // Primary account is not set. |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| EXPECT_TRUE( |
| interceptor()->ShouldEnforceEnterpriseProfileSeparation(account_info_1)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| ShouldEnforceEnterpriseProfileSeparationReauth) { |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_strict"); |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info); |
| primary_account_info.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| // Primary account is set. |
| ASSERT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| ASSERT_TRUE(primary_account_info.IsManaged()); |
| EXPECT_TRUE(interceptor()->ShouldEnforceEnterpriseProfileSeparation( |
| primary_account_info)); |
| |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile()->GetPath()); |
| entry->SetUserAcceptedAccountManagement(true); |
| |
| EXPECT_FALSE(interceptor()->ShouldEnforceEnterpriseProfileSeparation( |
| primary_account_info)); |
| } |
| |
| class DiceWebSigninInterceptorManagedAccountTest |
| : public DiceWebSigninInterceptorTest, |
| public testing::WithParamInterface<bool> { |
| public: |
| DiceWebSigninInterceptorManagedAccountTest() |
| : signin_interception_enabled_(GetParam()) {} |
| |
| protected: |
| void SetUp() override { |
| DiceWebSigninInterceptorTest::SetUp(); |
| profile()->GetPrefs()->SetBoolean(prefs::kSigninInterceptionEnabled, |
| signin_interception_enabled_); |
| } |
| |
| bool signin_interception_enabled_; |
| }; |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| NoForcedInterceptionShowsDialogIfFeatureEnabled) { |
| base::test::ScopedFeatureList scoped_list; |
| scoped_list.InitAndEnableFeature( |
| features::kEnterpriseUpdatedProfileCreationScreen); |
| // Reauth intercepted if enterprise confirmation not shown yet for forced |
| // managed separation. |
| AccountInfo account_info = identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| interceptor()->SetInterceptedAccountProfileSeparationPoliciesForTesting( |
| policy::ProfileSeparationPolicies("")); |
| |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseAcceptManagement, |
| account_info, account_info, SkColor(), |
| /*show_link_data_option=*/true, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestAsynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise); |
| } |
| |
| TEST_P( |
| DiceWebSigninInterceptorManagedAccountTest, |
| NoForcedInterceptionShowsNoDialogIfFeatureEnabledButDisabledDialogByPolicy) { |
| base::test::ScopedFeatureList scoped_list; |
| scoped_list.InitAndEnableFeature( |
| features::kEnterpriseUpdatedProfileCreationScreen); |
| // Reauth intercepted if enterprise confirmation not shown yet for forced |
| // managed separation. |
| AccountInfo account_info = identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| interceptor()->SetInterceptedAccountProfileSeparationPoliciesForTesting( |
| policy::ProfileSeparationPolicies( |
| policy::ProfileSeparationSettings::DISABLED, std::nullopt)); |
| |
| if (signin_interception_enabled_) { |
| TestAsynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortAccountInfoNotCompatible); |
| } else { |
| TestAsynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortInterceptionDisabled); |
| } |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| NoForcedInterceptionShowsNoBubble) { |
| // Reauth intercepted if enterprise confirmation not shown yet for forced |
| // managed separation. |
| AccountInfo account_info = identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| interceptor()->SetInterceptedAccountProfileSeparationPoliciesForTesting( |
| policy::ProfileSeparationPolicies("")); |
| |
| if (signin_interception_enabled_) { |
| TestAsynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortAccountInfoNotCompatible); |
| } else { |
| TestAsynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortInterceptionDisabled); |
| } |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountAsPrimaryReauth) { |
| profile()->GetPrefs()->SetBoolean( |
| prefs::kManagedAccountsSigninRestrictionScopeMachine, true); |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account"); |
| |
| // Reauth intercepted if enterprise confirmation not shown yet for forced |
| // managed separation. |
| AccountInfo account_info = identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account"); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/false, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountAsPrimaryManaged) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_strict"); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, AccountInfo(), SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountAsPrimaryManagedLinkData) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| interceptor()->SetInterceptedAccountProfileSeparationPoliciesForTesting( |
| policy::ProfileSeparationPolicies("primary_account_keep_existing_data")); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, AccountInfo(), SkColor(), |
| /*show_link_data_option=*/true, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestAsynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountAsPrimaryManagedLinkDataSecondaryAccount) { |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| profile()->GetPrefs()->SetBoolean( |
| prefs::kManagedAccountsSigninRestrictionScopeMachine, true); |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_keep_existing_data"); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountAsPrimaryManagedStrictLinkData) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_strict_keep_existing_data"); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, AccountInfo(), SkColor(), |
| /*show_link_data_option=*/true, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountAsPrimaryManagedStrictLinkDataSecondaryAccount) { |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_strict_keep_existing_data"); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountAsPrimaryProfileSwitch) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| profile()->GetPrefs()->SetBoolean( |
| prefs::kManagedAccountsSigninRestrictionScopeMachine, true); |
| profile()->GetPrefs()->SetString(prefs::kManagedAccountsSigninRestriction, |
| "primary_account_strict"); |
| |
| // Setup for profile switch interception. |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(account_info.email), |
| /*is_consented_primary_account=*/false); |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitchForced, |
| account_info, AccountInfo(), SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception(account_info, /*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome:: |
| kInterceptEnterpriseForcedProfileSwitch); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountSecondaryAccountNotAllowed) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("notexample.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountSecondaryAccountAllowedReauth) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("notexample.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| TestSynchronousInterception( |
| primary_account_info, /*is_new_account=*/false, /*is_sync_signin=*/false, |
| profile()->GetPrefs()->GetBoolean(prefs::kSigninInterceptionEnabled) |
| ? SigninInterceptionHeuristicOutcome::kAbortAccountNotNew |
| : SigninInterceptionHeuristicOutcome::kAbortInterceptionDisabled); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountSecondaryAccountNotAllowedReauth) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("notexample.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/false, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountSecondaryConsumerAccountNotAllowed) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("example.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| std::string email = "bob@gmail.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/false); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced); |
| } |
| |
| TEST_P(DiceWebSigninInterceptorManagedAccountTest, |
| EnforceManagedAccountSecondaryAccountAllowed) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("gmail.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "alice@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&primary_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| std::string email = "bob@gmail.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| if (!profile()->GetPrefs()->GetBoolean(prefs::kSigninInterceptionEnabled)) { |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortInterceptionDisabled); |
| return; |
| } |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/false); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestAsynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| DiceWebSigninInterceptorManagedAccountTest, |
| ::testing::Bool(), |
| &ParamToTestSuffixForInterceptionAndSyncPromo); |
| |
| TEST_F(DiceWebSigninInterceptorTest, ShouldShowEnterpriseBubbleWithoutUPA) { |
| AccountInfo account_info_1 = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&account_info_1); |
| account_info_1.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_1); |
| AccountInfo account_info_2 = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info_2); |
| account_info_2.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_2); |
| |
| // Primary account is not set. |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| EXPECT_FALSE(interceptor()->ShouldShowEnterpriseBubble(account_info_1)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, ShouldShowMultiUserBubble) { |
| // Setup two accounts in the profile. |
| AccountInfo account_info_1 = identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| MakeValidAccountInfo(&account_info_1); |
| account_info_1.given_name = "Bob"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_1); |
| AccountInfo account_info_2 = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| |
| // The other account does not have full account info (empty name). |
| ASSERT_TRUE(account_info_2.given_name.empty()); |
| EXPECT_TRUE(interceptor()->ShouldShowMultiUserBubble(account_info_1)); |
| |
| // Accounts with different names. |
| account_info_1.given_name = "Bob"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_1); |
| MakeValidAccountInfo(&account_info_2); |
| account_info_2.given_name = "Alice"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_2); |
| EXPECT_TRUE(interceptor()->ShouldShowMultiUserBubble(account_info_1)); |
| |
| // Accounts with same names. |
| account_info_1.given_name = "Alice"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_1); |
| EXPECT_FALSE(interceptor()->ShouldShowMultiUserBubble(account_info_1)); |
| |
| // Comparison is case insensitive. |
| account_info_1.given_name = "alice"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_1); |
| EXPECT_FALSE(interceptor()->ShouldShowMultiUserBubble(account_info_1)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| ShouldShowMultiUserBubbleNoPrimaryAccount) { |
| // Setup two accounts in the profile. |
| AccountInfo account_info_1 = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&account_info_1); |
| account_info_1.given_name = "Bob"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info_1); |
| AccountInfo account_info_2 = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| account_info_2.given_name = "Alice"; |
| EXPECT_FALSE(interceptor()->ShouldShowMultiUserBubble(account_info_1)); |
| |
| identity_test_env()->SetPrimaryAccount("bob@example.com", |
| signin::ConsentLevel::kSignin); |
| EXPECT_TRUE(interceptor()->ShouldShowMultiUserBubble(account_info_1)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, NoInterception) { |
| // Setup for profile switch interception. |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| |
| if (switches::IsExplicitBrowserSigninUIOnDesktopEnabled()) { |
| // Suppress the signin bubble. |
| SigninPrefs(*profile()->GetPrefs()) |
| .SetChromeSigninInterceptionUserChoice( |
| account_info.gaia, ChromeSigninUserChoice::kDoNotSignin); |
| } |
| |
| // Check that Sync signin is not intercepted. |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/true, |
| SigninInterceptionHeuristicOutcome::kAbortSyncSignin); |
| |
| // Check that reauth is not intercepted. |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/false, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortAccountNotNew); |
| |
| // Check that interception works otherwise, as a sanity check. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitch, |
| account_info, AccountInfo()); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch); |
| } |
| |
| // Checks that the heuristic still works if the account was not added to Chrome |
| // yet. |
| TEST_F(DiceWebSigninInterceptorTest, HeuristicAccountNotAdded) { |
| // Setup for profile switch interception. |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo("dummy_gaia_id", base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| EXPECT_EQ(interceptor()->GetHeuristicOutcome( |
| /*is_new_account=*/true, /*is_sync_signin=*/false, email), |
| SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch); |
| } |
| |
| // Checks that the heuristic defaults to gmail.com when no domain is specified. |
| TEST_F(DiceWebSigninInterceptorTest, HeuristicDefaultsToGmail) { |
| // Setup for profile switch interception. |
| std::string email = "bob@gmail.com"; |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo("dummy_gaia_id", base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| // No domain defaults to gmail.com |
| EXPECT_EQ(interceptor()->GetHeuristicOutcome( |
| /*is_new_account=*/true, /*is_sync_signin=*/false, "bob"), |
| SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch); |
| } |
| |
| // Checks that no heuristic is returned if signin interception is disabled. |
| TEST_F(DiceWebSigninInterceptorTest, InterceptionDisabled) { |
| // Setup for profile switch interception. |
| std::string email = "bob@gmail.com"; |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| profile()->GetPrefs()->SetBoolean(prefs::kSigninInterceptionEnabled, false); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo("dummy_gaia_id", base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| EXPECT_EQ(interceptor()->GetHeuristicOutcome( |
| /*is_new_account=*/true, /*is_sync_signin=*/false, "bob"), |
| SigninInterceptionHeuristicOutcome::kAbortInterceptionDisabled); |
| EXPECT_EQ( |
| interceptor()->GetHeuristicOutcome( |
| /*is_new_account=*/true, /*is_sync_signin=*/false, "bob@example.com"), |
| std::nullopt); |
| |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| EXPECT_EQ( |
| interceptor()->GetHeuristicOutcome( |
| /*is_new_account=*/true, /*is_sync_signin=*/false, "bob@example.com"), |
| SigninInterceptionHeuristicOutcome::kAbortInterceptionDisabled); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, TabClosed) { |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| /*web_contents=*/nullptr, CoreAccountId(), |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/true, /*is_sync_signin=*/false); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kAbortTabClosed, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, InterceptionInProgress) { |
| // Setup for profile switch interception. |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| |
| // Start an interception. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitch, |
| account_info, AccountInfo()); |
| base::OnceCallback<void(SigninInterceptionResult)> delegate_callback; |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)) |
| .WillOnce(testing::WithArg<2>(testing::Invoke( |
| [&delegate_callback]( |
| base::OnceCallback<void(SigninInterceptionResult)> callback) { |
| delegate_callback = std::move(callback); |
| return nullptr; |
| }))); |
| MaybeIntercept(account_info.account_id); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| EXPECT_TRUE(interceptor()->is_interception_in_progress()); |
| |
| // Check that there is no interception while another one is in progress. |
| base::HistogramTester histogram_tester; |
| MaybeIntercept(account_info.account_id); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kAbortInterceptInProgress, 1); |
| |
| // Complete the interception that was in progress. |
| std::move(delegate_callback).Run(SigninInterceptionResult::kDeclined); |
| EXPECT_FALSE(interceptor()->is_interception_in_progress()); |
| |
| // A new interception can now start. |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, DeclineCreationRepeatedly) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| const int kMaxProfileCreationDeclinedCount = 2; |
| // Decline the interception kMaxProfileCreationDeclinedCount times. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| for (int i = 0; i < kMaxProfileCreationDeclinedCount; ++i) { |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)) |
| .WillOnce(testing::WithArg<2>(testing::Invoke( |
| [](base::OnceCallback<void(SigninInterceptionResult)> callback) { |
| std::move(callback).Run(SigninInterceptionResult::kDeclined); |
| return nullptr; |
| }))); |
| MaybeIntercept(account_info.account_id); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), false); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise, i + 1); |
| } |
| |
| // Next time the interception is not shown again. |
| MaybeIntercept(account_info.account_id); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), false); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kAbortUserDeclinedProfileForAccount, |
| 1); |
| |
| // Another account can still be intercepted. |
| account_info.email = "oscar@example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| expected_parameters.intercepted_account = account_info; |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise, |
| kMaxProfileCreationDeclinedCount + 1); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), true); |
| } |
| |
| // Regression test for https://crbug.com/1309647 |
| TEST_F(DiceWebSigninInterceptorTest, |
| DeclineCreationRepeatedlyWithPolicyFetcher) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| interceptor()->SetInterceptedAccountProfileSeparationPoliciesForTesting( |
| policy::ProfileSeparationPolicies("")); |
| |
| const int kMaxProfileCreationDeclinedCount = 2; |
| // Decline the interception kMaxProfileCreationDeclinedCount times. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| for (int i = 0; i < kMaxProfileCreationDeclinedCount; ++i) { |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)) |
| .WillOnce(testing::WithArg<2>(testing::Invoke( |
| [](base::OnceCallback<void(SigninInterceptionResult)> callback) { |
| std::move(callback).Run(SigninInterceptionResult::kDeclined); |
| return nullptr; |
| }))); |
| MaybeIntercept(account_info.account_id); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), false); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise, i + 1); |
| } |
| |
| // Next time the interception is not shown again. |
| MaybeIntercept(account_info.account_id); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), false); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kAbortUserDeclinedProfileForAccount, |
| 1); |
| |
| // Another account can still be intercepted. |
| account_info.email = "oscar@example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| expected_parameters.intercepted_account = account_info; |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise, |
| kMaxProfileCreationDeclinedCount + 1); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), true); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, DeclineSwitchRepeatedly_NoLimit) { |
| base::HistogramTester histogram_tester; |
| // Setup for profile switch interception. |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| |
| // Test that the profile switch can be declined multiple times. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitch, |
| account_info, AccountInfo()); |
| for (int i = 0; i < 10; ++i) { |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)) |
| .WillOnce(testing::WithArg<2>(testing::Invoke( |
| [](base::OnceCallback<void(SigninInterceptionResult)> callback) { |
| std::move(callback).Run(SigninInterceptionResult::kDeclined); |
| return nullptr; |
| }))); |
| MaybeIntercept(account_info.account_id); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), false); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptProfileSwitch, i + 1); |
| } |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, PersistentHash) { |
| // The hash is persistent (the value should never change). |
| EXPECT_EQ("email_174", |
| interceptor()->GetPersistentEmailHash("alice@example.com")); |
| // Different email get another hash. |
| EXPECT_NE(interceptor()->GetPersistentEmailHash("bob@gmail.com"), |
| interceptor()->GetPersistentEmailHash("alice@example.com")); |
| // Equivalent emails get the same hash. |
| EXPECT_EQ(interceptor()->GetPersistentEmailHash("bob"), |
| interceptor()->GetPersistentEmailHash("bob@gmail.com")); |
| EXPECT_EQ(interceptor()->GetPersistentEmailHash("bo.b@gmail.com"), |
| interceptor()->GetPersistentEmailHash("bob@gmail.com")); |
| // Dots are removed only for gmail accounts. |
| EXPECT_NE(interceptor()->GetPersistentEmailHash("alice@example.com"), |
| interceptor()->GetPersistentEmailHash("al.ice@example.com")); |
| } |
| |
| // Interception other than the profile switch require at least 2 accounts. |
| TEST_F(DiceWebSigninInterceptorTest, NoInterceptionWithOneAccount) { |
| base::HistogramTester histogram_tester; |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("bob@gmail.com"); |
| // Interception aborts even if the account info is not available. |
| ASSERT_FALSE(identity_test_env() |
| ->identity_manager() |
| ->FindExtendedAccountInfoByAccountId(account_info.account_id) |
| .IsValid()); |
| |
| if (switches::IsExplicitBrowserSigninUIOnDesktopEnabled()) { |
| // Suppress the signin bubble. |
| SigninPrefs(*profile()->GetPrefs()) |
| .SetChromeSigninInterceptionUserChoice( |
| account_info.gaia, ChromeSigninUserChoice::kDoNotSignin); |
| } |
| |
| TestSynchronousInterception( |
| account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortSingleAccount); |
| } |
| |
| // When profile creation is disallowed, profile switch interception is still |
| // enabled, but others are disabled. |
| TEST_F(DiceWebSigninInterceptorTest, ProfileCreationDisallowed) { |
| base::HistogramTester histogram_tester; |
| g_browser_process->local_state()->SetBoolean(prefs::kBrowserAddPersonEnabled, |
| false); |
| // Setup for profile switch interception. |
| std::string email = "bob@example.com"; |
| AccountInfo account_info = identity_test_env()->MakeAccountAvailable(email); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| AccountInfo other_account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&other_account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(other_account_info); |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(email), |
| /*is_consented_primary_account=*/false); |
| |
| if (switches::IsExplicitBrowserSigninUIOnDesktopEnabled()) { |
| // Suppress the signin bubble. |
| SigninPrefs(*profile()->GetPrefs()) |
| .SetChromeSigninInterceptionUserChoice( |
| other_account_info.gaia, ChromeSigninUserChoice::kDoNotSignin); |
| } |
| |
| // Interception that would offer creating a new profile does not work. |
| TestSynchronousInterception( |
| other_account_info, /*is_new_account=*/true, /*is_sync_signin=*/false, |
| SigninInterceptionHeuristicOutcome::kAbortProfileCreationDisallowed); |
| |
| // Profile switch interception still works. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitch, |
| account_info, AccountInfo()); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, WaitForAccountInfoAvailable) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| EXPECT_FALSE(interceptor() |
| ->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email) |
| .has_value()); |
| MaybeIntercept(account_info.account_id); |
| // Delegate was not called yet. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| // Account info becomes available, interception happens. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, AccountInfoAlreadyAvailable) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account info is already available, interception happens immediately. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, MultiUserInterception) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account info is already available, interception happens immediately. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kMultiUser, account_info, |
| primary_account_info); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptMultiUser, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| AccountInfoAndCapabilitiesAlreadyAvailable) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account info is already available, interception happens immediately. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterprise, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| AccountInfoAlreadyAvailableWaitForCapabilities) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfoWithoutCapabilities(&account_info, "example.com"); |
| EXPECT_FALSE(interceptor() |
| ->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email) |
| .has_value()); |
| MaybeIntercept(account_info.account_id); |
| // Delegate was not called yet. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| // Account capabilities become available, interception happens. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MakeValidAccountCapabilities(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| AccountCapabilitiesAlreadyAvailableWaitForInfo) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountCapabilities(&account_info); |
| EXPECT_FALSE(interceptor() |
| ->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email) |
| .has_value()); |
| MaybeIntercept(account_info.account_id); |
| // Delegate was not called yet. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| // Account info becomes available, interception happens. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, WaitForAccountInfoTimeout) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| EXPECT_FALSE(interceptor() |
| ->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email) |
| .has_value()); |
| MaybeIntercept(account_info.account_id); |
| // Delegate was not called yet. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| // No interception happens, as we time out without the required info. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| task_environment()->FastForwardBy(base::Seconds(5)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, AccountInfoRemovedWhileWaiting) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| EXPECT_FALSE(interceptor() |
| ->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email) |
| .has_value()); |
| MaybeIntercept(account_info.account_id); |
| // Delegate was not called yet, interception is in progress. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| EXPECT_TRUE(interceptor()->is_interception_in_progress()); |
| |
| // Clear primary account. |
| identity_test_env()->EnableRemovalOfExtendedAccountInfo(); |
| identity_test_env()->RemoveRefreshTokenForAccount(account_info.account_id); |
| |
| // Interception is cancelled. |
| EXPECT_FALSE(interceptor()->is_interception_in_progress()); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kAbortSignedOut, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, WaitForAccountCapabilitiesTimeout) { |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfoWithoutCapabilities(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| EXPECT_FALSE(interceptor() |
| ->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email) |
| .has_value()); |
| MaybeIntercept(account_info.account_id); |
| |
| // Delegate was not called yet. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| // Interception happens, as capabilities are not required. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterprise, account_info, |
| primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/true); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| task_environment()->FastForwardBy(base::Seconds(5)); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| ConsumerAccountForcedEnterpriseInterceptionOnEmptyProfile) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("notexample.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| base::HistogramTester histogram_tester; |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@gmail.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account info is already available, interception happens immediately. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, AccountInfo(), SkColor(), |
| /*show_link_data_option=*/true, /*show_managed_disclaimer=*/false); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, ConsumerAccountAllowedOnEmptyProfile) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("gmail.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| base::HistogramTester histogram_tester; |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@gmail.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| if (switches::IsExplicitBrowserSigninUIOnDesktopEnabled()) { |
| // Suppress the signin bubble. |
| SigninPrefs(*profile()->GetPrefs()) |
| .SetChromeSigninInterceptionUserChoice( |
| account_info.gaia, ChromeSigninUserChoice::kDoNotSignin); |
| } |
| |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kAbortSingleAccount, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| ConsumerAccountForcedEnterpriseInterceptionOnManagedProfile) { |
| base::Value::List profile_separation_exception_list; |
| profile_separation_exception_list.Append(base::Value("notexample.com")); |
| profile()->GetPrefs()->SetList(prefs::kProfileSeparationDomainExceptionList, |
| std::move(profile_separation_exception_list)); |
| |
| base::HistogramTester histogram_tester; |
| AccountInfo primary_account_info = |
| identity_test_env()->MakePrimaryAccountAvailable( |
| "bob@example.com", signin::ConsentLevel::kSignin); |
| primary_account_info.hosted_domain = "example.com"; |
| identity_test_env()->UpdateAccountInfoForAccount(primary_account_info); |
| |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@gmail.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account info is already available, interception happens immediately. |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kEnterpriseForced, |
| account_info, primary_account_info, SkColor(), |
| /*show_link_data_option=*/false, /*show_managed_disclaimer=*/false); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(account_info.account_id); |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.HeuristicOutcome", |
| SigninInterceptionHeuristicOutcome::kInterceptEnterpriseForced, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, StateResetTest) { |
| // This is a simplification of the equality check. There is no need to |
| // implement a full exhaustive check for the test. |
| auto AreStatesEqual = |
| [](const DiceWebSigninInterceptor::ResetableState* state1, |
| const DiceWebSigninInterceptor::ResetableState* state2) { |
| return state1->is_interception_in_progress_ == |
| state2->is_interception_in_progress_; |
| }; |
| |
| // Create the default values to be compared to. |
| DiceWebSigninInterceptor::ResetableState default_values; |
| |
| DiceWebSigninInterceptor::ResetableState* state_ = |
| interceptor()->state_.get(); |
| // Ensure initial default values. |
| EXPECT_TRUE(AreStatesEqual(state_, &default_values)); |
| |
| // Simulate default state value modifications |
| state_->is_interception_in_progress_ = true; |
| |
| ASSERT_FALSE(AreStatesEqual(state_, &default_values)); |
| |
| // Reset and check the default values equality. |
| interceptor()->Reset(); |
| |
| // Values should be properly reset to default values. |
| EXPECT_TRUE(AreStatesEqual(interceptor()->state_.get(), &default_values)); |
| } |
| |
| // Tests the recording of metrics relating to the supervised user capability. |
| class DiceWebSigninInterceptorTestSupervisionMetrics |
| : public DiceWebSigninInterceptorTest, |
| public testing::WithParamInterface< |
| std::tuple<signin::Tribool, |
| WebSigninInterceptor::SigninInterceptionType>> { |
| public: |
| DiceWebSigninInterceptorTestSupervisionMetrics() { |
| feature_list_.InitAndEnableFeature( |
| switches::kExplicitBrowserSigninUIOnDesktop); |
| } |
| |
| signin::Tribool IsSupervisedUser() { return std::get<0>(GetParam()); } |
| WebSigninInterceptor::SigninInterceptionType GetInterceptionType() { |
| return std::get<1>(GetParam()); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // helper |
| std::string InterceptionTypeString( |
| WebSigninInterceptor::SigninInterceptionType interception_type) { |
| switch (interception_type) { |
| case WebSigninInterceptor::SigninInterceptionType::kChromeSignin: |
| return "ChromeSignin"; |
| case WebSigninInterceptor::SigninInterceptionType::kMultiUser: |
| return "MultiUser"; |
| case WebSigninInterceptor::SigninInterceptionType::kProfileSwitch: |
| return "ProfileSwitch"; |
| default: |
| return ""; |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| DiceWebSigninInterceptorTestSupervisionMetrics, |
| testing::Combine( |
| testing::Values(signin::Tribool::kTrue, |
| signin::Tribool::kFalse, |
| signin::Tribool::kUnknown), |
| testing::Values( |
| WebSigninInterceptor::SigninInterceptionType::kChromeSignin, |
| WebSigninInterceptor::SigninInterceptionType::kMultiUser, |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitch)), |
| [](const auto& info) { |
| std::string name = ""; |
| switch (std::get<0>(info.param)) { |
| case signin::Tribool::kTrue: |
| name += "ForSupervisedUser"; |
| break; |
| case signin::Tribool::kFalse: |
| name += "ForRegularUser"; |
| break; |
| case signin::Tribool::kUnknown: |
| name += "ForUnknownSupervision"; |
| break; |
| } |
| name += InterceptionTypeString(std::get<1>(info.param)); |
| return name; |
| }); |
| |
| TEST_P(DiceWebSigninInterceptorTestSupervisionMetrics, RecordMetrics) { |
| base::HistogramTester histogram_tester; |
| |
| std::string intercepted_account_email = "alice@example.com"; |
| std::string other_account_email = "bob@example.com"; |
| |
| AccountInfo other_account_info; |
| if (GetInterceptionType() == |
| WebSigninInterceptor::SigninInterceptionType::kMultiUser) { |
| // For the multi-use case, set the other account as the primary account. |
| other_account_info = identity_test_env()->MakePrimaryAccountAvailable( |
| other_account_email, signin::ConsentLevel::kSignin); |
| } |
| |
| AccountInfo intercepted_account_info = |
| identity_test_env()->MakeAccountAvailable(intercepted_account_email); |
| MakeValidAccountInfoWithoutCapabilities(&intercepted_account_info); |
| |
| // Set supervised user capabilities and expectations. |
| AccountCapabilitiesTestMutator mutator( |
| &intercepted_account_info.capabilities); |
| SinginInterceptSupervisionState expected_state; |
| switch (IsSupervisedUser()) { |
| case (signin::Tribool::kTrue): |
| mutator.set_is_subject_to_parental_controls(true); |
| expected_state = SinginInterceptSupervisionState::kSupervisedUser; |
| break; |
| case (signin::Tribool::kFalse): |
| mutator.set_is_subject_to_parental_controls(false); |
| expected_state = SinginInterceptSupervisionState::kRegularUser; |
| break; |
| case (signin::Tribool::kUnknown): |
| expected_state = SinginInterceptSupervisionState::kUnknownSupervision; |
| break; |
| } |
| identity_test_env()->UpdateAccountInfoForAccount(intercepted_account_info); |
| |
| if (GetInterceptionType() == |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitch) { |
| // For the profile switch case, create an existing profile for the account |
| // to be intercepted. |
| Profile* profile_2 = CreateTestingProfile("Profile 2"); |
| ProfileAttributesEntry* entry = |
| profile_attributes_storage()->GetProfileAttributesWithPath( |
| profile_2->GetPath()); |
| ASSERT_NE(entry, nullptr); |
| entry->SetAuthInfo(intercepted_account_info.gaia, |
| base::UTF8ToUTF16(intercepted_account_email), |
| /*is_consented_primary_account=*/false); |
| } |
| |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| GetInterceptionType(), intercepted_account_info, other_account_info); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MaybeIntercept(intercepted_account_info.account_id); |
| |
| if (IsSupervisedUser() == signin::Tribool::kUnknown) { |
| // Timeout the capabilities and account info fetching, as this is the case |
| // the supervised user capability is still unknown. |
| task_environment()->FastForwardBy(base::Seconds(5)); |
| } |
| |
| int expected_count_multiuser = |
| GetInterceptionType() == |
| WebSigninInterceptor::SigninInterceptionType::kMultiUser |
| ? 1 |
| : 0; |
| int expected_count_signin = |
| GetInterceptionType() == |
| WebSigninInterceptor::SigninInterceptionType::kChromeSignin |
| ? 1 |
| : 0; |
| int expected_count_switch = |
| GetInterceptionType() == |
| WebSigninInterceptor::SigninInterceptionType::kProfileSwitch |
| ? 1 |
| : 0; |
| histogram_tester.ExpectBucketCount( |
| "Signin.Intercept.Heuristic.SupervisionState.ChromeSignin", |
| expected_state, expected_count_signin); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Intercept.Heuristic.SupervisionState.MultiUser", expected_state, |
| expected_count_multiuser); |
| histogram_tester.ExpectBucketCount( |
| "Signin.Intercept.Heuristic.SupervisionState.Switch", expected_state, |
| expected_count_switch); |
| } |
| |
| class DiceWebSigninInterceptorTestWithUnoEnabled |
| : public DiceWebSigninInterceptorTest { |
| private: |
| base::test::ScopedFeatureList feature_list_{ |
| switches::kExplicitBrowserSigninUIOnDesktop}; |
| }; |
| |
| TEST_F(DiceWebSigninInterceptorTestWithUnoEnabled, |
| InterceptShouldShowChromeSigninBubbleOnAccountSigninAndChromeSignOut) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account is valid. |
| ASSERT_TRUE(account_info.IsValid()); |
| // Primary account is not set, Chrome is not signed in. |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kChromeSignin, |
| /*intercepted_account=*/account_info, |
| /*primary_account=*/AccountInfo()); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| |
| auto expected_outcome = |
| SigninInterceptionHeuristicOutcome::kInterceptChromeSignin; |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/true, /*is_sync_signin=*/false); |
| EXPECT_EQ( |
| interceptor()->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email, account_info.gaia), |
| expected_outcome); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", |
| expected_outcome, 1); |
| histogram_tester.ExpectUniqueTimeSample("Signin.Intercept.HeuristicLatency", |
| base::Milliseconds(0), 1); |
| |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.Heuristic.ShouldShowChromeSigninBubbleWithReason", |
| ShouldShowChromeSigninBubbleWithReason::kShouldShow, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTestWithUnoEnabled, |
| InterceptShouldShowChromeSigninReauthAccountInfoAvailable) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account is valid. |
| ASSERT_TRUE(account_info.IsValid()); |
| // Primary account is not set, Chrome is not signed in. |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kChromeSignin, |
| /*intercepted_account=*/account_info, |
| /*primary_account=*/AccountInfo()); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| |
| auto expected_outcome = |
| SigninInterceptionHeuristicOutcome::kInterceptChromeSignin; |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/false, /*is_sync_signin=*/false); |
| EXPECT_EQ( |
| interceptor()->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email, account_info.gaia), |
| expected_outcome); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", |
| expected_outcome, 1); |
| histogram_tester.ExpectUniqueTimeSample("Signin.Intercept.HeuristicLatency", |
| base::Milliseconds(0), 1); |
| |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.Heuristic.ShouldShowChromeSigninBubbleWithReason", |
| ShouldShowChromeSigninBubbleWithReason::kShouldShow, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTestWithUnoEnabled, |
| InterceptShouldShowChromeSigninReauthWaitOnAccountInfo) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| // Primary account is not set, Chrome is not signed in. |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| |
| auto expected_outcome = |
| SigninInterceptionHeuristicOutcome::kInterceptChromeSignin; |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/true, /*is_sync_signin=*/false); |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), true); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kChromeSignin, |
| /*intercepted_account=*/account_info, |
| /*primary_account=*/AccountInfo()); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", |
| expected_outcome, 1); |
| histogram_tester.ExpectUniqueTimeSample("Signin.Intercept.HeuristicLatency", |
| base::Milliseconds(0), 1); |
| |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.Heuristic.ShouldShowChromeSigninBubbleWithReason", |
| ShouldShowChromeSigninBubbleWithReason::kShouldShow, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTestWithUnoEnabled, |
| InterceptShouldShowChromeSigninBubbleSecondaryAccount) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account is valid. |
| ASSERT_TRUE(account_info.IsValid()); |
| // Primary account is not set, Chrome is not signed in. |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| |
| WebSigninInterceptor::Delegate::BubbleParameters expected_parameters( |
| WebSigninInterceptor::SigninInterceptionType::kChromeSignin, |
| /*intercepted_account=*/account_info, |
| /*primary_account=*/AccountInfo()); |
| EXPECT_CALL(*mock_delegate(), |
| ShowSigninInterceptionBubble( |
| web_contents(), MatchBubbleParameters(expected_parameters), |
| testing::_)); |
| |
| auto expected_outcome = |
| SigninInterceptionHeuristicOutcome::kInterceptChromeSignin; |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/true, /*is_sync_signin=*/false); |
| EXPECT_EQ( |
| interceptor()->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email, account_info.gaia), |
| expected_outcome); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", |
| expected_outcome, 1); |
| histogram_tester.ExpectUniqueTimeSample("Signin.Intercept.HeuristicLatency", |
| base::Milliseconds(0), 1); |
| |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.Heuristic.ShouldShowChromeSigninBubbleWithReason", |
| ShouldShowChromeSigninBubbleWithReason::kShouldShow, 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTest, |
| InterceptShouldNotShowWaitForAccountInfoAvailableMetricRecorded) { |
| base::HistogramTester histogram_tester; |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| EXPECT_FALSE(interceptor() |
| ->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email) |
| .has_value()); |
| EXPECT_CALL(*mock_delegate(), ShowSigninInterceptionBubble( |
| web_contents(), testing::_, testing::_)) |
| .Times(0); |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, |
| /*is_new_account=*/true, |
| /*is_sync_signin=*/false); |
| // Delegate was not called yet. |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| |
| MakeValidAccountInfo(&account_info, "example.com"); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| auto expected_outcome = |
| SigninInterceptionHeuristicOutcome::kAbortAccountInfoNotCompatible; |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.Heuristic.ShouldShowChromeSigninBubbleWithReason", |
| ShouldShowChromeSigninBubbleWithReason::kShouldNotShowUnknownAccessPoint, |
| 1); |
| } |
| |
| TEST_F(DiceWebSigninInterceptorTestWithUnoEnabled, |
| NoInterceptionIfPrimaryAccountAlreadySet) { |
| // Set up first account. |
| const std::string primary_email = "alice@example.com"; |
| AccountInfo first_account_info = |
| identity_test_env()->MakeAccountAvailable(primary_email); |
| MakeValidAccountInfo(&first_account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(first_account_info); |
| |
| // Set up second account. |
| AccountInfo second_account_info = |
| identity_test_env()->MakeAccountAvailable("bob@example.com"); |
| MakeValidAccountInfo(&second_account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(second_account_info); |
| |
| // Accounts are valid. |
| ASSERT_TRUE(first_account_info.IsValid()); |
| ASSERT_TRUE(second_account_info.IsValid()); |
| |
| // Set the primary account. |
| identity_test_env()->SetPrimaryAccount(primary_email, |
| signin::ConsentLevel::kSignin); |
| ASSERT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| |
| // Sign in interception bubble should not be shown because this is not the |
| // first account but there is no primary account. |
| EXPECT_CALL(*mock_delegate(), ShowSigninInterceptionBubble( |
| web_contents(), testing::_, testing::_)) |
| .Times(0); |
| |
| auto expected_outcome = |
| SigninInterceptionHeuristicOutcome::kAbortAccountInfoNotCompatible; |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), second_account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/true, /*is_sync_signin=*/false); |
| EXPECT_EQ(interceptor()->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| second_account_info.email), |
| std::nullopt); |
| testing::Mock::VerifyAndClearExpectations(mock_delegate()); |
| histogram_tester.ExpectUniqueSample("Signin.Intercept.HeuristicOutcome", |
| expected_outcome, 1); |
| histogram_tester.ExpectUniqueTimeSample("Signin.Intercept.HeuristicLatency", |
| base::Milliseconds(0), 1); |
| |
| EXPECT_EQ(interceptor()->is_interception_in_progress(), |
| SigninInterceptionHeuristicOutcomeIsSuccess(expected_outcome)); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.Heuristic.ShouldShowChromeSigninBubbleWithReason", |
| ShouldShowChromeSigninBubbleWithReason::kShouldNotShowAlreadySignedIn, 1); |
| } |
| |
| class DiceWebSigninInterceptorTestWithUnoDisabled |
| : public DiceWebSigninInterceptorTest { |
| public: |
| DiceWebSigninInterceptorTestWithUnoDisabled() { |
| feature_list_.InitAndDisableFeature( |
| switches::kExplicitBrowserSigninUIOnDesktop); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(DiceWebSigninInterceptorTestWithUnoDisabled, |
| InterceptShouldLogChromeSigninBubbleOfferedForControlGroup) { |
| AccountInfo account_info = |
| identity_test_env()->MakeAccountAvailable("alice@example.com"); |
| MakeValidAccountInfo(&account_info); |
| identity_test_env()->UpdateAccountInfoForAccount(account_info); |
| |
| // Account is valid. |
| ASSERT_TRUE(account_info.IsValid()); |
| // Primary account is not set, Chrome is not signed in. |
| ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| |
| EXPECT_CALL(*mock_delegate(), ShowSigninInterceptionBubble( |
| web_contents(), testing::_, testing::_)) |
| .Times(0); |
| base::HistogramTester histogram_tester; |
| interceptor()->MaybeInterceptWebSignin( |
| web_contents(), account_info.account_id, |
| signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, |
| /*is_new_account=*/true, /*is_sync_signin=*/false); |
| EXPECT_EQ(interceptor()->GetHeuristicOutcome(/*is_new_account=*/true, |
| /*is_sync_signin=*/false, |
| account_info.email), |
| SigninInterceptionHeuristicOutcome::kAbortSingleAccount); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Signin.Intercept.Heuristic.ShouldShowChromeSigninBubbleWithReason", |
| ShouldShowChromeSigninBubbleWithReason::kShouldShow, 1); |
| } |