Commit 4974f436 authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Wait for pref/bgpage in ExtensionForceInstallMixin

Add ability to wait for the given events into
ExtensionForceInstallMixin:
* the pref gets updated;
* the extension's background page is loaded for the first time.

Migrate the tests in
challenge_response_auth_keys_loader_browsertest.cc onto
ExtensionForceInstallMixin (instead of
TestCertificateProviderExtensionLoginScreenMixin).

Bug: 1090941
Change-Id: I2b71546564b99a682a74fef70abc243d3e198c8c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2312640
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarOmar Morsi <omorsi@google.com>
Reviewed-by: default avatarFabian Sommer <fabiansommer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#791215}
parent 93bc19d3
...@@ -14,9 +14,11 @@ ...@@ -14,9 +14,11 @@
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/path_service.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/api/certificate_provider.h" #include "chrome/common/extensions/api/certificate_provider.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/notification_details.h" #include "content/public/browser/notification_details.h"
...@@ -37,6 +39,11 @@ ...@@ -37,6 +39,11 @@
namespace { namespace {
constexpr char kExtensionId[] = "ecmhnokcdiianioonpgakiooenfnonid"; constexpr char kExtensionId[] = "ecmhnokcdiianioonpgakiooenfnonid";
// Paths relative to |chrome::DIR_TEST_DATA|:
constexpr base::FilePath::CharType kExtensionPath[] =
FILE_PATH_LITERAL("extensions/test_certificate_provider/extension/");
constexpr base::FilePath::CharType kExtensionPemPath[] =
FILE_PATH_LITERAL("extensions/test_certificate_provider/extension.pem");
// List of algorithms that the extension claims to support for the returned // List of algorithms that the extension claims to support for the returned
// certificates. // certificates.
...@@ -123,6 +130,18 @@ extensions::ExtensionId TestCertificateProviderExtension::extension_id() { ...@@ -123,6 +130,18 @@ extensions::ExtensionId TestCertificateProviderExtension::extension_id() {
return kExtensionId; return kExtensionId;
} }
// static
base::FilePath TestCertificateProviderExtension::GetExtensionSourcePath() {
return base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
.Append(kExtensionPath);
}
// static
base::FilePath TestCertificateProviderExtension::GetExtensionPemPath() {
return base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
.Append(kExtensionPemPath);
}
// static // static
scoped_refptr<net::X509Certificate> scoped_refptr<net::X509Certificate>
TestCertificateProviderExtension::GetCertificate() { TestCertificateProviderExtension::GetCertificate() {
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/boringssl/src/include/openssl/evp.h"
namespace base { namespace base {
class FilePath;
class Value; class Value;
} }
...@@ -41,6 +42,8 @@ class TestCertificateProviderExtension final ...@@ -41,6 +42,8 @@ class TestCertificateProviderExtension final
: public content::NotificationObserver { : public content::NotificationObserver {
public: public:
static extensions::ExtensionId extension_id(); static extensions::ExtensionId extension_id();
static base::FilePath GetExtensionSourcePath();
static base::FilePath GetExtensionPemPath();
// Returns the certificate provided by the extension. // Returns the certificate provided by the extension.
static scoped_refptr<net::X509Certificate> GetCertificate(); static scoped_refptr<net::X509Certificate> GetCertificate();
static std::string GetCertificateSpki(); static std::string GetCertificateSpki();
......
...@@ -10,23 +10,21 @@ ...@@ -10,23 +10,21 @@
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "chrome/browser/chromeos/certificate_provider/test_certificate_provider_extension.h" #include "chrome/browser/chromeos/certificate_provider/test_certificate_provider_extension.h"
#include "chrome/browser/chromeos/certificate_provider/test_certificate_provider_extension_login_screen_mixin.h"
#include "chrome/browser/chromeos/login/test/device_state_mixin.h" #include "chrome/browser/chromeos/login/test/device_state_mixin.h"
#include "chrome/browser/chromeos/login/test/oobe_base_test.h" #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/policy/extension_force_install_mixin.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chromeos/login/auth/challenge_response/known_user_pref_utils.h" #include "chromeos/login/auth/challenge_response/known_user_pref_utils.h"
#include "chromeos/login/auth/challenge_response_key.h" #include "chromeos/login/auth/challenge_response_key.h"
#include "components/account_id/account_id.h" #include "components/account_id/account_id.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/known_user.h" #include "components/user_manager/known_user.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
#include "extensions/browser/extension_host.h" #include "extensions/browser/extension_host.h"
#include "extensions/browser/pref_names.h"
#include "extensions/browser/process_manager.h" #include "extensions/browser/process_manager.h"
#include "extensions/browser/process_manager_observer.h" #include "extensions/browser/process_manager_observer.h"
#include "extensions/common/extension_id.h" #include "extensions/common/extension_id.h"
#include "extensions/common/features/simple_feature.h"
namespace chromeos { namespace chromeos {
...@@ -34,12 +32,12 @@ namespace { ...@@ -34,12 +32,12 @@ namespace {
constexpr char kUserEmail[] = "testuser@example.com"; constexpr char kUserEmail[] = "testuser@example.com";
content::BrowserContext* GetBrowserContext() { Profile* GetProfile() {
return ProfileHelper::GetSigninProfile()->GetOriginalProfile(); return ProfileHelper::GetSigninProfile()->GetOriginalProfile();
} }
extensions::ProcessManager* GetProcessManager() { extensions::ProcessManager* GetProcessManager() {
return extensions::ProcessManager::Get(GetBrowserContext()); return extensions::ProcessManager::Get(GetProfile());
} }
} // namespace } // namespace
...@@ -47,7 +45,7 @@ extensions::ProcessManager* GetProcessManager() { ...@@ -47,7 +45,7 @@ extensions::ProcessManager* GetProcessManager() {
class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest { class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest {
public: public:
ChallengeResponseAuthKeysLoaderBrowserTest() { ChallengeResponseAuthKeysLoaderBrowserTest() {
// Required for TestCertificateProviderExtensionLoginScreenMixin // Allow the forced installation of extensions in the background.
needs_background_networking_ = true; needs_background_networking_ = true;
} }
ChallengeResponseAuthKeysLoaderBrowserTest( ChallengeResponseAuthKeysLoaderBrowserTest(
...@@ -63,11 +61,17 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest { ...@@ -63,11 +61,17 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest {
challenge_response_auth_keys_loader_->SetMaxWaitTimeForTesting( challenge_response_auth_keys_loader_->SetMaxWaitTimeForTesting(
base::TimeDelta::Max()); base::TimeDelta::Max());
cert_provider_extension_ =
std::make_unique<TestCertificateProviderExtension>(GetProfile());
extension_force_install_mixin_.InitWithDeviceStateMixin(
GetProfile(), &device_state_mixin_);
// Register the ChallengeResponseKey for the user. // Register the ChallengeResponseKey for the user.
user_manager::known_user::SaveKnownUser(account_id_); user_manager::known_user::SaveKnownUser(account_id_);
} }
void TearDownOnMainThread() override { void TearDownOnMainThread() override {
cert_provider_extension_.reset();
if (!should_delete_loader_after_shutdown_) if (!should_delete_loader_after_shutdown_)
challenge_response_auth_keys_loader_.reset(); challenge_response_auth_keys_loader_.reset();
OobeBaseTest::TearDownOnMainThread(); OobeBaseTest::TearDownOnMainThread();
...@@ -105,41 +109,12 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest { ...@@ -105,41 +109,12 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest {
} }
void InstallExtension(bool wait_on_extension_loaded) { void InstallExtension(bool wait_on_extension_loaded) {
cert_provider_extension_mixin_.AddExtensionForForceInstallation(); EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromSourceDir(
if (wait_on_extension_loaded) { TestCertificateProviderExtension::GetExtensionSourcePath(),
cert_provider_extension_mixin_.WaitUntilExtensionLoaded(); TestCertificateProviderExtension::GetExtensionPemPath(),
} else { wait_on_extension_loaded
// Even though we do not want to wait until the extension is fully ready, ? ExtensionForceInstallMixin::WaitMode::kBackgroundPageFirstLoad
// wait until the extension has been registered as a force-installed : ExtensionForceInstallMixin::WaitMode::kPrefSet));
// login-screen extension in profile preferences.
WaitUntilPrefUpdated();
}
}
void PrefChangedCallback() {
const PrefService* prefs = ProfileHelper::GetSigninProfile()->GetPrefs();
const PrefService::Preference* pref =
prefs->FindPreference(extensions::pref_names::kLoginScreenExtensions);
if (pref->IsManaged() && wait_for_pref_change_run_loop_) {
wait_for_pref_change_run_loop_->Quit();
}
}
void CheckExtensionInstallPolicyApplied() {
// Check that the extension is registered as a force-installed login-screen
// extension.
const PrefService* const prefs =
ProfileHelper::GetSigninProfile()->GetPrefs();
const PrefService::Preference* const pref =
prefs->FindPreference(extensions::pref_names::kLoginScreenExtensions);
EXPECT_TRUE(pref);
EXPECT_TRUE(pref->IsManaged());
EXPECT_EQ(pref->GetType(), base::Value::Type::DICTIONARY);
EXPECT_EQ(pref->GetValue()->DictSize(), static_cast<size_t>(1));
for (const auto& item : pref->GetValue()->DictItems()) {
EXPECT_EQ(item.first, extension_id());
}
} }
std::vector<ChallengeResponseKey> LoadChallengeResponseKeys() { std::vector<ChallengeResponseKey> LoadChallengeResponseKeys() {
...@@ -152,9 +127,8 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest { ...@@ -152,9 +127,8 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest {
return challenge_response_keys; return challenge_response_keys;
} }
std::string GetSpki() const { static std::string GetSpki() {
return cert_provider_extension_mixin_.test_certificate_provider_extension() return TestCertificateProviderExtension::GetCertificateSpki();
->GetCertificateSpki();
} }
static extensions::ExtensionId extension_id() { static extensions::ExtensionId extension_id() {
...@@ -176,32 +150,16 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest { ...@@ -176,32 +150,16 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest {
} }
private: private:
void WaitUntilPrefUpdated() {
PrefChangeRegistrar pref_change_registrar;
pref_change_registrar.Init(ProfileHelper::GetSigninProfile()->GetPrefs());
pref_change_registrar.Add(
extensions::pref_names::kLoginScreenExtensions,
base::BindRepeating(
&ChallengeResponseAuthKeysLoaderBrowserTest::PrefChangedCallback,
weak_ptr_factory_.GetWeakPtr()));
const PrefService* prefs = ProfileHelper::GetSigninProfile()->GetPrefs();
const PrefService::Preference* pref =
prefs->FindPreference(extensions::pref_names::kLoginScreenExtensions);
if (!pref->IsManaged()) {
base::RunLoop wait_for_pref_change_run_loop;
wait_for_pref_change_run_loop_ = &wait_for_pref_change_run_loop;
wait_for_pref_change_run_loop.Run();
}
}
const AccountId account_id_{AccountId::FromUserEmail(kUserEmail)}; const AccountId account_id_{AccountId::FromUserEmail(kUserEmail)};
// Bypass "signin_screen" feature only enabled for allowlisted extensions.
extensions::SimpleFeature::ScopedThreadUnsafeAllowlistForTest
feature_allowlist_{extension_id()};
DeviceStateMixin device_state_mixin_{ DeviceStateMixin device_state_mixin_{
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED}; &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
TestCertificateProviderExtensionLoginScreenMixin std::unique_ptr<TestCertificateProviderExtension> cert_provider_extension_;
cert_provider_extension_mixin_{&mixin_host_, &device_state_mixin_, ExtensionForceInstallMixin extension_force_install_mixin_{&mixin_host_};
/*load_extension_immediately=*/false};
base::RunLoop* wait_for_pref_change_run_loop_ = nullptr;
std::unique_ptr<ChallengeResponseAuthKeysLoader> std::unique_ptr<ChallengeResponseAuthKeysLoader>
challenge_response_auth_keys_loader_; challenge_response_auth_keys_loader_;
...@@ -218,7 +176,6 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest { ...@@ -218,7 +176,6 @@ class ChallengeResponseAuthKeysLoaderBrowserTest : public OobeBaseTest {
IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest, IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest,
NoKeyRegistered) { NoKeyRegistered) {
InstallExtension(/*wait_on_extension_loaded=*/true); InstallExtension(/*wait_on_extension_loaded=*/true);
CheckExtensionInstallPolicyApplied();
// Challenge Response Auth Keys cannot be loaded. // Challenge Response Auth Keys cannot be loaded.
EXPECT_FALSE( EXPECT_FALSE(
...@@ -245,7 +202,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest, ...@@ -245,7 +202,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest,
LoadingKeysAfterExtensionIsInstalled) { LoadingKeysAfterExtensionIsInstalled) {
RegisterChallengeResponseKey(/*with_extension_id=*/true); RegisterChallengeResponseKey(/*with_extension_id=*/true);
InstallExtension(/*wait_on_extension_loaded=*/true); InstallExtension(/*wait_on_extension_loaded=*/true);
CheckExtensionInstallPolicyApplied();
// Challenge Response Auth Keys can be loaded. // Challenge Response Auth Keys can be loaded.
EXPECT_TRUE( EXPECT_TRUE(
...@@ -267,7 +223,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest, ...@@ -267,7 +223,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest,
LoadingKeysWhileExtensionIsBeingInstalled) { LoadingKeysWhileExtensionIsBeingInstalled) {
RegisterChallengeResponseKey(/*with_extension_id=*/true); RegisterChallengeResponseKey(/*with_extension_id=*/true);
InstallExtension(/*wait_on_extension_loaded=*/false); InstallExtension(/*wait_on_extension_loaded=*/false);
CheckExtensionInstallPolicyApplied();
// Challenge Response Auth Keys can be loaded. // Challenge Response Auth Keys can be loaded.
EXPECT_TRUE( EXPECT_TRUE(
...@@ -304,7 +259,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest, ...@@ -304,7 +259,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest,
LoadingKeysWithoutExtensionId) { LoadingKeysWithoutExtensionId) {
RegisterChallengeResponseKey(/*with_extension_id=*/false); RegisterChallengeResponseKey(/*with_extension_id=*/false);
InstallExtension(/*wait_on_extension_loaded=*/true); InstallExtension(/*wait_on_extension_loaded=*/true);
CheckExtensionInstallPolicyApplied();
// Challenge Response Auth Keys can be loaded. // Challenge Response Auth Keys can be loaded.
EXPECT_TRUE( EXPECT_TRUE(
...@@ -323,7 +277,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest, ...@@ -323,7 +277,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest,
DestroyedBeforeCompletion) { DestroyedBeforeCompletion) {
RegisterChallengeResponseKey(/*with_extension_id=*/true); RegisterChallengeResponseKey(/*with_extension_id=*/true);
InstallExtension(/*wait_on_extension_loaded=*/false); InstallExtension(/*wait_on_extension_loaded=*/false);
CheckExtensionInstallPolicyApplied();
// Challenge Response Auth Keys can be loaded. // Challenge Response Auth Keys can be loaded.
EXPECT_TRUE( EXPECT_TRUE(
...@@ -347,7 +300,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest, ...@@ -347,7 +300,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseAuthKeysLoaderBrowserTest,
AfterShutdown) { AfterShutdown) {
RegisterChallengeResponseKey(/*with_extension_id=*/true); RegisterChallengeResponseKey(/*with_extension_id=*/true);
InstallExtension(/*wait_on_extension_loaded=*/false); InstallExtension(/*wait_on_extension_loaded=*/false);
CheckExtensionInstallPolicyApplied();
// Challenge Response Auth Keys can be loaded. // Challenge Response Auth Keys can be loaded.
EXPECT_TRUE( EXPECT_TRUE(
...@@ -436,7 +388,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseExtensionLoadObserverTest, ...@@ -436,7 +388,6 @@ IN_PROC_BROWSER_TEST_F(ChallengeResponseExtensionLoadObserverTest,
RegisterChallengeResponseKey(/*with_extension_id=*/true); RegisterChallengeResponseKey(/*with_extension_id=*/true);
InstallExtension(/*wait_on_extension_loaded=*/false); InstallExtension(/*wait_on_extension_loaded=*/false);
CheckExtensionInstallPolicyApplied();
// Challenge Response Auth Keys can be loaded. // Challenge Response Auth Keys can be loaded.
EXPECT_TRUE( EXPECT_TRUE(
......
...@@ -10,13 +10,17 @@ ...@@ -10,13 +10,17 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/bind.h"
#include "base/check.h" #include "base/check.h"
#include "base/check_op.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/important_file_writer.h" #include "base/files/important_file_writer.h"
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
...@@ -25,15 +29,19 @@ ...@@ -25,15 +29,19 @@
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "components/crx_file/crx_verifier.h" #include "components/crx_file/crx_verifier.h"
#include "components/crx_file/id_util.h" #include "components/crx_file/id_util.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/extension_creator.h" #include "extensions/browser/extension_creator.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h" #include "extensions/browser/extension_system.h"
#include "extensions/browser/pref_names.h"
#include "extensions/browser/runtime_data.h" #include "extensions/browser/runtime_data.h"
#include "extensions/browser/test_extension_registry_observer.h" #include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "extensions/common/extension_id.h" #include "extensions/common/extension_id.h"
#include "extensions/common/file_util.h" #include "extensions/common/file_util.h"
#include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_constants.h"
#include "extensions/test/test_background_page_first_load_observer.h"
#include "extensions/test/test_background_page_ready_observer.h" #include "extensions/test/test_background_page_ready_observer.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -43,6 +51,7 @@ ...@@ -43,6 +51,7 @@
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/test/device_state_mixin.h" #include "chrome/browser/chromeos/login/test/device_state_mixin.h"
#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "components/policy/proto/chrome_device_policy.pb.h" #include "components/policy/proto/chrome_device_policy.pb.h"
#endif #endif
...@@ -64,6 +73,78 @@ constexpr char kUpdateManifestTemplate[] = ...@@ -64,6 +73,78 @@ constexpr char kUpdateManifestTemplate[] =
</app> </app>
</gupdate>)"; </gupdate>)";
// Implements waiting until the given extension appears in the
// force-installation pref.
class ForceInstallPrefObserver final {
public:
ForceInstallPrefObserver(Profile* profile,
const extensions::ExtensionId& extension_id);
ForceInstallPrefObserver(const ForceInstallPrefObserver&) = delete;
ForceInstallPrefObserver& operator=(const ForceInstallPrefObserver&) = delete;
~ForceInstallPrefObserver();
void Wait();
private:
void OnPrefChanged();
bool IsForceInstallPrefSet() const;
PrefService* const pref_service_;
const std::string pref_name_;
const extensions::ExtensionId extension_id_;
PrefChangeRegistrar pref_change_registrar_;
base::RunLoop run_loop_;
base::WeakPtrFactory<ForceInstallPrefObserver> weak_ptr_factory_{this};
};
std::string GetForceInstallPrefName(Profile* profile) {
#if defined(OS_CHROMEOS)
if (chromeos::ProfileHelper::IsSigninProfile(profile))
return extensions::pref_names::kLoginScreenExtensions;
#endif // OS_CHROMEOS
return extensions::pref_names::kInstallForceList;
}
ForceInstallPrefObserver::ForceInstallPrefObserver(
Profile* profile,
const extensions::ExtensionId& extension_id)
: pref_service_(profile->GetPrefs()),
pref_name_(GetForceInstallPrefName(profile)),
extension_id_(extension_id) {
pref_change_registrar_.Init(pref_service_);
pref_change_registrar_.Add(
pref_name_, base::BindRepeating(&ForceInstallPrefObserver::OnPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
}
ForceInstallPrefObserver::~ForceInstallPrefObserver() = default;
void ForceInstallPrefObserver::Wait() {
if (IsForceInstallPrefSet())
return;
run_loop_.Run();
}
void ForceInstallPrefObserver::OnPrefChanged() {
if (IsForceInstallPrefSet())
run_loop_.Quit();
}
bool ForceInstallPrefObserver::IsForceInstallPrefSet() const {
const PrefService::Preference* const pref =
pref_service_->FindPreference(pref_name_);
if (!pref || !pref->IsManaged()) {
// Note that we intentionally ignore the pref if it's set but isn't managed,
// mimicking the real behavior of the Extensions system that only respects
// trusted (policy-set) values. Normally there's no "untrusted" value in
// these prefs, but in theory this is an attack that the Extensions system
// protects against, and there might be tests that simulate this scenario.
return false;
}
DCHECK_EQ(pref->GetType(), base::Value::Type::DICTIONARY);
return pref->GetValue()->FindKey(extension_id_) != nullptr;
}
// Implements waiting for the mixin's specified event. // Implements waiting for the mixin's specified event.
class ForceInstallWaiter final { class ForceInstallWaiter final {
public: public:
...@@ -86,9 +167,12 @@ class ForceInstallWaiter final { ...@@ -86,9 +167,12 @@ class ForceInstallWaiter final {
const ExtensionForceInstallMixin::WaitMode wait_mode_; const ExtensionForceInstallMixin::WaitMode wait_mode_;
const extensions::ExtensionId extension_id_; const extensions::ExtensionId extension_id_;
Profile* const profile_; Profile* const profile_;
std::unique_ptr<ForceInstallPrefObserver> force_install_pref_observer_;
std::unique_ptr<extensions::TestExtensionRegistryObserver> registry_observer_; std::unique_ptr<extensions::TestExtensionRegistryObserver> registry_observer_;
std::unique_ptr<extensions::ExtensionBackgroundPageReadyObserver> std::unique_ptr<extensions::ExtensionBackgroundPageReadyObserver>
background_page_ready_observer_; background_page_ready_observer_;
std::unique_ptr<extensions::TestBackgroundPageFirstLoadObserver>
background_page_first_load_observer_;
}; };
ForceInstallWaiter::ForceInstallWaiter( ForceInstallWaiter::ForceInstallWaiter(
...@@ -101,15 +185,24 @@ ForceInstallWaiter::ForceInstallWaiter( ...@@ -101,15 +185,24 @@ ForceInstallWaiter::ForceInstallWaiter(
switch (wait_mode_) { switch (wait_mode_) {
case ExtensionForceInstallMixin::WaitMode::kNone: case ExtensionForceInstallMixin::WaitMode::kNone:
break; break;
case ExtensionForceInstallMixin::WaitMode::kPrefSet:
force_install_pref_observer_ =
std::make_unique<ForceInstallPrefObserver>(profile_, extension_id_);
break;
case ExtensionForceInstallMixin::WaitMode::kLoad: case ExtensionForceInstallMixin::WaitMode::kLoad:
registry_observer_ = registry_observer_ =
std::make_unique<extensions::TestExtensionRegistryObserver>( std::make_unique<extensions::TestExtensionRegistryObserver>(
extensions::ExtensionRegistry::Get(profile_), extension_id); extensions::ExtensionRegistry::Get(profile_), extension_id_);
break; break;
case ExtensionForceInstallMixin::WaitMode::kBackgroundPageReady: case ExtensionForceInstallMixin::WaitMode::kBackgroundPageReady:
background_page_ready_observer_ = background_page_ready_observer_ =
std::make_unique<extensions::ExtensionBackgroundPageReadyObserver>( std::make_unique<extensions::ExtensionBackgroundPageReadyObserver>(
profile_, extension_id); profile_, extension_id_);
break;
case ExtensionForceInstallMixin::WaitMode::kBackgroundPageFirstLoad:
background_page_first_load_observer_ =
std::make_unique<extensions::TestBackgroundPageFirstLoadObserver>(
profile_, extension_id_);
break; break;
} }
} }
...@@ -128,14 +221,24 @@ void ForceInstallWaiter::WaitImpl(bool* success) { ...@@ -128,14 +221,24 @@ void ForceInstallWaiter::WaitImpl(bool* success) {
// No waiting needed. // No waiting needed.
*success = true; *success = true;
break; break;
case ExtensionForceInstallMixin::WaitMode::kPrefSet:
// Wait and assert that the waiting run loop didn't time out.
ASSERT_NO_FATAL_FAILURE(force_install_pref_observer_->Wait());
*success = true;
break;
case ExtensionForceInstallMixin::WaitMode::kLoad: case ExtensionForceInstallMixin::WaitMode::kLoad:
*success = registry_observer_->WaitForExtensionLoaded() != nullptr; *success = registry_observer_->WaitForExtensionLoaded() != nullptr;
break; break;
case ExtensionForceInstallMixin::WaitMode::kBackgroundPageReady: { case ExtensionForceInstallMixin::WaitMode::kBackgroundPageReady:
// Wait and assert that the waiting run loop didn't time out.
ASSERT_NO_FATAL_FAILURE(background_page_ready_observer_->Wait()); ASSERT_NO_FATAL_FAILURE(background_page_ready_observer_->Wait());
*success = true; *success = true;
break; break;
} case ExtensionForceInstallMixin::WaitMode::kBackgroundPageFirstLoad:
// Wait and assert that the waiting run loop didn't time out.
ASSERT_NO_FATAL_FAILURE(background_page_first_load_observer_->Wait());
*success = true;
break;
} }
} }
......
...@@ -73,10 +73,14 @@ class ExtensionForceInstallMixin final : public InProcessBrowserTestMixin { ...@@ -73,10 +73,14 @@ class ExtensionForceInstallMixin final : public InProcessBrowserTestMixin {
enum class WaitMode { enum class WaitMode {
// Don't wait, and return immediately. // Don't wait, and return immediately.
kNone, kNone,
// Wait until the force-installation pref is updated.
kPrefSet,
// Wait until the extension is loaded. // Wait until the extension is loaded.
kLoad, kLoad,
// Wait until the extension's background page is ready. // Wait until the extension's background page is ready.
kBackgroundPageReady, kBackgroundPageReady,
// Wait until the extension's background page is loaded for the first time.
kBackgroundPageFirstLoad,
}; };
explicit ExtensionForceInstallMixin(InProcessBrowserTestMixinHost* host); explicit ExtensionForceInstallMixin(InProcessBrowserTestMixinHost* host);
......
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