blob: e80c8b2196681d35f3f1ab913e5ac8efb5473441 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/login/login_screen_extensions_lifetime_manager.h"
#include <string>
#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "chrome/browser/ash/login/lock/screen_locker_tester.h"
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/policy/extension_force_install_mixin.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/extension_host_test_helper.h"
#include "extensions/common/mojom/view_type.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
constexpr char kAllowlistedAppId[] = "bjaiihebfngildkcjkjckolinodhliff";
constexpr char kAllowlistedAppCrxPath[] =
"extensions/signin_screen_manual_test_app/app_signed_by_webstore.crx";
// Returns the profile into which login-screen extensions are force-installed.
Profile* GetOriginalSigninProfile() {
return ProfileHelper::GetSigninProfile()->GetOriginalProfile();
}
} // namespace
class LoginScreenExtensionsLifetimeManagerTest
: public MixinBasedInProcessBrowserTest {
protected:
LoginScreenExtensionsLifetimeManagerTest() {
// Don't shut down when no browser is open, since it breaks the test and
// since it's not the real Chrome OS behavior.
set_exit_when_last_browser_closes(false);
}
LoginScreenExtensionsLifetimeManagerTest(
const LoginScreenExtensionsLifetimeManagerTest&) = delete;
LoginScreenExtensionsLifetimeManagerTest& operator=(
const LoginScreenExtensionsLifetimeManagerTest&) = delete;
~LoginScreenExtensionsLifetimeManagerTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
// Skip showing post-login screens, as advancing through them isn't faked in
// the test.
command_line->AppendSwitch(switches::kOobeSkipPostLogin);
MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
}
void SetUpOnMainThread() override {
MixinBasedInProcessBrowserTest::SetUpOnMainThread();
extension_force_install_mixin_.InitWithDeviceStateMixin(
GetOriginalSigninProfile(), &device_state_mixin_);
}
void LogIn() {
login_manager_mixin_.LoginAsNewRegularUser();
login_manager_mixin_.WaitForActiveSession();
}
void LockSession() { ScreenLockerTester().Lock(); }
void UnlockSession() {
const std::string kPassword = "pass";
const AccountId account_id =
user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId();
ScreenLockerTester screen_locker_tester;
screen_locker_tester.SetUnlockPassword(account_id, kPassword);
screen_locker_tester.UnlockWithPassword(account_id, kPassword);
screen_locker_tester.WaitForUnlock();
}
ExtensionForceInstallMixin* extension_force_install_mixin() {
return &extension_force_install_mixin_;
}
bool IsExtensionInstalled(const std::string& extension_id) const {
return extension_force_install_mixin_.GetInstalledExtension(extension_id) !=
nullptr;
}
bool IsExtensionEnabled(const std::string& extension_id) const {
return extension_force_install_mixin_.GetEnabledExtension(extension_id) !=
nullptr;
}
private:
DeviceStateMixin device_state_mixin_{
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
LoginManagerMixin login_manager_mixin_{&mixin_host_};
ExtensionForceInstallMixin extension_force_install_mixin_{&mixin_host_};
};
// Tests that an extension force-installed on the login/lock screen gets
// disabled during an active user session.
IN_PROC_BROWSER_TEST_F(LoginScreenExtensionsLifetimeManagerTest, Basic) {
// Force-install the app while on the login screen. The app gets loaded.
EXPECT_TRUE(extension_force_install_mixin()->ForceInstallFromCrx(
base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
.AppendASCII(kAllowlistedAppCrxPath),
ExtensionForceInstallMixin::WaitMode::kBackgroundPageFirstLoad));
ASSERT_TRUE(IsExtensionEnabled(kAllowlistedAppId));
// The user logs in. The app gets disabled, although still installed.
LogIn();
EXPECT_TRUE(IsExtensionInstalled(kAllowlistedAppId));
EXPECT_FALSE(IsExtensionEnabled(kAllowlistedAppId));
// The user locks the session. The app gets enabled and the background page
// is loaded again.
{
extensions::ExtensionHostTestHelper background_ready(
GetOriginalSigninProfile(), kAllowlistedAppId);
background_ready.RestrictToType(
extensions::mojom::ViewType::kExtensionBackgroundPage);
LockSession();
background_ready.WaitForHostCompletedFirstLoad();
ASSERT_TRUE(IsExtensionEnabled(kAllowlistedAppId));
}
// The user unlocks the session. The app gets disabled again.
UnlockSession();
EXPECT_TRUE(IsExtensionInstalled(kAllowlistedAppId));
EXPECT_FALSE(IsExtensionEnabled(kAllowlistedAppId));
}
// Tests that an extension force-installed into the login/lock screen when
// they're not active doesn't get launched.
IN_PROC_BROWSER_TEST_F(LoginScreenExtensionsLifetimeManagerTest,
InstalledDuringSession) {
// Force-install the app during an active user session. The app gets
// installed, but almost immediately (in an async job) gets disabled.
LogIn();
EXPECT_TRUE(extension_force_install_mixin()->ForceInstallFromCrx(
base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
.AppendASCII(kAllowlistedAppCrxPath),
ExtensionForceInstallMixin::WaitMode::kLoad));
EXPECT_TRUE(IsExtensionInstalled(kAllowlistedAppId));
// Wait until the extension gets disabled. Sadly, the extensions system
// doesn't provide a proper way to wait until that happens, so we're relying
// on the production code doing this in zero-delayed async job.
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(IsExtensionEnabled(kAllowlistedAppId));
// The user locks the session. The app gets enabled and the background page is
// loaded again.
extensions::ExtensionHostTestHelper background_ready(
GetOriginalSigninProfile(), kAllowlistedAppId);
background_ready.RestrictToType(
extensions::mojom::ViewType::kExtensionBackgroundPage);
LockSession();
background_ready.WaitForHostCompletedFirstLoad();
ASSERT_TRUE(IsExtensionEnabled(kAllowlistedAppId));
}
} // namespace ash