demo_mode: Fall back to MGS on demo account setup failure
In demo mode, the device will try to set up a demo account first and use it to log in. If it fails to set up the demo account, it falls back to the managed guest session. Bug: 364214790 Change-Id: I4a233c43abf89785f3b0265cf58c3816ccf617c5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6034618 Reviewed-by: Haifan Wang <wanghaifan@google.com> Commit-Queue: Xiqi Ruan <xiqiruan@chromium.org> Reviewed-by: Xiyuan Xia <xiyuan@chromium.org> Cr-Commit-Position: refs/heads/main@{#1387178}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
24947a958b
commit
dbff683a77
chrome/browser/ash/login
chromeos/ash/components/demo_mode/utils
@ -101,6 +101,7 @@ static_library("login") {
|
||||
"//chrome/browser/ash/policy/enrollment",
|
||||
"//chrome/browser/profiles:profile",
|
||||
"//chromeos/ash/components/dbus/session_manager",
|
||||
"//chromeos/ash/components/demo_mode",
|
||||
"//chromeos/ash/components/login/auth",
|
||||
"//chromeos/ash/components/login/auth/public:authpublic",
|
||||
"//chromeos/ash/components/login/auth/public:challenge_response_key",
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/uuid.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/ash/login/existing_user_controller.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/ui/ash/login/login_display_host.h"
|
||||
#include "chrome/browser/ui/ash/login/login_screen_client_impl.h"
|
||||
@ -271,16 +272,16 @@ DemoLoginController::~DemoLoginController() = default;
|
||||
void DemoLoginController::OnLoginScreenShown() {
|
||||
// Stop observe login screen since it may get invoked in session. Demo account
|
||||
// should be setup only once for each session. Follow up response will
|
||||
// instruct retry or fallback to public account.
|
||||
// instruct retry or fall back to public account.
|
||||
scoped_observation_.Reset();
|
||||
|
||||
if (!demo_mode::IsDeviceInDemoMode()) {
|
||||
return;
|
||||
}
|
||||
// Try demo account login first by disable auto-login to managed guest
|
||||
// session.
|
||||
demo_mode::SetShouldFallBackMGS(false);
|
||||
|
||||
// TODO(crbug.com/370806573): Skip auto login public account in
|
||||
// `ExistingUserController::StartAutoLoginTimer` if this feature enable
|
||||
// Maybe add a policy.
|
||||
MaybeCleanupPreviousDemoAccount();
|
||||
}
|
||||
|
||||
@ -321,8 +322,6 @@ void DemoLoginController::OnSetupDemoAccountComplete(
|
||||
HandleSetupDemoAcountResponse(sign_in_scoped_device_id,
|
||||
std::move(response_body));
|
||||
} else {
|
||||
// TODO(crbug.com/364214790): Handle any errors (maybe earlier for net
|
||||
// connection error) and fallback to MGS.
|
||||
OnSetupDemoAccountError(result);
|
||||
}
|
||||
}
|
||||
@ -362,6 +361,12 @@ void DemoLoginController::OnSetupDemoAccountError(
|
||||
if (setup_failed_callback_for_testing_) {
|
||||
std::move(setup_failed_callback_for_testing_).Run(result_code);
|
||||
}
|
||||
|
||||
// Login public account session when set up failed.
|
||||
demo_mode::SetShouldFallBackMGS(true);
|
||||
auto* existing_user_controller =
|
||||
ash::ExistingUserController::current_controller();
|
||||
existing_user_controller->ConfigureAutoLogin();
|
||||
}
|
||||
|
||||
void DemoLoginController::MaybeCleanupPreviousDemoAccount() {
|
||||
|
@ -4,19 +4,29 @@
|
||||
|
||||
#include "chrome/browser/ash/login/demo_mode/demo_login_controller.h"
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
#include "ash/login/test_login_screen.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/mock_callback.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "chrome/browser/ash/login/existing_user_controller.h"
|
||||
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
|
||||
#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
|
||||
#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
|
||||
#include "chrome/browser/ui/ash/login/mock_login_display_host.h"
|
||||
#include "chrome/test/base/scoped_testing_local_state.h"
|
||||
#include "chrome/test/base/testing_browser_process.h"
|
||||
#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
|
||||
#include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h"
|
||||
#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
|
||||
#include "chromeos/ash/components/settings/cros_settings_names.h"
|
||||
#include "chromeos/ash/components/system/fake_statistics_provider.h"
|
||||
#include "components/account_id/account_id.h"
|
||||
#include "components/policy/core/common/device_local_account_type.h"
|
||||
#include "components/session_manager/core/session_manager.h"
|
||||
#include "components/user_manager/scoped_user_manager.h"
|
||||
#include "content/public/test/browser_task_environment.h"
|
||||
#include "google_apis/google_api_keys.h"
|
||||
#include "net/base/url_util.h"
|
||||
@ -50,6 +60,8 @@ constexpr char kCleanUpDemoAccountUrl[] =
|
||||
|
||||
constexpr char kApiKeyParam[] = "key";
|
||||
|
||||
constexpr char kPublicAccountUserId[] = "public_session_user@localhost";
|
||||
|
||||
} // namespace
|
||||
|
||||
class DemoLoginControllerTest : public testing::Test {
|
||||
@ -67,7 +79,22 @@ class DemoLoginControllerTest : public testing::Test {
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
attributes_.Get()->SetDemoMode();
|
||||
features_.InitAndEnableFeature(features::kDemoModeSignIn);
|
||||
|
||||
settings_helper_.InstallAttributes()->SetDemoMode();
|
||||
fake_user_manager_->AddPublicAccountUser(auto_login_account_id_);
|
||||
settings_helper_.ReplaceDeviceSettingsProviderWithStub();
|
||||
|
||||
base::Value::Dict account;
|
||||
account.Set(kAccountsPrefDeviceLocalAccountsKeyId, kPublicAccountUserId);
|
||||
account.Set(
|
||||
kAccountsPrefDeviceLocalAccountsKeyType,
|
||||
static_cast<int>(policy::DeviceLocalAccountType::kPublicSession));
|
||||
base::Value::List accounts;
|
||||
accounts.Append(std::move(account));
|
||||
settings_helper_.Set(kAccountsPrefDeviceLocalAccounts,
|
||||
base::Value(std::move(accounts)));
|
||||
|
||||
login_screen_client_ = std::make_unique<LoginScreenClientImpl>();
|
||||
demo_login_controller_ =
|
||||
std::make_unique<DemoLoginController>(login_screen_client_.get());
|
||||
@ -117,17 +144,39 @@ class DemoLoginControllerTest : public testing::Test {
|
||||
loop.Run();
|
||||
}
|
||||
|
||||
void ExpectGetExistingController() {
|
||||
EXPECT_CALL(login_display_host(), GetExistingUserController())
|
||||
.WillRepeatedly(testing::Return(&existing_user_controller_));
|
||||
}
|
||||
|
||||
ScopedCrosSettingsTestHelper* settings_helper() { return &settings_helper_; }
|
||||
ExistingUserController* existing_user_controller() {
|
||||
return &existing_user_controller_;
|
||||
}
|
||||
|
||||
network::TestURLLoaderFactory test_url_loader_factory_;
|
||||
|
||||
private:
|
||||
base::test::ScopedFeatureList features_;
|
||||
content::BrowserTaskEnvironment task_environment_;
|
||||
ScopedStubInstallAttributes attributes_;
|
||||
|
||||
testing::NiceMock<ash::MockLoginDisplayHost> mock_login_display_host_;
|
||||
ScopedTestingLocalState local_state_{TestingBrowserProcess::GetGlobal()};
|
||||
system::FakeStatisticsProvider statistics_provider_;
|
||||
|
||||
// Dependencies for `LoginScreenClientImpl`:
|
||||
// Dependencies for `ExistingUserController`:
|
||||
FakeSessionManagerClient fake_session_manager_client_;
|
||||
ScopedCrosSettingsTestHelper settings_helper_;
|
||||
user_manager::TypedScopedUserManager<ash::FakeChromeUserManager>
|
||||
fake_user_manager_{std::make_unique<FakeChromeUserManager>()};
|
||||
session_manager::SessionManager session_manager_;
|
||||
const AccountId auto_login_account_id_ =
|
||||
AccountId::FromUserEmail(policy::GenerateDeviceLocalAccountUserId(
|
||||
kPublicAccountUserId,
|
||||
policy::DeviceLocalAccountType::kPublicSession));
|
||||
ExistingUserController existing_user_controller_;
|
||||
|
||||
// Dependencies for `LoginScreenClientImpl`:
|
||||
TestLoginScreen test_login_screen_;
|
||||
std::unique_ptr<LoginScreenClientImpl> login_screen_client_;
|
||||
|
||||
@ -163,7 +212,7 @@ TEST_F(DemoLoginControllerTest, OnSetupDemoAccountSuccessFirstTime) {
|
||||
|
||||
TEST_F(DemoLoginControllerTest, InValidGaia) {
|
||||
test_url_loader_factory_.AddResponse(GetSetupUrl().spec(), kInValidGaiaCreds);
|
||||
|
||||
ExpectGetExistingController();
|
||||
base::RunLoop loop;
|
||||
EXPECT_CALL(login_display_host(), CompleteLogin).Times(0);
|
||||
demo_login_controller()->SetSetupFailedCallbackForTest(
|
||||
@ -230,6 +279,32 @@ TEST_F(DemoLoginControllerTest, CleanUpFailed) {
|
||||
EXPECT_NE(new_session_id, last_session_id);
|
||||
}
|
||||
|
||||
TEST_F(DemoLoginControllerTest, FallbackToMGS) {
|
||||
// Mock setup failed by returning invalid credential.
|
||||
test_url_loader_factory_.AddResponse(GetSetupUrl().spec(), kInValidGaiaCreds);
|
||||
ExpectGetExistingController();
|
||||
|
||||
// Configure auto login settings. This is done by policy in prod env.
|
||||
settings_helper()->SetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
|
||||
kPublicAccountUserId);
|
||||
settings_helper()->SetInteger(kAccountsPrefDeviceLocalAccountAutoLoginDelay,
|
||||
0);
|
||||
|
||||
base::RunLoop loop;
|
||||
EXPECT_CALL(login_display_host(), CompleteLogin).Times(0);
|
||||
demo_login_controller()->SetSetupFailedCallbackForTest(
|
||||
base::BindLambdaForTesting(
|
||||
[&](const DemoLoginController::ResultCode result_code) {
|
||||
loop.Quit();
|
||||
}));
|
||||
login_display_host().StartSignInScreen();
|
||||
login_screen_client()->OnLoginScreenShown();
|
||||
loop.Run();
|
||||
|
||||
// Expect auto login managed guest session starts.
|
||||
EXPECT_TRUE(existing_user_controller()->IsAutoLoginTimerRunningForTesting());
|
||||
}
|
||||
|
||||
// TODO(crbug.com/372771485): Add more request fail test cases.
|
||||
|
||||
} // namespace ash
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "chrome/browser/ash/boot_times_recorder/boot_times_recorder.h"
|
||||
#include "chrome/browser/ash/customization/customization_document.h"
|
||||
#include "chrome/browser/ash/login/auth/chrome_login_performer.h"
|
||||
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
|
||||
#include "chrome/browser/ash/login/enterprise_user_session_metrics.h"
|
||||
#include "chrome/browser/ash/login/helper.h"
|
||||
#include "chrome/browser/ash/login/profile_auth_data.h"
|
||||
@ -93,6 +92,7 @@
|
||||
#include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
|
||||
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
|
||||
#include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
|
||||
#include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h"
|
||||
#include "chromeos/ash/components/install_attributes/install_attributes.h"
|
||||
#include "chromeos/ash/components/login/auth/public/auth_failure.h"
|
||||
#include "chromeos/ash/components/login/auth/public/key.h"
|
||||
@ -1286,17 +1286,20 @@ void ExistingUserController::CancelPasswordChangedFlow() {
|
||||
|
||||
void ExistingUserController::StartAutoLoginTimer() {
|
||||
auto session_state = session_manager::SessionManager::Get()->session_state();
|
||||
bool is_demo_mode = demo_mode::IsDeviceInDemoMode();
|
||||
if (is_login_in_progress_ ||
|
||||
!public_session_auto_login_account_id_.is_valid() ||
|
||||
(session_state == session_manager::SessionState::OOBE &&
|
||||
!DemoSession::IsDeviceInDemoMode())) {
|
||||
(session_state == session_manager::SessionState::OOBE && !is_demo_mode) ||
|
||||
(is_demo_mode && !demo_mode::ShouldFallBackToMGS())) {
|
||||
VLOG(2) << "Not starting autologin timer, because:";
|
||||
VLOG_IF(2, is_login_in_progress_) << "* Login is in process;";
|
||||
VLOG_IF(2, !public_session_auto_login_account_id_.is_valid())
|
||||
<< "* No valid autologin account;";
|
||||
VLOG_IF(2, session_state == session_manager::SessionState::OOBE &&
|
||||
!DemoSession::IsDeviceInDemoMode())
|
||||
!is_demo_mode)
|
||||
<< "* OOBE isn't completed and device isn't in demo mode;";
|
||||
VLOG_IF(2, is_demo_mode && !demo_mode::ShouldFallBackToMGS())
|
||||
<< "* Should not fall back to manage guest session for demo mode;";
|
||||
return;
|
||||
}
|
||||
VLOG(2) << "Starting autologin timer with delay: " << auto_login_delay_;
|
||||
|
@ -146,6 +146,10 @@ class ExistingUserController : public HttpAuthDialog::Observer,
|
||||
// Calls login() on previously-used `login_performer_`.
|
||||
void LoginAuthenticated(std::unique_ptr<UserContext> user_context);
|
||||
|
||||
// Retrieve public session auto-login policy and update the
|
||||
// timer.
|
||||
void ConfigureAutoLogin();
|
||||
|
||||
private:
|
||||
friend class ExistingUserControllerTest;
|
||||
friend class ExistingUserControllerAutoLoginTest;
|
||||
@ -160,9 +164,6 @@ class ExistingUserController : public HttpAuthDialog::Observer,
|
||||
void LoginAsGuest();
|
||||
void LoginAsPublicSession(const UserContext& user_context);
|
||||
void LoginAsKioskApp(KioskAppId kiosk_app_id);
|
||||
// Retrieve public session auto-login policy and update the
|
||||
// timer.
|
||||
void ConfigureAutoLogin();
|
||||
|
||||
// Trigger public session auto-login.
|
||||
void OnPublicSessionAutoLoginTimerFire();
|
||||
|
@ -4,12 +4,17 @@
|
||||
|
||||
#include "chromeos/ash/components/demo_mode/utils/demo_session_utils.h"
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
#include "chromeos/ash/components/install_attributes/install_attributes.h"
|
||||
#include "components/prefs/pref_registry_simple.h"
|
||||
|
||||
namespace ash::demo_mode {
|
||||
|
||||
namespace {
|
||||
bool g_should_fall_back_mgs = false;
|
||||
}
|
||||
|
||||
bool IsDeviceInDemoMode() {
|
||||
if (!InstallAttributes::IsInitialized()) {
|
||||
// TODO(b/281905036): Add a log to indicate that the install
|
||||
@ -39,4 +44,13 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
|
||||
std::string());
|
||||
}
|
||||
|
||||
bool ShouldFallBackToMGS() {
|
||||
// Always fall back to MGS if demo mode sign in not enable.
|
||||
return !features::IsDemoModeSignInEnabled() || g_should_fall_back_mgs;
|
||||
}
|
||||
|
||||
void SetShouldFallBackMGS(bool should_fall_back_mgs) {
|
||||
g_should_fall_back_mgs = should_fall_back_mgs;
|
||||
}
|
||||
|
||||
} // namespace ash::demo_mode
|
||||
|
@ -26,6 +26,14 @@ bool IsDeviceInDemoMode();
|
||||
COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DEMO_MODE)
|
||||
void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
|
||||
|
||||
COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DEMO_MODE)
|
||||
// Whether the device should fall back to manage guest sesison in demo mode.
|
||||
bool ShouldFallBackToMGS();
|
||||
|
||||
COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_DEMO_MODE)
|
||||
// Whether the device is in demo account session.
|
||||
void SetShouldFallBackMGS(bool is_demo_account_session);
|
||||
|
||||
} // namespace ash::demo_mode
|
||||
|
||||
#endif // CHROMEOS_ASH_COMPONENTS_DEMO_MODE_UTILS_DEMO_SESSION_UTILS_H_
|
||||
|
Reference in New Issue
Block a user