device_local_account_browsertest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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.
4
5#include <map>
6#include <string>
7
8#include "base/basictypes.h"
9#include "base/bind.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/json/json_reader.h"
16#include "base/memory/scoped_ptr.h"
17#include "base/message_loop/message_loop.h"
18#include "base/path_service.h"
19#include "base/run_loop.h"
20#include "base/strings/string_util.h"
21#include "base/strings/stringprintf.h"
22#include "base/strings/utf_string_conversions.h"
23#include "base/values.h"
24#include "chrome/browser/browser_process.h"
25#include "chrome/browser/chrome_notification_types.h"
26#include "chrome/browser/chromeos/login/existing_user_controller.h"
27#include "chrome/browser/chromeos/login/login_display_host.h"
28#include "chrome/browser/chromeos/login/login_display_host_impl.h"
29#include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
30#include "chrome/browser/chromeos/login/screens/wizard_screen.h"
31#include "chrome/browser/chromeos/login/user.h"
32#include "chrome/browser/chromeos/login/user_manager.h"
33#include "chrome/browser/chromeos/login/webui_login_view.h"
34#include "chrome/browser/chromeos/login/wizard_controller.h"
35#include "chrome/browser/chromeos/policy/device_local_account.h"
36#include "chrome/browser/chromeos/policy/device_policy_builder.h"
37#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
38#include "chrome/browser/extensions/extension_service.h"
39#include "chrome/browser/extensions/extension_system.h"
40#include "chrome/browser/lifetime/application_lifetime.h"
41#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
42#include "chrome/browser/policy/cloud/policy_builder.h"
43#include "chrome/browser/policy/policy_service.h"
44#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
45#include "chrome/browser/policy/test/local_policy_test_server.h"
46#include "chrome/browser/prefs/session_startup_pref.h"
47#include "chrome/browser/profiles/profile.h"
48#include "chrome/browser/profiles/profile_manager.h"
49#include "chrome/browser/ui/browser.h"
50#include "chrome/browser/ui/browser_commands.h"
51#include "chrome/browser/ui/browser_finder.h"
52#include "chrome/browser/ui/browser_list.h"
53#include "chrome/browser/ui/browser_window.h"
54#include "chrome/browser/ui/host_desktop.h"
55#include "chrome/browser/ui/tabs/tab_strip_model.h"
56#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
57#include "chrome/common/chrome_paths.h"
58#include "chrome/common/chrome_switches.h"
59#include "chrome/common/extensions/extension.h"
60#include "chromeos/chromeos_switches.h"
61#include "chromeos/dbus/cryptohome_client.h"
62#include "chromeos/dbus/dbus_method_call_status.h"
63#include "chromeos/dbus/fake_session_manager_client.h"
64#include "chromeos/dbus/session_manager_client.h"
65#include "content/public/browser/notification_details.h"
66#include "content/public/browser/notification_source.h"
67#include "content/public/browser/web_contents.h"
68#include "content/public/browser/web_ui.h"
69#include "content/public/test/browser_test_utils.h"
70#include "content/public/test/test_utils.h"
71#include "crypto/rsa_private_key.h"
72#include "grit/chromium_strings.h"
73#include "grit/generated_resources.h"
74#include "net/base/url_util.h"
75#include "net/http/http_status_code.h"
76#include "net/test/embedded_test_server/embedded_test_server.h"
77#include "net/test/embedded_test_server/http_request.h"
78#include "net/test/embedded_test_server/http_response.h"
79#include "testing/gmock/include/gmock/gmock.h"
80#include "third_party/cros_system_api/dbus/service_constants.h"
81#include "ui/base/l10n/l10n_util.h"
82#include "url/gurl.h"
83
84namespace em = enterprise_management;
85
86using testing::InvokeWithoutArgs;
87using testing::Return;
88using testing::_;
89
90namespace policy {
91
92namespace {
93
94const char kDomain[] = "example.com";
95const char kAccountId1[] = "dla1@example.com";
96const char kAccountId2[] = "dla2@example.com";
97const char kDisplayName[] = "display name";
98const char* kStartupURLs[] = {
99  "chrome://policy",
100  "chrome://about",
101};
102const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt";
103const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt";
104const char kRelativeUpdateURL[] = "/service/update2/crx";
105const char kUpdateManifestHeader[] =
106    "<?xml version='1.0' encoding='UTF-8'?>\n"
107    "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n";
108const char kUpdateManifestTemplate[] =
109    "  <app appid='%s'>\n"
110    "    <updatecheck codebase='%s' version='%s' />\n"
111    "  </app>\n";
112const char kUpdateManifestFooter[] =
113    "</gupdate>\n";
114const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
115const char kHostedAppCRXPath[] = "extensions/hosted_app.crx";
116const char kHostedAppVersion[] = "0.1";
117const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
118const char kGoodExtensionPath[] = "extensions/good.crx";
119const char kGoodExtensionVersion[] = "1.0";
120
121// Helper that serves extension update manifests to Chrome.
122class TestingUpdateManifestProvider {
123 public:
124
125  // Update manifests will be served at |relative_update_url|.
126  explicit TestingUpdateManifestProvider(
127      const std::string& relative_update_url);
128  ~TestingUpdateManifestProvider();
129
130  // When an update manifest is requested for the given extension |id|, indicate
131  // that |version| of the extension can be downloaded at |crx_url|.
132  void AddUpdate(const std::string& id,
133                 const std::string& version,
134                 const GURL& crx_url);
135
136  // This method must be registered with the test's EmbeddedTestServer to start
137  // serving update manifests.
138  scoped_ptr<net::test_server::HttpResponse> HandleRequest(
139      const net::test_server::HttpRequest& request);
140
141 private:
142  struct Update {
143   public:
144    Update(const std::string& version, const GURL& crx_url);
145    Update();
146
147    std::string version;
148    GURL crx_url;
149  };
150  typedef std::map<std::string, Update> UpdateMap;
151  UpdateMap updates_;
152
153  const std::string relative_update_url_;
154
155  DISALLOW_COPY_AND_ASSIGN(TestingUpdateManifestProvider);
156};
157
158TestingUpdateManifestProvider::Update::Update(const std::string& version,
159                                              const GURL& crx_url)
160    : version(version),
161      crx_url(crx_url) {
162}
163
164TestingUpdateManifestProvider::Update::Update() {
165}
166
167TestingUpdateManifestProvider::TestingUpdateManifestProvider(
168    const std::string& relative_update_url)
169    : relative_update_url_(relative_update_url) {
170}
171
172TestingUpdateManifestProvider::~TestingUpdateManifestProvider() {
173}
174
175void TestingUpdateManifestProvider::AddUpdate(const std::string& id,
176                                              const std::string& version,
177                                              const GURL& crx_url) {
178  updates_[id] = Update(version, crx_url);
179}
180
181scoped_ptr<net::test_server::HttpResponse>
182    TestingUpdateManifestProvider::HandleRequest(
183        const net::test_server::HttpRequest& request) {
184  const GURL url("http://localhost" + request.relative_url);
185  if (url.path() != relative_update_url_)
186    return scoped_ptr<net::test_server::HttpResponse>();
187
188  std::string content = kUpdateManifestHeader;
189  for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
190    if (it.GetKey() != "x")
191      continue;
192    // Extract the extension id from the subquery. Since GetValueForKeyInQuery()
193    // expects a complete URL, dummy scheme and host must be prepended.
194    std::string id;
195    net::GetValueForKeyInQuery(GURL("http://dummy?" + it.GetUnescapedValue()),
196                               "id", &id);
197    UpdateMap::const_iterator entry = updates_.find(id);
198    if (entry != updates_.end()) {
199      content += base::StringPrintf(kUpdateManifestTemplate,
200                                    id.c_str(),
201                                    entry->second.crx_url.spec().c_str(),
202                                    entry->second.version.c_str());
203    }
204  }
205  content += kUpdateManifestFooter;
206  scoped_ptr<net::test_server::BasicHttpResponse>
207      http_response(new net::test_server::BasicHttpResponse);
208  http_response->set_code(net::HTTP_OK);
209  http_response->set_content(content);
210  http_response->set_content_type("text/xml");
211  return http_response.PassAs<net::test_server::HttpResponse>();
212}
213
214bool DoesInstallSuccessReferToId(const std::string& id,
215                                 const content::NotificationSource& source,
216                                 const content::NotificationDetails& details) {
217  return content::Details<const extensions::InstalledExtensionInfo>(details)->
218      extension->id() == id;
219}
220
221bool DoesInstallFailureReferToId(const std::string& id,
222                                 const content::NotificationSource& source,
223                                 const content::NotificationDetails& details) {
224  return content::Details<const string16>(details)->find(UTF8ToUTF16(id)) !=
225      string16::npos;
226}
227
228}  // namespace
229
230class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest {
231 protected:
232  DeviceLocalAccountTest()
233      : user_id_1_(GenerateDeviceLocalAccountUserId(
234            kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
235        user_id_2_(GenerateDeviceLocalAccountUserId(
236            kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)) {}
237
238  virtual ~DeviceLocalAccountTest() {}
239
240  virtual void SetUp() OVERRIDE {
241    // Configure and start the test server.
242    scoped_ptr<crypto::RSAPrivateKey> signing_key(
243        PolicyBuilder::CreateTestSigningKey());
244    ASSERT_TRUE(test_server_.SetSigningKey(signing_key.get()));
245    signing_key.reset();
246    test_server_.RegisterClient(PolicyBuilder::kFakeToken,
247                                PolicyBuilder::kFakeDeviceId);
248    ASSERT_TRUE(test_server_.Start());
249
250    DevicePolicyCrosBrowserTest::SetUp();
251  }
252
253  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
254    command_line->AppendSwitch(chromeos::switches::kLoginManager);
255    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
256    command_line->AppendSwitchASCII(
257        switches::kDeviceManagementUrl, test_server_.GetServiceURL().spec());
258    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
259  }
260
261  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
262    DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
263
264    // Clear command-line arguments (but keep command-line switches) so the
265    // startup pages policy takes effect.
266    CommandLine* command_line = CommandLine::ForCurrentProcess();
267    CommandLine::StringVector argv(command_line->argv());
268    argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(),
269               argv.end());
270    command_line->InitFromArgv(argv);
271
272    InstallOwnerKey();
273    MarkAsEnterpriseOwned();
274
275    InitializePolicy();
276  }
277
278  virtual void CleanUpOnMainThread() OVERRIDE {
279    // This shuts down the login UI.
280    base::MessageLoop::current()->PostTask(FROM_HERE,
281                                           base::Bind(&chrome::AttemptExit));
282    base::RunLoop().RunUntilIdle();
283  }
284
285  void InitializePolicy() {
286    device_policy()->policy_data().set_public_key_version(1);
287    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
288    proto.mutable_show_user_names()->set_show_user_names(true);
289
290    device_local_account_policy_.policy_data().set_policy_type(
291        dm_protocol::kChromePublicAccountPolicyType);
292    device_local_account_policy_.policy_data().set_username(kAccountId1);
293    device_local_account_policy_.policy_data().set_settings_entity_id(
294        kAccountId1);
295    device_local_account_policy_.policy_data().set_public_key_version(1);
296    device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
297        kDisplayName);
298  }
299
300  void BuildDeviceLocalAccountPolicy() {
301    device_local_account_policy_.SetDefaultSigningKey();
302    device_local_account_policy_.Build();
303  }
304
305  void UploadDeviceLocalAccountPolicy() {
306    BuildDeviceLocalAccountPolicy();
307    ASSERT_TRUE(session_manager_client()->device_local_account_policy(
308        kAccountId1).empty());
309    test_server_.UpdatePolicy(
310        dm_protocol::kChromePublicAccountPolicyType, kAccountId1,
311        device_local_account_policy_.payload().SerializeAsString());
312  }
313
314  void UploadAndInstallDeviceLocalAccountPolicy() {
315    UploadDeviceLocalAccountPolicy();
316    session_manager_client()->set_device_local_account_policy(
317        kAccountId1, device_local_account_policy_.GetBlob());
318  }
319
320  void AddPublicSessionToDevicePolicy(const std::string& username) {
321    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
322    em::DeviceLocalAccountInfoProto* account =
323        proto.mutable_device_local_accounts()->add_account();
324    account->set_account_id(username);
325    account->set_type(
326        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
327    RefreshDevicePolicy();
328    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
329                              std::string(), proto.SerializeAsString());
330  }
331
332  void CheckPublicSessionPresent(const std::string& id) {
333    const chromeos::User* user = chromeos::UserManager::Get()->FindUser(id);
334    ASSERT_TRUE(user);
335    EXPECT_EQ(id, user->email());
336    EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType());
337  }
338
339  const std::string user_id_1_;
340  const std::string user_id_2_;
341
342  UserPolicyBuilder device_local_account_policy_;
343  LocalPolicyTestServer test_server_;
344};
345
346static bool IsKnownUser(const std::string& account_id) {
347  return chromeos::UserManager::Get()->IsKnownUser(account_id);
348}
349
350IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) {
351  AddPublicSessionToDevicePolicy(kAccountId1);
352  AddPublicSessionToDevicePolicy(kAccountId2);
353
354  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
355                                        base::Bind(&IsKnownUser, user_id_1_))
356      .Wait();
357  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
358                                        base::Bind(&IsKnownUser, user_id_2_))
359      .Wait();
360
361  CheckPublicSessionPresent(user_id_1_);
362  CheckPublicSessionPresent(user_id_2_);
363}
364
365static bool DisplayNameMatches(const std::string& account_id,
366                               const std::string& display_name) {
367  const chromeos::User* user =
368      chromeos::UserManager::Get()->FindUser(account_id);
369  if (!user || user->display_name().empty())
370    return false;
371  EXPECT_EQ(UTF8ToUTF16(display_name), user->display_name());
372  return true;
373}
374
375IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
376  UploadAndInstallDeviceLocalAccountPolicy();
377  AddPublicSessionToDevicePolicy(kAccountId1);
378
379  content::WindowedNotificationObserver(
380      chrome::NOTIFICATION_USER_LIST_CHANGED,
381      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
382}
383
384IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) {
385  UploadDeviceLocalAccountPolicy();
386  AddPublicSessionToDevicePolicy(kAccountId1);
387
388  // Policy for the account is not installed in session_manager_client. Because
389  // of this, the presence of the display name (which comes from policy) can be
390  // used as a signal that indicates successful policy download.
391  content::WindowedNotificationObserver(
392      chrome::NOTIFICATION_USER_LIST_CHANGED,
393      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
394
395  // Sanity check: The policy should be present now.
396  ASSERT_FALSE(session_manager_client()->device_local_account_policy(
397      kAccountId1).empty());
398}
399
400static bool IsNotKnownUser(const std::string& account_id) {
401  return !IsKnownUser(account_id);
402}
403
404IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) {
405  AddPublicSessionToDevicePolicy(kAccountId1);
406  AddPublicSessionToDevicePolicy(kAccountId2);
407
408  // Wait until the login screen is up.
409  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
410                                        base::Bind(&IsKnownUser, user_id_1_))
411      .Wait();
412  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
413                                        base::Bind(&IsKnownUser, user_id_2_))
414      .Wait();
415
416  // Update policy to remove kAccountId2.
417  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
418  proto.mutable_device_local_accounts()->clear_account();
419  AddPublicSessionToDevicePolicy(kAccountId1);
420
421  em::ChromeDeviceSettingsProto policy;
422  policy.mutable_show_user_names()->set_show_user_names(true);
423  em::DeviceLocalAccountInfoProto* account1 =
424      policy.mutable_device_local_accounts()->add_account();
425  account1->set_account_id(kAccountId1);
426  account1->set_type(
427      em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
428
429  test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(),
430                            policy.SerializeAsString());
431  g_browser_process->policy_service()->RefreshPolicies(base::Closure());
432
433  // Make sure the second device-local account disappears.
434  content::WindowedNotificationObserver(
435      chrome::NOTIFICATION_USER_LIST_CHANGED,
436      base::Bind(&IsNotKnownUser, user_id_2_)).Wait();
437}
438
439static bool IsSessionStarted() {
440  return chromeos::UserManager::Get()->IsSessionStarted();
441}
442
443IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) {
444  // Specify startup pages.
445  device_local_account_policy_.payload().mutable_restoreonstartup()->set_value(
446      SessionStartupPref::kPrefValueURLs);
447  em::StringListPolicyProto* startup_urls_proto =
448      device_local_account_policy_.payload().mutable_restoreonstartupurls();
449  for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
450    startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
451  UploadAndInstallDeviceLocalAccountPolicy();
452  AddPublicSessionToDevicePolicy(kAccountId1);
453
454  // This observes the display name becoming available as this indicates
455  // device-local account policy is fully loaded, which is a prerequisite for
456  // successful login.
457  content::WindowedNotificationObserver(
458      chrome::NOTIFICATION_USER_LIST_CHANGED,
459      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
460
461  // Wait for the login UI to be ready.
462  chromeos::LoginDisplayHostImpl* host =
463      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
464          chromeos::LoginDisplayHostImpl::default_host());
465  ASSERT_TRUE(host);
466  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
467  ASSERT_TRUE(oobe_ui);
468  base::RunLoop run_loop;
469  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
470  if (!oobe_ui_ready)
471    run_loop.Run();
472
473  // Start login into the device-local account.
474  host->StartSignInScreen();
475  chromeos::ExistingUserController* controller =
476      chromeos::ExistingUserController::current_controller();
477  ASSERT_TRUE(controller);
478  controller->LoginAsPublicAccount(user_id_1_);
479
480  // Wait for the session to start.
481  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
482                                        base::Bind(IsSessionStarted)).Wait();
483
484  // Check that the startup pages specified in policy were opened.
485  BrowserList* browser_list =
486    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
487  EXPECT_EQ(1U, browser_list->size());
488  Browser* browser = browser_list->get(0);
489  ASSERT_TRUE(browser);
490
491  TabStripModel* tabs = browser->tab_strip_model();
492  ASSERT_TRUE(tabs);
493  int expected_tab_count = static_cast<int>(arraysize(kStartupURLs));
494  EXPECT_EQ(expected_tab_count, tabs->count());
495  for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) {
496    EXPECT_EQ(GURL(kStartupURLs[i]),
497              tabs->GetWebContentsAt(i)->GetVisibleURL());
498  }
499}
500
501IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) {
502  UploadAndInstallDeviceLocalAccountPolicy();
503  AddPublicSessionToDevicePolicy(kAccountId1);
504
505  // This observes the display name becoming available as this indicates
506  // device-local account policy is fully loaded, which is a prerequisite for
507  // successful login.
508  content::WindowedNotificationObserver(
509      chrome::NOTIFICATION_USER_LIST_CHANGED,
510      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
511
512  // Wait for the login UI to be ready.
513  chromeos::LoginDisplayHostImpl* host =
514      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
515          chromeos::LoginDisplayHostImpl::default_host());
516  ASSERT_TRUE(host);
517  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
518  ASSERT_TRUE(oobe_ui);
519  base::RunLoop run_loop;
520  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
521  if (!oobe_ui_ready)
522    run_loop.Run();
523
524  // Ensure that the browser stays alive, even though no windows are opened
525  // during session start.
526  chrome::StartKeepAlive();
527
528  // Start login into the device-local account.
529  host->StartSignInScreen();
530  chromeos::ExistingUserController* controller =
531      chromeos::ExistingUserController::current_controller();
532  ASSERT_TRUE(controller);
533  controller->LoginAsPublicAccount(user_id_1_);
534
535  // Wait for the session to start.
536  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
537                                        base::Bind(IsSessionStarted)).Wait();
538
539  // Open a browser window.
540  chrome::NewEmptyWindow(ProfileManager::GetDefaultProfile(),
541                         chrome::HOST_DESKTOP_TYPE_ASH);
542  BrowserList* browser_list =
543    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
544  EXPECT_EQ(1U, browser_list->size());
545  Browser* browser = browser_list->get(0);
546  ASSERT_TRUE(browser);
547  BrowserWindow* browser_window = browser->window();
548  ASSERT_TRUE(browser_window);
549  chrome::EndKeepAlive();
550
551  // Verify that an attempt to enter fullscreen mode is denied.
552  EXPECT_FALSE(browser_window->IsFullscreen());
553  chrome::ToggleFullscreenMode(browser);
554  EXPECT_FALSE(browser_window->IsFullscreen());
555}
556
557IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionWhitelist) {
558  // Make it possible to force-install a hosted app and an extension.
559  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
560  TestingUpdateManifestProvider testing_update_manifest_provider(
561      kRelativeUpdateURL);
562  testing_update_manifest_provider.AddUpdate(
563      kHostedAppID,
564      kHostedAppVersion,
565      embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath));
566  testing_update_manifest_provider.AddUpdate(
567      kGoodExtensionID,
568      kGoodExtensionVersion,
569      embedded_test_server()->GetURL(std::string("/") + kGoodExtensionPath));
570  embedded_test_server()->RegisterRequestHandler(
571      base::Bind(&TestingUpdateManifestProvider::HandleRequest,
572                 base::Unretained(&testing_update_manifest_provider)));
573
574  // Specify policy to force-install the hosted app and the extension.
575  em::StringList* forcelist = device_local_account_policy_.payload()
576      .mutable_extensioninstallforcelist()->mutable_value();
577  forcelist->add_entries(base::StringPrintf(
578      "%s;%s",
579      kHostedAppID,
580      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
581  forcelist->add_entries(base::StringPrintf(
582      "%s;%s",
583      kGoodExtensionID,
584      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
585
586  UploadAndInstallDeviceLocalAccountPolicy();
587  AddPublicSessionToDevicePolicy(kAccountId1);
588
589  // This observes the display name becoming available as this indicates
590  // device-local account policy is fully loaded, which is a prerequisite for
591  // successful login.
592  content::WindowedNotificationObserver(
593      chrome::NOTIFICATION_USER_LIST_CHANGED,
594      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
595
596  // Wait for the login UI to be ready.
597  chromeos::LoginDisplayHostImpl* host =
598      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
599          chromeos::LoginDisplayHostImpl::default_host());
600  ASSERT_TRUE(host);
601  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
602  ASSERT_TRUE(oobe_ui);
603  base::RunLoop run_loop;
604  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
605  if (!oobe_ui_ready)
606    run_loop.Run();
607
608  // Ensure that the browser stays alive, even though no windows are opened
609  // during session start.
610  chrome::StartKeepAlive();
611
612  // Start listening for app/extension installation results.
613  content::WindowedNotificationObserver hosted_app_observer(
614      chrome::NOTIFICATION_EXTENSION_INSTALLED,
615      base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
616  content::WindowedNotificationObserver extension_observer(
617      chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
618      base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
619
620  // Start login into the device-local account.
621  host->StartSignInScreen();
622  chromeos::ExistingUserController* controller =
623      chromeos::ExistingUserController::current_controller();
624  ASSERT_TRUE(controller);
625  controller->LoginAsPublicAccount(user_id_1_);
626
627  // Wait for the hosted app installation to succeed and the extension
628  // installation to fail.
629  hosted_app_observer.Wait();
630  extension_observer.Wait();
631
632  // Verify that the hosted app was installed.
633  Profile* profile = ProfileManager::GetDefaultProfile();
634  ASSERT_TRUE(profile);
635  ExtensionService* extension_service =
636      extensions::ExtensionSystem::Get(profile)->extension_service();
637  EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
638
639  // Verify that the extension was not installed.
640  EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
641}
642
643class TermsOfServiceTest : public DeviceLocalAccountTest,
644                           public testing::WithParamInterface<bool> {
645};
646
647IN_PROC_BROWSER_TEST_P(TermsOfServiceTest, TermsOfServiceScreen) {
648  // Specify Terms of Service URL.
649  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
650  device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
651      embedded_test_server()->GetURL(
652            std::string("/") +
653                (GetParam() ? kExistentTermsOfServicePath
654                            : kNonexistentTermsOfServicePath)).spec());
655  UploadAndInstallDeviceLocalAccountPolicy();
656  AddPublicSessionToDevicePolicy(kAccountId1);
657
658  // Wait for the device-local account policy to be fully loaded.
659  content::WindowedNotificationObserver(
660      chrome::NOTIFICATION_USER_LIST_CHANGED,
661      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
662
663  // Wait for the login UI to be ready.
664  chromeos::LoginDisplayHostImpl* host =
665      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
666          chromeos::LoginDisplayHostImpl::default_host());
667  ASSERT_TRUE(host);
668  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
669  ASSERT_TRUE(oobe_ui);
670  base::RunLoop oobe_ui_wait_run_loop;
671  const bool oobe_ui_ready =
672      oobe_ui->IsJSReady(oobe_ui_wait_run_loop.QuitClosure());
673  if (!oobe_ui_ready)
674    oobe_ui_wait_run_loop.Run();
675
676  // Start login into the device-local account.
677  host->StartSignInScreen();
678  chromeos::ExistingUserController* controller =
679      chromeos::ExistingUserController::current_controller();
680  ASSERT_TRUE(controller);
681  controller->LoginAsPublicAccount(user_id_1_);
682
683  // Set up an observer that will quit the message loop when login has succeeded
684  // and the first wizard screen, if any, is being shown.
685  base::RunLoop login_wait_run_loop;
686  chromeos::MockConsumer login_status_consumer;
687  EXPECT_CALL(login_status_consumer, OnLoginSuccess(_, false, false))
688      .Times(1)
689      .WillOnce(InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
690
691  // Spin the loop until the observer fires. Then, unregister the observer.
692  controller->set_login_status_consumer(&login_status_consumer);
693  login_wait_run_loop.Run();
694  controller->set_login_status_consumer(NULL);
695
696  // Verify that the Terms of Service screen is being shown.
697  chromeos::WizardController* wizard_controller =
698        chromeos::WizardController::default_controller();
699  ASSERT_TRUE(wizard_controller);
700  ASSERT_TRUE(wizard_controller->current_screen());
701  EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
702            wizard_controller->current_screen()->GetName());
703
704  // Wait for the Terms of Service to finish downloading, then get the status of
705  // the screen's UI elements.
706  chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView();
707  ASSERT_TRUE(web_ui_login_view);
708  content::WebUI* web_ui = web_ui_login_view->GetWebUI();
709  ASSERT_TRUE(web_ui);
710  content::WebContents* contents = web_ui->GetWebContents();
711  ASSERT_TRUE(contents);
712  std::string json;
713  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents,
714      "var screen = document.getElementById('terms-of-service');"
715      "function SendReplyIfDownloadDone() {"
716      "  if (screen.classList.contains('tos-loading'))"
717      "    return false;"
718      "  var status = {};"
719      "  status.heading = document.getElementById('tos-heading').textContent;"
720      "  status.subheading ="
721      "      document.getElementById('tos-subheading').textContent;"
722      "  status.contentHeading ="
723      "      document.getElementById('tos-content-heading').textContent;"
724      "  status.content ="
725      "      document.getElementById('tos-content-main').textContent;"
726      "  status.error = screen.classList.contains('error');"
727      "  status.acceptEnabled ="
728      "      !document.getElementById('tos-accept-button').disabled;"
729      "  domAutomationController.send(JSON.stringify(status));"
730      "  observer.disconnect();"
731      "  return true;"
732      "}"
733      "var observer = new MutationObserver(SendReplyIfDownloadDone);"
734      "if (!SendReplyIfDownloadDone()) {"
735      "  var options = { attributes: true, attributeFilter: [ 'class' ] };"
736      "  observer.observe(screen, options);"
737      "}",
738      &json));
739  scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
740  const base::DictionaryValue* status = NULL;
741  ASSERT_TRUE(value_ptr.get());
742  ASSERT_TRUE(value_ptr->GetAsDictionary(&status));
743  std::string heading;
744  EXPECT_TRUE(status->GetString("heading", &heading));
745  std::string subheading;
746  EXPECT_TRUE(status->GetString("subheading", &subheading));
747  std::string content_heading;
748  EXPECT_TRUE(status->GetString("contentHeading", &content_heading));
749  std::string content;
750  EXPECT_TRUE(status->GetString("content", &content));
751  bool error;
752  EXPECT_TRUE(status->GetBoolean("error", &error));
753  bool accept_enabled;
754  EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled));
755
756  // Verify that the screen's headings have been set correctly.
757  EXPECT_EQ(
758      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING,
759                                UTF8ToUTF16(kDomain)),
760      heading);
761  EXPECT_EQ(
762      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING,
763                                UTF8ToUTF16(kDomain)),
764      subheading);
765  EXPECT_EQ(
766      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING,
767                                UTF8ToUTF16(kDomain)),
768      content_heading);
769
770  if (!GetParam()) {
771    // The Terms of Service URL was invalid. Verify that the screen is showing
772    // an error and the accept button is disabled.
773    EXPECT_TRUE(error);
774    EXPECT_FALSE(accept_enabled);
775    return;
776  }
777
778  // The Terms of Service URL was valid. Verify that the screen is showing the
779  // downloaded Terms of Service and the accept button is enabled.
780  base::FilePath test_dir;
781  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
782  std::string terms_of_service;
783  ASSERT_TRUE(base::ReadFileToString(
784      test_dir.Append(kExistentTermsOfServicePath), &terms_of_service));
785  EXPECT_EQ(terms_of_service, content);
786  EXPECT_FALSE(error);
787  EXPECT_TRUE(accept_enabled);
788
789  // Click the accept button.
790  ASSERT_TRUE(content::ExecuteScript(contents,
791                                     "$('tos-accept-button').click();"));
792
793  // Wait for the session to start.
794  if (!IsSessionStarted()) {
795    content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
796                                          base::Bind(IsSessionStarted)).Wait();
797  }
798}
799
800INSTANTIATE_TEST_CASE_P(TermsOfServiceTestInstance,
801                        TermsOfServiceTest, testing::Bool());
802
803}  // namespace policy
804