blob: 8236254868e2b8d509fbffd4b4939f9f6b7832ac [file] [log] [blame]
// Copyright 2012 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/ash/login/existing_user_controller.h"
#include <string>
#include <vector>
#include "ash/components/arc/test/arc_util_test_support.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/login_screen_test_api.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "base/threading/thread_restrictions.h"
#include "base/timer/timer.h"
#include "chrome/browser/ash/app_list/arc/arc_app_list_prefs_factory.h"
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/arc/session/arc_session_manager.h"
#include "chrome/browser/ash/login/help_app_launcher.h"
#include "chrome/browser/ash/login/helper.h"
#include "chrome/browser/ash/login/lock/screen_locker_tester.h"
#include "chrome/browser/ash/login/login_manager_test.h"
#include "chrome/browser/ash/login/screens/user_selection_screen.h"
#include "chrome/browser/ash/login/session/user_session_manager.h"
#include "chrome/browser/ash/login/session/user_session_manager_test_api.h"
#include "chrome/browser/ash/login/test/cryptohome_mixin.h"
#include "chrome/browser/ash/login/test/js_checker.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/ash/login/test/oobe_base_test.h"
#include "chrome/browser/ash/login/test/oobe_screen_waiter.h"
#include "chrome/browser/ash/login/test/oobe_screens_utils.h"
#include "chrome/browser/ash/login/test/user_policy_mixin.h"
#include "chrome/browser/ash/login/wizard_context.h"
#include "chrome/browser/ash/login/wizard_controller.h"
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/policy/core/device_local_account_policy_service.h"
#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/login/mock_login_display_host.h"
#include "chrome/browser/ui/ash/login/mock_signin_ui.h"
#include "chrome/browser/ui/ash/login/signin_ui.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/locale_switch_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/terms_of_service_screen_handler.h"
#include "chrome/browser/ui/webui/ash/login/tpm_error_screen_handler.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/fake_gaia_mixin.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "chromeos/ash/components/dbus/userdataauth/fake_userdataauth_client.h"
#include "chromeos/ash/components/login/auth/public/key.h"
#include "chromeos/ash/components/login/auth/public/user_context.h"
#include "chromeos/ash/components/login/auth/stub_authenticator_builder.h"
#include "chromeos/ash/components/network/network_state_test_helper.h"
#include "chromeos/ash/components/settings/cros_settings.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "chromeos/ash/components/settings/cros_settings_provider.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "components/account_id/account_id.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/core/common/cloud/cloud_policy_core.h"
#include "components/policy/core/common/cloud/cloud_policy_store.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
#include "components/policy/core/common/cloud/test/policy_builder.h"
#include "components/policy/core/common/device_local_account_type.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/policy_constants.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/session_manager/core/session_manager.h"
#include "components/session_manager/core/session_manager_observer.h"
#include "components/user_manager/known_user.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_type.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
#include "google_apis/gaia/gaia_id.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
namespace ash {
namespace {
namespace em = ::enterprise_management;
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::InvokeWithoutArgs;
using ::testing::Mock;
using ::testing::Return;
const char kObjectGuid[] = "12345";
const char kAdUsername[] = "test_user@ad-domain.com";
const char kNewUser[] = "new_test_user@gmail.com";
const char kNewGaiaID[] = "11111";
const char kExistingUser[] = "existing_test_user@gmail.com";
const char kExistingGaiaID[] = "22222";
const char kManagedUser[] = "user@example.com";
const char kManagedGaiaID[] = "33333";
const char kManager[] = "admin@example.com";
const char kManagedDomain[] = "example.com";
const char kPublicSessionUserEmail[] = "public_session_user@localhost";
const char kPublicSessionSecondUserEmail[] =
"public_session_second_user@localhost";
const int kAutoLoginNoDelay = 0;
const int kAutoLoginShortDelay = 1;
const int kAutoLoginLongDelay = 10000;
// Wait for cros settings to become permanently untrusted and run `callback`.
void WaitForPermanentlyUntrustedStatusAndRun(base::OnceClosure callback) {
auto split_callback = base::SplitOnceCallback(std::move(callback));
while (true) {
const CrosSettingsProvider::TrustedStatus status =
CrosSettings::Get()->PrepareTrustedValues(
base::BindOnce(&WaitForPermanentlyUntrustedStatusAndRun,
std::move(split_callback.first)));
switch (status) {
case CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
std::move(split_callback.second).Run();
return;
case CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
return;
case CrosSettingsProvider::TRUSTED:
content::RunAllPendingInMessageLoop();
break;
}
}
}
class UserProfileLoadedObserver
: public session_manager::SessionManagerObserver {
public:
UserProfileLoadedObserver() {
session_observation_.Observe(session_manager::SessionManager::Get());
}
// session_manager::SessionManagerObserver:
void OnUserProfileLoaded(const AccountId& account_id) override {
session_observation_.Reset();
account_id_ = account_id;
run_loop_.Quit();
}
AccountId Wait() {
run_loop_.Run();
DCHECK(!account_id_.empty());
return account_id_;
}
private:
base::RunLoop run_loop_;
AccountId account_id_ = EmptyAccountId();
base::ScopedObservation<session_manager::SessionManager,
session_manager::SessionManagerObserver>
session_observation_{this};
};
} // namespace
class ExistingUserControllerTest : public policy::DevicePolicyCrosBrowserTest {
public:
ExistingUserControllerTest(const ExistingUserControllerTest&) = delete;
ExistingUserControllerTest& operator=(const ExistingUserControllerTest&) =
delete;
protected:
ExistingUserControllerTest() = default;
ExistingUserController* existing_user_controller() {
return ExistingUserController::current_controller();
}
const ExistingUserController* existing_user_controller() const {
return ExistingUserController::current_controller();
}
void SetUpInProcessBrowserTestFixture() override {
DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
mock_login_display_host_ = std::make_unique<MockLoginDisplayHost>();
mock_signin_ui_ = std::make_unique<MockSigninUI>();
SetUpLoginDisplay();
}
virtual void SetUpLoginDisplay() {
ON_CALL(*mock_login_display_host_, GetSigninUI())
.WillByDefault(Return(mock_signin_ui_.get()));
ON_CALL(*mock_login_display_host_, GetWizardContext())
.WillByDefault(Return(&dummy_wizard_context_));
}
void SetUpOnMainThread() override {
policy::DevicePolicyCrosBrowserTest::SetUpOnMainThread();
existing_user_controller_ = std::make_unique<ExistingUserController>();
EXPECT_CALL(*mock_login_display_host_, GetExistingUserController())
.Times(AnyNumber())
.WillRepeatedly(Return(existing_user_controller_.get()));
ASSERT_EQ(existing_user_controller(), existing_user_controller_.get());
existing_user_controller_->Init(user_manager::UserList());
// Prevent browser start in user session so that we do not need to wait
// for its initialization.
test::UserSessionManagerTestApi(UserSessionManager::GetInstance())
.SetShouldLaunchBrowserInTests(false);
ash::AuthEventsRecorder::Get()->OnAuthenticationSurfaceChange(
AuthEventsRecorder::AuthenticationSurface::kLogin);
}
void TearDownOnMainThread() override {
DevicePolicyCrosBrowserTest::InProcessBrowserTest::TearDownOnMainThread();
// `existing_user_controller_` has data members that are CrosSettings
// observers. They need to be destructed before CrosSettings.
Mock::VerifyAndClear(mock_login_display_host_.get());
existing_user_controller_.reset();
mock_login_display_host_.reset();
// Test case may be configured with the real user manager but empty user
// list initially. So network OOBE screen is initialized.
// Need to reset it manually so that we don't end up with CrosSettings
// observer that wasn't removed.
WizardController* controller = WizardController::default_controller();
if (controller && controller->current_screen())
controller->current_screen()->Hide();
}
void ExpectLoginFailure() {
EXPECT_CALL(*mock_signin_ui_,
ShowSigninError(SigninError::kOwnerKeyLost, std::string()))
.Times(1);
}
void MakeCrosSettingsPermanentlyUntrusted() {
device_policy()->policy().set_policy_data_signature("bad signature");
session_manager_client()->set_device_policy(device_policy()->GetBlob());
session_manager_client()->OnPropertyChangeComplete(true);
base::RunLoop run_loop;
WaitForPermanentlyUntrustedStatusAndRun(run_loop.QuitClosure());
run_loop.Run();
}
// ExistingUserController private member accessors.
base::OneShotTimer* auto_login_timer() {
return existing_user_controller()->auto_login_timer_.get();
}
AccountId auto_login_account_id() const {
return existing_user_controller()->public_session_auto_login_account_id_;
}
int auto_login_delay() const {
return existing_user_controller()->auto_login_delay_;
}
bool is_login_in_progress() const {
return existing_user_controller()->is_login_in_progress_;
}
std::unique_ptr<ExistingUserController> existing_user_controller_;
std::unique_ptr<MockSigninUI> mock_signin_ui_;
std::unique_ptr<MockLoginDisplayHost> mock_login_display_host_;
const AccountId ad_account_id_ =
AccountId::AdFromUserEmailObjGuid(kAdUsername, kObjectGuid);
const LoginManagerMixin::TestUserInfo new_user_{
AccountId::FromUserEmailGaiaId(kNewUser, GaiaId(kNewGaiaID))};
const LoginManagerMixin::TestUserInfo existing_user_{
AccountId::FromUserEmailGaiaId(kExistingUser, GaiaId(kExistingGaiaID))};
CryptohomeMixin cryptohome_mixin_{&mixin_host_};
LoginManagerMixin login_manager_{&mixin_host_,
{existing_user_},
nullptr,
&cryptohome_mixin_};
WizardContext dummy_wizard_context_;
};
IN_PROC_BROWSER_TEST_F(ExistingUserControllerTest, ExistingUserLogin) {
EXPECT_CALL(*mock_login_display_host_,
StartWizard(TermsOfServiceScreenView::kScreenId.AsId()))
.Times(0);
UserProfileLoadedObserver profile_loaded_observer;
login_manager_.LoginWithDefaultContext(existing_user_);
profile_loaded_observer.Wait();
}
// Verifies that when the cros settings are untrusted, no new session can be
// started.
class ExistingUserControllerUntrustedTest : public ExistingUserControllerTest {
public:
ExistingUserControllerUntrustedTest() = default;
ExistingUserControllerUntrustedTest(
const ExistingUserControllerUntrustedTest&) = delete;
ExistingUserControllerUntrustedTest& operator=(
const ExistingUserControllerUntrustedTest&) = delete;
void SetUpOnMainThread() override {
ExistingUserControllerTest::SetUpOnMainThread();
MakeCrosSettingsPermanentlyUntrusted();
ExpectLoginFailure();
}
};
IN_PROC_BROWSER_TEST_F(ExistingUserControllerUntrustedTest,
ExistingUserLoginForbidden) {
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(existing_user_));
existing_user_controller()->Login(user_context, SigninSpecifics());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerUntrustedTest,
NewUserLoginForbidden) {
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(new_user_));
existing_user_controller()->CompleteLogin(user_context);
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerUntrustedTest,
GuestLoginForbidden) {
existing_user_controller()->Login(
UserContext(user_manager::UserType::kGuest, EmptyAccountId()),
SigninSpecifics());
}
class ExistingUserControllerPublicSessionTest
: public ExistingUserControllerTest,
public user_manager::UserManager::Observer {
public:
ExistingUserControllerPublicSessionTest(
const ExistingUserControllerPublicSessionTest&) = delete;
ExistingUserControllerPublicSessionTest& operator=(
const ExistingUserControllerPublicSessionTest&) = delete;
protected:
ExistingUserControllerPublicSessionTest() = default;
void SetUpOnMainThread() override {
ExistingUserControllerTest::SetUpOnMainThread();
// Wait for the public session user to be created.
if (!user_manager::UserManager::Get()->IsKnownUser(
public_session_account_id_)) {
user_manager::UserManager::Get()->AddObserver(this);
local_state_changed_run_loop_ = std::make_unique<base::RunLoop>();
local_state_changed_run_loop_->Run();
user_manager::UserManager::Get()->RemoveObserver(this);
}
EXPECT_TRUE(user_manager::UserManager::Get()->IsKnownUser(
public_session_account_id_));
// Wait for the device local account policy to be installed.
policy::CloudPolicyStore* store =
TestingBrowserProcess::GetGlobal()
->platform_part()
->browser_policy_connector_ash()
->GetDeviceLocalAccountPolicyService()
->GetBrokerForUser(public_session_account_id_.GetUserEmail())
->core()
->store();
if (!store->has_policy()) {
policy::MockCloudPolicyStoreObserver observer;
base::RunLoop loop;
store->AddObserver(&observer);
EXPECT_CALL(observer, OnStoreLoaded(store))
.Times(1)
.WillOnce(InvokeWithoutArgs(&loop, &base::RunLoop::Quit));
loop.Run();
store->RemoveObserver(&observer);
}
}
void SetUpInProcessBrowserTestFixture() override {
ExistingUserControllerTest::SetUpInProcessBrowserTestFixture();
// Setup the device policy.
em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
em::DeviceLocalAccountInfoProto* account =
proto.mutable_device_local_accounts()->add_account();
account->set_account_id(kPublicSessionUserEmail);
account->set_type(
em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
RefreshDevicePolicy();
// Setup the device local account policy.
policy::UserPolicyBuilder device_local_account_policy;
device_local_account_policy.policy_data().set_username(
kPublicSessionUserEmail);
device_local_account_policy.policy_data().set_policy_type(
policy::dm_protocol::kChromePublicAccountPolicyType);
device_local_account_policy.policy_data().set_settings_entity_id(
kPublicSessionUserEmail);
device_local_account_policy.Build();
session_manager_client()->set_device_local_account_policy(
kPublicSessionUserEmail, device_local_account_policy.GetBlob());
}
void TearDownOnMainThread() override {
ExistingUserControllerTest::TearDownOnMainThread();
// Test case may be configured with the real user manager but empty user
// list initially. So network OOBE screen is initialized.
// Need to reset it manually so that we don't end up with CrosSettings
// observer that wasn't removed.
WizardController* controller = WizardController::default_controller();
if (controller && controller->current_screen())
controller->current_screen()->Hide();
}
// user_manager::UserManager::Observer:
void LocalStateChanged(user_manager::UserManager* user_manager) override {
local_state_changed_run_loop_->Quit();
}
void ExpectSuccessfulLogin(const UserContext& user_context) {
test::UserSessionManagerTestApi session_manager_test_api(
UserSessionManager::GetInstance());
session_manager_test_api.InjectStubUserContext(user_context);
// There may be in-session oobe or an initial login screen created from
// --login-manager.
EXPECT_CALL(*mock_login_display_host_,
StartWizard(LocaleSwitchView::kScreenId.AsId()))
.Times(AnyNumber());
}
void SetAutoLoginPolicy(const std::string& user_email, int delay) {
// Wait until ExistingUserController has finished auto-login
// configuration by observing the same settings that trigger
// ConfigureAutoLogin.
em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
// If both settings have changed we need to wait for both to
// propagate, so check the new values against the old ones.
scoped_refptr<content::MessageLoopRunner> runner1;
base::CallbackListSubscription subscription1;
if (!proto.has_device_local_accounts() ||
!proto.device_local_accounts().has_auto_login_id() ||
proto.device_local_accounts().auto_login_id() != user_email) {
runner1 = new content::MessageLoopRunner;
subscription1 = CrosSettings::Get()->AddSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginId,
base::BindLambdaForTesting([&]() { runner1->Quit(); }));
}
scoped_refptr<content::MessageLoopRunner> runner2;
base::CallbackListSubscription subscription2;
if (!proto.has_device_local_accounts() ||
!proto.device_local_accounts().has_auto_login_delay() ||
proto.device_local_accounts().auto_login_delay() != delay) {
runner2 = new content::MessageLoopRunner;
subscription2 = CrosSettings::Get()->AddSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
base::BindLambdaForTesting([&]() { runner2->Quit(); }));
}
// Update the policy.
proto.mutable_device_local_accounts()->set_auto_login_id(user_email);
proto.mutable_device_local_accounts()->set_auto_login_delay(delay);
RefreshDevicePolicy();
// Wait for ExistingUserController to read the updated settings.
if (runner1.get())
runner1->Run();
if (runner2.get())
runner2->Run();
}
void ConfigureAutoLogin() {
existing_user_controller()->ConfigureAutoLogin();
}
void FireAutoLogin() {
existing_user_controller()->OnPublicSessionAutoLoginTimerFire();
}
const AccountId public_session_account_id_ =
AccountId::FromUserEmail(policy::GenerateDeviceLocalAccountUserId(
kPublicSessionUserEmail,
policy::DeviceLocalAccountType::kPublicSession));
private:
std::unique_ptr<base::RunLoop> local_state_changed_run_loop_;
};
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
ConfigureAutoLoginUsingPolicy) {
EXPECT_TRUE(!auto_login_account_id().is_valid());
EXPECT_EQ(0, auto_login_delay());
EXPECT_FALSE(auto_login_timer());
// Set the policy.
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginLongDelay);
EXPECT_EQ(public_session_account_id_, auto_login_account_id());
EXPECT_EQ(kAutoLoginLongDelay, auto_login_delay());
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
// Unset the policy.
SetAutoLoginPolicy("", 0);
EXPECT_TRUE(!auto_login_account_id().is_valid());
EXPECT_EQ(0, auto_login_delay());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
AutoLoginNoDelay) {
// Set up mocks to check login success.
UserContext user_context(user_manager::UserType::kPublicAccount,
public_session_account_id_);
user_context.SetUserIDHash(user_context.GetAccountId().GetUserEmail());
ExpectSuccessfulLogin(user_context);
// Start auto-login and wait for login tasks to complete.
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginNoDelay);
content::RunAllPendingInMessageLoop();
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
AutoLoginShortDelay) {
// Set up mocks to check login success.
UserContext user_context(user_manager::UserType::kPublicAccount,
public_session_account_id_);
user_context.SetUserIDHash(user_context.GetAccountId().GetUserEmail());
ExpectSuccessfulLogin(user_context);
UserProfileLoadedObserver profile_loaded_observer;
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginShortDelay);
ASSERT_TRUE(auto_login_timer());
// Don't assert that timer is running: with the short delay sometimes
// the trigger happens before the assert. We've already tested that
// the timer starts when it should.
// Wait for the timer to fire.
base::RunLoop runner;
base::OneShotTimer timer;
timer.Start(FROM_HERE, base::Milliseconds(kAutoLoginShortDelay + 1),
runner.QuitClosure());
runner.Run();
profile_loaded_observer.Wait();
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
LoginStopsAutoLogin) {
// Set up mocks to check login success.
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(new_user_));
ExpectSuccessfulLogin(user_context);
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginLongDelay);
EXPECT_TRUE(auto_login_timer());
UserProfileLoadedObserver profile_loaded_observer;
// Log in and check that it stopped the timer.
existing_user_controller()->Login(user_context, SigninSpecifics());
EXPECT_TRUE(is_login_in_progress());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
profile_loaded_observer.Wait();
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
GuestModeLoginStopsAutoLogin) {
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(new_user_));
test::UserSessionManagerTestApi session_manager_test_api(
UserSessionManager::GetInstance());
session_manager_test_api.InjectStubUserContext(user_context);
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginLongDelay);
EXPECT_TRUE(auto_login_timer());
// Login and check that it stopped the timer.
existing_user_controller()->Login(
UserContext(user_manager::UserType::kGuest, EmptyAccountId()),
SigninSpecifics());
EXPECT_TRUE(is_login_in_progress());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
CompleteLoginStopsAutoLogin) {
// Set up mocks to check login success.
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(new_user_));
ExpectSuccessfulLogin(user_context);
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginLongDelay);
EXPECT_TRUE(auto_login_timer());
UserProfileLoadedObserver profile_loaded_observer;
// Check that login completes and stops the timer.
existing_user_controller()->CompleteLogin(user_context);
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
profile_loaded_observer.Wait();
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
PublicSessionLoginStopsAutoLogin) {
// Set up mocks to check login success.
UserContext user_context(user_manager::UserType::kPublicAccount,
public_session_account_id_);
user_context.SetUserIDHash(user_context.GetAccountId().GetUserEmail());
ExpectSuccessfulLogin(user_context);
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginLongDelay);
EXPECT_TRUE(auto_login_timer());
UserProfileLoadedObserver profile_loaded_observer;
// Login and check that it stopped the timer.
existing_user_controller()->Login(
UserContext(user_manager::UserType::kPublicAccount,
public_session_account_id_),
SigninSpecifics());
EXPECT_TRUE(is_login_in_progress());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
profile_loaded_observer.Wait();
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
LoginForbiddenWhenUntrusted) {
// Make cros settings untrusted.
MakeCrosSettingsPermanentlyUntrusted();
// Check that the attempt to start a public session fails with an error.
ExpectLoginFailure();
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(new_user_));
existing_user_controller()->Login(user_context, SigninSpecifics());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
NoAutoLoginWhenUntrusted) {
// Start the public session timer.
SetAutoLoginPolicy(kPublicSessionUserEmail, kAutoLoginLongDelay);
EXPECT_TRUE(auto_login_timer());
// Make cros settings untrusted.
MakeCrosSettingsPermanentlyUntrusted();
// Check that when the timer fires, auto-login fails with an error.
ExpectLoginFailure();
FireAutoLogin();
}
class ExistingUserControllerSecondPublicSessionTest
: public ExistingUserControllerPublicSessionTest {
public:
void SetUpInProcessBrowserTestFixture() override {
ExistingUserControllerPublicSessionTest::SetUpInProcessBrowserTestFixture();
AddSecondPublicSessionAccount();
}
private:
void AddSecondPublicSessionAccount() {
// Setup the device policy.
em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
em::DeviceLocalAccountInfoProto* account =
proto.mutable_device_local_accounts()->add_account();
account->set_account_id(kPublicSessionSecondUserEmail);
account->set_type(
em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
RefreshDevicePolicy();
// Setup the device local account policy.
policy::UserPolicyBuilder device_local_account_policy;
device_local_account_policy.policy_data().set_username(
kPublicSessionSecondUserEmail);
device_local_account_policy.policy_data().set_policy_type(
policy::dm_protocol::kChromePublicAccountPolicyType);
device_local_account_policy.policy_data().set_settings_entity_id(
kPublicSessionSecondUserEmail);
device_local_account_policy.Build();
session_manager_client()->set_device_local_account_policy(
kPublicSessionSecondUserEmail, device_local_account_policy.GetBlob());
}
};
class ExistingUserControllerSavePasswordHashTest
: public ExistingUserControllerTest {
public:
ExistingUserControllerSavePasswordHashTest() = default;
~ExistingUserControllerSavePasswordHashTest() override = default;
void SetUpInProcessBrowserTestFixture() override {
ExistingUserControllerTest::SetUpInProcessBrowserTestFixture();
RefreshDevicePolicy();
}
};
// Tests that successful GAIA online login saves SyncPasswordData to user
// profile prefs.
IN_PROC_BROWSER_TEST_F(ExistingUserControllerSavePasswordHashTest,
GaiaOnlineLoginSavesPasswordHashToPrefs) {
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(new_user_));
UserProfileLoadedObserver profile_loaded_observer;
existing_user_controller()->CompleteLogin(user_context);
AccountId account_id = profile_loaded_observer.Wait();
// Verify password hash and salt are saved to prefs.
Profile* profile = ProfileHelper::Get()->GetProfileByAccountId(account_id);
EXPECT_TRUE(profile->GetPrefs()->HasPrefPath(
password_manager::prefs::kPasswordHashDataList));
}
// Tests that successful offline login saves SyncPasswordData to user profile
// prefs.
IN_PROC_BROWSER_TEST_F(ExistingUserControllerSavePasswordHashTest,
OfflineLoginSavesPasswordHashToPrefs) {
UserContext user_context(
LoginManagerMixin::CreateDefaultUserContext(existing_user_));
UserProfileLoadedObserver profile_loaded_observer;
existing_user_controller()->Login(user_context, SigninSpecifics());
AccountId account_id = profile_loaded_observer.Wait();
// Verify password hash and salt are saved to prefs.
Profile* profile = ProfileHelper::Get()->GetProfileByAccountId(account_id);
EXPECT_TRUE(profile->GetPrefs()->HasPrefPath(
password_manager::prefs::kPasswordHashDataList));
}
// Tests different auth failures for an existing user login attempts.
class ExistingUserControllerAuthFailureTest : public OobeBaseTest {
public:
ExistingUserControllerAuthFailureTest() = default;
~ExistingUserControllerAuthFailureTest() override = default;
void SetUpStubAuthenticatorAndAttemptLogin(
AuthFailure::FailureReason failure_reason) {
const UserContext user_context =
LoginManagerMixin::CreateDefaultUserContext(test_user_);
auto authenticator_builder =
std::make_unique<StubAuthenticatorBuilder>(user_context);
if (failure_reason != AuthFailure::NONE)
authenticator_builder->SetUpAuthFailure(failure_reason);
test::UserSessionManagerTestApi(UserSessionManager::GetInstance())
.InjectAuthenticatorBuilder(std::move(authenticator_builder));
// Some auth failure tests verify that error bubble is shown in the login
// UI. Given that login UI ignores auth failures, unless it attempted a
// login, the login attempt cannot be shortcut by login manager mixin API -
// it has to go through login UI.
const std::string& password = user_context.GetKey()->GetSecret();
LoginScreenTestApi::SubmitPassword(test_user_.account_id, password,
true /*check_if_submittable*/);
}
void SetUpStubAuthenticatorAndAttemptLoginWithWrongPassword() {
const UserContext user_context =
LoginManagerMixin::CreateDefaultUserContext(test_user_);
auto authenticator_builder =
std::make_unique<StubAuthenticatorBuilder>(user_context);
test::UserSessionManagerTestApi(UserSessionManager::GetInstance())
.InjectAuthenticatorBuilder(std::move(authenticator_builder));
LoginScreenTestApi::SubmitPassword(test_user_.account_id, "wrong!!!!!",
true /*check_if_submittable*/);
}
// Waits for auth error message to be shown in login UI.
void WaitForAuthErrorMessage() {
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(LoginScreenTestApi::IsAuthErrorBubbleShown());
}
protected:
FakeGaiaMixin fake_gaia_{&mixin_host_};
const LoginManagerMixin::TestUserInfo test_user_{
AccountId::FromUserEmailGaiaId("user@gmail.com", GaiaId("user"))};
LoginManagerMixin login_manager_{&mixin_host_, {test_user_}};
};
IN_PROC_BROWSER_TEST_F(ExistingUserControllerAuthFailureTest,
CryptohomeMissing) {
SetUpStubAuthenticatorAndAttemptLogin(AuthFailure::MISSING_CRYPTOHOME);
WaitForGaiaPageLoad();
EXPECT_TRUE(LoginScreenTestApi::IsOobeDialogVisible());
EXPECT_EQ(fake_gaia_.fake_gaia()->prefilled_email(),
test_user_.account_id.GetUserEmail());
const user_manager::User* user =
user_manager::UserManager::Get()->FindUser(test_user_.account_id);
ASSERT_TRUE(user);
EXPECT_TRUE(user->force_online_signin());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerAuthFailureTest,
CryptohomeUnrecoverable) {
SetUpStubAuthenticatorAndAttemptLogin(AuthFailure::UNRECOVERABLE_CRYPTOHOME);
WaitForGaiaPageLoad();
EXPECT_TRUE(LoginScreenTestApi::IsOobeDialogVisible());
EXPECT_EQ(fake_gaia_.fake_gaia()->prefilled_email(),
test_user_.account_id.GetUserEmail());
const user_manager::User* user =
user_manager::UserManager::Get()->FindUser(test_user_.account_id);
ASSERT_TRUE(user);
EXPECT_TRUE(user->force_online_signin());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerAuthFailureTest, TpmError) {
SetUpStubAuthenticatorAndAttemptLogin(AuthFailure::TPM_ERROR);
OobeScreenWaiter(TpmErrorView::kScreenId).Wait();
EXPECT_TRUE(LoginScreenTestApi::IsOobeDialogVisible());
EXPECT_EQ(
0, chromeos::FakePowerManagerClient::Get()->num_request_restart_calls());
test::TapOnPathAndWaitForOobeToBeDestroyed(
{"tpm-error-message", "restartButton"});
EXPECT_EQ(
1, chromeos::FakePowerManagerClient::Get()->num_request_restart_calls());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerAuthFailureTest, OwnerRequired) {
SetUpStubAuthenticatorAndAttemptLogin(AuthFailure::OWNER_REQUIRED);
WaitForAuthErrorMessage();
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerAuthFailureTest, WrongPassword) {
SetUpStubAuthenticatorAndAttemptLoginWithWrongPassword();
WaitForAuthErrorMessage();
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerAuthFailureTest,
WrongPasswordWhileOffline) {
NetworkStateTestHelper network_state_test_helper(
/*use_default_devices_and_services=*/false);
network_state_test_helper.ClearServices();
SetUpStubAuthenticatorAndAttemptLoginWithWrongPassword();
WaitForAuthErrorMessage();
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerAuthFailureTest,
CryptohomeUnavailable) {
FakeUserDataAuthClient::TestApi::Get()->SetServiceIsAvailable(false);
SetUpStubAuthenticatorAndAttemptLogin(AuthFailure::NONE);
FakeUserDataAuthClient::TestApi::Get()->ReportServiceIsNotAvailable();
WaitForAuthErrorMessage();
}
class ExistingUserControllerProfileTest : public LoginManagerTest {
public:
ExistingUserControllerProfileTest() = default;
void SetUpInProcessBrowserTestFixture() override {
LoginManagerTest::SetUpInProcessBrowserTestFixture();
// Login as a managed user would save force-online-signin to true and
// invalidate the auth token into local state, which would prevent to focus
// during the second part of the test which happens in the login screen.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kSkipForceOnlineSignInForTesting);
}
void TearDownInProcessBrowserTestFixture() override {
LoginManagerTest::TearDownInProcessBrowserTestFixture();
base::CommandLine::ForCurrentProcess()->RemoveSwitch(
switches::kSkipForceOnlineSignInForTesting);
}
protected:
void SetManagedBy(std::string managed_by) {
std::unique_ptr<ScopedUserPolicyUpdate> scoped_user_policy_update =
user_policy_mixin_.RequestPolicyUpdate();
if (!managed_by.empty()) {
scoped_user_policy_update->policy_data()->set_managed_by(managed_by);
} else {
scoped_user_policy_update->policy_data()->clear_managed_by();
}
}
void Login(const LoginManagerMixin::TestUserInfo& test_user) {
login_manager_mixin_.SkipPostLoginScreens();
auto context = LoginManagerMixin::CreateDefaultUserContext(test_user);
login_manager_mixin_.LoginAsNewRegularUser(context);
login_manager_mixin_.WaitForActiveSession();
}
std::u16string ConstructManagedSessionUserWarning(std::string manager) {
return l10n_util::GetStringFUTF16(
IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_USER_WARNING,
base::UTF8ToUTF16(manager));
}
const LoginManagerMixin::TestUserInfo not_managed_user_{
AccountId::FromUserEmailGaiaId(kNewUser, GaiaId(kNewGaiaID))};
const LoginManagerMixin::TestUserInfo managed_user_{
AccountId::FromUserEmailGaiaId(kManagedUser, GaiaId(kManagedGaiaID))};
UserPolicyMixin user_policy_mixin_{&mixin_host_, managed_user_.account_id};
LoginManagerMixin login_manager_mixin_{&mixin_host_};
};
IN_PROC_BROWSER_TEST_F(ExistingUserControllerProfileTest,
ManagedUserManagedBy) {
SetManagedBy(kManager);
Login(managed_user_);
user_manager::KnownUser known_user(g_browser_process->local_state());
EXPECT_TRUE(known_user.GetIsEnterpriseManaged(managed_user_.account_id));
// Verify that managed_by has been stored in prefs
const std::string* manager =
known_user.GetAccountManager(managed_user_.account_id);
ASSERT_TRUE(manager);
EXPECT_EQ(*manager, kManager);
// Set the lock screen so that the managed warning can be queried.
ScreenLockerTester().Lock();
EXPECT_TRUE(
LoginScreenTestApi::ShowRemoveAccountDialog(managed_user_.account_id));
EXPECT_TRUE(LoginScreenTestApi::IsManagedMessageInDialogShown(
managed_user_.account_id));
// Verify that the lock screen text uses the prefs value for its construction.
EXPECT_EQ(
LoginScreenTestApi::GetManagementDisclosureText(managed_user_.account_id),
ConstructManagedSessionUserWarning(kManager));
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerProfileTest, ManagedUserDomain) {
SetManagedBy(std::string());
Login(managed_user_);
user_manager::KnownUser known_user(g_browser_process->local_state());
EXPECT_TRUE(known_user.GetIsEnterpriseManaged(managed_user_.account_id));
// Verify that managed_by has been stored in prefs
const std::string* manager =
known_user.GetAccountManager(managed_user_.account_id);
ASSERT_TRUE(manager);
EXPECT_EQ(*manager, kManagedDomain);
// Set the lock screen so that the managed warning can be queried.
ScreenLockerTester().Lock();
EXPECT_TRUE(
LoginScreenTestApi::ShowRemoveAccountDialog(managed_user_.account_id));
EXPECT_TRUE(LoginScreenTestApi::IsManagedMessageInDialogShown(
managed_user_.account_id));
// Verify that the lock screen text uses the prefs value for its construction.
EXPECT_EQ(
LoginScreenTestApi::GetManagementDisclosureText(managed_user_.account_id),
ConstructManagedSessionUserWarning(kManagedDomain));
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerProfileTest, NotManagedUserLogin) {
Login(not_managed_user_);
user_manager::KnownUser known_user(g_browser_process->local_state());
EXPECT_FALSE(known_user.GetIsEnterpriseManaged(not_managed_user_.account_id));
// Verify that no value is stored in prefs for this user.
EXPECT_FALSE(known_user.GetAccountManager(not_managed_user_.account_id));
ScreenLockerTester().Lock();
EXPECT_TRUE(LoginScreenTestApi::ShowRemoveAccountDialog(
not_managed_user_.account_id));
// Verify that no managed warning is shown for an unmanaged user.
EXPECT_FALSE(LoginScreenTestApi::IsManagedMessageInDialogShown(
not_managed_user_.account_id));
}
} // namespace ash