blob: 07cc57821ee85713816168fab887e503f389a613 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <string>
#include <vector>
#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece_forward.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/ash/login/existing_user_controller.h"
#include "chrome/browser/ash/login/session/user_session_manager.h"
#include "chrome/browser/ash/login/test/embedded_policy_test_server_mixin.h"
#include "chrome/browser/ash/login/test/session_manager_state_waiter.h"
#include "chrome/browser/ash/login/ui/login_display_host.h"
#include "chrome/browser/ash/login/wizard_controller.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/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/test/web_app_test_observers.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "components/policy/core/common/cloud/test/policy_builder.h"
#include "components/policy/core/common/policy_namespace.h"
#include "components/policy/policy_constants.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
namespace web_app {
namespace {
constexpr char kUpdateManifestFileName[] = "update_manifest.json";
constexpr char kIwaBundleFileName[] = "iwa_bundle.swbn";
constexpr char kUpdateManifestTemplate[] = R"(
{"versions":[
{"version": "1.0.0", "src": "https://example.com/not-used.swbn"},
{"version": "7.0.6", "src": "$1"}]
})";
constexpr char kIsolatedWebAppPolicyTemplate[] = R"([
{
"update_manifest_url": "$1",
"web_bundle_id": "$2"
}
])";
const char kAccountId[] = "dla@example.com";
const char kDisplayName[] = "display name";
} // namespace
class IsolatedWebAppPolicyManagerAshBrowserTest
: public policy::DevicePolicyCrosBrowserTest {
public:
IsolatedWebAppPolicyManagerAshBrowserTest(
const IsolatedWebAppPolicyManagerAshBrowserTest&) = delete;
IsolatedWebAppPolicyManagerAshBrowserTest& operator=(
const IsolatedWebAppPolicyManagerAshBrowserTest&) = delete;
protected:
IsolatedWebAppPolicyManagerAshBrowserTest() = default;
~IsolatedWebAppPolicyManagerAshBrowserTest() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(ash::switches::kLoginManager);
command_line->AppendSwitch(ash::switches::kForceLoginManagerInTests);
}
void SetUpInProcessBrowserTestFixture() override {
DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
// Turning on device local account.
device_policy()->policy_data().set_public_key_version(1);
policy::DeviceLocalAccountTestHelper::SetupDeviceLocalAccount(
&device_local_account_policy_, kAccountId, kDisplayName);
}
void UploadAndInstallDeviceLocalAccountPolicy() {
// Build device local account policy.
device_local_account_policy_.SetDefaultSigningKey();
device_local_account_policy_.Build();
policy_test_server_mixin_.UpdatePolicy(
policy::dm_protocol::kChromePublicAccountPolicyType, kAccountId,
device_local_account_policy_.payload().SerializeAsString());
session_manager_client()->set_device_local_account_policy(
kAccountId, device_local_account_policy_.GetBlob());
}
void AddManagedGuestSessionToDevicePolicy() {
em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
policy::DeviceLocalAccountTestHelper::AddPublicSession(&proto, kAccountId);
RefreshDevicePolicy();
policy_test_server_mixin_.UpdateDevicePolicy(proto);
}
void AddForceInstallIsolatedWebAppsToAccountPolicy() {
const std::string swb_id = iwa_bundle_.id.id();
em::StringPolicyProto* const isolated_web_apps_proto =
device_local_account_policy_.payload()
.mutable_isolatedwebappinstallforcelist();
std::vector<std::string> replacements = {
iwa_server_.GetURL(base::StrCat({"/", kUpdateManifestFileName})).spec(),
swb_id};
const std::string policy_value = base::ReplaceStringPlaceholders(
kIsolatedWebAppPolicyTemplate, replacements, nullptr);
isolated_web_apps_proto->set_value(policy_value);
}
// Returns a profile which can be used for testing.
Profile* GetProfileForTest() {
// Any profile can be used here since this test does not test multi profile.
return ProfileManager::GetActiveUserProfile();
}
void WaitForPolicy() {
// Wait for the display name becoming available as that indicates
// device-local account policy is fully loaded, which is a prerequisite for
// successful login.
policy::DictionaryLocalStateValueWaiter("UserDisplayName", kDisplayName,
account_id_.GetUserEmail())
.Wait();
}
void StartLogin() {
// Start login into the device-local account.
auto* host = ash::LoginDisplayHost::default_host();
ASSERT_TRUE(host);
host->StartSignInScreen();
auto* controller = ash::ExistingUserController::current_controller();
ASSERT_TRUE(controller);
ash::UserContext user_context(user_manager::USER_TYPE_PUBLIC_ACCOUNT,
account_id_);
controller->Login(user_context, ash::SigninSpecifics());
}
void WaitForSessionStart() {
if (session_manager::SessionManager::Get()->IsSessionStarted()) {
return;
}
if (ash::WizardController::default_controller()) {
ash::WizardController::default_controller()
->SkipPostLoginScreensForTesting();
}
ash::test::WaitForPrimaryUserSessionStart();
}
void WriteFile(const base::FilePath::StringType& filename,
base::StringPiece contents) {
base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_TRUE(
base::WriteFile(temp_dir_.GetPath().Append(filename), contents));
}
void SetupServer() {
// Set up server that will serve update manifest and the Web Bundle
// of the IWA.
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
iwa_server_.ServeFilesFromDirectory(temp_dir_.GetPath());
ASSERT_TRUE(iwa_server_.Start());
const std::vector<std::string> replacements = {
iwa_server_.GetURL(std::string("/") + kIwaBundleFileName).spec(),
iwa_bundle_.id.id()};
const std::string update_manifest_value = base::ReplaceStringPlaceholders(
kUpdateManifestTemplate, replacements, nullptr);
WriteFile(kUpdateManifestFileName, update_manifest_value);
WriteFile(kIwaBundleFileName,
std::string(iwa_bundle_.data.begin(), iwa_bundle_.data.end()));
}
const AccountId account_id_ =
AccountId::FromUserEmail(GenerateDeviceLocalAccountUserId(
kAccountId,
policy::DeviceLocalAccount::TYPE_PUBLIC_SESSION));
policy::UserPolicyBuilder device_local_account_policy_;
const web_app::TestSignedWebBundle iwa_bundle_ =
web_app::BuildDefaultTestSignedWebBundle();
private:
ash::EmbeddedPolicyTestServerMixin policy_test_server_mixin_{&mixin_host_};
base::ScopedTempDir temp_dir_;
net::EmbeddedTestServer iwa_server_;
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(IsolatedWebAppPolicyManagerAshBrowserTest,
InstallIsolatedWebApp) {
SetupServer();
AddManagedGuestSessionToDevicePolicy();
AddForceInstallIsolatedWebAppsToAccountPolicy();
UploadAndInstallDeviceLocalAccountPolicy();
WaitForPolicy();
// Log in in the managed guest session.
ASSERT_NO_FATAL_FAILURE(StartLogin());
WaitForSessionStart();
Profile* profile = GetProfileForTest();
// Wait for the IWA to be installed.
WebAppTestInstallObserver observer(profile);
const AppId id = observer.BeginListeningAndWait();
ASSERT_EQ(id,
IsolatedWebAppUrlInfo::CreateFromSignedWebBundleId(iwa_bundle_.id)
.app_id());
const WebAppProvider* provider = WebAppProvider::GetForTest(profile);
ASSERT_TRUE(provider->registrar_unsafe().IsInstalled(id));
}
} // namespace web_app