1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/basictypes.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/files/file_path.h"
15 #include "base/files/scoped_temp_dir.h"
16 #include "base/json/json_reader.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/path_service.h"
20 #include "base/run_loop.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/test/scoped_path_override.h"
26 #include "base/values.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/chrome_notification_types.h"
29 #include "chrome/browser/chromeos/login/existing_user_controller.h"
30 #include "chrome/browser/chromeos/login/login_display_host.h"
31 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
32 #include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
33 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
34 #include "chrome/browser/chromeos/login/user.h"
35 #include "chrome/browser/chromeos/login/user_manager.h"
36 #include "chrome/browser/chromeos/login/webui_login_view.h"
37 #include "chrome/browser/chromeos/login/wizard_controller.h"
38 #include "chrome/browser/chromeos/policy/device_local_account.h"
39 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
40 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
41 #include "chrome/browser/extensions/extension_service.h"
42 #include "chrome/browser/extensions/extension_system.h"
43 #include "chrome/browser/lifetime/application_lifetime.h"
44 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
45 #include "chrome/browser/policy/cloud/policy_builder.h"
46 #include "chrome/browser/policy/policy_service.h"
47 #include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
48 #include "chrome/browser/policy/test/local_policy_test_server.h"
49 #include "chrome/browser/prefs/session_startup_pref.h"
50 #include "chrome/browser/profiles/profile.h"
51 #include "chrome/browser/profiles/profile_manager.h"
52 #include "chrome/browser/ui/browser.h"
53 #include "chrome/browser/ui/browser_commands.h"
54 #include "chrome/browser/ui/browser_finder.h"
55 #include "chrome/browser/ui/browser_list.h"
56 #include "chrome/browser/ui/browser_window.h"
57 #include "chrome/browser/ui/host_desktop.h"
58 #include "chrome/browser/ui/tabs/tab_strip_model.h"
59 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
60 #include "chrome/common/chrome_paths.h"
61 #include "chrome/common/chrome_switches.h"
62 #include "chrome/common/extensions/extension.h"
63 #include "chromeos/chromeos_paths.h"
64 #include "chromeos/chromeos_switches.h"
65 #include "chromeos/dbus/cryptohome_client.h"
66 #include "chromeos/dbus/dbus_method_call_status.h"
67 #include "chromeos/dbus/fake_session_manager_client.h"
68 #include "chromeos/dbus/session_manager_client.h"
69 #include "content/public/browser/notification_details.h"
70 #include "content/public/browser/notification_source.h"
71 #include "content/public/browser/web_contents.h"
72 #include "content/public/browser/web_ui.h"
73 #include "content/public/test/browser_test_utils.h"
74 #include "content/public/test/test_utils.h"
75 #include "crypto/rsa_private_key.h"
76 #include "grit/chromium_strings.h"
77 #include "grit/generated_resources.h"
78 #include "net/base/url_util.h"
79 #include "net/http/http_status_code.h"
80 #include "net/test/embedded_test_server/embedded_test_server.h"
81 #include "net/test/embedded_test_server/http_request.h"
82 #include "net/test/embedded_test_server/http_response.h"
83 #include "testing/gmock/include/gmock/gmock.h"
84 #include "third_party/cros_system_api/dbus/service_constants.h"
85 #include "ui/base/l10n/l10n_util.h"
88 namespace em = enterprise_management;
90 using testing::InvokeWithoutArgs;
91 using testing::Return;
98 const char kDomain[] = "example.com";
99 const char kAccountId1[] = "dla1@example.com";
100 const char kAccountId2[] = "dla2@example.com";
101 const char kDisplayName[] = "display name";
102 const char* kStartupURLs[] = {
106 const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt";
107 const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt";
108 const char kRelativeUpdateURL[] = "/service/update2/crx";
109 const char kUpdateManifestHeader[] =
110 "<?xml version='1.0' encoding='UTF-8'?>\n"
111 "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n";
112 const char kUpdateManifestTemplate[] =
113 " <app appid='%s'>\n"
114 " <updatecheck codebase='%s' version='%s' />\n"
116 const char kUpdateManifestFooter[] =
118 const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
119 const char kHostedAppCRXPath[] = "extensions/hosted_app.crx";
120 const char kHostedAppVersion[] = "1.0.0.0";
121 const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
122 const char kGoodExtensionCRXPath[] = "extensions/good.crx";
123 const char kGoodExtensionVersion[] = "1.0";
125 // Helper that serves extension update manifests to Chrome.
126 class TestingUpdateManifestProvider {
129 // Update manifests will be served at |relative_update_url|.
130 explicit TestingUpdateManifestProvider(
131 const std::string& relative_update_url);
132 ~TestingUpdateManifestProvider();
134 // When an update manifest is requested for the given extension |id|, indicate
135 // that |version| of the extension can be downloaded at |crx_url|.
136 void AddUpdate(const std::string& id,
137 const std::string& version,
138 const GURL& crx_url);
140 // This method must be registered with the test's EmbeddedTestServer to start
141 // serving update manifests.
142 scoped_ptr<net::test_server::HttpResponse> HandleRequest(
143 const net::test_server::HttpRequest& request);
148 Update(const std::string& version, const GURL& crx_url);
154 typedef std::map<std::string, Update> UpdateMap;
157 const std::string relative_update_url_;
159 DISALLOW_COPY_AND_ASSIGN(TestingUpdateManifestProvider);
162 TestingUpdateManifestProvider::Update::Update(const std::string& version,
168 TestingUpdateManifestProvider::Update::Update() {
171 TestingUpdateManifestProvider::TestingUpdateManifestProvider(
172 const std::string& relative_update_url)
173 : relative_update_url_(relative_update_url) {
176 TestingUpdateManifestProvider::~TestingUpdateManifestProvider() {
179 void TestingUpdateManifestProvider::AddUpdate(const std::string& id,
180 const std::string& version,
181 const GURL& crx_url) {
182 updates_[id] = Update(version, crx_url);
185 scoped_ptr<net::test_server::HttpResponse>
186 TestingUpdateManifestProvider::HandleRequest(
187 const net::test_server::HttpRequest& request) {
188 const GURL url("http://localhost" + request.relative_url);
189 if (url.path() != relative_update_url_)
190 return scoped_ptr<net::test_server::HttpResponse>();
192 std::string content = kUpdateManifestHeader;
193 for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
194 if (it.GetKey() != "x")
196 // Extract the extension id from the subquery. Since GetValueForKeyInQuery()
197 // expects a complete URL, dummy scheme and host must be prepended.
199 net::GetValueForKeyInQuery(GURL("http://dummy?" + it.GetUnescapedValue()),
201 UpdateMap::const_iterator entry = updates_.find(id);
202 if (entry != updates_.end()) {
203 content += base::StringPrintf(kUpdateManifestTemplate,
205 entry->second.crx_url.spec().c_str(),
206 entry->second.version.c_str());
209 content += kUpdateManifestFooter;
210 scoped_ptr<net::test_server::BasicHttpResponse>
211 http_response(new net::test_server::BasicHttpResponse);
212 http_response->set_code(net::HTTP_OK);
213 http_response->set_content(content);
214 http_response->set_content_type("text/xml");
215 return http_response.PassAs<net::test_server::HttpResponse>();
218 bool DoesInstallSuccessReferToId(const std::string& id,
219 const content::NotificationSource& source,
220 const content::NotificationDetails& details) {
221 return content::Details<const extensions::InstalledExtensionInfo>(details)->
222 extension->id() == id;
225 bool DoesInstallFailureReferToId(const std::string& id,
226 const content::NotificationSource& source,
227 const content::NotificationDetails& details) {
228 return content::Details<const string16>(details)->find(UTF8ToUTF16(id)) !=
234 class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest {
236 DeviceLocalAccountTest()
237 : user_id_1_(GenerateDeviceLocalAccountUserId(
238 kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
239 user_id_2_(GenerateDeviceLocalAccountUserId(
240 kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)) {}
242 virtual ~DeviceLocalAccountTest() {}
244 virtual void SetUp() OVERRIDE {
245 // Configure and start the test server.
246 scoped_ptr<crypto::RSAPrivateKey> signing_key(
247 PolicyBuilder::CreateTestSigningKey());
248 ASSERT_TRUE(test_server_.SetSigningKey(signing_key.get()));
250 test_server_.RegisterClient(PolicyBuilder::kFakeToken,
251 PolicyBuilder::kFakeDeviceId);
252 ASSERT_TRUE(test_server_.Start());
254 ASSERT_TRUE(extension_cache_root_dir_.CreateUniqueTempDir());
255 extension_cache_root_dir_override_.reset(new base::ScopedPathOverride(
256 chromeos::DIR_DEVICE_LOCAL_ACCOUNT_CACHE,
257 extension_cache_root_dir_.path()));
259 DevicePolicyCrosBrowserTest::SetUp();
262 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
263 command_line->AppendSwitch(chromeos::switches::kLoginManager);
264 command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
265 command_line->AppendSwitchASCII(
266 switches::kDeviceManagementUrl, test_server_.GetServiceURL().spec());
267 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
270 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
271 DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
273 // Clear command-line arguments (but keep command-line switches) so the
274 // startup pages policy takes effect.
275 CommandLine* command_line = CommandLine::ForCurrentProcess();
276 CommandLine::StringVector argv(command_line->argv());
277 argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(),
279 command_line->InitFromArgv(argv);
282 MarkAsEnterpriseOwned();
287 virtual void CleanUpOnMainThread() OVERRIDE {
288 // This shuts down the login UI.
289 base::MessageLoop::current()->PostTask(FROM_HERE,
290 base::Bind(&chrome::AttemptExit));
291 base::RunLoop().RunUntilIdle();
294 void InitializePolicy() {
295 device_policy()->policy_data().set_public_key_version(1);
296 em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
297 proto.mutable_show_user_names()->set_show_user_names(true);
299 device_local_account_policy_.policy_data().set_policy_type(
300 dm_protocol::kChromePublicAccountPolicyType);
301 device_local_account_policy_.policy_data().set_username(kAccountId1);
302 device_local_account_policy_.policy_data().set_settings_entity_id(
304 device_local_account_policy_.policy_data().set_public_key_version(1);
305 device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
309 void BuildDeviceLocalAccountPolicy() {
310 device_local_account_policy_.SetDefaultSigningKey();
311 device_local_account_policy_.Build();
314 void UploadDeviceLocalAccountPolicy() {
315 BuildDeviceLocalAccountPolicy();
316 ASSERT_TRUE(session_manager_client()->device_local_account_policy(
317 kAccountId1).empty());
318 test_server_.UpdatePolicy(
319 dm_protocol::kChromePublicAccountPolicyType, kAccountId1,
320 device_local_account_policy_.payload().SerializeAsString());
323 void UploadAndInstallDeviceLocalAccountPolicy() {
324 UploadDeviceLocalAccountPolicy();
325 session_manager_client()->set_device_local_account_policy(
326 kAccountId1, device_local_account_policy_.GetBlob());
329 void AddPublicSessionToDevicePolicy(const std::string& username) {
330 em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
331 em::DeviceLocalAccountInfoProto* account =
332 proto.mutable_device_local_accounts()->add_account();
333 account->set_account_id(username);
335 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
336 RefreshDevicePolicy();
337 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
338 std::string(), proto.SerializeAsString());
341 void CheckPublicSessionPresent(const std::string& id) {
342 const chromeos::User* user = chromeos::UserManager::Get()->FindUser(id);
344 EXPECT_EQ(id, user->email());
345 EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType());
348 base::FilePath GetCacheDirectoryForAccountID(const std::string& account_id) {
349 return extension_cache_root_dir_.path()
350 .Append(base::HexEncode(account_id.c_str(), account_id.size()));
353 base::FilePath GetCacheCRXFile(const std::string& account_id,
354 const std::string& id,
355 const std::string& version) {
356 return GetCacheDirectoryForAccountID(account_id)
357 .Append(base::StringPrintf("%s-%s.crx", id.c_str(), version.c_str()));
360 const std::string user_id_1_;
361 const std::string user_id_2_;
363 base::ScopedTempDir extension_cache_root_dir_;
364 scoped_ptr<base::ScopedPathOverride> extension_cache_root_dir_override_;
366 UserPolicyBuilder device_local_account_policy_;
367 LocalPolicyTestServer test_server_;
370 static bool IsKnownUser(const std::string& account_id) {
371 return chromeos::UserManager::Get()->IsKnownUser(account_id);
374 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) {
375 AddPublicSessionToDevicePolicy(kAccountId1);
376 AddPublicSessionToDevicePolicy(kAccountId2);
378 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
379 base::Bind(&IsKnownUser, user_id_1_))
381 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
382 base::Bind(&IsKnownUser, user_id_2_))
385 CheckPublicSessionPresent(user_id_1_);
386 CheckPublicSessionPresent(user_id_2_);
389 static bool DisplayNameMatches(const std::string& account_id,
390 const std::string& display_name) {
391 const chromeos::User* user =
392 chromeos::UserManager::Get()->FindUser(account_id);
393 if (!user || user->display_name().empty())
395 EXPECT_EQ(UTF8ToUTF16(display_name), user->display_name());
399 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
400 UploadAndInstallDeviceLocalAccountPolicy();
401 AddPublicSessionToDevicePolicy(kAccountId1);
403 content::WindowedNotificationObserver(
404 chrome::NOTIFICATION_USER_LIST_CHANGED,
405 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
408 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) {
409 UploadDeviceLocalAccountPolicy();
410 AddPublicSessionToDevicePolicy(kAccountId1);
412 // Policy for the account is not installed in session_manager_client. Because
413 // of this, the presence of the display name (which comes from policy) can be
414 // used as a signal that indicates successful policy download.
415 content::WindowedNotificationObserver(
416 chrome::NOTIFICATION_USER_LIST_CHANGED,
417 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
419 // Sanity check: The policy should be present now.
420 ASSERT_FALSE(session_manager_client()->device_local_account_policy(
421 kAccountId1).empty());
424 static bool IsNotKnownUser(const std::string& account_id) {
425 return !IsKnownUser(account_id);
428 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) {
429 AddPublicSessionToDevicePolicy(kAccountId1);
430 AddPublicSessionToDevicePolicy(kAccountId2);
432 // Wait until the login screen is up.
433 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
434 base::Bind(&IsKnownUser, user_id_1_))
436 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
437 base::Bind(&IsKnownUser, user_id_2_))
440 // Update policy to remove kAccountId2.
441 em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
442 proto.mutable_device_local_accounts()->clear_account();
443 AddPublicSessionToDevicePolicy(kAccountId1);
445 em::ChromeDeviceSettingsProto policy;
446 policy.mutable_show_user_names()->set_show_user_names(true);
447 em::DeviceLocalAccountInfoProto* account1 =
448 policy.mutable_device_local_accounts()->add_account();
449 account1->set_account_id(kAccountId1);
451 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
453 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(),
454 policy.SerializeAsString());
455 g_browser_process->policy_service()->RefreshPolicies(base::Closure());
457 // Make sure the second device-local account disappears.
458 content::WindowedNotificationObserver(
459 chrome::NOTIFICATION_USER_LIST_CHANGED,
460 base::Bind(&IsNotKnownUser, user_id_2_)).Wait();
463 static bool IsSessionStarted() {
464 return chromeos::UserManager::Get()->IsSessionStarted();
467 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) {
468 // Specify startup pages.
469 device_local_account_policy_.payload().mutable_restoreonstartup()->set_value(
470 SessionStartupPref::kPrefValueURLs);
471 em::StringListPolicyProto* startup_urls_proto =
472 device_local_account_policy_.payload().mutable_restoreonstartupurls();
473 for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
474 startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
475 UploadAndInstallDeviceLocalAccountPolicy();
476 AddPublicSessionToDevicePolicy(kAccountId1);
478 // This observes the display name becoming available as this indicates
479 // device-local account policy is fully loaded, which is a prerequisite for
481 content::WindowedNotificationObserver(
482 chrome::NOTIFICATION_USER_LIST_CHANGED,
483 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
485 // Wait for the login UI to be ready.
486 chromeos::LoginDisplayHostImpl* host =
487 reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
488 chromeos::LoginDisplayHostImpl::default_host());
490 chromeos::OobeUI* oobe_ui = host->GetOobeUI();
491 ASSERT_TRUE(oobe_ui);
492 base::RunLoop run_loop;
493 const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
497 // Start login into the device-local account.
498 host->StartSignInScreen();
499 chromeos::ExistingUserController* controller =
500 chromeos::ExistingUserController::current_controller();
501 ASSERT_TRUE(controller);
502 controller->LoginAsPublicAccount(user_id_1_);
504 // Wait for the session to start.
505 content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
506 base::Bind(IsSessionStarted)).Wait();
508 // Check that the startup pages specified in policy were opened.
509 BrowserList* browser_list =
510 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
511 EXPECT_EQ(1U, browser_list->size());
512 Browser* browser = browser_list->get(0);
513 ASSERT_TRUE(browser);
515 TabStripModel* tabs = browser->tab_strip_model();
517 int expected_tab_count = static_cast<int>(arraysize(kStartupURLs));
518 EXPECT_EQ(expected_tab_count, tabs->count());
519 for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) {
520 EXPECT_EQ(GURL(kStartupURLs[i]),
521 tabs->GetWebContentsAt(i)->GetVisibleURL());
525 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) {
526 UploadAndInstallDeviceLocalAccountPolicy();
527 AddPublicSessionToDevicePolicy(kAccountId1);
529 // This observes the display name becoming available as this indicates
530 // device-local account policy is fully loaded, which is a prerequisite for
532 content::WindowedNotificationObserver(
533 chrome::NOTIFICATION_USER_LIST_CHANGED,
534 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
536 // Wait for the login UI to be ready.
537 chromeos::LoginDisplayHostImpl* host =
538 reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
539 chromeos::LoginDisplayHostImpl::default_host());
541 chromeos::OobeUI* oobe_ui = host->GetOobeUI();
542 ASSERT_TRUE(oobe_ui);
543 base::RunLoop run_loop;
544 const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
548 // Ensure that the browser stays alive, even though no windows are opened
549 // during session start.
550 chrome::StartKeepAlive();
552 // Start login into the device-local account.
553 host->StartSignInScreen();
554 chromeos::ExistingUserController* controller =
555 chromeos::ExistingUserController::current_controller();
556 ASSERT_TRUE(controller);
557 controller->LoginAsPublicAccount(user_id_1_);
559 // Wait for the session to start.
560 content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
561 base::Bind(IsSessionStarted)).Wait();
563 // Open a browser window.
564 chrome::NewEmptyWindow(ProfileManager::GetDefaultProfile(),
565 chrome::HOST_DESKTOP_TYPE_ASH);
566 BrowserList* browser_list =
567 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
568 EXPECT_EQ(1U, browser_list->size());
569 Browser* browser = browser_list->get(0);
570 ASSERT_TRUE(browser);
571 BrowserWindow* browser_window = browser->window();
572 ASSERT_TRUE(browser_window);
573 chrome::EndKeepAlive();
575 // Verify that an attempt to enter fullscreen mode is denied.
576 EXPECT_FALSE(browser_window->IsFullscreen());
577 chrome::ToggleFullscreenMode(browser);
578 EXPECT_FALSE(browser_window->IsFullscreen());
581 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsUncached) {
582 // Make it possible to force-install a hosted app and an extension.
583 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
584 TestingUpdateManifestProvider testing_update_manifest_provider(
586 testing_update_manifest_provider.AddUpdate(
589 embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath));
590 testing_update_manifest_provider.AddUpdate(
592 kGoodExtensionVersion,
593 embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath));
594 embedded_test_server()->RegisterRequestHandler(
595 base::Bind(&TestingUpdateManifestProvider::HandleRequest,
596 base::Unretained(&testing_update_manifest_provider)));
598 // Specify policy to force-install the hosted app and the extension.
599 em::StringList* forcelist = device_local_account_policy_.payload()
600 .mutable_extensioninstallforcelist()->mutable_value();
601 forcelist->add_entries(base::StringPrintf(
604 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
605 forcelist->add_entries(base::StringPrintf(
608 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
610 UploadAndInstallDeviceLocalAccountPolicy();
611 AddPublicSessionToDevicePolicy(kAccountId1);
613 // This observes the display name becoming available as this indicates
614 // device-local account policy is fully loaded, which is a prerequisite for
616 content::WindowedNotificationObserver(
617 chrome::NOTIFICATION_USER_LIST_CHANGED,
618 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
620 // Wait for the login UI to be ready.
621 chromeos::LoginDisplayHostImpl* host =
622 reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
623 chromeos::LoginDisplayHostImpl::default_host());
625 chromeos::OobeUI* oobe_ui = host->GetOobeUI();
626 ASSERT_TRUE(oobe_ui);
627 base::RunLoop run_loop;
628 const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
632 // Ensure that the browser stays alive, even though no windows are opened
633 // during session start.
634 chrome::StartKeepAlive();
636 // Start listening for app/extension installation results.
637 content::WindowedNotificationObserver hosted_app_observer(
638 chrome::NOTIFICATION_EXTENSION_INSTALLED,
639 base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
640 content::WindowedNotificationObserver extension_observer(
641 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
642 base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
644 // Start login into the device-local account.
645 host->StartSignInScreen();
646 chromeos::ExistingUserController* controller =
647 chromeos::ExistingUserController::current_controller();
648 ASSERT_TRUE(controller);
649 controller->LoginAsPublicAccount(user_id_1_);
651 // Wait for the hosted app installation to succeed and the extension
652 // installation to fail (because hosted apps are whitelisted for use in
653 // device-local accounts and extensions are not).
654 hosted_app_observer.Wait();
655 extension_observer.Wait();
657 // Verify that the hosted app was installed.
658 Profile* profile = ProfileManager::GetDefaultProfile();
659 ASSERT_TRUE(profile);
660 ExtensionService* extension_service =
661 extensions::ExtensionSystem::Get(profile)->extension_service();
662 EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
664 // Verify that the extension was not installed.
665 EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
667 // Verify that the app was copied to the account's extension cache.
668 base::FilePath test_dir;
669 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
670 EXPECT_TRUE(ContentsEqual(
671 GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion),
672 test_dir.Append(kHostedAppCRXPath)));
674 // Verify that the extension was not copied to the account's extension cache.
675 EXPECT_FALSE(PathExists(GetCacheCRXFile(
676 kAccountId1, kGoodExtensionID, kGoodExtensionVersion)));
679 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsCached) {
680 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
682 // Pre-populate the device local account's extension cache with a hosted app
684 EXPECT_TRUE(file_util::CreateDirectory(
685 GetCacheDirectoryForAccountID(kAccountId1)));
686 base::FilePath test_dir;
687 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
688 const base::FilePath cached_hosted_app =
689 GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion);
690 EXPECT_TRUE(CopyFile(test_dir.Append(kHostedAppCRXPath),
692 const base::FilePath cached_extension =
693 GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion);
694 EXPECT_TRUE(CopyFile(test_dir.Append(kGoodExtensionCRXPath),
697 // Specify policy to force-install the hosted app.
698 em::StringList* forcelist = device_local_account_policy_.payload()
699 .mutable_extensioninstallforcelist()->mutable_value();
700 forcelist->add_entries(base::StringPrintf(
703 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
704 forcelist->add_entries(base::StringPrintf(
707 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
709 UploadAndInstallDeviceLocalAccountPolicy();
710 AddPublicSessionToDevicePolicy(kAccountId1);
712 // This observes the display name becoming available as this indicates
713 // device-local account policy is fully loaded, which is a prerequisite for
715 content::WindowedNotificationObserver(
716 chrome::NOTIFICATION_USER_LIST_CHANGED,
717 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
719 // Wait for the login UI to be ready.
720 chromeos::LoginDisplayHostImpl* host =
721 reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
722 chromeos::LoginDisplayHostImpl::default_host());
724 chromeos::OobeUI* oobe_ui = host->GetOobeUI();
725 ASSERT_TRUE(oobe_ui);
726 base::RunLoop run_loop;
727 const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
731 // Ensure that the browser stays alive, even though no windows are opened
732 // during session start.
733 chrome::StartKeepAlive();
735 // Start listening for app/extension installation results.
736 content::WindowedNotificationObserver hosted_app_observer(
737 chrome::NOTIFICATION_EXTENSION_INSTALLED,
738 base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
739 content::WindowedNotificationObserver extension_observer(
740 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
741 base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
743 // Start login into the device-local account.
744 host->StartSignInScreen();
745 chromeos::ExistingUserController* controller =
746 chromeos::ExistingUserController::current_controller();
747 ASSERT_TRUE(controller);
748 controller->LoginAsPublicAccount(user_id_1_);
750 // Wait for the hosted app installation to succeed and the extension
751 // installation to fail.
752 hosted_app_observer.Wait();
753 extension_observer.Wait();
755 // Verify that the hosted app was installed.
756 Profile* profile = ProfileManager::GetDefaultProfile();
757 ASSERT_TRUE(profile);
758 ExtensionService* extension_service =
759 extensions::ExtensionSystem::Get(profile)->extension_service();
760 EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
762 // Verify that the extension was not installed.
763 EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
765 // Verify that the app is still in the account's extension cache.
766 EXPECT_TRUE(PathExists(cached_hosted_app));
768 // Verify that the extension was removed from the account's extension cache.
769 EXPECT_FALSE(PathExists(cached_extension));
772 class TermsOfServiceTest : public DeviceLocalAccountTest,
773 public testing::WithParamInterface<bool> {
776 IN_PROC_BROWSER_TEST_P(TermsOfServiceTest, TermsOfServiceScreen) {
777 // Specify Terms of Service URL.
778 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
779 device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
780 embedded_test_server()->GetURL(
782 (GetParam() ? kExistentTermsOfServicePath
783 : kNonexistentTermsOfServicePath)).spec());
784 UploadAndInstallDeviceLocalAccountPolicy();
785 AddPublicSessionToDevicePolicy(kAccountId1);
787 // Wait for the device-local account policy to be fully loaded.
788 content::WindowedNotificationObserver(
789 chrome::NOTIFICATION_USER_LIST_CHANGED,
790 base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
792 // Wait for the login UI to be ready.
793 chromeos::LoginDisplayHostImpl* host =
794 reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
795 chromeos::LoginDisplayHostImpl::default_host());
797 chromeos::OobeUI* oobe_ui = host->GetOobeUI();
798 ASSERT_TRUE(oobe_ui);
799 base::RunLoop oobe_ui_wait_run_loop;
800 const bool oobe_ui_ready =
801 oobe_ui->IsJSReady(oobe_ui_wait_run_loop.QuitClosure());
803 oobe_ui_wait_run_loop.Run();
805 // Start login into the device-local account.
806 host->StartSignInScreen();
807 chromeos::ExistingUserController* controller =
808 chromeos::ExistingUserController::current_controller();
809 ASSERT_TRUE(controller);
810 controller->LoginAsPublicAccount(user_id_1_);
812 // Set up an observer that will quit the message loop when login has succeeded
813 // and the first wizard screen, if any, is being shown.
814 base::RunLoop login_wait_run_loop;
815 chromeos::MockConsumer login_status_consumer;
816 EXPECT_CALL(login_status_consumer, OnLoginSuccess(_))
818 .WillOnce(InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
820 // Spin the loop until the observer fires. Then, unregister the observer.
821 controller->set_login_status_consumer(&login_status_consumer);
822 login_wait_run_loop.Run();
823 controller->set_login_status_consumer(NULL);
825 // Verify that the Terms of Service screen is being shown.
826 chromeos::WizardController* wizard_controller =
827 chromeos::WizardController::default_controller();
828 ASSERT_TRUE(wizard_controller);
829 ASSERT_TRUE(wizard_controller->current_screen());
830 EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
831 wizard_controller->current_screen()->GetName());
833 // Wait for the Terms of Service to finish downloading, then get the status of
834 // the screen's UI elements.
835 chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView();
836 ASSERT_TRUE(web_ui_login_view);
837 content::WebUI* web_ui = web_ui_login_view->GetWebUI();
839 content::WebContents* contents = web_ui->GetWebContents();
840 ASSERT_TRUE(contents);
842 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents,
843 "var screen = document.getElementById('terms-of-service');"
844 "function SendReplyIfDownloadDone() {"
845 " if (screen.classList.contains('tos-loading'))"
848 " status.heading = document.getElementById('tos-heading').textContent;"
849 " status.subheading ="
850 " document.getElementById('tos-subheading').textContent;"
851 " status.contentHeading ="
852 " document.getElementById('tos-content-heading').textContent;"
854 " document.getElementById('tos-content-main').textContent;"
855 " status.error = screen.classList.contains('error');"
856 " status.acceptEnabled ="
857 " !document.getElementById('tos-accept-button').disabled;"
858 " domAutomationController.send(JSON.stringify(status));"
859 " observer.disconnect();"
862 "var observer = new MutationObserver(SendReplyIfDownloadDone);"
863 "if (!SendReplyIfDownloadDone()) {"
864 " var options = { attributes: true, attributeFilter: [ 'class' ] };"
865 " observer.observe(screen, options);"
868 scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
869 const base::DictionaryValue* status = NULL;
870 ASSERT_TRUE(value_ptr.get());
871 ASSERT_TRUE(value_ptr->GetAsDictionary(&status));
873 EXPECT_TRUE(status->GetString("heading", &heading));
874 std::string subheading;
875 EXPECT_TRUE(status->GetString("subheading", &subheading));
876 std::string content_heading;
877 EXPECT_TRUE(status->GetString("contentHeading", &content_heading));
879 EXPECT_TRUE(status->GetString("content", &content));
881 EXPECT_TRUE(status->GetBoolean("error", &error));
883 EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled));
885 // Verify that the screen's headings have been set correctly.
887 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING,
888 UTF8ToUTF16(kDomain)),
891 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING,
892 UTF8ToUTF16(kDomain)),
895 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING,
896 UTF8ToUTF16(kDomain)),
900 // The Terms of Service URL was invalid. Verify that the screen is showing
901 // an error and the accept button is disabled.
903 EXPECT_FALSE(accept_enabled);
907 // The Terms of Service URL was valid. Verify that the screen is showing the
908 // downloaded Terms of Service and the accept button is enabled.
909 base::FilePath test_dir;
910 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
911 std::string terms_of_service;
912 ASSERT_TRUE(base::ReadFileToString(
913 test_dir.Append(kExistentTermsOfServicePath), &terms_of_service));
914 EXPECT_EQ(terms_of_service, content);
916 EXPECT_TRUE(accept_enabled);
918 // Click the accept button.
919 ASSERT_TRUE(content::ExecuteScript(contents,
920 "$('tos-accept-button').click();"));
922 // Wait for the session to start.
923 if (!IsSessionStarted()) {
924 content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
925 base::Bind(IsSessionStarted)).Wait();
929 INSTANTIATE_TEST_CASE_P(TermsOfServiceTestInstance,
930 TermsOfServiceTest, testing::Bool());
932 } // namespace policy