| // Copyright 2013 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/policy/core/device_local_account.h" |
| |
| #include <stddef.h> |
| |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "ash/constants/ash_paths.h" |
| #include "ash/constants/ash_switches.h" |
| #include "ash/public/cpp/login_screen_test_api.h" |
| #include "ash/shell.h" |
| #include "ash/system/session/logout_confirmation_controller.h" |
| #include "ash/system/session/logout_confirmation_dialog.h" |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/json/json_writer.h" |
| #include "base/location.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/path_service.h" |
| #include "base/run_loop.h" |
| #include "base/scoped_observation.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/synchronization/lock.h" |
| #include "base/test/gtest_tags.h" |
| #include "base/test/repeating_test_future.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/test/test_future.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "chrome/browser/apps/app_service/app_service_proxy.h" |
| #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" |
| #include "chrome/browser/apps/app_service/launch_utils.h" |
| #include "chrome/browser/ash/extensions/external_cache.h" |
| #include "chrome/browser/ash/login/existing_user_controller.h" |
| #include "chrome/browser/ash/login/screens/base_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/signin_specifics.h" |
| #include "chrome/browser/ash/login/test/js_checker.h" |
| #include "chrome/browser/ash/login/test/login_or_lock_screen_visible_waiter.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/profile_prepared_waiter.h" |
| #include "chrome/browser/ash/login/test/session_manager_state_waiter.h" |
| #include "chrome/browser/ash/login/test/test_predicate_waiter.h" |
| #include "chrome/browser/ash/login/test/webview_content_extractor.h" |
| #include "chrome/browser/ash/login/ui/login_display_host.h" |
| #include "chrome/browser/ash/login/users/avatar/user_image_manager_test_util.h" |
| #include "chrome/browser/ash/login/users/chrome_user_manager.h" |
| #include "chrome/browser/ash/login/users/chrome_user_manager_impl.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_broker.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/policy/external_data/cloud_external_data_manager_base_test_util.h" |
| #include "chrome/browser/ash/policy/test_support/embedded_policy_test_server_mixin.h" |
| #include "chrome/browser/ash/profiles/profile_helper.h" |
| #include "chrome/browser/ash/session_length_limiter.h" |
| #include "chrome/browser/ash/system/timezone_util.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browser_process_platform_part.h" |
| #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h" |
| #include "chrome/browser/extensions/crx_installer.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/updater/chromeos_extension_cache_delegate.h" |
| #include "chrome/browser/extensions/updater/extension_cache_impl.h" |
| #include "chrome/browser/extensions/updater/local_extension_cache.h" |
| #include "chrome/browser/lifetime/application_lifetime.h" |
| #include "chrome/browser/net/profile_network_context_service.h" |
| #include "chrome/browser/net/profile_network_context_service_test_utils.h" |
| #include "chrome/browser/policy/networking/device_network_configuration_updater_ash.h" |
| #include "chrome/browser/policy/policy_test_utils.h" |
| #include "chrome/browser/policy/profile_policy_connector.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/profiles/profile_manager_observer.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_list_observer.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/webui/ash/login/oobe_ui.h" |
| #include "chrome/browser/ui/webui/ash/login/terms_of_service_screen_handler.h" |
| #include "chrome/browser/web_applications/web_app_provider.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/grit/chromium_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h" |
| #include "chromeos/ash/components/login/auth/public/user_context.h" |
| #include "chromeos/ash/components/network/policy_certificate_provider.h" |
| #include "chromeos/ash/components/settings/timezone_settings.h" |
| #include "components/crx_file/crx_verifier.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/test/policy_builder.h" |
| #include "components/policy/core/common/external_data_fetcher.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/policy/core/common/policy_namespace.h" |
| #include "components/policy/core/common/policy_service.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/policy/proto/chrome_device_policy.pb.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/session_manager/core/session_manager.h" |
| #include "components/signin/public/identity_manager/identity_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/browser/web_contents.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "extensions/browser/app_window/app_window.h" |
| #include "extensions/browser/app_window/app_window_registry.h" |
| #include "extensions/browser/app_window/native_app_window.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/extension_system.h" |
| #include "extensions/browser/management_policy.h" |
| #include "extensions/browser/sandboxed_unpacker.h" |
| #include "extensions/browser/updater/extension_downloader_test_helper.h" |
| #include "extensions/common/extension.h" |
| #include "net/base/url_util.h" |
| #include "net/http/http_status_code.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| #include "third_party/icu/source/common/unicode/locid.h" |
| #include "ui/base/ime/ash/extension_ime_util.h" |
| #include "ui/base/ime/ash/input_method_descriptor.h" |
| #include "ui/base/ime/ash/input_method_manager.h" |
| #include "ui/base/ime/ash/input_method_util.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/window_open_disposition.h" |
| #include "ui/display/display.h" |
| #include "ui/display/screen.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "ui/views/widget/widget.h" |
| #include "url/gurl.h" |
| |
| using base::test::TestFuture; |
| using extensions::CrxInstallError; |
| |
| namespace policy { |
| |
| namespace { |
| |
| namespace em = ::enterprise_management; |
| |
| using ::ash::test::GetOobeElementPath; |
| |
| const char16_t kDomain[] = u"example.com"; |
| const char kAccountId1[] = "dla1@example.com"; |
| const char kAccountId2[] = "dla2@example.com"; |
| const char kDisplayName1[] = "display name 1"; |
| const char kDisplayName2[] = "display name 2"; |
| const char* const kStartupURLs[] = { |
| "chrome://policy", |
| "chrome://about", |
| }; |
| const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt"; |
| const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt"; |
| const char kRelativeUpdateURL[] = "/service/update2/crx"; |
| const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi"; |
| const char kHostedAppCRXPath[] = "extensions/hosted_app.crx"; |
| const char kHostedAppVersion[] = "1.0.0.0"; |
| const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; |
| const char kGoodExtensionCRXPath[] = "extensions/good.crx"; |
| const char kGoodExtensionVersion[] = "1.0"; |
| const char kPackagedAppCRXPath[] = "extensions/platform_apps/app_window_2.crx"; |
| const char kShowManagedStorageID[] = "ongnjlefhnoajpbodoldndkbkdgfomlp"; |
| const char kShowManagedStorageCRXPath[] = "extensions/show_managed_storage.crx"; |
| const char kShowManagedStorageVersion[] = "1.0"; |
| |
| const char kExternalData[] = "External data"; |
| const char kExternalDataPath[] = "/external"; |
| |
| const char* const kSingleRecommendedLocale[] = { |
| "el", |
| }; |
| const char* const kRecommendedLocales1[] = { |
| "pl", |
| "et", |
| "en-US", |
| }; |
| const char* const kRecommendedLocales2[] = { |
| "fr", |
| "nl", |
| }; |
| const char* const kInvalidRecommendedLocale[] = { |
| "xx", |
| }; |
| const char kPublicSessionLocale[] = "de"; |
| const char kPublicSessionInputMethodIDTemplate[] = "_comp_ime_%sxkb:de:neo:ger"; |
| |
| const char kFakeOncWithCertificate[] = |
| "{\"Certificates\":[" |
| "{\"Type\":\"Authority\"," |
| "\"TrustBits\":[\"Web\"]," |
| "\"X509\":\"-----BEGIN CERTIFICATE-----\n" |
| "MIICVTCCAb6gAwIBAgIJAK8kOY/OQDsKMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV\n" |
| "BAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn\n" |
| "aXRzIFB0eSBMdGQwHhcNMTgxMjI3MTIyNjI0WhcNMTkxMjI3MTIyNjI0WjBCMQsw\n" |
| "CQYDVQQGEwJERTEQMA4GA1UECAwHQmF2YXJpYTEhMB8GA1UECgwYSW50ZXJuZXQg\n" |
| "V2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbFncT\n" |
| "Q8slhRgLg7sK9DhkYZaNiD1jVbdGvuXahex3uQl+2bACyQ7Peq/MkpFLy4M75nj3\n" |
| "WrydAycw1KCDPENPz2jmdHwGl5+6P7bob0Rqe+4i/9XwGdl8EPH5GFZbaz8aSYiL\n" |
| "/aaVvOm+8IYrhbp44s3cOLriPaQDbWtZMZKCiwIDAQABo1MwUTAdBgNVHQ4EFgQU\n" |
| "26bvyiqj3uQynNcZru72m3Uv3eswHwYDVR0jBBgwFoAU26bvyiqj3uQynNcZru72\n" |
| "m3Uv3eswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCHKz8NJg6f\n" |
| "qwkFmG+tOsfyn3JHj3NfkMGJugSV6Yf7LYJXHpc4kWmfGuseTtHt57PG/BzCjLs1\n" |
| "qTF8svVecDj5Qku/SbGQCf2Vg/tLnq8XidbMmp26nUXrLzNQnTm0MJYEk6PJRiod\n" |
| "BIrpuq5z+9r//9f27iXidR94qFbbvServw==\n" |
| "-----END CERTIFICATE-----\"," |
| "\"GUID\":\"{00f79111-51e0-e6e0-76b3b55450d80a1b}\"}" |
| "]}"; |
| |
| bool IsLogoutConfirmationDialogShowing() { |
| return !!ash::Shell::Get() |
| ->logout_confirmation_controller() |
| ->dialog_for_testing(); |
| } |
| |
| void CloseLogoutConfirmationDialog() { |
| // TODO(mash): Add mojo test API for this. |
| ash::LogoutConfirmationDialog* dialog = |
| ash::Shell::Get()->logout_confirmation_controller()->dialog_for_testing(); |
| ASSERT_TRUE(dialog); |
| dialog->GetWidget()->Close(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| // Helper that serves extension update manifests to Chrome. |
| class TestingUpdateManifestProvider |
| : public base::RefCountedThreadSafe<TestingUpdateManifestProvider> { |
| public: |
| // Update manifests will be served at |relative_update_url|. |
| explicit TestingUpdateManifestProvider( |
| const std::string& relative_update_url); |
| |
| // When an update manifest is requested for the given extension |id|, indicate |
| // that |version| of the extension can be downloaded at |crx_url|. |
| void AddUpdate(const std::string& id, |
| const std::string& version, |
| const GURL& crx_url); |
| |
| // This method must be registered with the test's EmbeddedTestServer to start |
| // serving update manifests. |
| std::unique_ptr<net::test_server::HttpResponse> HandleRequest( |
| const net::test_server::HttpRequest& request); |
| |
| private: |
| struct Update { |
| public: |
| Update(const std::string& version, const GURL& crx_url); |
| Update(); |
| |
| std::string version; |
| GURL crx_url; |
| }; |
| typedef std::map<std::string, Update> UpdateMap; |
| |
| TestingUpdateManifestProvider(const TestingUpdateManifestProvider&) = delete; |
| TestingUpdateManifestProvider& operator=( |
| const TestingUpdateManifestProvider&) = delete; |
| |
| ~TestingUpdateManifestProvider(); |
| friend class RefCountedThreadSafe<TestingUpdateManifestProvider>; |
| |
| // Protects other members against concurrent access from main thread and |
| // test server io thread. |
| base::Lock lock_; |
| |
| std::string relative_update_url_; |
| UpdateMap updates_; |
| }; |
| |
| TestingUpdateManifestProvider::Update::Update(const std::string& version, |
| const GURL& crx_url) |
| : version(version), crx_url(crx_url) {} |
| |
| TestingUpdateManifestProvider::Update::Update() {} |
| |
| TestingUpdateManifestProvider::TestingUpdateManifestProvider( |
| const std::string& relative_update_url) |
| : relative_update_url_(relative_update_url) {} |
| |
| void TestingUpdateManifestProvider::AddUpdate(const std::string& id, |
| const std::string& version, |
| const GURL& crx_url) { |
| base::AutoLock auto_lock(lock_); |
| updates_[id] = Update(version, crx_url); |
| } |
| |
| std::unique_ptr<net::test_server::HttpResponse> |
| TestingUpdateManifestProvider::HandleRequest( |
| const net::test_server::HttpRequest& request) { |
| base::AutoLock auto_lock(lock_); |
| const GURL url("http://localhost" + request.relative_url); |
| if (url.path() != relative_update_url_) |
| return nullptr; |
| |
| std::vector<extensions::UpdateManifestItem> update_manifest; |
| for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) { |
| if (it.GetKey() != "x") |
| continue; |
| // Extract the extension id from the subquery. Since GetValueForKeyInQuery() |
| // expects a complete URL, dummy scheme and host must be prepended. |
| std::string id; |
| net::GetValueForKeyInQuery(GURL("http://dummy?" + it.GetUnescapedValue()), |
| "id", &id); |
| UpdateMap::const_iterator entry = updates_.find(id); |
| if (entry != updates_.end()) { |
| update_manifest.emplace_back(extensions::UpdateManifestItem(id) |
| .version(entry->second.version) |
| .codebase(entry->second.crx_url.spec())); |
| } |
| } |
| |
| std::string content = |
| extensions::CreateUpdateManifest(std::move(update_manifest)); |
| |
| std::unique_ptr<net::test_server::BasicHttpResponse> http_response( |
| new net::test_server::BasicHttpResponse); |
| http_response->set_code(net::HTTP_OK); |
| http_response->set_content(content); |
| http_response->set_content_type("text/xml"); |
| return std::move(http_response); |
| } |
| |
| TestingUpdateManifestProvider::~TestingUpdateManifestProvider() {} |
| |
| bool IsSessionStarted() { |
| return session_manager::SessionManager::Get()->IsSessionStarted(); |
| } |
| |
| const base::Value* RefreshAndWaitForPolicies( |
| policy::PolicyService* policy_service, |
| const policy::PolicyNamespace& ns) { |
| PolicyChangeRegistrar policy_registrar(policy_service, ns); |
| base::test::RepeatingTestFuture<const base::Value*, const base::Value*> |
| future; |
| policy_registrar.Observe("string", future.GetCallback()); |
| policy_service->RefreshPolicies(base::OnceClosure()); |
| return std::get<1>(future.Take()); |
| } |
| |
| DeviceLocalAccountPolicyBroker* GetDeviceLocalAccountPolicyBroker( |
| AccountId account) { |
| return g_browser_process->platform_part() |
| ->browser_policy_connector_ash() |
| ->GetDeviceLocalAccountPolicyService() |
| ->GetBrokerForUser(account.GetUserEmail()); |
| } |
| |
| bool IsFullManagementDisclosureNeeded(AccountId account) { |
| auto* broker = GetDeviceLocalAccountPolicyBroker(account); |
| return ash::ChromeUserManager::Get()->IsFullManagementDisclosureNeeded( |
| broker); |
| } |
| |
| } // namespace |
| |
| class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest, |
| public user_manager::UserManager::Observer, |
| public BrowserListObserver, |
| public extensions::AppWindowRegistry::Observer { |
| public: |
| DeviceLocalAccountTest(const DeviceLocalAccountTest&) = delete; |
| DeviceLocalAccountTest& operator=(const DeviceLocalAccountTest&) = delete; |
| |
| protected: |
| static constexpr char kDisplayNameTag[] = |
| "screenplay-6fef6eb9-1132-4d67-9ff7-f7d68b34fc3c"; |
| static constexpr char kExtensionsCachedTag[] = |
| "screenplay-ac6c2f45-b38f-46b2-b107-36546701bcb2"; |
| static constexpr char kExtensionsUncachedTag[] = |
| "screenplay-0834405c-3800-4c41-b5d5-cc57c9bfd472"; |
| static constexpr char kUserAvatarImageTag[] = |
| "screenplay-91d50c4f-f526-4fad-a04d-5c9e1a90fb2b"; |
| static constexpr char kSessionLengthLimitTag[] = |
| "screenplay-a91d99d7-8ea0-4ec7-9c64-bc614a759d02"; |
| |
| DeviceLocalAccountTest() |
| : public_session_input_method_id_( |
| base::StringPrintf(kPublicSessionInputMethodIDTemplate, |
| ash::extension_ime_util::kXkbExtensionId)) { |
| set_exit_when_last_browser_closes(false); |
| } |
| |
| ~DeviceLocalAccountTest() override {} |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line); |
| command_line->AppendSwitch(ash::switches::kLoginManager); |
| command_line->AppendSwitch(ash::switches::kForceLoginManagerInTests); |
| command_line->AppendSwitchASCII(ash::switches::kLoginProfile, "user"); |
| } |
| |
| void SetUpInProcessBrowserTestFixture() override { |
| DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture(); |
| |
| // Clear command-line arguments (but keep command-line switches) so the |
| // startup pages policy takes effect. |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| base::CommandLine::StringVector argv(command_line->argv()); |
| argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(), |
| argv.end()); |
| command_line->InitFromArgv(argv); |
| |
| InitializePolicy(); |
| } |
| |
| void SetUpOnMainThread() override { |
| DevicePolicyCrosBrowserTest::SetUpOnMainThread(); |
| BrowserList::AddObserver(this); |
| |
| initial_locale_ = g_browser_process->GetApplicationLocale(); |
| initial_language_ = l10n_util::GetLanguage(initial_locale_); |
| |
| ash::LoginOrLockScreenVisibleWaiter().Wait(); |
| |
| auto* host = ash::LoginDisplayHost::default_host(); |
| ASSERT_TRUE(host->GetOobeWebContents()); |
| |
| // Wait for the login UI to be ready. |
| ash::OobeUI* oobe_ui = host->GetOobeUI(); |
| ASSERT_TRUE(oobe_ui); |
| base::RunLoop run_loop; |
| const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure()); |
| if (!oobe_ui_ready) |
| run_loop.Run(); |
| |
| // Skip to the login screen. |
| ash::OobeScreenWaiter(ash::OobeBaseTest::GetFirstSigninScreen()).Wait(); |
| |
| ash::test::UserSessionManagerTestApi session_manager_test_api( |
| ash::UserSessionManager::GetInstance()); |
| session_manager_test_api.SetShouldObtainTokenHandleInTests(false); |
| } |
| |
| void TearDownOnMainThread() override { |
| BrowserList::RemoveObserver(this); |
| DevicePolicyCrosBrowserTest::TearDownOnMainThread(); |
| } |
| |
| // user_manager::UserManager::Observer: |
| void LocalStateChanged(user_manager::UserManager* user_manager) override { |
| if (local_state_changed_run_loop_) |
| local_state_changed_run_loop_->Quit(); |
| } |
| |
| // BrowserListObserver: |
| void OnBrowserRemoved(Browser* browser) override { |
| if (run_loop_) |
| run_loop_->Quit(); |
| } |
| |
| // extensions::AppWindowRegistry::Observer: |
| void OnAppWindowAdded(extensions::AppWindow* app_window) override { |
| if (run_loop_) |
| run_loop_->Quit(); |
| } |
| |
| void OnAppWindowRemoved(extensions::AppWindow* app_window) override { |
| if (run_loop_) |
| run_loop_->Quit(); |
| } |
| |
| void InitializePolicy() { |
| device_policy()->policy_data().set_public_key_version(1); |
| DeviceLocalAccountTestHelper::SetupDeviceLocalAccount( |
| &device_local_account_policy_, kAccountId1, kDisplayName1); |
| } |
| |
| void BuildDeviceLocalAccountPolicy() { |
| device_local_account_policy_.SetDefaultSigningKey(); |
| device_local_account_policy_.Build(); |
| } |
| |
| void UploadDeviceLocalAccountPolicy() { |
| BuildDeviceLocalAccountPolicy(); |
| policy_test_server_mixin_.UpdatePolicy( |
| dm_protocol::kChromePublicAccountPolicyType, kAccountId1, |
| device_local_account_policy_.payload().SerializeAsString()); |
| } |
| |
| void UploadAndInstallDeviceLocalAccountPolicy() { |
| UploadDeviceLocalAccountPolicy(); |
| session_manager_client()->set_device_local_account_policy( |
| kAccountId1, device_local_account_policy_.GetBlob()); |
| } |
| |
| void SetRecommendedLocales(const char* const recommended_locales[], |
| size_t array_size) { |
| em::StringListPolicyProto* session_locales_proto = |
| device_local_account_policy_.payload().mutable_sessionlocales(); |
| session_locales_proto->mutable_policy_options()->set_mode( |
| em::PolicyOptions_PolicyMode_RECOMMENDED); |
| session_locales_proto->mutable_value()->Clear(); |
| for (size_t i = 0; i < array_size; ++i) { |
| session_locales_proto->mutable_value()->add_entries( |
| recommended_locales[i]); |
| } |
| } |
| |
| void WaitForPublicSessionLocalesChange(const AccountId& account_id) { |
| std::vector<ash::LocaleItem> locales = |
| ash::LoginScreenTestApi::GetPublicSessionLocales(account_id); |
| ash::test::TestPredicateWaiter( |
| base::BindRepeating( |
| [](const std::vector<ash::LocaleItem>& locales, |
| const AccountId& account_id) { |
| return locales != |
| ash::LoginScreenTestApi::GetPublicSessionLocales( |
| account_id); |
| }, |
| locales, account_id)) |
| .Wait(); |
| } |
| |
| void AddPublicSessionToDevicePolicy(const std::string& username) { |
| em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); |
| DeviceLocalAccountTestHelper::AddPublicSession(&proto, username); |
| RefreshDevicePolicy(); |
| policy_test_server_mixin_.UpdateDevicePolicy(proto); |
| } |
| |
| void EnableAutoLogin() { |
| em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); |
| em::DeviceLocalAccountsProto* device_local_accounts = |
| proto.mutable_device_local_accounts(); |
| device_local_accounts->set_auto_login_id(kAccountId1); |
| device_local_accounts->set_auto_login_delay(0); |
| RefreshDevicePolicy(); |
| policy_test_server_mixin_.UpdateDevicePolicy(proto); |
| } |
| |
| void CheckPublicSessionPresent(const AccountId& account_id) { |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id); |
| ASSERT_TRUE(user) << " account " << account_id.GetUserEmail() |
| << " not found"; |
| EXPECT_EQ(account_id, user->GetAccountId()); |
| EXPECT_EQ(user_manager::USER_TYPE_PUBLIC_ACCOUNT, user->GetType()); |
| } |
| |
| void SetSystemTimezoneAutomaticDetectionPolicy( |
| em::SystemTimezoneProto_AutomaticTimezoneDetectionType policy) { |
| em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); |
| proto.mutable_system_timezone()->set_timezone_detection_type(policy); |
| RefreshDevicePolicy(); |
| |
| LocalStateValueWaiter(prefs::kSystemTimezoneAutomaticDetectionPolicy, |
| base::Value(policy)) |
| .Wait(); |
| policy_test_server_mixin_.UpdateDevicePolicy(proto); |
| } |
| |
| base::FilePath GetExtensionCacheDirectoryForAccountID( |
| const std::string& account_id) { |
| base::FilePath extension_cache_root_dir; |
| if (!base::PathService::Get(ash::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS, |
| &extension_cache_root_dir)) { |
| ADD_FAILURE(); |
| } |
| return extension_cache_root_dir.Append( |
| base::HexEncode(account_id.c_str(), account_id.size())); |
| } |
| |
| base::FilePath GetCacheCRXFilePath(const std::string& id, |
| const std::string& version, |
| const base::FilePath& path) { |
| return path.Append( |
| extensions::LocalExtensionCache::ExtensionFileName(id, version, "")); |
| } |
| |
| base::FilePath GetCacheCRXFile(const std::string& account_id, |
| const std::string& id, |
| const std::string& version) { |
| return GetCacheCRXFilePath( |
| id, version, GetExtensionCacheDirectoryForAccountID(account_id)); |
| } |
| |
| // 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 WaitForDisplayName(const std::string& user_id, |
| const std::string& expected_display_name) { |
| DictionaryLocalStateValueWaiter("UserDisplayName", expected_display_name, |
| user_id) |
| .Wait(); |
| } |
| |
| 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. |
| WaitForDisplayName(account_id_1_.GetUserEmail(), kDisplayName1); |
| } |
| |
| void ExpandPublicSessionPod(bool expect_advanced) { |
| ASSERT_TRUE(ash::LoginScreenTestApi::ExpandPublicSessionPod(account_id_1_)); |
| ASSERT_EQ(ash::LoginScreenTestApi::IsExpandedPublicSessionAdvanced(), |
| expect_advanced); |
| // Verify that the construction of the pod's language list did not affect |
| // the current ICU locale. |
| EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); |
| } |
| |
| // GetKeyboardLayoutsForLocale() posts a task to a background task runner and |
| // handles the response on the main thread. This method flushes both the |
| // thread pool backing the background task runner and the main thread. |
| void WaitForGetKeyboardLayoutsForLocaleToFinish() { |
| content::RunAllTasksUntilIdle(); |
| |
| // Verify that the construction of the keyboard layout list did not affect |
| // the current ICU locale. |
| EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); |
| } |
| |
| void StartLogin(const std::string& locale, const std::string& input_method) { |
| // 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_1_); |
| user_context.SetPublicSessionLocale(locale); |
| user_context.SetPublicSessionInputMethod(input_method); |
| controller->Login(user_context, ash::SigninSpecifics()); |
| } |
| |
| void WaitForSessionStart() { |
| if (IsSessionStarted()) |
| return; |
| if (ash::WizardController::default_controller()) { |
| ash::WizardController::default_controller() |
| ->SkipPostLoginScreensForTesting(); |
| } |
| ash::test::WaitForPrimaryUserSessionStart(); |
| } |
| |
| void WaitUntilLocalStateChanged() { |
| local_state_changed_run_loop_ = std::make_unique<base::RunLoop>(); |
| user_manager::UserManager::Get()->AddObserver(this); |
| local_state_changed_run_loop_->Run(); |
| user_manager::UserManager::Get()->RemoveObserver(this); |
| } |
| |
| static std::string GetDefaultKeyboardIdFromLanguageCode( |
| const std::string& language_code) { |
| auto* input_method_manager = ash::input_method::InputMethodManager::Get(); |
| std::vector<std::string> layouts_from_locale; |
| input_method_manager->GetInputMethodUtil() |
| ->GetInputMethodIdsFromLanguageCode( |
| language_code, ash::input_method::kKeyboardLayoutsOnly, |
| &layouts_from_locale); |
| EXPECT_FALSE(layouts_from_locale.empty()); |
| if (layouts_from_locale.empty()) |
| return std::string(); |
| return layouts_from_locale.front(); |
| } |
| void VerifyKeyboardLayoutMatchesLocale() { |
| auto* input_method_manager = ash::input_method::InputMethodManager::Get(); |
| EXPECT_EQ(GetDefaultKeyboardIdFromLanguageCode( |
| g_browser_process->GetApplicationLocale()), |
| input_method_manager->GetActiveIMEState() |
| ->GetCurrentInputMethod() |
| .id()); |
| } |
| |
| void RunWithRecommendedLocale(const char* const locales[], |
| size_t locales_size) { |
| SetRecommendedLocales(locales, locales_size); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| EnableAutoLogin(); |
| |
| WaitForPolicy(); |
| |
| WaitForSessionStart(); |
| |
| EXPECT_EQ(locales[0], g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(locales[0]), |
| icu::Locale::getDefault().getLanguage()); |
| VerifyKeyboardLayoutMatchesLocale(); |
| } |
| |
| void SetSessionLengthLimitPolicy(int limit) { |
| device_local_account_policy_.payload() |
| .mutable_sessionlengthlimit() |
| ->set_value(limit); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| } |
| |
| const AccountId account_id_1_ = |
| AccountId::FromUserEmail(GenerateDeviceLocalAccountUserId( |
| kAccountId1, |
| DeviceLocalAccount::TYPE_PUBLIC_SESSION)); |
| const AccountId account_id_2_ = |
| AccountId::FromUserEmail(GenerateDeviceLocalAccountUserId( |
| kAccountId2, |
| DeviceLocalAccount::TYPE_PUBLIC_SESSION)); |
| const std::string public_session_input_method_id_; |
| |
| std::string initial_locale_; |
| std::string initial_language_; |
| |
| std::unique_ptr<base::RunLoop> run_loop_; |
| |
| // Specifically exists to assist with waiting for a LocalStateChanged() |
| // invocation. |
| std::unique_ptr<base::RunLoop> local_state_changed_run_loop_; |
| |
| UserPolicyBuilder device_local_account_policy_; |
| ash::EmbeddedPolicyTestServerMixin policy_test_server_mixin_{&mixin_host_}; |
| |
| // These are member variables so they're guaranteed that the destructors |
| // (which may delete a directory) run in a scope where file IO is allowed. |
| base::ScopedTempDir temp_dir_; |
| base::ScopedTempDir cache_dir_; |
| |
| private: |
| extensions::SandboxedUnpacker::ScopedVerifierFormatOverrideForTest |
| verifier_format_override_{crx_file::VerifierFormat::CRX3}; |
| }; |
| |
| static bool IsKnownUser(const AccountId& account_id) { |
| return user_manager::UserManager::Get()->IsKnownUser(account_id); |
| } |
| |
| // Helper that listen extension installation when new profile is created. |
| class ExtensionInstallObserver : public ProfileManagerObserver, |
| public extensions::ExtensionRegistryObserver { |
| public: |
| explicit ExtensionInstallObserver(const std::string& extension_id) |
| : registry_(nullptr), |
| waiting_extension_id_(extension_id), |
| observed_(false) { |
| profile_manager_observer_.Observe(g_browser_process->profile_manager()); |
| } |
| |
| ExtensionInstallObserver(const ExtensionInstallObserver&) = delete; |
| ExtensionInstallObserver& operator=(const ExtensionInstallObserver&) = delete; |
| |
| ~ExtensionInstallObserver() override { |
| if (registry_ != nullptr) |
| registry_->RemoveObserver(this); |
| } |
| |
| // Wait until an extension with |extension_id| is installed. |
| void Wait() { |
| if (!observed_) |
| run_loop_.Run(); |
| } |
| |
| private: |
| // extensions::ExtensionRegistryObserver: |
| void OnExtensionWillBeInstalled(content::BrowserContext* browser_context, |
| const extensions::Extension* extension, |
| bool is_update, |
| const std::string& old_name) override { |
| if (waiting_extension_id_ == extension->id()) { |
| observed_ = true; |
| run_loop_.Quit(); |
| } |
| } |
| |
| // ProfileManagerObserver: |
| void OnProfileAdded(Profile* profile) override { |
| // Ignore lock screen apps profile. |
| if (ash::ProfileHelper::IsLockScreenAppProfile(profile)) |
| return; |
| registry_ = extensions::ExtensionRegistry::Get(profile); |
| profile_manager_observer_.Reset(); |
| |
| // Check if extension is already installed with newly created profile. |
| if (registry_->GetInstalledExtension(waiting_extension_id_)) { |
| observed_ = true; |
| run_loop_.Quit(); |
| return; |
| } |
| |
| // Start listening for extension installation. |
| registry_->AddObserver(this); |
| } |
| |
| raw_ptr<extensions::ExtensionRegistry, ExperimentalAsh> registry_; |
| base::RunLoop run_loop_; |
| base::ScopedObservation<ProfileManager, ProfileManagerObserver> |
| profile_manager_observer_{this}; |
| std::string waiting_extension_id_; |
| bool observed_; |
| }; |
| |
| // Fake implementation to advance the clock for SessionLengthLimiter. |
| class FakeDelegateImpl : public ash::SessionLengthLimiter::Delegate { |
| public: |
| FakeDelegateImpl() { clock_.SetNow(base::Time::Now()); } |
| |
| FakeDelegateImpl(const FakeDelegateImpl&) = delete; |
| FakeDelegateImpl& operator=(const FakeDelegateImpl&) = delete; |
| |
| ~FakeDelegateImpl() override {} |
| |
| const base::Clock* GetClock() const override { return &clock_; } |
| void StopSession() override { |
| chrome::AttemptUserExit(); |
| session_stopped_ = true; |
| } |
| |
| void AdvanceClock(base::TimeDelta delta) { clock_.Advance(delta); } |
| bool session_stopped() const { return session_stopped_; } |
| |
| private: |
| base::SimpleTestClock clock_; |
| bool session_stopped_ = false; |
| }; |
| |
| // Tests that the data associated with a device local account is removed when |
| // that local account is no longer part of policy. |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PRE_DataIsRemoved) { |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitUntilLocalStateChanged(); |
| |
| EXPECT_TRUE(IsKnownUser(account_id_1_)); |
| CheckPublicSessionPresent(account_id_1_); |
| |
| // Data for the account is normally added after successful authentication. |
| // Shortcut that here. |
| ScopedDictPrefUpdate given_name_update(g_browser_process->local_state(), |
| "UserGivenName"); |
| given_name_update->Set(account_id_1_.GetUserEmail(), "Elaine"); |
| |
| // Add some arbitrary data to make sure the "UserGivenName" dictionary isn't |
| // cleaning up itself. |
| given_name_update->Set("sanity.check@example.com", "Anne"); |
| } |
| |
| // Disabled on ASan and LSAn builds due to a consistent failure. See |
| // crbug.com/1004228 |
| #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) |
| #define MAYBE_DataIsRemoved DISABLED_DataIsRemoved |
| #else |
| #define MAYBE_DataIsRemoved DataIsRemoved |
| #endif |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MAYBE_DataIsRemoved) { |
| // The device local account should have been removed. |
| EXPECT_FALSE(g_browser_process->local_state() |
| ->GetDict("UserGivenName") |
| .Find(account_id_1_.GetUserEmail())); |
| |
| // The arbitrary data remains. |
| const std::string* value = g_browser_process->local_state() |
| ->GetDict("UserGivenName") |
| .FindString("sanity.check@example.com"); |
| ASSERT_TRUE(value); |
| EXPECT_EQ("Anne", *value); |
| } |
| |
| // Test is flaky: https://crbug.com/1334470 |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DISABLED_LoginScreen) { |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| AddPublicSessionToDevicePolicy(kAccountId2); |
| |
| WaitUntilLocalStateChanged(); |
| EXPECT_TRUE(IsKnownUser(account_id_1_)); |
| EXPECT_TRUE(IsKnownUser(account_id_2_)); |
| |
| CheckPublicSessionPresent(account_id_1_); |
| CheckPublicSessionPresent(account_id_2_); |
| |
| ASSERT_TRUE(user_manager::UserManager::Get()->FindUser(account_id_1_)); |
| EXPECT_TRUE(user_manager::UserManager::Get() |
| ->FindUser(account_id_1_) |
| ->IsAffiliated()); |
| |
| ASSERT_TRUE(user_manager::UserManager::Get()->FindUser(account_id_2_)); |
| EXPECT_TRUE(user_manager::UserManager::Get() |
| ->FindUser(account_id_2_) |
| ->IsAffiliated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) { |
| base::AddFeatureIdTagToTestResult(DeviceLocalAccountTest::kDisplayNameTag); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| // Verify that the display name is shown in the UI. |
| std::string display_name = |
| ash::LoginScreenTestApi::GetDisplayedName(account_id_1_); |
| EXPECT_EQ(kDisplayName1, display_name); |
| // Click on the pod to expand it. |
| ASSERT_TRUE(ash::LoginScreenTestApi::ExpandPublicSessionPod(account_id_1_)); |
| // Change the display name. |
| device_local_account_policy_.payload().mutable_userdisplayname()->set_value( |
| kDisplayName2); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| DeviceLocalAccountPolicyBroker* broker = |
| GetDeviceLocalAccountPolicyBroker(account_id_1_); |
| ASSERT_TRUE(broker); |
| broker->core()->client()->FetchPolicy(); |
| WaitForDisplayName(account_id_1_.GetUserEmail(), kDisplayName2); |
| |
| // Verify that the new display name is shown in the UI. |
| display_name = ash::LoginScreenTestApi::GetDisplayedName(account_id_1_); |
| EXPECT_EQ(kDisplayName2, display_name); |
| // Verify that the pod is still expanded. This indicates that the UI updated |
| // without reloading and losing state. |
| EXPECT_TRUE(ash::LoginScreenTestApi::IsPublicSessionExpanded()); |
| } |
| |
| // Tests that display name is saved in kUserDisplayName pref in local state. |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, CachedDisplayName) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForDisplayName(account_id_1_.GetUserEmail(), kDisplayName1); |
| const auto& dict = |
| g_browser_process->local_state()->GetDict(key::kUserDisplayName); |
| ASSERT_TRUE(dict.Find(account_id_1_.GetUserEmail()) != nullptr); |
| EXPECT_EQ(kDisplayName1, *dict.FindString(account_id_1_.GetUserEmail())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) { |
| UploadDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| // Sanity check: The policy should be present now. |
| ASSERT_FALSE(session_manager_client() |
| ->device_local_account_policy(kAccountId1) |
| .empty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, AccountListChange) { |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| AddPublicSessionToDevicePolicy(kAccountId2); |
| |
| WaitUntilLocalStateChanged(); |
| EXPECT_TRUE(IsKnownUser(account_id_1_)); |
| EXPECT_TRUE(IsKnownUser(account_id_2_)); |
| |
| // Update policy to remove kAccountId2. |
| em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); |
| proto.mutable_device_local_accounts()->clear_account(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| em::ChromeDeviceSettingsProto policy; |
| policy.mutable_show_user_names()->set_show_user_names(true); |
| em::DeviceLocalAccountInfoProto* account1 = |
| policy.mutable_device_local_accounts()->add_account(); |
| account1->set_account_id(kAccountId1); |
| account1->set_type( |
| em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); |
| |
| policy_test_server_mixin_.UpdateDevicePolicy(policy); |
| g_browser_process->policy_service()->RefreshPolicies(base::OnceClosure()); |
| |
| // Make sure the second device-local account disappears. |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_FALSE(IsKnownUser(account_id_2_)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) { |
| // Specify startup pages. |
| device_local_account_policy_.payload().mutable_restoreonstartup()->set_value( |
| SessionStartupPref::kPrefValueURLs); |
| em::StringListPolicyProto* startup_urls_proto = |
| device_local_account_policy_.payload().mutable_restoreonstartupurls(); |
| for (size_t i = 0; i < std::size(kStartupURLs); ++i) |
| startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| // Check that the startup pages specified in policy were opened. |
| BrowserList* browser_list = BrowserList::GetInstance(); |
| EXPECT_EQ(1U, browser_list->size()); |
| Browser* browser = browser_list->get(0); |
| ASSERT_TRUE(browser); |
| |
| TabStripModel* tabs = browser->tab_strip_model(); |
| ASSERT_TRUE(tabs); |
| int expected_tab_count = static_cast<int>(std::size(kStartupURLs)); |
| EXPECT_EQ(expected_tab_count, tabs->count()); |
| for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) { |
| EXPECT_EQ(GURL(kStartupURLs[i]), |
| tabs->GetWebContentsAt(i)->GetVisibleURL()); |
| } |
| |
| // Verify that the session is not considered to be logged in with a GAIA |
| // account. |
| Profile* profile = GetProfileForTest(); |
| ASSERT_TRUE(profile); |
| EXPECT_FALSE( |
| IdentityManagerFactory::GetForProfile(profile)->HasPrimaryAccount( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenAllowed) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| BrowserList* browser_list = BrowserList::GetInstance(); |
| EXPECT_EQ(1U, browser_list->size()); |
| Browser* browser = browser_list->get(0); |
| ASSERT_TRUE(browser); |
| BrowserWindow* browser_window = browser->window(); |
| ASSERT_TRUE(browser_window); |
| |
| // Verify that an attempt to enter fullscreen mode is allowed. |
| EXPECT_FALSE(browser_window->IsFullscreen()); |
| chrome::ToggleFullscreenMode(browser); |
| EXPECT_TRUE(browser_window->IsFullscreen()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsUncached) { |
| base::AddFeatureIdTagToTestResult( |
| DeviceLocalAccountTest::kExtensionsUncachedTag); |
| |
| // Make it possible to force-install a hosted app and an extension. |
| ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| scoped_refptr<TestingUpdateManifestProvider> testing_update_manifest_provider( |
| new TestingUpdateManifestProvider(kRelativeUpdateURL)); |
| testing_update_manifest_provider->AddUpdate( |
| kHostedAppID, kHostedAppVersion, |
| embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath)); |
| testing_update_manifest_provider->AddUpdate( |
| kGoodExtensionID, kGoodExtensionVersion, |
| embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath)); |
| embedded_test_server()->RegisterRequestHandler( |
| base::BindRepeating(&TestingUpdateManifestProvider::HandleRequest, |
| testing_update_manifest_provider)); |
| embedded_test_server()->StartAcceptingConnections(); |
| |
| // Specify policy to force-install the hosted app and the extension. |
| em::StringList* forcelist = device_local_account_policy_.payload() |
| .mutable_extensioninstallforcelist() |
| ->mutable_value(); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", kHostedAppID, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", kGoodExtensionID, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| // Start listening for app/extension installation results. |
| ExtensionInstallObserver hosted_app_install_observer(kHostedAppID); |
| ExtensionInstallObserver extension_install_observer(kGoodExtensionID); |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| |
| // Wait for the hosted app & extension installations to succeed. |
| hosted_app_install_observer.Wait(); |
| extension_install_observer.Wait(); |
| |
| // Verify that the hosted app & extension were installed. |
| Profile* profile = GetProfileForTest(); |
| ASSERT_TRUE(profile); |
| extensions::ExtensionRegistry* extension_registry = |
| extensions::ExtensionRegistry::Get(profile); |
| EXPECT_TRUE(extension_registry->enabled_extensions().GetByID(kHostedAppID)); |
| EXPECT_TRUE( |
| extension_registry->enabled_extensions().GetByID(kGoodExtensionID)); |
| |
| // Verify that the hosted app & extension were downloaded to the account's |
| // extension cache. |
| base::FilePath test_dir; |
| ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| EXPECT_TRUE(ContentsEqual( |
| GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion), |
| test_dir.Append(kHostedAppCRXPath))); |
| EXPECT_TRUE(ContentsEqual( |
| GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion), |
| test_dir.Append(kGoodExtensionCRXPath))); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsCached) { |
| base::AddFeatureIdTagToTestResult( |
| DeviceLocalAccountTest::kExtensionsCachedTag); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Pre-populate the device local account's extension cache with a hosted app |
| // and an extension. |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE(base::CreateDirectory( |
| GetExtensionCacheDirectoryForAccountID(kAccountId1))); |
| } |
| base::FilePath test_dir; |
| ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| const base::FilePath cached_hosted_app = |
| GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion); |
| const base::FilePath cached_extension = |
| GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion); |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE( |
| CopyFile(test_dir.Append(kHostedAppCRXPath), cached_hosted_app)); |
| EXPECT_TRUE( |
| CopyFile(test_dir.Append(kGoodExtensionCRXPath), cached_extension)); |
| } |
| |
| // Specify policy to force-install the hosted app & the extension. |
| em::StringList* forcelist = device_local_account_policy_.payload() |
| .mutable_extensioninstallforcelist() |
| ->mutable_value(); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", kHostedAppID, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", kGoodExtensionID, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| // Start listening for app/extension installation results. |
| ExtensionInstallObserver hosted_app_install_observer(kHostedAppID); |
| ExtensionInstallObserver extension_install_observer(kGoodExtensionID); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| |
| // Wait for the hosted app & extension installations to succeed. |
| hosted_app_install_observer.Wait(); |
| extension_install_observer.Wait(); |
| |
| // Verify that the hosted app & extension were installed. |
| Profile* profile = GetProfileForTest(); |
| ASSERT_TRUE(profile); |
| extensions::ExtensionRegistry* extension_registry = |
| extensions::ExtensionRegistry::Get(profile); |
| EXPECT_TRUE(extension_registry->enabled_extensions().GetByID(kHostedAppID)); |
| EXPECT_TRUE( |
| extension_registry->enabled_extensions().GetByID(kGoodExtensionID)); |
| |
| // Verify that the hosted app is still in the account's extension cache. |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE(PathExists(cached_hosted_app)); |
| } |
| |
| // Verify that the extension is still in the account's extension cache. |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE(PathExists(cached_extension)); |
| } |
| } |
| |
| static void OnPutExtension(std::unique_ptr<base::RunLoop>* run_loop, |
| const base::FilePath& file_path, |
| bool file_ownership_passed) { |
| ASSERT_TRUE(*run_loop); |
| (*run_loop)->Quit(); |
| } |
| |
| static void OnExtensionCacheImplInitialized( |
| std::unique_ptr<base::RunLoop>* run_loop) { |
| ASSERT_TRUE(*run_loop); |
| (*run_loop)->Quit(); |
| } |
| |
| static void CreateFile(const base::FilePath& file, |
| size_t size, |
| const base::Time& timestamp) { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| std::string data(size, 0); |
| EXPECT_TRUE(base::WriteFile(file, data)); |
| EXPECT_TRUE(base::TouchFile(file, timestamp, timestamp)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionCacheImplTest) { |
| // Make it possible to force-install a hosted app and an extension. |
| ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| scoped_refptr<TestingUpdateManifestProvider> testing_update_manifest_provider( |
| new TestingUpdateManifestProvider(kRelativeUpdateURL)); |
| testing_update_manifest_provider->AddUpdate( |
| kHostedAppID, kHostedAppVersion, |
| embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath)); |
| testing_update_manifest_provider->AddUpdate( |
| kGoodExtensionID, kGoodExtensionVersion, |
| embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath)); |
| embedded_test_server()->RegisterRequestHandler( |
| base::BindRepeating(&TestingUpdateManifestProvider::HandleRequest, |
| testing_update_manifest_provider)); |
| embedded_test_server()->StartAcceptingConnections(); |
| // Create and initialize local cache. |
| base::FilePath impl_path; |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE(cache_dir_.CreateUniqueTempDir()); |
| impl_path = cache_dir_.GetPath(); |
| EXPECT_TRUE(base::CreateDirectory(impl_path)); |
| } |
| CreateFile(impl_path.Append( |
| extensions::LocalExtensionCache::kCacheReadyFlagFileName), |
| 0, base::Time::Now()); |
| extensions::ExtensionCacheImpl cache_impl( |
| std::make_unique<extensions::ChromeOSExtensionCacheDelegate>(impl_path)); |
| auto run_loop = std::make_unique<base::RunLoop>(); |
| cache_impl.Start(base::BindOnce(&OnExtensionCacheImplInitialized, &run_loop)); |
| run_loop->Run(); |
| |
| // Put extension in the local cache. |
| base::FilePath temp_path; |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| temp_path = temp_dir_.GetPath(); |
| EXPECT_TRUE(base::CreateDirectory(temp_path)); |
| } |
| const base::FilePath temp_file = |
| GetCacheCRXFilePath(kGoodExtensionID, kGoodExtensionVersion, temp_path); |
| base::FilePath test_dir; |
| std::string hash; |
| ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE(CopyFile(test_dir.Append(kGoodExtensionCRXPath), temp_file)); |
| } |
| cache_impl.AllowCaching(kGoodExtensionID); |
| run_loop = std::make_unique<base::RunLoop>(); |
| cache_impl.PutExtension(kGoodExtensionID, hash, temp_file, |
| kGoodExtensionVersion, |
| base::BindOnce(&OnPutExtension, &run_loop)); |
| run_loop->Run(); |
| |
| // Verify that the extension file was added to the local cache. |
| const base::FilePath local_file = |
| GetCacheCRXFilePath(kGoodExtensionID, kGoodExtensionVersion, impl_path); |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| EXPECT_TRUE(PathExists(local_file)); |
| } |
| |
| // Specify policy to force-install the hosted app and the extension. |
| em::StringList* forcelist = device_local_account_policy_.payload() |
| .mutable_extensioninstallforcelist() |
| ->mutable_value(); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", kHostedAppID, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", kGoodExtensionID, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| // Start listening for app/extension installation results. |
| ExtensionInstallObserver hosted_app_install_observer(kHostedAppID); |
| ExtensionInstallObserver extension_install_observer(kGoodExtensionID); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| |
| // Wait for the hosted app & extension installations to succeed. |
| hosted_app_install_observer.Wait(); |
| extension_install_observer.Wait(); |
| |
| // Verify that the extension was kept in the local cache. |
| EXPECT_TRUE( |
| cache_impl.GetExtension(kGoodExtensionID, hash, nullptr, nullptr)); |
| |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| // Verify that the extension file was kept in the local cache. |
| EXPECT_TRUE(PathExists(local_file)); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExternalData) { |
| // user_manager::UserManager requests an external data fetch whenever |
| // the key::kUserAvatarImage policy is set. Since this test wants to |
| // verify that the underlying policy subsystem will start a fetch |
| // without this request as well, the user_manager::UserManager must be |
| // prevented from seeing the policy change. |
| static_cast<ash::ChromeUserManagerImpl*>(user_manager::UserManager::Get()) |
| ->StopPolicyObserverForTesting(); |
| |
| UploadDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| // Start serving external data. |
| std::unique_ptr<base::RunLoop> run_loop(new base::RunLoop); |
| EXPECT_TRUE(embedded_test_server()->InitializeAndListen()); |
| embedded_test_server()->RegisterRequestHandler(base::BindRepeating( |
| [](const base::RepeatingClosure& quit_closure, |
| const net::test_server::HttpRequest& request) |
| -> std::unique_ptr<net::test_server::HttpResponse> { |
| if (request.relative_url != kExternalDataPath) |
| return nullptr; |
| |
| auto response = std::make_unique<net::test_server::BasicHttpResponse>(); |
| response->set_content(kExternalData); |
| |
| quit_closure.Run(); |
| return response; |
| }, |
| run_loop->QuitClosure())); |
| embedded_test_server()->StartAcceptingConnections(); |
| |
| // Specify an external data reference for the key::kUserAvatarImage policy. |
| base::Value::Dict metadata = test::ConstructExternalDataReference( |
| embedded_test_server()->GetURL(kExternalDataPath).spec(), kExternalData); |
| std::string policy; |
| base::JSONWriter::Write(metadata, &policy); |
| device_local_account_policy_.payload().mutable_useravatarimage()->set_value( |
| policy); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| DeviceLocalAccountPolicyBroker* broker = |
| GetDeviceLocalAccountPolicyBroker(account_id_1_); |
| ASSERT_TRUE(broker); |
| broker->core()->store()->Load(); |
| |
| // The external data should be fetched and cached automatically. Wait for this |
| // fetch. |
| run_loop->Run(); |
| |
| // Stop serving external data. |
| EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); |
| |
| const PolicyMap::Entry* policy_entry = |
| broker->core()->store()->policy_map().Get(key::kUserAvatarImage); |
| ASSERT_TRUE(policy_entry); |
| ASSERT_TRUE(policy_entry->external_data_fetcher); |
| |
| // Retrieve the external data. Although the data is no longer being served, |
| // the retrieval should succeed because the data has been cached. |
| { |
| base::test::TestFuture<std::unique_ptr<std::string>, const base::FilePath&> |
| fetch_data_future; |
| policy_entry->external_data_fetcher->Fetch(fetch_data_future.GetCallback()); |
| ASSERT_TRUE(fetch_data_future.Get<std::unique_ptr<std::string>>()); |
| EXPECT_EQ(kExternalData, |
| *fetch_data_future.Get<std::unique_ptr<std::string>>()); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| // Verify that the external data reference has propagated to the device-local |
| // account's ProfilePolicyConnector. |
| ProfilePolicyConnector* policy_connector = |
| GetProfileForTest()->GetProfilePolicyConnector(); |
| ASSERT_TRUE(policy_connector); |
| const PolicyMap& policies = policy_connector->policy_service()->GetPolicies( |
| PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); |
| policy_entry = policies.Get(key::kUserAvatarImage); |
| ASSERT_TRUE(policy_entry); |
| ASSERT_TRUE(policy_entry->value(base::Value::Type::DICT)); |
| EXPECT_EQ(metadata, policy_entry->value(base::Value::Type::DICT)->GetDict()); |
| ASSERT_TRUE(policy_entry->external_data_fetcher); |
| |
| // Retrieve the external data via the ProfilePolicyConnector. The retrieval |
| // should succeed because the data has been cached. |
| { |
| base::test::TestFuture<std::unique_ptr<std::string>, const base::FilePath&> |
| fetch_data_future; |
| policy_entry->external_data_fetcher->Fetch(fetch_data_future.GetCallback()); |
| ASSERT_TRUE(fetch_data_future.Get<std::unique_ptr<std::string>>()); |
| EXPECT_EQ(kExternalData, |
| *fetch_data_future.Get<std::unique_ptr<std::string>>()); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, UserAvatarImage) { |
| base::AddFeatureIdTagToTestResult( |
| DeviceLocalAccountTest::kUserAvatarImageTag); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| UploadDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| base::FilePath test_dir; |
| ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| std::string image_data; |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| ASSERT_TRUE(base::ReadFileToString( |
| test_dir.Append(ash::test::kUserAvatarImage1RelativePath), |
| &image_data)); |
| } |
| |
| std::string policy; |
| base::JSONWriter::Write( |
| test::ConstructExternalDataReference( |
| embedded_test_server() |
| ->GetURL(std::string("/") + |
| ash::test::kUserAvatarImage1RelativePath) |
| .spec(), |
| image_data), |
| &policy); |
| device_local_account_policy_.payload().mutable_useravatarimage()->set_value( |
| policy); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| DeviceLocalAccountPolicyBroker* broker = |
| GetDeviceLocalAccountPolicyBroker(account_id_1_); |
| ASSERT_TRUE(broker); |
| |
| broker->core()->store()->Load(); |
| WaitUntilLocalStateChanged(); |
| |
| gfx::ImageSkia policy_image = |
| ash::test::ImageLoader( |
| test_dir.Append(ash::test::kUserAvatarImage1RelativePath)) |
| .Load(); |
| ASSERT_FALSE(policy_image.isNull()); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| |
| base::FilePath user_data_dir; |
| ASSERT_TRUE(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)); |
| const base::FilePath saved_image_path = |
| user_data_dir.Append(account_id_1_.GetUserEmail()).AddExtension("jpg"); |
| |
| EXPECT_FALSE(user->HasDefaultImage()); |
| EXPECT_EQ(user_manager::User::USER_IMAGE_EXTERNAL, user->image_index()); |
| EXPECT_TRUE(ash::test::AreImagesEqual(policy_image, user->GetImage())); |
| const base::Value::Dict& images_pref = |
| g_browser_process->local_state()->GetDict("user_image_info"); |
| const base::Value::Dict* image_properties = |
| images_pref.FindDict(account_id_1_.GetUserEmail()); |
| ASSERT_TRUE(image_properties); |
| absl::optional<int> image_index = image_properties->FindInt("index"); |
| const std::string* image_path = image_properties->FindString("path"); |
| ASSERT_TRUE(image_index.has_value()); |
| ASSERT_TRUE(image_path); |
| EXPECT_EQ(user_manager::User::USER_IMAGE_EXTERNAL, image_index.value()); |
| EXPECT_EQ(saved_image_path.value(), *image_path); |
| |
| gfx::ImageSkia saved_image = ash::test::ImageLoader(saved_image_path).Load(); |
| ASSERT_FALSE(saved_image.isNull()); |
| |
| // Check image dimensions. Images can't be compared since JPEG is lossy. |
| EXPECT_EQ(policy_image.width(), saved_image.width()); |
| EXPECT_EQ(policy_image.height(), saved_image.height()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LastWindowClosedLogoutReminder) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| Profile* profile = GetProfileForTest(); |
| ASSERT_TRUE(profile); |
| extensions::AppWindowRegistry* app_window_registry = |
| extensions::AppWindowRegistry::Get(profile); |
| app_window_registry->AddObserver(this); |
| |
| // Verify that the logout confirmation dialog is not showing. |
| EXPECT_FALSE(IsLogoutConfirmationDialogShowing()); |
| |
| // Remove policy that allows only explicitly allowlisted apps to be installed |
| // in a public session. |
| extensions::ExtensionSystem* extension_system = |
| extensions::ExtensionSystem::Get(profile); |
| ASSERT_TRUE(extension_system); |
| extension_system->management_policy()->UnregisterAllProviders(); |
| |
| // Install and a platform app. |
| scoped_refptr<extensions::CrxInstaller> installer = |
| extensions::CrxInstaller::CreateSilent( |
| extension_system->extension_service()); |
| installer->set_allow_silent_install(true); |
| installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD); |
| installer->set_creation_flags(extensions::Extension::FROM_WEBSTORE); |
| |
| { |
| TestFuture<const absl::optional<CrxInstallError>&> installer_done_future; |
| installer->AddInstallerCallback(installer_done_future.GetCallback()); |
| |
| base::FilePath test_dir; |
| ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| installer->InstallCrx(test_dir.Append(kPackagedAppCRXPath)); |
| |
| const absl::optional<CrxInstallError>& error = installer_done_future.Get(); |
| EXPECT_THAT(error, testing::Eq(absl::nullopt)); |
| } |
| |
| const extensions::Extension* app = installer->extension(); |
| |
| // Start the platform app, causing it to open a window. |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile); |
| proxy->Launch(app->id(), |
| apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW, |
| false /* preferred_containner */), |
| apps::LaunchSource::kFromChromeInternal, |
| std::make_unique<apps::WindowInfo>( |
| display::Screen::GetScreen()->GetPrimaryDisplay().id())); |
| run_loop_->Run(); |
| EXPECT_EQ(1U, app_window_registry->app_windows().size()); |
| |
| // Close the only open browser window. |
| BrowserList* browser_list = BrowserList::GetInstance(); |
| EXPECT_EQ(1U, browser_list->size()); |
| Browser* browser = browser_list->get(0); |
| ASSERT_TRUE(browser); |
| BrowserWindow* browser_window = browser->window(); |
| ASSERT_TRUE(browser_window); |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| browser_window->Close(); |
| browser_window = nullptr; |
| run_loop_->Run(); |
| browser = nullptr; |
| EXPECT_TRUE(browser_list->empty()); |
| |
| // Verify that the logout confirmation dialog is not showing because an app |
| // window is still open. |
| EXPECT_FALSE(IsLogoutConfirmationDialogShowing()); |
| |
| // Open a browser window. |
| Browser* first_browser = CreateBrowser(profile); |
| EXPECT_EQ(1U, browser_list->size()); |
| |
| // Close the app window. |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| ASSERT_EQ(1U, app_window_registry->app_windows().size()); |
| app_window_registry->app_windows().front()->GetBaseWindow()->Close(); |
| run_loop_->Run(); |
| EXPECT_TRUE(app_window_registry->app_windows().empty()); |
| |
| // Verify that the logout confirmation dialog is not showing because a browser |
| // window is still open. |
| EXPECT_FALSE(IsLogoutConfirmationDialogShowing()); |
| |
| // Open a second browser window. |
| Browser* second_browser = CreateBrowser(profile); |
| EXPECT_EQ(2U, browser_list->size()); |
| |
| // Close the first browser window. |
| browser_window = first_browser->window(); |
| ASSERT_TRUE(browser_window); |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| browser_window->Close(); |
| browser_window = nullptr; |
| run_loop_->Run(); |
| first_browser = nullptr; |
| EXPECT_EQ(1U, browser_list->size()); |
| |
| // Verify that the logout confirmation dialog is not showing because a browser |
| // window is still open. |
| EXPECT_FALSE(IsLogoutConfirmationDialogShowing()); |
| |
| // Close the second browser window. |
| browser_window = second_browser->window(); |
| ASSERT_TRUE(browser_window); |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| browser_window->Close(); |
| browser_window = nullptr; |
| run_loop_->Run(); |
| second_browser = nullptr; |
| EXPECT_TRUE(browser_list->empty()); |
| |
| // Verify that the logout confirmation dialog is showing. |
| EXPECT_TRUE(IsLogoutConfirmationDialogShowing()); |
| |
| // Deny the logout. |
| ASSERT_NO_FATAL_FAILURE(CloseLogoutConfirmationDialog()); |
| |
| // Verify that the logout confirmation dialog is no longer showing. |
| EXPECT_FALSE(IsLogoutConfirmationDialogShowing()); |
| |
| // Open a browser window. |
| browser = CreateBrowser(profile); |
| EXPECT_EQ(1U, browser_list->size()); |
| |
| // Close the browser window. |
| browser_window = browser->window(); |
| ASSERT_TRUE(browser_window); |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| browser_window->Close(); |
| browser_window = nullptr; |
| run_loop_->Run(); |
| browser = nullptr; |
| EXPECT_TRUE(browser_list->empty()); |
| |
| // Verify that the logout confirmation dialog is showing again. |
| EXPECT_TRUE(IsLogoutConfirmationDialogShowing()); |
| |
| // Deny the logout. |
| ASSERT_NO_FATAL_FAILURE(CloseLogoutConfirmationDialog()); |
| |
| app_window_registry->RemoveObserver(this); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleNoSwitch) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ExpandPublicSessionPod(false); |
| |
| // Click the enter button to start the session. |
| ash::LoginScreenTestApi::ClickPublicExpandedSubmitButton(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the locale has not changed and the first keyboard layout |
| // applicable to the locale was chosen. |
| EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); |
| VerifyKeyboardLayoutMatchesLocale(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleSwitch) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ExpandPublicSessionPod(false); |
| |
| // Click the link that switches the pod to its advanced form. Verify that the |
| // pod switches from basic to advanced. |
| ash::LoginScreenTestApi::ClickPublicExpandedAdvancedViewButton(); |
| ASSERT_TRUE(ash::LoginScreenTestApi::IsExpandedPublicSessionAdvanced()); |
| ash::LoginScreenTestApi::SetPublicSessionLocale(kPublicSessionLocale); |
| // The UI will have requested an updated list of keyboard layouts at this |
| // point. Wait for the constructions of this list to finish. |
| WaitForGetKeyboardLayoutsForLocaleToFinish(); |
| |
| // Manually select a different keyboard layout. |
| ash::LoginScreenTestApi::SetPublicSessionKeyboard( |
| public_session_input_method_id_); |
| |
| ash::LoginScreenTestApi::ClickPublicExpandedSubmitButton(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the locale and keyboard layout have been applied. |
| EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), |
| icu::Locale::getDefault().getLanguage()); |
| EXPECT_EQ(public_session_input_method_id_, |
| ash::input_method::InputMethodManager::Get() |
| ->GetActiveIMEState() |
| ->GetCurrentInputMethod() |
| .id()); |
| } |
| |
| // Tests whether or not managed guest session users can change the system |
| // timezone, which should be possible iff the timezone automatic detection |
| // policy is set to either DISABLED or USERS_DECIDE. |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ManagedSessionTimezoneChange) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| EnableAutoLogin(); |
| |
| WaitForPolicy(); |
| |
| WaitForSessionStart(); |
| |
| CheckPublicSessionPresent(account_id_1_); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| ASSERT_EQ(user->GetType(), user_manager::USER_TYPE_PUBLIC_ACCOUNT); |
| |
| std::u16string timezone_id1(u"America/Los_Angeles"); |
| std::string timezone_id2("Europe/Berlin"); |
| std::u16string timezone_id2_utf16(u"Europe/Berlin"); |
| |
| ash::system::TimezoneSettings* timezone_settings = |
| ash::system::TimezoneSettings::GetInstance(); |
| |
| timezone_settings->SetTimezoneFromID(timezone_id1); |
| SetSystemTimezoneAutomaticDetectionPolicy(em::SystemTimezoneProto::DISABLED); |
| ash::system::SetSystemTimezone(user, timezone_id2); |
| EXPECT_EQ(timezone_settings->GetCurrentTimezoneID(), timezone_id2_utf16); |
| |
| timezone_settings->SetTimezoneFromID(timezone_id1); |
| SetSystemTimezoneAutomaticDetectionPolicy( |
| em::SystemTimezoneProto::USERS_DECIDE); |
| ash::system::SetSystemTimezone(user, timezone_id2); |
| EXPECT_EQ(timezone_settings->GetCurrentTimezoneID(), timezone_id2_utf16); |
| |
| timezone_settings->SetTimezoneFromID(timezone_id1); |
| SetSystemTimezoneAutomaticDetectionPolicy(em::SystemTimezoneProto::IP_ONLY); |
| ash::system::SetSystemTimezone(user, timezone_id2); |
| EXPECT_NE(timezone_settings->GetCurrentTimezoneID(), timezone_id2_utf16); |
| |
| timezone_settings->SetTimezoneFromID(timezone_id1); |
| SetSystemTimezoneAutomaticDetectionPolicy( |
| em::SystemTimezoneProto::SEND_WIFI_ACCESS_POINTS); |
| ash::system::SetSystemTimezone(user, timezone_id2); |
| EXPECT_NE(timezone_settings->GetCurrentTimezoneID(), timezone_id2_utf16); |
| |
| timezone_settings->SetTimezoneFromID(timezone_id1); |
| SetSystemTimezoneAutomaticDetectionPolicy( |
| em::SystemTimezoneProto::SEND_ALL_LOCATION_INFO); |
| ash::system::SetSystemTimezone(user, timezone_id2); |
| EXPECT_NE(timezone_settings->GetCurrentTimezoneID(), timezone_id2_utf16); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, OneRecommendedLocale) { |
| // Specify a recommended locale. |
| SetRecommendedLocales(kSingleRecommendedLocale, |
| std::size(kSingleRecommendedLocale)); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ExpandPublicSessionPod(false); |
| |
| WaitForGetKeyboardLayoutsForLocaleToFinish(); |
| |
| // Click the enter button to start the session. |
| ash::LoginScreenTestApi::ClickPublicExpandedSubmitButton(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the recommended locale has been applied and the first keyboard |
| // layout applicable to the locale was chosen. |
| EXPECT_EQ(kSingleRecommendedLocale[0], |
| g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(kSingleRecommendedLocale[0]), |
| icu::Locale::getDefault().getLanguage()); |
| VerifyKeyboardLayoutMatchesLocale(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MultipleRecommendedLocales) { |
| // Specify recommended locales. |
| SetRecommendedLocales(kRecommendedLocales1, std::size(kRecommendedLocales1)); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| AddPublicSessionToDevicePolicy(kAccountId2); |
| |
| WaitForPolicy(); |
| |
| ExpandPublicSessionPod(true); |
| |
| // Verify that the pod shows a list of locales beginning with the recommended |
| // ones, followed by others. |
| std::vector<ash::LocaleItem> locales = |
| ash::LoginScreenTestApi::GetExpandedPublicSessionLocales(); |
| EXPECT_LT(std::size(kRecommendedLocales1), locales.size()); |
| |
| // Verify that the list starts with the recommended locales, in correct order. |
| for (size_t i = 0; i < std::size(kRecommendedLocales1); ++i) { |
| EXPECT_EQ(kRecommendedLocales1[i], locales[i].language_code); |
| } |
| |
| // Verify that the recommended locales do not appear again in the remainder of |
| // the list. |
| std::set<std::string> recommended_locales; |
| for (size_t i = 0; i < std::size(kRecommendedLocales1); ++i) |
| recommended_locales.insert(kRecommendedLocales1[i]); |
| for (size_t i = std::size(kRecommendedLocales1); i < locales.size(); ++i) { |
| const std::string& locale = locales[i].language_code; |
| EXPECT_EQ(recommended_locales.end(), recommended_locales.find(locale)); |
| } |
| |
| // Verify that the first recommended locale is selected. |
| std::string selected_locale = |
| ash::LoginScreenTestApi::GetExpandedPublicSessionSelectedLocale(); |
| |
| EXPECT_EQ(kRecommendedLocales1[0], selected_locale); |
| |
| // Change the list of recommended locales. |
| SetRecommendedLocales(kRecommendedLocales2, std::size(kRecommendedLocales2)); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| DeviceLocalAccountPolicyBroker* broker = |
| GetDeviceLocalAccountPolicyBroker(account_id_1_); |
| ASSERT_TRUE(broker); |
| broker->core()->client()->FetchPolicy(); |
| WaitForPublicSessionLocalesChange(account_id_1_); |
| |
| // Verify that the new list of locales is shown in the UI. |
| locales = ash::LoginScreenTestApi::GetExpandedPublicSessionLocales(); |
| EXPECT_LT(std::size(kRecommendedLocales2), locales.size()); |
| for (size_t i = 0; i < std::size(kRecommendedLocales2); ++i) { |
| const std::string& locale = locales[i].language_code; |
| EXPECT_EQ(kRecommendedLocales2[i], locale); |
| } |
| |
| // Verify that the first new recommended locale is selected. |
| selected_locale = |
| ash::LoginScreenTestApi::GetExpandedPublicSessionSelectedLocale(); |
| EXPECT_EQ(kRecommendedLocales2[0], selected_locale); |
| |
| // Manually select a different locale. |
| ash::LoginScreenTestApi::SetPublicSessionLocale(kPublicSessionLocale); |
| |
| // Change the list of recommended locales. |
| SetRecommendedLocales(kRecommendedLocales1, std::size(kRecommendedLocales1)); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| broker->core()->client()->FetchPolicy(); |
| WaitForPublicSessionLocalesChange(account_id_1_); |
| |
| // Verify that the manually selected locale is still selected. |
| selected_locale = |
| ash::LoginScreenTestApi::GetExpandedPublicSessionSelectedLocale(); |
| EXPECT_EQ(kPublicSessionLocale, selected_locale); |
| |
| // The UI will request an updated list of keyboard layouts at this point. Wait |
| // for the constructions of this list to finish. |
| WaitForGetKeyboardLayoutsForLocaleToFinish(); |
| |
| // Manually select a different keyboard layout. |
| ash::LoginScreenTestApi::SetPublicSessionKeyboard( |
| public_session_input_method_id_); |
| |
| ASSERT_TRUE(ash::LoginScreenTestApi::HidePublicSessionExpandedPod()); |
| |
| // Click on a different pod, causing focus to shift away and the pod to |
| // contract. |
| ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(account_id_2_)); |
| |
| // Click on the pod again, causing it to expand again. Verify that the pod has |
| // reset all its state (the advanced form is being shown, the manually |
| // selected locale and keyboard layout are selected). |
| ASSERT_TRUE(ash::LoginScreenTestApi::FocusUser(account_id_1_)); |
| ExpandPublicSessionPod(true); |
| EXPECT_EQ(kRecommendedLocales1[0], |
| ash::LoginScreenTestApi::GetExpandedPublicSessionSelectedLocale()); |
| |
| std::string selected_keyboard_layout = |
| ash::LoginScreenTestApi::GetExpandedPublicSessionSelectedKeyboard(); |
| |
| std::string default_keyboard_id = |
| GetDefaultKeyboardIdFromLanguageCode(kRecommendedLocales1[0]); |
| EXPECT_EQ(default_keyboard_id, selected_keyboard_layout); |
| |
| ash::LoginScreenTestApi::SetPublicSessionLocale(kPublicSessionLocale); |
| WaitForGetKeyboardLayoutsForLocaleToFinish(); |
| ash::LoginScreenTestApi::SetPublicSessionKeyboard( |
| public_session_input_method_id_); |
| |
| // Click the enter button to start the session. |
| ash::LoginScreenTestApi::ClickPublicExpandedSubmitButton(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the locale and keyboard layout have been applied. |
| EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), |
| icu::Locale::getDefault().getLanguage()); |
| EXPECT_EQ(public_session_input_method_id_, |
| ash::input_method::InputMethodManager::Get() |
| ->GetActiveIMEState() |
| ->GetCurrentInputMethod() |
| .id()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, InvalidRecommendedLocale) { |
| // Specify an invalid recommended locale. |
| SetRecommendedLocales(kInvalidRecommendedLocale, |
| std::size(kInvalidRecommendedLocale)); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| // Click on the pod to expand it. Verify that the pod expands to its basic |
| // form as there is only one recommended locale. |
| ExpandPublicSessionPod(false); |
| ash::LoginScreenTestApi::ClickPublicExpandedSubmitButton(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that since the recommended locale was invalid, the locale has not |
| // changed and the first keyboard layout applicable to the locale was chosen. |
| EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(initial_locale_), |
| icu::Locale::getDefault().getLanguage()); |
| VerifyKeyboardLayoutMatchesLocale(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LocaleWithIME) { |
| // Specify a locale that has real IMEs in addition to a keyboard layout one. |
| const char* const kSingleLocaleWithIME[] = {"ja"}; |
| RunWithRecommendedLocale(kSingleLocaleWithIME, |
| std::size(kSingleLocaleWithIME)); |
| |
| EXPECT_GT(ash::input_method::InputMethodManager::Get() |
| ->GetActiveIMEState() |
| ->GetNumEnabledInputMethods(), |
| 1u); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LocaleWithNoIME) { |
| // Specify a locale that has only keyboard layout. |
| const char* const kSingleLocaleWithNoIME[] = {"de"}; |
| RunWithRecommendedLocale(kSingleLocaleWithNoIME, |
| std::size(kSingleLocaleWithNoIME)); |
| |
| EXPECT_EQ(1u, ash::input_method::InputMethodManager::Get() |
| ->GetActiveIMEState() |
| ->GetNumEnabledInputMethods()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, |
| AutoLoginWithoutRecommendedLocales) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| EnableAutoLogin(); |
| |
| WaitForPolicy(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the locale has not changed and the first keyboard layout |
| // applicable to the locale was chosen. |
| EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); |
| VerifyKeyboardLayoutMatchesLocale(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, |
| AutoLoginWithRecommendedLocales) { |
| // Specify recommended locales. |
| SetRecommendedLocales(kRecommendedLocales1, std::size(kRecommendedLocales1)); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| EnableAutoLogin(); |
| |
| WaitForPolicy(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the first recommended locale has been applied and the first |
| // keyboard layout applicable to the locale was chosen. |
| EXPECT_EQ(kRecommendedLocales1[0], g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(kRecommendedLocales1[0]), |
| icu::Locale::getDefault().getLanguage()); |
| VerifyKeyboardLayoutMatchesLocale(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, TermsOfServiceWithLocaleSwitch) { |
| // Specify Terms of Service URL. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value( |
| embedded_test_server() |
| ->GetURL(std::string("/") + kExistentTermsOfServicePath) |
| .spec()); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| // Prevent browser start in user session so that we do not need to wait |
| // for its initialization. |
| ash::test::UserSessionManagerTestApi(ash::UserSessionManager::GetInstance()) |
| .SetShouldLaunchBrowserInTests(false); |
| |
| ExpandPublicSessionPod(false); |
| |
| // Select a different locale. |
| ash::LoginScreenTestApi::SetPublicSessionLocale(kPublicSessionLocale); |
| |
| // The UI will have requested an updated list of keyboard layouts at this |
| // point. Wait for the constructions of this list to finish. |
| WaitForGetKeyboardLayoutsForLocaleToFinish(); |
| |
| ash::test::ProfilePreparedWaiter profile_prepared(account_id_1_); |
| // Manually select a different keyboard layout and click the enter button to |
| // start the session. |
| ash::LoginScreenTestApi::SetPublicSessionKeyboard( |
| public_session_input_method_id_); |
| ash::LoginScreenTestApi::ClickPublicExpandedSubmitButton(); |
| profile_prepared.Wait(); |
| |
| // Wait for the Terms of Service screen is being shown. |
| ash::OobeScreenWaiter(ash::TermsOfServiceScreenView::kScreenId).Wait(); |
| |
| // Wait for the Terms of Service to finish downloading. |
| ash::test::OobeJS() |
| .CreateVisibilityWaiter(true, {"terms-of-service", "step-loaded"}) |
| ->Wait(); |
| |
| // Verify that the locale and keyboard layout have been applied. |
| EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), |
| icu::Locale::getDefault().getLanguage()); |
| EXPECT_EQ(public_session_input_method_id_, |
| ash::input_method::InputMethodManager::Get() |
| ->GetActiveIMEState() |
| ->GetCurrentInputMethod() |
| .id()); |
| |
| // Wait for 'tos-accept-button' to become enabled. |
| ash::test::OobeJS() |
| .CreateEnabledWaiter(true, {"terms-of-service", "acceptButton"}) |
| ->Wait(); |
| |
| // Click the accept button. |
| ash::test::OobeJS().ClickOnPath({"terms-of-service", "acceptButton"}); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the locale and keyboard layout are still in force. |
| EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), |
| icu::Locale::getDefault().getLanguage()); |
| EXPECT_EQ(public_session_input_method_id_, |
| ash::input_method::InputMethodManager::Get() |
| ->GetActiveIMEState() |
| ->GetCurrentInputMethod() |
| .id()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PublicSessionWithLocaleSwitch) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| ExpandPublicSessionPod(false); |
| |
| // Select a different locale. |
| EXPECT_NE(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); |
| ash::LoginScreenTestApi::SetPublicSessionLocale(kPublicSessionLocale); |
| |
| // Submit the locale change. |
| ash::LoginScreenTestApi::ClickPublicExpandedSubmitButton(); |
| |
| WaitForSessionStart(); |
| |
| // Verify that the locale. |
| EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); |
| EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), |
| icu::Locale::getDefault().getLanguage()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyForExtensions) { |
| // Set up a test update server for the Show Managed Storage app. |
| ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| scoped_refptr<TestingUpdateManifestProvider> testing_update_manifest_provider( |
| new TestingUpdateManifestProvider(kRelativeUpdateURL)); |
| testing_update_manifest_provider->AddUpdate( |
| kShowManagedStorageID, kShowManagedStorageVersion, |
| embedded_test_server()->GetURL(std::string("/") + |
| kShowManagedStorageCRXPath)); |
| embedded_test_server()->RegisterRequestHandler( |
| base::BindRepeating(&TestingUpdateManifestProvider::HandleRequest, |
| testing_update_manifest_provider)); |
| embedded_test_server()->StartAcceptingConnections(); |
| |
| // Force-install the Show Managed Storage app. This app can be installed in |
| // public sessions because it's allowlisted for testing purposes. |
| em::StringList* forcelist = device_local_account_policy_.payload() |
| .mutable_extensioninstallforcelist() |
| ->mutable_value(); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", kShowManagedStorageID, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| |
| // Set a policy for the app at the policy testserver. |
| // Note that the policy for the device-local account will be fetched before |
| // the session is started, so the policy for the app must be installed before |
| // the first device policy fetch. |
| policy_test_server_mixin_.UpdateExternalPolicy( |
| dm_protocol::kChromeExtensionPolicyType, kShowManagedStorageID, |
| "{" |
| " \"string\": {" |
| " \"Value\": \"policy test value one\"" |
| " }" |
| "}"); |
| |
| // Install and refresh the device policy now. This will also fetch the initial |
| // user policy for the device-local account now. |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| // Observe the app installation after login. |
| ExtensionInstallObserver install_observer(kShowManagedStorageID); |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| install_observer.Wait(); |
| |
| // Verify that the app was installed. |
| Profile* profile = GetProfileForTest(); |
| ASSERT_TRUE(profile); |
| extensions::ExtensionRegistry* extension_registry = |
| extensions::ExtensionRegistry::Get(profile); |
| EXPECT_TRUE( |
| extension_registry->enabled_extensions().GetByID(kShowManagedStorageID)); |
| |
| // Wait for the app policy if it hasn't been fetched yet. |
| ProfilePolicyConnector* connector = profile->GetProfilePolicyConnector(); |
| ASSERT_TRUE(connector); |
| PolicyService* policy_service = connector->policy_service(); |
| ASSERT_TRUE(policy_service); |
| const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kShowManagedStorageID); |
| if (policy_service->GetPolicies(ns).Get("string") == nullptr) { |
| RefreshAndWaitForPolicies(policy_service, ns); |
| } |
| |
| // Verify that the app policy was set. |
| base::Value expected_value("policy test value one"); |
| EXPECT_EQ(expected_value, *policy_service->GetPolicies(ns).GetValue( |
| "string", base::Value::Type::STRING)); |
| |
| // Now update the policy at the server. |
| policy_test_server_mixin_.UpdateExternalPolicy( |
| dm_protocol::kChromeExtensionPolicyType, kShowManagedStorageID, |
| "{" |
| " \"string\": {" |
| " \"Value\": \"policy test value two\"" |
| " }" |
| "}"); |
| |
| // And issue a policy refresh. |
| const base::Value* new_value = RefreshAndWaitForPolicies(policy_service, ns); |
| |
| // Verify that the app policy was updated. |
| base::Value expected_new_value("policy test value two"); |
| EXPECT_EQ(expected_new_value, *new_value); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginWarningShown) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ExpandPublicSessionPod(false); |
| |
| // Click the link that switches the pod to its advanced form. Verify that the |
| // pod switches from basic to advanced. |
| ash::LoginScreenTestApi::ClickPublicExpandedAdvancedViewButton(); |
| ASSERT_TRUE(ash::LoginScreenTestApi::IsExpandedPublicSessionAdvanced()); |
| ASSERT_TRUE(ash::LoginScreenTestApi::IsPublicSessionWarningShown()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, SessionLengthLimit) { |
| base::AddFeatureIdTagToTestResult( |
| DeviceLocalAccountTest::kSessionLengthLimitTag); |
| constexpr int kThreeHoursInMs = 3 * 60 * 60 * 1000; |
| constexpr int kTwoHoursInMs = 2 * 60 * 60 * 1000; |
| |
| PolicyTestAppTerminationObserver observer; |
| |
| // Install and refresh the device policy now. This will also fetch the initial |
| // user policy for the device-local account now. |
| SetSessionLengthLimitPolicy(kThreeHoursInMs); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| // Setup a fake delegate to advance clock. |
| auto delegate_ptr = std::make_unique<FakeDelegateImpl>(); |
| auto* delegate = delegate_ptr.get(); |
| static_cast<ash::ChromeUserManagerImpl*>(user_manager::UserManager::Get()) |
| ->GetSessionLengthLimiterForTesting() |
| ->SetDelegateForTesting(std::move(delegate_ptr)); |
| |
| // Ensure the SessionLengthLimit is updated. |
| LocalStateValueWaiter(prefs::kSessionLengthLimit, |
| base::Value(kThreeHoursInMs)) |
| .Wait(); |
| |
| // The session is not terminated. |
| EXPECT_FALSE(observer.WasAppTerminated()); |
| EXPECT_FALSE(delegate->session_stopped()); |
| |
| // Advance the clock by 3 hours. |
| delegate->AdvanceClock(base::Hours(3)); |
| |
| // Update the SessionLengthLimit policy to limit the session by two hours. |
| // The session is expected to be terminated asap, because the current time is |
| // later than the max session length. |
| SetSessionLengthLimitPolicy(kTwoHoursInMs); |
| |
| // Fetch the policy update. |
| { |
| DeviceLocalAccountPolicyBroker* broker = |
| GetDeviceLocalAccountPolicyBroker(account_id_1_); |
| ASSERT_TRUE(broker); |
| broker->core()->client()->FetchPolicy(); |
| } |
| // Ensure the SessionLengthLimit is updated. |
| LocalStateValueWaiter(prefs::kSessionLengthLimit, base::Value(kTwoHoursInMs)) |
| .Wait(); |
| |
| // The session is terminated. |
| EXPECT_TRUE(observer.WasAppTerminated()); |
| EXPECT_TRUE(delegate->session_stopped()); |
| } |
| |
| class DeviceLocalAccountWarnings : public DeviceLocalAccountTest { |
| void SetUpInProcessBrowserTestFixture() override { |
| DeviceLocalAccountTest::SetUpInProcessBrowserTestFixture(); |
| SetManagedSessionsWarningDisabled(); |
| } |
| |
| void SetManagedSessionsWarningDisabled() { |
| em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); |
| em::ManagedGuestSessionPrivacyWarningsProto* managed_sessions_warnings = |
| proto.mutable_managed_guest_session_privacy_warnings(); |
| managed_sessions_warnings->set_enabled(false); |
| RefreshDevicePolicy(); |
| policy_test_server_mixin_.UpdateDevicePolicy(proto); |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountWarnings, NoLoginWarningShown) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ExpandPublicSessionPod(false); |
| |
| // Click the link that switches the pod to its advanced form. Verify that the |
| // pod switches from basic to advanced. |
| ash::LoginScreenTestApi::ClickPublicExpandedAdvancedViewButton(); |
| ASSERT_TRUE(ash::LoginScreenTestApi::IsExpandedPublicSessionAdvanced()); |
| ASSERT_FALSE(ash::LoginScreenTestApi::IsPublicSessionWarningShown()); |
| } |
| |
| class ManagedSessionsTest : public DeviceLocalAccountTest { |
| protected: |
| class CertsObserver : public ash::PolicyCertificateProvider::Observer { |
| public: |
| explicit CertsObserver(base::OnceClosure on_change) |
| : on_change_(std::move(on_change)) {} |
| |
| void OnPolicyProvidedCertsChanged() override { |
| std::move(on_change_).Run(); |
| } |
| |
| private: |
| base::OnceClosure on_change_; |
| }; |
| |
| void StartTestExtensionsServer() { |
| ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); |
| scoped_refptr<TestingUpdateManifestProvider> |
| testing_update_manifest_provider( |
| new TestingUpdateManifestProvider(kRelativeUpdateURL)); |
| testing_update_manifest_provider->AddUpdate( |
| kGoodExtensionID, kGoodExtensionVersion, |
| embedded_test_server()->GetURL(std::string("/") + |
| kGoodExtensionCRXPath)); |
| testing_update_manifest_provider->AddUpdate( |
| kHostedAppID, kHostedAppVersion, |
| embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath)); |
| testing_update_manifest_provider->AddUpdate( |
| kShowManagedStorageID, kShowManagedStorageVersion, |
| embedded_test_server()->GetURL(std::string("/") + |
| kShowManagedStorageCRXPath)); |
| embedded_test_server()->RegisterRequestHandler( |
| base::BindRepeating(&TestingUpdateManifestProvider::HandleRequest, |
| testing_update_manifest_provider)); |
| embedded_test_server()->StartAcceptingConnections(); |
| } |
| |
| void AddExtension(const char* extension_id) { |
| // Specify policy to install an extension. |
| em::StringList* forcelist = device_local_account_policy_.payload() |
| .mutable_extensioninstallforcelist() |
| ->mutable_value(); |
| forcelist->add_entries(base::StringPrintf( |
| "%s;%s", extension_id, |
| embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); |
| } |
| |
| void AddForceInstalledSafeExtension() { AddExtension(kHostedAppID); } |
| |
| void AddForceInstalledUnsafeExtension() { |
| // has effective hosts: |
| // http://*.example.com/* |
| // http://*.google.com/* |
| // https://*.google.com/* |
| AddExtension(kGoodExtensionID); |
| } |
| |
| void AddForceInstalledAllowlistedExtension() { |
| AddExtension(kShowManagedStorageID); |
| } |
| |
| void WaitForCertificateUpdate() { |
| DeviceNetworkConfigurationUpdaterAsh* updater = |
| g_browser_process->platform_part() |
| ->browser_policy_connector_ash() |
| ->GetDeviceNetworkConfigurationUpdater(); |
| base::RunLoop run_loop; |
| auto observer = std::make_unique<CertsObserver>(run_loop.QuitClosure()); |
| updater->AddPolicyProvidedCertsObserver(observer.get()); |
| run_loop.Run(); |
| updater->RemovePolicyProvidedCertsObserver(observer.get()); |
| } |
| |
| void AddNetworkCertificateToDevicePolicy() { |
| em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); |
| proto.mutable_open_network_configuration()->set_open_network_configuration( |
| kFakeOncWithCertificate); |
| RefreshDevicePolicy(); |
| WaitForCertificateUpdate(); |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(ManagedSessionsTest, ManagedSessionsEnabledNonRisky) { |
| // Install and refresh the device policy now. This will also fetch the initial |
| // user policy for the device-local account now. |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| |
| // Management disclosure warning is shown in the beginning, because |
| // kManagedSessionUseFullLoginWarning pref is set to true in the beginning. |
| EXPECT_TRUE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| // After the login, kManagedSessionUseFullLoginWarning pref is updated. |
| // Check that management disclosure warning is not shown when managed sessions |
| // are enabled, but policy settings are not risky. |
| ASSERT_FALSE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ManagedSessionsTest, ForceInstalledSafeExtension) { |
| StartTestExtensionsServer(); |
| AddForceInstalledSafeExtension(); |
| |
| // Install and refresh the device policy now. This will also fetch the initial |
| // user policy for the device-local account now. |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| |
| // Management disclosure warning is shown in the beginning, because |
| // kManagedSessionUseFullLoginWarning pref is set to true in the beginning. |
| ASSERT_TRUE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| |
| ExtensionInstallObserver install_observer(kHostedAppID); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| install_observer.Wait(); |
| |
| // After the login, kManagedSessionUseFullLoginWarning pref is updated. |
| // Check that force-installed extension activates managed session mode for |
| // device-local users. |
| EXPECT_FALSE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ManagedSessionsTest, ForceInstalledUnsafeExtension) { |
| StartTestExtensionsServer(); |
| AddForceInstalledUnsafeExtension(); |
| |
| // Install and refresh the device policy now. This will also fetch the initial |
| // user policy for the device-local account now. |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| |
| // Management disclosure warning is shown in the beginning, because |
| // kManagedSessionUseFullLoginWarning pref is set to true in the beginning. |
| ASSERT_TRUE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| |
| ExtensionInstallObserver install_observer(kGoodExtensionID); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| install_observer.Wait(); |
| |
| // After the login, kManagedSessionUseFullLoginWarning pref is updated. |
| // Check that force-installed extension activates managed session mode for |
| // device-local users. |
| EXPECT_TRUE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ManagedSessionsTest, AllowlistedExtension) { |
| StartTestExtensionsServer(); |
| AddForceInstalledAllowlistedExtension(); |
| |
| // Install and refresh the device policy now. This will also fetch the initial |
| // user policy for the device-local account now. |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| |
| // Management disclosure warning is shown in the beginning, because |
| // kManagedSessionUseFullLoginWarning pref is set to true in the beginning. |
| ASSERT_TRUE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| |
| ExtensionInstallObserver install_observer(kShowManagedStorageID); |
| |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| WaitForSessionStart(); |
| |
| install_observer.Wait(); |
| |
| // After the login, kManagedSessionUseFullLoginWarning pref is updated. |
| // Check that white-listed extension is not considered risky and doesn't |
| // activate managed session mode. |
| EXPECT_FALSE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ManagedSessionsTest, NetworkCertificate) { |
| device_local_account_policy_.payload() |
| .mutable_opennetworkconfiguration() |
| ->set_value(kFakeOncWithCertificate); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| |
| // Check that network certificate pushed via policy activates managed sessions |
| // mode. |
| EXPECT_TRUE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ManagedSessionsTest, AllowCrossOriginAuthPrompt) { |
| device_local_account_policy_.payload() |
| .mutable_allowcrossoriginauthprompt() |
| ->set_value(true); |
| |
| // Install and refresh the device policy now. This will also fetch the initial |
| // user policy for the device-local account now. |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| const user_manager::User* user = |
| user_manager::UserManager::Get()->FindUser(account_id_1_); |
| ASSERT_TRUE(user); |
| |
| // Check that setting a value to 'AllowCrossOriginAuthPrompt' activates |
| // managed sessions mode. |
| ASSERT_TRUE(IsFullManagementDisclosureNeeded(account_id_1_)); |
| } |
| |
| class TermsOfServiceDownloadTest : public DeviceLocalAccountTest, |
| public testing::WithParamInterface<bool> { |
| public: |
| void SetUpOnMainThread() override { |
| DeviceLocalAccountTest::SetUpOnMainThread(); |
| |
| // Prevent browser start in user session so that we do not need to wait |
| // for its initialization. |
| ash::test::UserSessionManagerTestApi(ash::UserSessionManager::GetInstance()) |
| .SetShouldLaunchBrowserInTests(false); |
| } |
| |
| bool UseValidURL() const { return GetParam(); } |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(TermsOfServiceDownloadTest, TermsOfServiceScreen) { |
| // Specify Terms of Service URL. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value( |
| embedded_test_server() |
| ->GetURL(std::string("/") + (UseValidURL() |
| ? kExistentTermsOfServicePath |
| : kNonexistentTermsOfServicePath)) |
| .spec()); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ash::test::ProfilePreparedWaiter profile_prepared(account_id_1_); |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| profile_prepared.Wait(); |
| |
| // Verify that the Terms of Service screen is being shown. |
| ash::OobeScreenWaiter(ash::TermsOfServiceScreenView::kScreenId).Wait(); |
| |
| // Wait for the Terms of Service to finish loading. |
| |
| if (!UseValidURL()) { |
| // The Terms of Service URL was invalid. Verify that the screen is showing |
| // an error and the accept button is disabled. |
| ash::test::OobeJS() |
| .CreateVisibilityWaiter(true, {"terms-of-service", "step-error"}) |
| ->Wait(); |
| |
| ash::test::OobeJS().ExpectDisabledPath( |
| {"terms-of-service", "acceptButton"}); |
| return; |
| } |
| |
| ash::test::OobeJS() |
| .CreateVisibilityWaiter(true, {"terms-of-service", "step-loaded"}) |
| ->Wait(); |
| |
| ash::test::OobeJS() |
| .CreateVisibilityWaiter(true, {"terms-of-service", "termsOfServiceFrame"}) |
| ->Wait(); |
| |
| // Get the Terms Of Service from the webview. |
| const std::string content = ash::test::GetWebViewContents( |
| {"terms-of-service", "termsOfServiceFrame"}); |
| |
| // Get the expected values for heading and subheading. |
| const std::string expected_heading = |
| l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING, kDomain); |
| const std::string expected_subheading = l10n_util::GetStringFUTF8( |
| IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING, kDomain); |
| |
| // Compare heading and subheading |
| ash::test::OobeJS().ExpectEQ( |
| GetOobeElementPath({"terms-of-service", "tosHeading"}) + ".textContent", |
| expected_heading); |
| ash::test::OobeJS().ExpectEQ( |
| GetOobeElementPath({"terms-of-service", "tosSubheading"}) + |
| ".textContent", |
| expected_subheading); |
| |
| // The Terms of Service URL was valid. Verify that the screen is showing the |
| // downloaded Terms of Service and the accept button is enabled. |
| base::FilePath test_dir; |
| ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| std::string terms_of_service; |
| { |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| ASSERT_TRUE(base::ReadFileToString( |
| test_dir.Append(kExistentTermsOfServicePath), &terms_of_service)); |
| } |
| EXPECT_EQ(terms_of_service, content); |
| |
| ash::test::OobeJS() |
| .CreateVisibilityWaiter(false, {"terms-of-service", "step-error"}) |
| ->Wait(); |
| |
| ash::test::OobeJS().ExpectEnabledPath({"terms-of-service", "acceptButton"}); |
| |
| // Click the accept button. |
| ash::test::OobeJS().ClickOnPath({"terms-of-service", "acceptButton"}); |
| |
| WaitForSessionStart(); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(TermsOfServiceDownloadTest, DeclineTermsOfService) { |
| // Specify Terms of Service URL. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value( |
| embedded_test_server() |
| ->GetURL(std::string("/") + (UseValidURL() |
| ? kExistentTermsOfServicePath |
| : kNonexistentTermsOfServicePath)) |
| .spec()); |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| |
| WaitForPolicy(); |
| |
| ash::test::ProfilePreparedWaiter profile_prepared(account_id_1_); |
| ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); |
| profile_prepared.Wait(); |
| |
| // Verify that the Terms of Service screen is being shown. |
| ash::OobeScreenWaiter(ash::TermsOfServiceScreenView::kScreenId).Wait(); |
| |
| if (!UseValidURL()) { |
| ash::test::OobeJS() |
| .CreateVisibilityWaiter(true, {"terms-of-service", "step-error"}) |
| ->Wait(); |
| ash::test::TapOnPathAndWaitForOobeToBeDestroyed( |
| {"terms-of-service", "errorBackButton"}); |
| } else { |
| ash::test::OobeJS() |
| .CreateVisibilityWaiter(true, {"terms-of-service", "step-loaded"}) |
| ->Wait(); |
| ash::test::TapOnPathAndWaitForOobeToBeDestroyed( |
| {"terms-of-service", "backButton"}); |
| } |
| EXPECT_TRUE(session_manager_client()->session_stopped()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(TermsOfServiceDownloadTestInstance, |
| TermsOfServiceDownloadTest, |
| testing::Bool()); |
| |
| IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, WebAppsInPublicSession) { |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| // Add an account with DeviceLocalAccount::Type::TYPE_PUBLIC_SESSION. |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| WaitForPolicy(); |
| |
| StartLogin(std::string(), std::string()); |
| WaitForSessionStart(); |
| |
| // WebAppProvider should be enabled for TYPE_PUBLIC_SESSION user account. |
| Profile* profile = GetProfileForTest(); |
| ASSERT_TRUE(profile); |
| EXPECT_TRUE(web_app::WebAppProvider::GetForTest(profile)); |
| } |
| |
| class AmbientAuthenticationManagedGuestSessionTest |
| : public DeviceLocalAccountTest, |
| public testing::WithParamInterface<net::AmbientAuthAllowedProfileTypes> { |
| public: |
| void SetAmbientAuthPolicy(net::AmbientAuthAllowedProfileTypes value) { |
| device_local_account_policy_.payload() |
| .mutable_ambientauthenticationinprivatemodesenabled() |
| ->set_value(static_cast<int>(value)); |
| UploadDeviceLocalAccountPolicy(); |
| } |
| |
| void IsAmbientAuthAllowedForProfilesTest() { |
| int policy_value = device_local_account_policy_.payload() |
| .ambientauthenticationinprivatemodesenabled() |
| .value(); |
| Profile* regular_profile = GetCurrentBrowser()->profile(); |
| Profile* incognito_profile = |
| regular_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true); |
| |
| EXPECT_TRUE(AmbientAuthenticationTestHelper::IsAmbientAuthAllowedForProfile( |
| regular_profile)); |
| EXPECT_EQ(AmbientAuthenticationTestHelper::IsAmbientAuthAllowedForProfile( |
| incognito_profile), |
| AmbientAuthenticationTestHelper::IsIncognitoAllowedInPolicy( |
| policy_value)); |
| } |
| |
| Browser* GetCurrentBrowser() { |
| BrowserList* browser_list = BrowserList::GetInstance(); |
| EXPECT_EQ(1U, browser_list->size()); |
| Browser* browser = browser_list->get(0); |
| DCHECK(browser); |
| return browser; |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(AmbientAuthenticationManagedGuestSessionTest, |
| AmbientAuthenticationInPrivateModesEnabledPolicy) { |
| SetAmbientAuthPolicy(GetParam()); |
| |
| UploadAndInstallDeviceLocalAccountPolicy(); |
| AddPublicSessionToDevicePolicy(kAccountId1); |
| EnableAutoLogin(); |
| |
| WaitForPolicy(); |
| |
| WaitForSessionStart(); |
| |
| CheckPublicSessionPresent(account_id_1_); |
| |
| IsAmbientAuthAllowedForProfilesTest(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AmbientAuthAllPolicyValuesTest, |
| AmbientAuthenticationManagedGuestSessionTest, |
| testing::Values(net::AmbientAuthAllowedProfileTypes::REGULAR_ONLY, |
| net::AmbientAuthAllowedProfileTypes::INCOGNITO_AND_REGULAR, |
| net::AmbientAuthAllowedProfileTypes::GUEST_AND_REGULAR, |
| net::AmbientAuthAllowedProfileTypes::ALL)); |
| |
| } // namespace policy |