Commit 85bd68c7 authored by Anastasiia Nikolaienko's avatar Anastasiia Nikolaienko Committed by Commit Bot

Disallow secondary accounts in ARC for Child users

Project Beaker on Chrome OS is going to allow child users the addition
of secondary accounts, but it's going to be limited to web only.

- If user has transitioned from child account to regular -
TriggerAccountsPushToArc will add accounts to ARC on startup.
- If user has transitioned from regular account to child -
HandleSupervisionTransition will remove all secondary accounts from
ARC.

Update is going to be executed on startup, since to transition to
another type, user need to sign-out and sign-in again (I think).

ARC CL: http://ag/9615344

Bug: 1017160
Change-Id: I323a18aca9c9f63e6a3869d9b9dd4dd34432c31c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1876089Reviewed-by: default avatarMattias Nissler <mnissler@chromium.org>
Reviewed-by: default avatarYury Khmel <khmel@chromium.org>
Commit-Queue: Anastasiia Nikolaienko <anastasiian@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711171}
parent 104865d0
......@@ -31,6 +31,7 @@
#include "chrome/browser/ui/settings_window_manager_chromeos.h"
#include "chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h"
#include "chrome/common/webui_url_constants.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "components/arc/arc_features.h"
#include "components/arc/arc_prefs.h"
......@@ -283,6 +284,13 @@ void ArcAuthService::OnConnectionReady() {
if (arc::IsArcProvisioned(profile_)) {
TriggerAccountManagerMigrationsIfRequired(profile_);
TriggerAccountsPushToArc(false /* filter_primary_account */);
if (chromeos::features::IsEduCoexistenceEnabled() &&
GetSupervisionTransition(profile_) ==
ArcSupervisionTransition::REGULAR_TO_CHILD) {
// If profile transitioned from Child to Regular, accounts have already
// been pushed to ARC.
RemoveSecondaryAccountsFromArc();
}
}
if (pending_get_arc_accounts_callback_)
......@@ -557,6 +565,11 @@ void ArcAuthService::OnRefreshTokenUpdatedForAccount(
if (!arc::IsArcProvisioned(profile_))
return;
// For child device accounts do not allow the propagation of secondary
// accounts from Chrome OS Account Manager to ARC.
if (profile_->IsChild() && !IsPrimaryGaiaAccount(account_info.gaia))
return;
if (identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
account_info.account_id)) {
VLOG(1) << "Ignoring account update due to lack of a valid token: "
......@@ -819,4 +832,13 @@ void ArcAuthService::OnMainAccountResolutionStatus(
UpdateMainAccountResolutionStatus(profile_, status);
}
void ArcAuthService::RemoveSecondaryAccountsFromArc() {
auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
RemoveSecondaryAccounts);
if (!instance)
return;
instance->RemoveSecondaryAccounts();
}
} // namespace arc
......@@ -193,6 +193,10 @@ class ArcAuthService : public KeyedService,
// Response for |mojom::GetMainAccountResolutionStatus|.
void OnMainAccountResolutionStatus(mojom::MainAccountResolutionStatus status);
// Removes secondary accounts from ARC. For child device accounts propagation
// of secondary accounts from Chrome OS Account Manager to ARC is not allowed.
void RemoveSecondaryAccountsFromArc();
// Non-owning pointers.
Profile* const profile_;
signin::IdentityManager* const identity_manager_;
......
......@@ -41,6 +41,7 @@
#include "chrome/browser/ui/app_list/arc/arc_data_removal_dialog.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/constants/chromeos_features.h"
......@@ -158,6 +159,10 @@ class FakeAuthInstance : public mojom::AuthInstance {
mojom::MainAccountResolutionStatus::HASH_CODE_MATCH_SINGLE_ACCOUNT);
}
void RemoveSecondaryAccounts() override {
++num_remove_secondary_accounts_calls_;
}
mojom::AccountInfo* account_info() { return account_info_.get(); }
mojom::ArcSignInStatus sign_in_status() const { return status_; }
......@@ -170,6 +175,10 @@ class FakeAuthInstance : public mojom::AuthInstance {
std::string last_removed_account() const { return last_removed_account_; }
int num_remove_secondary_accounts_calls() const {
return num_remove_secondary_accounts_calls_;
}
private:
void OnAccountInfoResponse(base::OnceClosure done_closure,
mojom::ArcSignInStatus status,
......@@ -189,13 +198,21 @@ class FakeAuthInstance : public mojom::AuthInstance {
int num_account_removed_calls_ = 0;
std::string last_removed_account_;
int num_remove_secondary_accounts_calls_ = 0;
base::WeakPtrFactory<FakeAuthInstance> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(FakeAuthInstance);
};
class ArcAuthServiceTest : public InProcessBrowserTest {
protected:
ArcAuthServiceTest() = default;
ArcAuthServiceTest() {
scoped_feature_list_.InitWithFeatures(
{kEnableChildToRegularTransitionFeature,
kEnableRegularToChildTransitionFeature,
chromeos::features::kEduCoexistence},
{});
}
// InProcessBrowserTest:
~ArcAuthServiceTest() override = default;
......@@ -295,7 +312,9 @@ class ArcAuthServiceTest : public InProcessBrowserTest {
identity_test_environment_adaptor_->identity_test_env();
identity_test_env->SetAutomaticIssueOfAccessTokens(true);
identity_test_env->MakePrimaryAccountAvailable(kFakeUserName);
}
void SetUpAuthService() {
profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true);
profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true);
MigrateSigninScopedDeviceId(profile());
......@@ -364,6 +383,7 @@ class ArcAuthServiceTest : public InProcessBrowserTest {
AccountInfo SetupGaiaAccount(const std::string& email) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
return SeedAccountInfo(email);
}
......@@ -405,6 +425,7 @@ class ArcAuthServiceTest : public InProcessBrowserTest {
// Not owned.
ArcAuthService* auth_service_ = nullptr;
ArcBridgeService* arc_bridge_service_ = nullptr;
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(ArcAuthServiceTest);
};
......@@ -415,6 +436,7 @@ class ArcAuthServiceTest : public InProcessBrowserTest {
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
SuccessfulBackgroundFetchViaDeprecatedApi) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
GetFakeAuthTokenResponse());
......@@ -436,6 +458,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
// Chrome supplies the info configured in SetAccountAndProfile() method.
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, SuccessfulBackgroundFetch) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
GetFakeAuthTokenResponse());
......@@ -456,6 +479,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, SuccessfulBackgroundFetch) {
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
ReAuthenticatePrimaryAccountSucceeds) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
GetFakeAuthTokenResponse());
......@@ -476,6 +500,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
ReAuthenticatePrimaryAccountFailsForInvalidAccount) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
std::string() /* response */,
net::HTTP_UNAUTHORIZED);
......@@ -492,6 +517,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, FetchSecondaryAccountInfoSucceeds) {
// Add a Secondary Account.
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
SeedAccountInfo(kSecondaryAccountEmail);
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
GetFakeAuthTokenResponse());
......@@ -515,6 +541,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
FetchSecondaryAccountInfoFailsForInvalidAccounts) {
// Add a Secondary Account.
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
SeedAccountInfo(kSecondaryAccountEmail);
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
std::string() /* response */,
......@@ -534,6 +561,7 @@ IN_PROC_BROWSER_TEST_F(
ArcAuthServiceTest,
FetchSecondaryAccountInfoReturnsErrorForNotFoundAccounts) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
// Don't add account with kSecondaryAccountEmail.
base::RunLoop run_loop;
......@@ -548,6 +576,7 @@ IN_PROC_BROWSER_TEST_F(
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, FetchGoogleAccountsFromArc) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
EXPECT_FALSE(arc_google_accounts_callback_called());
RequestGoogleAccountsInArc();
......@@ -563,6 +592,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, FetchGoogleAccountsFromArc) {
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
FetchGoogleAccountsFromArcWorksAcrossConnectionResets) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
// Close the connection.
arc_bridge_service().auth()->CloseInstance(&auth_instance());
......@@ -587,6 +617,7 @@ IN_PROC_BROWSER_TEST_F(
ArcAuthServiceTest,
PrimaryAccountReauthIsNotAttemptedJustAfterProvisioning) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
const int initial_num_calls = auth_instance().num_account_upserted_calls();
// Our test setup manually sets the device as provisioned and invokes
// |ArcAuthService::OnConnectionReady|. Hence, we would have received an
......@@ -627,6 +658,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, AccountUpdatesArePropagated) {
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, AccountRemovalsArePropagated) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SetUpAuthService();
SeedAccountInfo(kSecondaryAccountEmail);
EXPECT_EQ(0, auth_instance().num_account_removed_calls());
......@@ -716,6 +748,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
chromeos::DemoSession::StartIfInDemoMode();
SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
SetUpAuthService();
test_url_loader_factory()->SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
......@@ -743,6 +776,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest, GetDemoAccount) {
chromeos::DemoSession::StartIfInDemoMode();
SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
SetUpAuthService();
test_url_loader_factory()->SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
......@@ -769,6 +803,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
chromeos::DemoSession::StartIfInDemoMode();
SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
SetUpAuthService();
base::RunLoop run_loop;
auth_instance().RequestAccountInfoDeprecated(run_loop.QuitClosure());
......@@ -789,6 +824,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest, GetOfflineDemoAccount) {
chromeos::DemoSession::StartIfInDemoMode();
SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
SetUpAuthService();
base::RunLoop run_loop;
auth_instance().RequestPrimaryAccountInfo(run_loop.QuitClosure());
......@@ -810,6 +846,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
chromeos::DemoSession::StartIfInDemoMode();
SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
SetUpAuthService();
test_url_loader_factory()->SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
......@@ -837,6 +874,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
chromeos::DemoSession::StartIfInDemoMode();
SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
SetUpAuthService();
test_url_loader_factory()->SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
......@@ -860,6 +898,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
RequestPublicAccountInfo) {
SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
SetUpAuthService();
profile()->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true);
test_url_loader_factory()->SetInterceptor(
......@@ -885,6 +924,7 @@ IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
// SetAccountAndProfile() above.
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildAccountFetchViaDeprecatedApi) {
SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
SetUpAuthService();
EXPECT_TRUE(profile()->IsChild());
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
GetFakeAuthTokenResponse());
......@@ -907,6 +947,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildAccountFetchViaDeprecatedApi) {
// Chrome supplies the info configured in SetAccountAndProfile() above.
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildAccountFetch) {
SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
SetUpAuthService();
EXPECT_TRUE(profile()->IsChild());
test_url_loader_factory()->AddResponse(arc::kAuthTokenExchangeEndPoint,
GetFakeAuthTokenResponse());
......@@ -927,6 +968,7 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildAccountFetch) {
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildTransition) {
SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
SetUpAuthService();
ArcSessionManager* session = ArcSessionManager::Get();
ASSERT_TRUE(session);
......@@ -1032,4 +1074,38 @@ IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest, ChildTransition) {
}
}
IN_PROC_BROWSER_TEST_F(ArcAuthServiceTest,
ChildUserSecondaryAccountsNotPropagated) {
SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
SetUpAuthService();
SeedAccountInfo(kSecondaryAccountEmail);
EXPECT_TRUE(profile()->IsChild());
EXPECT_EQ(1, auth_instance().num_account_upserted_calls());
}
IN_PROC_BROWSER_TEST_F(
ArcAuthServiceTest,
RegularToChildTransitionShouldRemoveSecondaryAccountsFromArc) {
SetAccountAndProfile(user_manager::USER_TYPE_CHILD);
SeedAccountInfo(kSecondaryAccountEmail);
profile()->GetPrefs()->SetInteger(
arc::prefs::kArcSupervisionTransition,
static_cast<int>(arc::ArcSupervisionTransition::REGULAR_TO_CHILD));
SetUpAuthService();
EXPECT_EQ(1, auth_instance().num_account_upserted_calls());
EXPECT_EQ(1, auth_instance().num_remove_secondary_accounts_calls());
}
IN_PROC_BROWSER_TEST_F(
ArcAuthServiceTest,
ChildToRegularTransitionShouldAddSecondaryAccountsToArc) {
SetAccountAndProfile(user_manager::USER_TYPE_REGULAR);
SeedAccountInfo(kSecondaryAccountEmail);
profile()->GetPrefs()->SetInteger(
arc::prefs::kArcSupervisionTransition,
static_cast<int>(arc::ArcSupervisionTransition::CHILD_TO_REGULAR));
SetUpAuthService();
EXPECT_EQ(2, auth_instance().num_account_upserted_calls());
}
} // namespace arc
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Next MinVersion: 23
// Next MinVersion: 24
module arc.mojom;
......@@ -338,7 +338,7 @@ interface AuthHost {
[MinVersion=20] HandleUpdateCredentialsRequest@17(string account_name);
};
// Next Method ID: 6
// Next Method ID: 7
interface AuthInstance {
// DEPRECATED: Please use Init@2 instead.
InitDeprecated@0(AuthHost host_ptr);
......@@ -371,4 +371,12 @@ interface AuthInstance {
// Gets resolution status of main account for statistics reporting.
[MinVersion=22] GetMainAccountResolutionStatus@5()
=> (MainAccountResolutionStatus status);
// A notification that all secondary accounts should be removed from ARC.
// Equivalent to calling |OnAccountUpdated| with AccountUpdateType::REMOVAL
// for each secondary account and in case of inconsistency between Chrome OS
// Account Manager and ARC accounts, inconsistent accounts will be also
// removed from ARC. Should be called on transition from Regular to Child
// account type.
[MinVersion=23] RemoveSecondaryAccounts@6();
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment