device_local_account_browsertest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 "apps/app_window_registry.h"
9#include "apps/ui/native_app_window.h"
10#include "ash/shell.h"
11#include "ash/system/chromeos/session/logout_confirmation_controller.h"
12#include "ash/system/chromeos/session/logout_confirmation_dialog.h"
13#include "base/basictypes.h"
14#include "base/bind.h"
15#include "base/bind_helpers.h"
16#include "base/callback.h"
17#include "base/command_line.h"
18#include "base/file_util.h"
19#include "base/files/file_path.h"
20#include "base/files/scoped_temp_dir.h"
21#include "base/json/json_reader.h"
22#include "base/json/json_writer.h"
23#include "base/location.h"
24#include "base/memory/ref_counted.h"
25#include "base/memory/scoped_ptr.h"
26#include "base/message_loop/message_loop.h"
27#include "base/message_loop/message_loop_proxy.h"
28#include "base/path_service.h"
29#include "base/prefs/pref_service.h"
30#include "base/run_loop.h"
31#include "base/sequenced_task_runner.h"
32#include "base/strings/string_number_conversions.h"
33#include "base/strings/string_util.h"
34#include "base/strings/stringprintf.h"
35#include "base/strings/utf_string_conversions.h"
36#include "base/test/scoped_path_override.h"
37#include "base/values.h"
38#include "chrome/browser/browser_process.h"
39#include "chrome/browser/chrome_notification_types.h"
40#include "chrome/browser/chromeos/login/existing_user_controller.h"
41#include "chrome/browser/chromeos/login/login_display_host.h"
42#include "chrome/browser/chromeos/login/login_display_host_impl.h"
43#include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
44#include "chrome/browser/chromeos/login/screens/wizard_screen.h"
45#include "chrome/browser/chromeos/login/user.h"
46#include "chrome/browser/chromeos/login/user_image_manager.h"
47#include "chrome/browser/chromeos/login/user_image_manager_impl.h"
48#include "chrome/browser/chromeos/login/user_image_manager_test_util.h"
49#include "chrome/browser/chromeos/login/user_manager.h"
50#include "chrome/browser/chromeos/login/user_manager_impl.h"
51#include "chrome/browser/chromeos/login/webui_login_view.h"
52#include "chrome/browser/chromeos/login/wizard_controller.h"
53#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
54#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
55#include "chrome/browser/chromeos/policy/device_local_account.h"
56#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
57#include "chrome/browser/chromeos/policy/device_policy_builder.h"
58#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
59#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
60#include "chrome/browser/extensions/crx_installer.h"
61#include "chrome/browser/extensions/extension_service.h"
62#include "chrome/browser/lifetime/application_lifetime.h"
63#include "chrome/browser/policy/profile_policy_connector.h"
64#include "chrome/browser/policy/profile_policy_connector_factory.h"
65#include "chrome/browser/policy/test/local_policy_test_server.h"
66#include "chrome/browser/prefs/session_startup_pref.h"
67#include "chrome/browser/profiles/profile.h"
68#include "chrome/browser/profiles/profile_manager.h"
69#include "chrome/browser/ui/browser.h"
70#include "chrome/browser/ui/browser_commands.h"
71#include "chrome/browser/ui/browser_finder.h"
72#include "chrome/browser/ui/browser_list.h"
73#include "chrome/browser/ui/browser_list_observer.h"
74#include "chrome/browser/ui/browser_window.h"
75#include "chrome/browser/ui/extensions/application_launch.h"
76#include "chrome/browser/ui/host_desktop.h"
77#include "chrome/browser/ui/tabs/tab_strip_model.h"
78#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
79#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
80#include "chrome/common/chrome_paths.h"
81#include "chrome/common/extensions/extension_constants.h"
82#include "chromeos/chromeos_paths.h"
83#include "chromeos/chromeos_switches.h"
84#include "chromeos/dbus/fake_session_manager_client.h"
85#include "components/policy/core/common/cloud/cloud_policy_constants.h"
86#include "components/policy/core/common/cloud/cloud_policy_core.h"
87#include "components/policy/core/common/cloud/cloud_policy_store.h"
88#include "components/policy/core/common/cloud/policy_builder.h"
89#include "components/policy/core/common/external_data_fetcher.h"
90#include "components/policy/core/common/policy_map.h"
91#include "components/policy/core/common/policy_namespace.h"
92#include "components/policy/core/common/policy_service.h"
93#include "components/policy/core/common/policy_switches.h"
94#include "content/public/browser/notification_details.h"
95#include "content/public/browser/notification_service.h"
96#include "content/public/browser/notification_source.h"
97#include "content/public/browser/web_contents.h"
98#include "content/public/browser/web_ui.h"
99#include "content/public/test/browser_test_utils.h"
100#include "content/public/test/test_utils.h"
101#include "crypto/rsa_private_key.h"
102#include "extensions/browser/extension_system.h"
103#include "extensions/browser/management_policy.h"
104#include "extensions/common/extension.h"
105#include "grit/chromium_strings.h"
106#include "grit/generated_resources.h"
107#include "net/base/url_util.h"
108#include "net/http/http_status_code.h"
109#include "net/test/embedded_test_server/embedded_test_server.h"
110#include "net/test/embedded_test_server/http_request.h"
111#include "net/test/embedded_test_server/http_response.h"
112#include "net/url_request/test_url_fetcher_factory.h"
113#include "net/url_request/url_fetcher_delegate.h"
114#include "net/url_request/url_request_status.h"
115#include "policy/policy_constants.h"
116#include "testing/gmock/include/gmock/gmock.h"
117#include "ui/base/l10n/l10n_util.h"
118#include "ui/base/window_open_disposition.h"
119#include "ui/gfx/image/image_skia.h"
120#include "ui/views/widget/widget.h"
121#include "url/gurl.h"
122//#include "third_party/cros_system_api/dbus/service_constants.h"
123
124namespace em = enterprise_management;
125
126using chromeos::LoginScreenContext;
127using testing::InvokeWithoutArgs;
128using testing::Return;
129using testing::_;
130
131namespace policy {
132
133namespace {
134
135const char kDomain[] = "example.com";
136const char kAccountId1[] = "dla1@example.com";
137const char kAccountId2[] = "dla2@example.com";
138const char kDisplayName[] = "display name";
139const char* kStartupURLs[] = {
140  "chrome://policy",
141  "chrome://about",
142};
143const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt";
144const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt";
145const char kRelativeUpdateURL[] = "/service/update2/crx";
146const char kUpdateManifestHeader[] =
147    "<?xml version='1.0' encoding='UTF-8'?>\n"
148    "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n";
149const char kUpdateManifestTemplate[] =
150    "  <app appid='%s'>\n"
151    "    <updatecheck codebase='%s' version='%s' />\n"
152    "  </app>\n";
153const char kUpdateManifestFooter[] =
154    "</gupdate>\n";
155const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi";
156const char kHostedAppCRXPath[] = "extensions/hosted_app.crx";
157const char kHostedAppVersion[] = "1.0.0.0";
158const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
159const char kGoodExtensionCRXPath[] = "extensions/good.crx";
160const char kGoodExtensionVersion[] = "1.0";
161const char kPackagedAppCRXPath[] = "extensions/platform_apps/app_window_2.crx";
162
163const char kExternalData[] = "External data";
164const char kExternalDataURL[] = "http://localhost/external_data";
165
166// Helper that serves extension update manifests to Chrome.
167class TestingUpdateManifestProvider {
168 public:
169  // Update manifests will be served at |relative_update_url|.
170  explicit TestingUpdateManifestProvider(
171      const std::string& relative_update_url);
172  ~TestingUpdateManifestProvider();
173
174  // When an update manifest is requested for the given extension |id|, indicate
175  // that |version| of the extension can be downloaded at |crx_url|.
176  void AddUpdate(const std::string& id,
177                 const std::string& version,
178                 const GURL& crx_url);
179
180  // This method must be registered with the test's EmbeddedTestServer to start
181  // serving update manifests.
182  scoped_ptr<net::test_server::HttpResponse> HandleRequest(
183      const net::test_server::HttpRequest& request);
184
185 private:
186  struct Update {
187   public:
188    Update(const std::string& version, const GURL& crx_url);
189    Update();
190
191    std::string version;
192    GURL crx_url;
193  };
194  typedef std::map<std::string, Update> UpdateMap;
195  UpdateMap updates_;
196
197  const std::string relative_update_url_;
198
199  DISALLOW_COPY_AND_ASSIGN(TestingUpdateManifestProvider);
200};
201
202TestingUpdateManifestProvider::Update::Update(const std::string& version,
203                                              const GURL& crx_url)
204    : version(version),
205      crx_url(crx_url) {
206}
207
208TestingUpdateManifestProvider::Update::Update() {
209}
210
211TestingUpdateManifestProvider::TestingUpdateManifestProvider(
212    const std::string& relative_update_url)
213    : relative_update_url_(relative_update_url) {
214}
215
216TestingUpdateManifestProvider::~TestingUpdateManifestProvider() {
217}
218
219void TestingUpdateManifestProvider::AddUpdate(const std::string& id,
220                                              const std::string& version,
221                                              const GURL& crx_url) {
222  updates_[id] = Update(version, crx_url);
223}
224
225scoped_ptr<net::test_server::HttpResponse>
226    TestingUpdateManifestProvider::HandleRequest(
227        const net::test_server::HttpRequest& request) {
228  const GURL url("http://localhost" + request.relative_url);
229  if (url.path() != relative_update_url_)
230    return scoped_ptr<net::test_server::HttpResponse>();
231
232  std::string content = kUpdateManifestHeader;
233  for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
234    if (it.GetKey() != "x")
235      continue;
236    // Extract the extension id from the subquery. Since GetValueForKeyInQuery()
237    // expects a complete URL, dummy scheme and host must be prepended.
238    std::string id;
239    net::GetValueForKeyInQuery(GURL("http://dummy?" + it.GetUnescapedValue()),
240                               "id", &id);
241    UpdateMap::const_iterator entry = updates_.find(id);
242    if (entry != updates_.end()) {
243      content += base::StringPrintf(kUpdateManifestTemplate,
244                                    id.c_str(),
245                                    entry->second.crx_url.spec().c_str(),
246                                    entry->second.version.c_str());
247    }
248  }
249  content += kUpdateManifestFooter;
250  scoped_ptr<net::test_server::BasicHttpResponse>
251      http_response(new net::test_server::BasicHttpResponse);
252  http_response->set_code(net::HTTP_OK);
253  http_response->set_content(content);
254  http_response->set_content_type("text/xml");
255  return http_response.PassAs<net::test_server::HttpResponse>();
256}
257
258bool DoesInstallSuccessReferToId(const std::string& id,
259                                 const content::NotificationSource& source,
260                                 const content::NotificationDetails& details) {
261  return content::Details<const extensions::InstalledExtensionInfo>(details)->
262      extension->id() == id;
263}
264
265bool DoesInstallFailureReferToId(const std::string& id,
266                                 const content::NotificationSource& source,
267                                 const content::NotificationDetails& details) {
268  return content::Details<const base::string16>(details)->
269      find(base::UTF8ToUTF16(id)) != base::string16::npos;
270}
271
272scoped_ptr<net::FakeURLFetcher> RunCallbackAndReturnFakeURLFetcher(
273    scoped_refptr<base::SequencedTaskRunner> task_runner,
274    const base::Closure& callback,
275    const GURL& url,
276    net::URLFetcherDelegate* delegate,
277    const std::string& response_data,
278    net::HttpStatusCode response_code,
279    net::URLRequestStatus::Status status) {
280  task_runner->PostTask(FROM_HERE, callback);
281  return make_scoped_ptr(new net::FakeURLFetcher(
282      url, delegate, response_data, response_code, status));
283}
284
285}  // namespace
286
287class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest,
288                               public chromeos::UserManager::Observer,
289                               public chrome::BrowserListObserver,
290                               public apps::AppWindowRegistry::Observer {
291 protected:
292  DeviceLocalAccountTest()
293      : user_id_1_(GenerateDeviceLocalAccountUserId(
294            kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)),
295        user_id_2_(GenerateDeviceLocalAccountUserId(
296            kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)) {
297    set_exit_when_last_browser_closes(false);
298  }
299
300  virtual ~DeviceLocalAccountTest() {}
301
302  virtual void SetUp() OVERRIDE {
303    // Configure and start the test server.
304    scoped_ptr<crypto::RSAPrivateKey> signing_key(
305        PolicyBuilder::CreateTestSigningKey());
306    ASSERT_TRUE(test_server_.SetSigningKeyAndSignature(
307        signing_key.get(), PolicyBuilder::GetTestSigningKeySignature()));
308    signing_key.reset();
309    test_server_.RegisterClient(PolicyBuilder::kFakeToken,
310                                PolicyBuilder::kFakeDeviceId);
311    ASSERT_TRUE(test_server_.Start());
312
313    ASSERT_TRUE(extension_cache_root_dir_.CreateUniqueTempDir());
314    extension_cache_root_dir_override_.reset(new base::ScopedPathOverride(
315        chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
316        extension_cache_root_dir_.path()));
317    ASSERT_TRUE(external_data_cache_dir_.CreateUniqueTempDir());
318    external_data_cache_dir_override_.reset(new base::ScopedPathOverride(
319        chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTERNAL_DATA,
320        external_data_cache_dir_.path()));
321
322    BrowserList::AddObserver(this);
323
324    DevicePolicyCrosBrowserTest::SetUp();
325  }
326
327  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
328    DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line);
329    command_line->AppendSwitch(chromeos::switches::kLoginManager);
330    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
331    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
332    command_line->AppendSwitchASCII(policy::switches::kDeviceManagementUrl,
333                                    test_server_.GetServiceURL().spec());
334    command_line->AppendSwitch(policy::switches::kEnablePolicyKeyVerification);
335  }
336
337  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
338    DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
339
340    // Clear command-line arguments (but keep command-line switches) so the
341    // startup pages policy takes effect.
342    CommandLine* command_line = CommandLine::ForCurrentProcess();
343    CommandLine::StringVector argv(command_line->argv());
344    argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(),
345               argv.end());
346    command_line->InitFromArgv(argv);
347
348    InstallOwnerKey();
349    MarkAsEnterpriseOwned();
350
351    InitializePolicy();
352  }
353
354  virtual void CleanUpOnMainThread() OVERRIDE {
355    BrowserList::RemoveObserver(this);
356
357    // This shuts down the login UI.
358    base::MessageLoop::current()->PostTask(FROM_HERE,
359                                           base::Bind(&chrome::AttemptExit));
360    base::RunLoop().RunUntilIdle();
361  }
362
363  virtual void LocalStateChanged(chromeos::UserManager* user_manager) OVERRIDE {
364    if (run_loop_)
365      run_loop_->Quit();
366  }
367
368  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE {
369    if (run_loop_)
370      run_loop_->Quit();
371  }
372
373  virtual void OnAppWindowAdded(apps::AppWindow* app_window) OVERRIDE {
374    if (run_loop_)
375      run_loop_->Quit();
376  }
377
378  virtual void OnAppWindowIconChanged(apps::AppWindow* app_window) OVERRIDE {}
379
380  virtual void OnAppWindowRemoved(apps::AppWindow* app_window) OVERRIDE {
381    if (run_loop_)
382      run_loop_->Quit();
383  }
384
385  void InitializePolicy() {
386    device_policy()->policy_data().set_public_key_version(1);
387    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
388    proto.mutable_show_user_names()->set_show_user_names(true);
389
390    device_local_account_policy_.policy_data().set_policy_type(
391        dm_protocol::kChromePublicAccountPolicyType);
392    device_local_account_policy_.policy_data().set_username(kAccountId1);
393    device_local_account_policy_.policy_data().set_settings_entity_id(
394        kAccountId1);
395    device_local_account_policy_.policy_data().set_public_key_version(1);
396    device_local_account_policy_.payload().mutable_userdisplayname()->set_value(
397        kDisplayName);
398  }
399
400  void BuildDeviceLocalAccountPolicy() {
401    device_local_account_policy_.SetDefaultSigningKey();
402    device_local_account_policy_.Build();
403  }
404
405  void UploadDeviceLocalAccountPolicy() {
406    BuildDeviceLocalAccountPolicy();
407    test_server_.UpdatePolicy(
408        dm_protocol::kChromePublicAccountPolicyType, kAccountId1,
409        device_local_account_policy_.payload().SerializeAsString());
410  }
411
412  void UploadAndInstallDeviceLocalAccountPolicy() {
413    UploadDeviceLocalAccountPolicy();
414    session_manager_client()->set_device_local_account_policy(
415        kAccountId1, device_local_account_policy_.GetBlob());
416  }
417
418  void AddPublicSessionToDevicePolicy(const std::string& username) {
419    em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
420    em::DeviceLocalAccountInfoProto* account =
421        proto.mutable_device_local_accounts()->add_account();
422    account->set_account_id(username);
423    account->set_type(
424        em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
425    RefreshDevicePolicy();
426    test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType,
427                              std::string(), proto.SerializeAsString());
428  }
429
430  void CheckPublicSessionPresent(const std::string& id) {
431    const chromeos::User* user = chromeos::UserManager::Get()->FindUser(id);
432    ASSERT_TRUE(user);
433    EXPECT_EQ(id, user->email());
434    EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType());
435  }
436
437  base::FilePath GetCacheDirectoryForAccountID(const std::string& account_id) {
438    return extension_cache_root_dir_.path()
439        .Append(base::HexEncode(account_id.c_str(), account_id.size()));
440  }
441
442  base::FilePath GetCacheCRXFile(const std::string& account_id,
443                                 const std::string& id,
444                                 const std::string& version) {
445    return GetCacheDirectoryForAccountID(account_id)
446        .Append(base::StringPrintf("%s-%s.crx", id.c_str(), version.c_str()));
447  }
448
449  // Returns a profile which can be used for testing.
450  Profile* GetProfileForTest() {
451    // Any profile can be used here since this test does not test multi profile.
452    return ProfileManager::GetActiveUserProfile();
453  }
454
455  const std::string user_id_1_;
456  const std::string user_id_2_;
457
458  scoped_ptr<base::RunLoop> run_loop_;
459
460  UserPolicyBuilder device_local_account_policy_;
461  LocalPolicyTestServer test_server_;
462
463 private:
464  base::ScopedTempDir extension_cache_root_dir_;
465  base::ScopedTempDir external_data_cache_dir_;
466  scoped_ptr<base::ScopedPathOverride> extension_cache_root_dir_override_;
467  scoped_ptr<base::ScopedPathOverride> external_data_cache_dir_override_;
468
469  DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountTest);
470};
471
472static bool IsKnownUser(const std::string& account_id) {
473  return chromeos::UserManager::Get()->IsKnownUser(account_id);
474}
475
476IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) {
477  AddPublicSessionToDevicePolicy(kAccountId1);
478  AddPublicSessionToDevicePolicy(kAccountId2);
479
480  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
481                                        base::Bind(&IsKnownUser, user_id_1_))
482      .Wait();
483  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
484                                        base::Bind(&IsKnownUser, user_id_2_))
485      .Wait();
486
487  CheckPublicSessionPresent(user_id_1_);
488  CheckPublicSessionPresent(user_id_2_);
489}
490
491static bool DisplayNameMatches(const std::string& account_id,
492                               const std::string& display_name) {
493  const chromeos::User* user =
494      chromeos::UserManager::Get()->FindUser(account_id);
495  if (!user || user->display_name().empty())
496    return false;
497  EXPECT_EQ(base::UTF8ToUTF16(display_name), user->display_name());
498  return true;
499}
500
501IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
502  UploadAndInstallDeviceLocalAccountPolicy();
503  AddPublicSessionToDevicePolicy(kAccountId1);
504
505  content::WindowedNotificationObserver(
506      chrome::NOTIFICATION_USER_LIST_CHANGED,
507      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
508}
509
510IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) {
511  UploadDeviceLocalAccountPolicy();
512  AddPublicSessionToDevicePolicy(kAccountId1);
513
514  // Policy for the account is not installed in session_manager_client. Because
515  // of this, the presence of the display name (which comes from policy) can be
516  // used as a signal that indicates successful policy download.
517  content::WindowedNotificationObserver(
518      chrome::NOTIFICATION_USER_LIST_CHANGED,
519      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
520
521  // Sanity check: The policy should be present now.
522  ASSERT_FALSE(session_manager_client()->device_local_account_policy(
523      kAccountId1).empty());
524}
525
526static bool IsNotKnownUser(const std::string& account_id) {
527  return !IsKnownUser(account_id);
528}
529
530IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) {
531  AddPublicSessionToDevicePolicy(kAccountId1);
532  AddPublicSessionToDevicePolicy(kAccountId2);
533
534  // Wait until the login screen is up.
535  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
536                                        base::Bind(&IsKnownUser, user_id_1_))
537      .Wait();
538  content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED,
539                                        base::Bind(&IsKnownUser, user_id_2_))
540      .Wait();
541
542  // Update policy to remove kAccountId2.
543  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
544  proto.mutable_device_local_accounts()->clear_account();
545  AddPublicSessionToDevicePolicy(kAccountId1);
546
547  em::ChromeDeviceSettingsProto policy;
548  policy.mutable_show_user_names()->set_show_user_names(true);
549  em::DeviceLocalAccountInfoProto* account1 =
550      policy.mutable_device_local_accounts()->add_account();
551  account1->set_account_id(kAccountId1);
552  account1->set_type(
553      em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION);
554
555  test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(),
556                            policy.SerializeAsString());
557  g_browser_process->policy_service()->RefreshPolicies(base::Closure());
558
559  // Make sure the second device-local account disappears.
560  content::WindowedNotificationObserver(
561      chrome::NOTIFICATION_USER_LIST_CHANGED,
562      base::Bind(&IsNotKnownUser, user_id_2_)).Wait();
563}
564
565static bool IsSessionStarted() {
566  return chromeos::UserManager::Get()->IsSessionStarted();
567}
568
569IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) {
570  // Specify startup pages.
571  device_local_account_policy_.payload().mutable_restoreonstartup()->set_value(
572      SessionStartupPref::kPrefValueURLs);
573  em::StringListPolicyProto* startup_urls_proto =
574      device_local_account_policy_.payload().mutable_restoreonstartupurls();
575  for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
576    startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
577  UploadAndInstallDeviceLocalAccountPolicy();
578  AddPublicSessionToDevicePolicy(kAccountId1);
579
580  // This observes the display name becoming available as this indicates
581  // device-local account policy is fully loaded, which is a prerequisite for
582  // successful login.
583  content::WindowedNotificationObserver(
584      chrome::NOTIFICATION_USER_LIST_CHANGED,
585      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
586
587  // Wait for the login UI to be ready.
588  chromeos::LoginDisplayHostImpl* host =
589      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
590          chromeos::LoginDisplayHostImpl::default_host());
591  ASSERT_TRUE(host);
592  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
593  ASSERT_TRUE(oobe_ui);
594  base::RunLoop run_loop;
595  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
596  if (!oobe_ui_ready)
597    run_loop.Run();
598
599  // Start login into the device-local account.
600  host->StartSignInScreen(LoginScreenContext());
601  chromeos::ExistingUserController* controller =
602      chromeos::ExistingUserController::current_controller();
603  ASSERT_TRUE(controller);
604  controller->LoginAsPublicAccount(user_id_1_);
605
606  // Wait for the session to start.
607  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
608                                        base::Bind(IsSessionStarted)).Wait();
609
610  // Check that the startup pages specified in policy were opened.
611  BrowserList* browser_list =
612    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
613  EXPECT_EQ(1U, browser_list->size());
614  Browser* browser = browser_list->get(0);
615  ASSERT_TRUE(browser);
616
617  TabStripModel* tabs = browser->tab_strip_model();
618  ASSERT_TRUE(tabs);
619  int expected_tab_count = static_cast<int>(arraysize(kStartupURLs));
620  EXPECT_EQ(expected_tab_count, tabs->count());
621  for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) {
622    EXPECT_EQ(GURL(kStartupURLs[i]),
623              tabs->GetWebContentsAt(i)->GetVisibleURL());
624  }
625}
626
627IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) {
628  UploadAndInstallDeviceLocalAccountPolicy();
629  AddPublicSessionToDevicePolicy(kAccountId1);
630
631  // This observes the display name becoming available as this indicates
632  // device-local account policy is fully loaded, which is a prerequisite for
633  // successful login.
634  content::WindowedNotificationObserver(
635      chrome::NOTIFICATION_USER_LIST_CHANGED,
636      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
637
638  // Wait for the login UI to be ready.
639  chromeos::LoginDisplayHostImpl* host =
640      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
641          chromeos::LoginDisplayHostImpl::default_host());
642  ASSERT_TRUE(host);
643  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
644  ASSERT_TRUE(oobe_ui);
645  base::RunLoop run_loop;
646  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
647  if (!oobe_ui_ready)
648    run_loop.Run();
649
650  // Start login into the device-local account.
651  host->StartSignInScreen(LoginScreenContext());
652  chromeos::ExistingUserController* controller =
653      chromeos::ExistingUserController::current_controller();
654  ASSERT_TRUE(controller);
655  controller->LoginAsPublicAccount(user_id_1_);
656
657  // Wait for the session to start.
658  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
659                                        base::Bind(IsSessionStarted)).Wait();
660
661  BrowserList* browser_list =
662    BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
663  EXPECT_EQ(1U, browser_list->size());
664  Browser* browser = browser_list->get(0);
665  ASSERT_TRUE(browser);
666  BrowserWindow* browser_window = browser->window();
667  ASSERT_TRUE(browser_window);
668
669  // Verify that an attempt to enter fullscreen mode is denied.
670  EXPECT_FALSE(browser_window->IsFullscreen());
671  chrome::ToggleFullscreenMode(browser);
672  EXPECT_FALSE(browser_window->IsFullscreen());
673}
674
675IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsUncached) {
676  // Make it possible to force-install a hosted app and an extension.
677  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
678  TestingUpdateManifestProvider testing_update_manifest_provider(
679      kRelativeUpdateURL);
680  testing_update_manifest_provider.AddUpdate(
681      kHostedAppID,
682      kHostedAppVersion,
683      embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath));
684  testing_update_manifest_provider.AddUpdate(
685      kGoodExtensionID,
686      kGoodExtensionVersion,
687      embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath));
688  embedded_test_server()->RegisterRequestHandler(
689      base::Bind(&TestingUpdateManifestProvider::HandleRequest,
690                 base::Unretained(&testing_update_manifest_provider)));
691
692  // Specify policy to force-install the hosted app and the extension.
693  em::StringList* forcelist = device_local_account_policy_.payload()
694      .mutable_extensioninstallforcelist()->mutable_value();
695  forcelist->add_entries(base::StringPrintf(
696      "%s;%s",
697      kHostedAppID,
698      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
699  forcelist->add_entries(base::StringPrintf(
700      "%s;%s",
701      kGoodExtensionID,
702      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
703
704  UploadAndInstallDeviceLocalAccountPolicy();
705  AddPublicSessionToDevicePolicy(kAccountId1);
706
707  // This observes the display name becoming available as this indicates
708  // device-local account policy is fully loaded, which is a prerequisite for
709  // successful login.
710  content::WindowedNotificationObserver(
711      chrome::NOTIFICATION_USER_LIST_CHANGED,
712      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
713
714  // Wait for the login UI to be ready.
715  chromeos::LoginDisplayHostImpl* host =
716      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
717          chromeos::LoginDisplayHostImpl::default_host());
718  ASSERT_TRUE(host);
719  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
720  ASSERT_TRUE(oobe_ui);
721  base::RunLoop run_loop;
722  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
723  if (!oobe_ui_ready)
724    run_loop.Run();
725
726  // Start listening for app/extension installation results.
727  content::WindowedNotificationObserver hosted_app_observer(
728      chrome::NOTIFICATION_EXTENSION_INSTALLED,
729      base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
730  content::WindowedNotificationObserver extension_observer(
731      chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
732      base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
733
734  // Start login into the device-local account.
735  host->StartSignInScreen(LoginScreenContext());
736  chromeos::ExistingUserController* controller =
737      chromeos::ExistingUserController::current_controller();
738  ASSERT_TRUE(controller);
739  controller->LoginAsPublicAccount(user_id_1_);
740
741  // Wait for the hosted app installation to succeed and the extension
742  // installation to fail (because hosted apps are whitelisted for use in
743  // device-local accounts and extensions are not).
744  hosted_app_observer.Wait();
745  extension_observer.Wait();
746
747  // Verify that the hosted app was installed.
748  Profile* profile = GetProfileForTest();
749  ASSERT_TRUE(profile);
750  ExtensionService* extension_service =
751      extensions::ExtensionSystem::Get(profile)->extension_service();
752  EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
753
754  // Verify that the extension was not installed.
755  EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
756
757  // Verify that the app was copied to the account's extension cache.
758  base::FilePath test_dir;
759  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
760  EXPECT_TRUE(ContentsEqual(
761          GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion),
762          test_dir.Append(kHostedAppCRXPath)));
763
764  // Verify that the extension was not copied to the account's extension cache.
765  EXPECT_FALSE(PathExists(GetCacheCRXFile(
766      kAccountId1, kGoodExtensionID, kGoodExtensionVersion)));
767}
768
769IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsCached) {
770  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
771
772  // Pre-populate the device local account's extension cache with a hosted app
773  // and an extension.
774  EXPECT_TRUE(base::CreateDirectory(
775      GetCacheDirectoryForAccountID(kAccountId1)));
776  base::FilePath test_dir;
777  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
778  const base::FilePath cached_hosted_app =
779      GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion);
780  EXPECT_TRUE(CopyFile(test_dir.Append(kHostedAppCRXPath),
781                       cached_hosted_app));
782  const base::FilePath cached_extension =
783      GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion);
784  EXPECT_TRUE(CopyFile(test_dir.Append(kGoodExtensionCRXPath),
785                       cached_extension));
786
787  // Specify policy to force-install the hosted app.
788  em::StringList* forcelist = device_local_account_policy_.payload()
789      .mutable_extensioninstallforcelist()->mutable_value();
790  forcelist->add_entries(base::StringPrintf(
791      "%s;%s",
792      kHostedAppID,
793      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
794  forcelist->add_entries(base::StringPrintf(
795      "%s;%s",
796      kGoodExtensionID,
797      embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str()));
798
799  UploadAndInstallDeviceLocalAccountPolicy();
800  AddPublicSessionToDevicePolicy(kAccountId1);
801
802  // This observes the display name becoming available as this indicates
803  // device-local account policy is fully loaded, which is a prerequisite for
804  // successful login.
805  content::WindowedNotificationObserver(
806      chrome::NOTIFICATION_USER_LIST_CHANGED,
807      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
808
809  // Wait for the login UI to be ready.
810  chromeos::LoginDisplayHostImpl* host =
811      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
812          chromeos::LoginDisplayHostImpl::default_host());
813  ASSERT_TRUE(host);
814  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
815  ASSERT_TRUE(oobe_ui);
816  base::RunLoop run_loop;
817  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
818  if (!oobe_ui_ready)
819    run_loop.Run();
820
821  // Start listening for app/extension installation results.
822  content::WindowedNotificationObserver hosted_app_observer(
823      chrome::NOTIFICATION_EXTENSION_INSTALLED,
824      base::Bind(DoesInstallSuccessReferToId, kHostedAppID));
825  content::WindowedNotificationObserver extension_observer(
826      chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
827      base::Bind(DoesInstallFailureReferToId, kGoodExtensionID));
828
829  // Start login into the device-local account.
830  host->StartSignInScreen(LoginScreenContext());
831  chromeos::ExistingUserController* controller =
832      chromeos::ExistingUserController::current_controller();
833  ASSERT_TRUE(controller);
834  controller->LoginAsPublicAccount(user_id_1_);
835
836  // Wait for the hosted app installation to succeed and the extension
837  // installation to fail.
838  hosted_app_observer.Wait();
839  extension_observer.Wait();
840
841  // Verify that the hosted app was installed.
842  Profile* profile = GetProfileForTest();
843  ASSERT_TRUE(profile);
844  ExtensionService* extension_service =
845      extensions::ExtensionSystem::Get(profile)->extension_service();
846  EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true));
847
848  // Verify that the extension was not installed.
849  EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true));
850
851  // Verify that the app is still in the account's extension cache.
852  EXPECT_TRUE(PathExists(cached_hosted_app));
853
854  // Verify that the extension was removed from the account's extension cache.
855  EXPECT_FALSE(PathExists(cached_extension));
856}
857
858IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExternalData) {
859  // chromeos::UserManager requests an external data fetch whenever
860  // the key::kUserAvatarImage policy is set. Since this test wants to
861  // verify that the underlying policy subsystem will start a fetch
862  // without this request as well, the chromeos::UserManager must be
863  // prevented from seeing the policy change.
864  reinterpret_cast<chromeos::UserManagerImpl*>(chromeos::UserManager::Get())->
865      StopPolicyObserverForTesting();
866
867  UploadDeviceLocalAccountPolicy();
868  AddPublicSessionToDevicePolicy(kAccountId1);
869
870  // This observes the display name becoming available as this indicates
871  // device-local account policy is fully loaded.
872  content::WindowedNotificationObserver(
873      chrome::NOTIFICATION_USER_LIST_CHANGED,
874      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
875
876  // Start serving external data at |kExternalDataURL|.
877  scoped_ptr<base::RunLoop> run_loop(new base::RunLoop);
878  scoped_ptr<net::FakeURLFetcherFactory> fetcher_factory(
879      new net::FakeURLFetcherFactory(
880          NULL,
881          base::Bind(&RunCallbackAndReturnFakeURLFetcher,
882                     base::MessageLoopProxy::current(),
883                     run_loop->QuitClosure())));
884  fetcher_factory->SetFakeResponse(GURL(kExternalDataURL),
885                                   kExternalData,
886                                   net::HTTP_OK,
887                                   net::URLRequestStatus::SUCCESS);
888
889  // Specify an external data reference for the key::kUserAvatarImage policy.
890  scoped_ptr<base::DictionaryValue> metadata =
891      test::ConstructExternalDataReference(kExternalDataURL, kExternalData);
892  std::string policy;
893  base::JSONWriter::Write(metadata.get(), &policy);
894  device_local_account_policy_.payload().mutable_useravatarimage()->set_value(
895      policy);
896  UploadAndInstallDeviceLocalAccountPolicy();
897  policy::BrowserPolicyConnectorChromeOS* connector =
898      g_browser_process->platform_part()->browser_policy_connector_chromeos();
899  DeviceLocalAccountPolicyBroker* broker =
900      connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
901          user_id_1_);
902  ASSERT_TRUE(broker);
903  broker->core()->store()->Load();
904
905  // The external data should be fetched and cached automatically. Wait for this
906  // fetch.
907  run_loop->Run();
908
909  // Stop serving external data at |kExternalDataURL|.
910  fetcher_factory.reset();
911
912  const PolicyMap::Entry* policy_entry =
913      broker->core()->store()->policy_map().Get(key::kUserAvatarImage);
914  ASSERT_TRUE(policy_entry);
915  ASSERT_TRUE(policy_entry->external_data_fetcher);
916
917  // Retrieve the external data. Although the data is no longer being served at
918  // |kExternalDataURL|, the retrieval should succeed because the data has been
919  // cached.
920  run_loop.reset(new base::RunLoop);
921  scoped_ptr<std::string> fetched_external_data;
922  policy_entry->external_data_fetcher->Fetch(base::Bind(
923      &test::ExternalDataFetchCallback,
924      &fetched_external_data,
925      run_loop->QuitClosure()));
926  run_loop->Run();
927
928  ASSERT_TRUE(fetched_external_data);
929  EXPECT_EQ(kExternalData, *fetched_external_data);
930
931  // Wait for the login UI to be ready.
932  chromeos::LoginDisplayHostImpl* host =
933      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
934          chromeos::LoginDisplayHostImpl::default_host());
935  ASSERT_TRUE(host);
936  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
937  ASSERT_TRUE(oobe_ui);
938  run_loop.reset(new base::RunLoop);
939  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop->QuitClosure());
940  if (!oobe_ui_ready)
941    run_loop->Run();
942
943  // Start login into the device-local account.
944  host->StartSignInScreen(LoginScreenContext());
945  chromeos::ExistingUserController* controller =
946      chromeos::ExistingUserController::current_controller();
947  ASSERT_TRUE(controller);
948  controller->LoginAsPublicAccount(user_id_1_);
949
950  // Wait for the session to start.
951  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
952                                        base::Bind(IsSessionStarted)).Wait();
953
954  // Verify that the external data reference has propagated to the device-local
955  // account's ProfilePolicyConnector.
956  ProfilePolicyConnector* policy_connector =
957      ProfilePolicyConnectorFactory::GetForProfile(GetProfileForTest());
958  ASSERT_TRUE(policy_connector);
959  const PolicyMap& policies = policy_connector->policy_service()->GetPolicies(
960      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
961  policy_entry = policies.Get(key::kUserAvatarImage);
962  ASSERT_TRUE(policy_entry);
963  EXPECT_TRUE(base::Value::Equals(metadata.get(), policy_entry->value));
964  ASSERT_TRUE(policy_entry->external_data_fetcher);
965
966  // Retrieve the external data via the ProfilePolicyConnector. The retrieval
967  // should succeed because the data has been cached.
968  run_loop.reset(new base::RunLoop);
969  fetched_external_data.reset();
970  policy_entry->external_data_fetcher->Fetch(base::Bind(
971      &test::ExternalDataFetchCallback,
972      &fetched_external_data,
973      run_loop->QuitClosure()));
974  run_loop->Run();
975
976  ASSERT_TRUE(fetched_external_data);
977  EXPECT_EQ(kExternalData, *fetched_external_data);
978}
979
980IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, UserAvatarImage) {
981  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
982
983  UploadDeviceLocalAccountPolicy();
984  AddPublicSessionToDevicePolicy(kAccountId1);
985
986  // This observes the display name becoming available as this indicates
987  // device-local account policy is fully loaded.
988  content::WindowedNotificationObserver(
989      chrome::NOTIFICATION_USER_LIST_CHANGED,
990      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
991
992  base::FilePath test_dir;
993  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
994  std::string image_data;
995  ASSERT_TRUE(base::ReadFileToString(
996      test_dir.Append(chromeos::test::kUserAvatarImage1RelativePath),
997      &image_data));
998
999  std::string policy;
1000  base::JSONWriter::Write(test::ConstructExternalDataReference(
1001      embedded_test_server()->GetURL(std::string("/") +
1002          chromeos::test::kUserAvatarImage1RelativePath).spec(),
1003      image_data).get(),
1004      &policy);
1005  device_local_account_policy_.payload().mutable_useravatarimage()->set_value(
1006      policy);
1007  UploadAndInstallDeviceLocalAccountPolicy();
1008  policy::BrowserPolicyConnectorChromeOS* connector =
1009      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1010  DeviceLocalAccountPolicyBroker* broker =
1011      connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
1012          user_id_1_);
1013  ASSERT_TRUE(broker);
1014
1015  run_loop_.reset(new base::RunLoop);
1016  chromeos::UserManager::Get()->AddObserver(this);
1017  broker->core()->store()->Load();
1018  run_loop_->Run();
1019  chromeos::UserManager::Get()->RemoveObserver(this);
1020
1021  scoped_ptr<gfx::ImageSkia> policy_image = chromeos::test::ImageLoader(
1022      test_dir.Append(chromeos::test::kUserAvatarImage1RelativePath)).Load();
1023  ASSERT_TRUE(policy_image);
1024
1025  const chromeos::User* user =
1026      chromeos::UserManager::Get()->FindUser(user_id_1_);
1027  ASSERT_TRUE(user);
1028
1029  base::FilePath user_data_dir;
1030  ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
1031  const base::FilePath saved_image_path =
1032      user_data_dir.Append(user_id_1_).AddExtension("jpg");
1033
1034  EXPECT_FALSE(user->HasDefaultImage());
1035  EXPECT_EQ(chromeos::User::kExternalImageIndex, user->image_index());
1036  EXPECT_TRUE(chromeos::test::AreImagesEqual(*policy_image, user->image()));
1037  const base::DictionaryValue* images_pref =
1038      g_browser_process->local_state()->GetDictionary("user_image_info");
1039  ASSERT_TRUE(images_pref);
1040  const base::DictionaryValue* image_properties;
1041  ASSERT_TRUE(images_pref->GetDictionaryWithoutPathExpansion(
1042      user_id_1_,
1043      &image_properties));
1044  int image_index;
1045  std::string image_path;
1046  ASSERT_TRUE(image_properties->GetInteger("index", &image_index));
1047  ASSERT_TRUE(image_properties->GetString("path", &image_path));
1048  EXPECT_EQ(chromeos::User::kExternalImageIndex, image_index);
1049  EXPECT_EQ(saved_image_path.value(), image_path);
1050
1051  scoped_ptr<gfx::ImageSkia> saved_image =
1052      chromeos::test::ImageLoader(saved_image_path).Load();
1053  ASSERT_TRUE(saved_image);
1054
1055  // Check image dimensions. Images can't be compared since JPEG is lossy.
1056  EXPECT_EQ(policy_image->width(), saved_image->width());
1057  EXPECT_EQ(policy_image->height(), saved_image->height());
1058}
1059
1060IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LastWindowClosedLogoutReminder) {
1061  UploadAndInstallDeviceLocalAccountPolicy();
1062  AddPublicSessionToDevicePolicy(kAccountId1);
1063
1064  // This observes the display name becoming available as this indicates
1065  // device-local account policy is fully loaded.
1066  content::WindowedNotificationObserver(
1067      chrome::NOTIFICATION_USER_LIST_CHANGED,
1068      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
1069
1070  // Wait for the login UI to be ready.
1071  chromeos::LoginDisplayHostImpl* host =
1072      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
1073          chromeos::LoginDisplayHostImpl::default_host());
1074  ASSERT_TRUE(host);
1075  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
1076  ASSERT_TRUE(oobe_ui);
1077  base::RunLoop run_loop;
1078  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
1079  if (!oobe_ui_ready)
1080    run_loop.Run();
1081
1082  // Start login into the device-local account.
1083  host->StartSignInScreen(LoginScreenContext());
1084  chromeos::ExistingUserController* controller =
1085      chromeos::ExistingUserController::current_controller();
1086  ASSERT_TRUE(controller);
1087  controller->LoginAsPublicAccount(user_id_1_);
1088
1089  // Wait for the session to start.
1090  content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
1091                                        base::Bind(IsSessionStarted)).Wait();
1092
1093  Profile* profile = GetProfileForTest();
1094  ASSERT_TRUE(profile);
1095  apps::AppWindowRegistry* app_window_registry =
1096      apps::AppWindowRegistry::Get(profile);
1097  app_window_registry->AddObserver(this);
1098
1099  // Verify that the logout confirmation dialog is not showing.
1100  ash::internal::LogoutConfirmationController* logout_confirmation_controller =
1101      ash::Shell::GetInstance()->logout_confirmation_controller();
1102  ASSERT_TRUE(logout_confirmation_controller);
1103  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1104
1105  // Remove policy that allows only explicitly whitelisted apps to be installed
1106  // in a public session.
1107  extensions::ExtensionSystem* extension_system =
1108      extensions::ExtensionSystem::Get(profile);
1109  ASSERT_TRUE(extension_system);
1110  extension_system->management_policy()->UnregisterAllProviders();
1111
1112  // Install and a platform app.
1113  scoped_refptr<extensions::CrxInstaller> installer =
1114      extensions::CrxInstaller::CreateSilent(
1115          extension_system->extension_service());
1116  installer->set_allow_silent_install(true);
1117  installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
1118  installer->set_creation_flags(extensions::Extension::FROM_WEBSTORE);
1119  content::WindowedNotificationObserver app_install_observer(
1120      chrome::NOTIFICATION_CRX_INSTALLER_DONE,
1121      content::NotificationService::AllSources());
1122  base::FilePath test_dir;
1123  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
1124  installer->InstallCrx(test_dir.Append(kPackagedAppCRXPath));
1125  app_install_observer.Wait();
1126  const extensions::Extension* app =
1127      content::Details<const extensions::Extension>(
1128          app_install_observer.details()).ptr();
1129
1130  // Start the platform app, causing it to open a window.
1131  run_loop_.reset(new base::RunLoop);
1132  OpenApplication(AppLaunchParams(
1133      profile, app, extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW));
1134  run_loop_->Run();
1135  EXPECT_EQ(1U, app_window_registry->app_windows().size());
1136
1137  // Close the only open browser window.
1138  BrowserList* browser_list =
1139      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
1140  EXPECT_EQ(1U, browser_list->size());
1141  Browser* browser = browser_list->get(0);
1142  ASSERT_TRUE(browser);
1143  BrowserWindow* browser_window = browser->window();
1144  ASSERT_TRUE(browser_window);
1145  run_loop_.reset(new base::RunLoop);
1146  browser_window->Close();
1147  browser_window = NULL;
1148  run_loop_->Run();
1149  browser = NULL;
1150  EXPECT_TRUE(browser_list->empty());
1151
1152  // Verify that the logout confirmation dialog is not showing because an app
1153  // window is still open.
1154  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1155
1156  // Open a browser window.
1157  Browser* first_browser = CreateBrowser(profile);
1158  EXPECT_EQ(1U, browser_list->size());
1159
1160  // Close the app window.
1161  run_loop_.reset(new base::RunLoop);
1162  ASSERT_EQ(1U, app_window_registry->app_windows().size());
1163  app_window_registry->app_windows().front()->GetBaseWindow()->Close();
1164  run_loop_->Run();
1165  EXPECT_TRUE(app_window_registry->app_windows().empty());
1166
1167  // Verify that the logout confirmation dialog is not showing because a browser
1168  // window is still open.
1169  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1170
1171  // Open a second browser window.
1172  Browser* second_browser = CreateBrowser(profile);
1173  EXPECT_EQ(2U, browser_list->size());
1174
1175  // Close the first browser window.
1176  browser_window = first_browser->window();
1177  ASSERT_TRUE(browser_window);
1178  run_loop_.reset(new base::RunLoop);
1179  browser_window->Close();
1180  browser_window = NULL;
1181  run_loop_->Run();
1182  first_browser = NULL;
1183  EXPECT_EQ(1U, browser_list->size());
1184
1185  // Verify that the logout confirmation dialog is not showing because a browser
1186  // window is still open.
1187  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1188
1189  // Close the second browser window.
1190  browser_window = second_browser->window();
1191  ASSERT_TRUE(browser_window);
1192  run_loop_.reset(new base::RunLoop);
1193  browser_window->Close();
1194  browser_window = NULL;
1195  run_loop_->Run();
1196  second_browser = NULL;
1197  EXPECT_TRUE(browser_list->empty());
1198
1199  // Verify that the logout confirmation dialog is showing.
1200  ash::internal::LogoutConfirmationDialog* dialog =
1201      logout_confirmation_controller->dialog_for_testing();
1202  ASSERT_TRUE(dialog);
1203
1204  // Deny the logout.
1205  dialog->GetWidget()->Close();
1206  dialog = NULL;
1207  base::RunLoop().RunUntilIdle();
1208
1209  // Verify that the logout confirmation dialog is no longer showing.
1210  EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing());
1211
1212  // Open a browser window.
1213  browser = CreateBrowser(profile);
1214  EXPECT_EQ(1U, browser_list->size());
1215
1216  // Close the browser window.
1217  browser_window = browser->window();
1218  ASSERT_TRUE(browser_window);
1219  run_loop_.reset(new base::RunLoop);
1220  browser_window->Close();
1221  browser_window = NULL;
1222  run_loop_->Run();
1223  browser = NULL;
1224  EXPECT_TRUE(browser_list->empty());
1225
1226  // Verify that the logout confirmation dialog is showing again.
1227  dialog = logout_confirmation_controller->dialog_for_testing();
1228  ASSERT_TRUE(dialog);
1229
1230  // Deny the logout.
1231  dialog->GetWidget()->Close();
1232  dialog = NULL;
1233  base::RunLoop().RunUntilIdle();
1234
1235  app_window_registry->RemoveObserver(this);
1236};
1237
1238class TermsOfServiceTest : public DeviceLocalAccountTest,
1239                           public testing::WithParamInterface<bool> {
1240};
1241
1242IN_PROC_BROWSER_TEST_P(TermsOfServiceTest, TermsOfServiceScreen) {
1243  // Specify Terms of Service URL.
1244  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
1245  device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
1246      embedded_test_server()->GetURL(
1247            std::string("/") +
1248                (GetParam() ? kExistentTermsOfServicePath
1249                            : kNonexistentTermsOfServicePath)).spec());
1250  UploadAndInstallDeviceLocalAccountPolicy();
1251  AddPublicSessionToDevicePolicy(kAccountId1);
1252
1253  // Wait for the device-local account policy to be fully loaded.
1254  content::WindowedNotificationObserver(
1255      chrome::NOTIFICATION_USER_LIST_CHANGED,
1256      base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
1257
1258  // Wait for the login UI to be ready.
1259  chromeos::LoginDisplayHostImpl* host =
1260      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
1261          chromeos::LoginDisplayHostImpl::default_host());
1262  ASSERT_TRUE(host);
1263  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
1264  ASSERT_TRUE(oobe_ui);
1265  base::RunLoop oobe_ui_wait_run_loop;
1266  const bool oobe_ui_ready =
1267      oobe_ui->IsJSReady(oobe_ui_wait_run_loop.QuitClosure());
1268  if (!oobe_ui_ready)
1269    oobe_ui_wait_run_loop.Run();
1270
1271  // Start login into the device-local account.
1272  host->StartSignInScreen(LoginScreenContext());
1273  chromeos::ExistingUserController* controller =
1274      chromeos::ExistingUserController::current_controller();
1275  ASSERT_TRUE(controller);
1276  controller->LoginAsPublicAccount(user_id_1_);
1277
1278  // Set up an observer that will quit the message loop when login has succeeded
1279  // and the first wizard screen, if any, is being shown.
1280  base::RunLoop login_wait_run_loop;
1281  chromeos::MockConsumer login_status_consumer;
1282  EXPECT_CALL(login_status_consumer, OnLoginSuccess(_))
1283      .Times(1)
1284      .WillOnce(InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
1285
1286  // Spin the loop until the observer fires. Then, unregister the observer.
1287  controller->set_login_status_consumer(&login_status_consumer);
1288  login_wait_run_loop.Run();
1289  controller->set_login_status_consumer(NULL);
1290
1291  // Verify that the Terms of Service screen is being shown.
1292  chromeos::WizardController* wizard_controller =
1293        chromeos::WizardController::default_controller();
1294  ASSERT_TRUE(wizard_controller);
1295  ASSERT_TRUE(wizard_controller->current_screen());
1296  EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
1297            wizard_controller->current_screen()->GetName());
1298
1299  // Wait for the Terms of Service to finish downloading, then get the status of
1300  // the screen's UI elements.
1301  chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView();
1302  ASSERT_TRUE(web_ui_login_view);
1303  content::WebUI* web_ui = web_ui_login_view->GetWebUI();
1304  ASSERT_TRUE(web_ui);
1305  content::WebContents* contents = web_ui->GetWebContents();
1306  ASSERT_TRUE(contents);
1307  std::string json;
1308  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents,
1309      "var screen = document.getElementById('terms-of-service');"
1310      "function SendReplyIfDownloadDone() {"
1311      "  if (screen.classList.contains('tos-loading'))"
1312      "    return false;"
1313      "  var status = {};"
1314      "  status.heading = document.getElementById('tos-heading').textContent;"
1315      "  status.subheading ="
1316      "      document.getElementById('tos-subheading').textContent;"
1317      "  status.contentHeading ="
1318      "      document.getElementById('tos-content-heading').textContent;"
1319      "  status.content ="
1320      "      document.getElementById('tos-content-main').textContent;"
1321      "  status.error = screen.classList.contains('error');"
1322      "  status.acceptEnabled ="
1323      "      !document.getElementById('tos-accept-button').disabled;"
1324      "  domAutomationController.send(JSON.stringify(status));"
1325      "  observer.disconnect();"
1326      "  return true;"
1327      "}"
1328      "var observer = new MutationObserver(SendReplyIfDownloadDone);"
1329      "if (!SendReplyIfDownloadDone()) {"
1330      "  var options = { attributes: true, attributeFilter: [ 'class' ] };"
1331      "  observer.observe(screen, options);"
1332      "}",
1333      &json));
1334  scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
1335  const base::DictionaryValue* status = NULL;
1336  ASSERT_TRUE(value_ptr.get());
1337  ASSERT_TRUE(value_ptr->GetAsDictionary(&status));
1338  std::string heading;
1339  EXPECT_TRUE(status->GetString("heading", &heading));
1340  std::string subheading;
1341  EXPECT_TRUE(status->GetString("subheading", &subheading));
1342  std::string content_heading;
1343  EXPECT_TRUE(status->GetString("contentHeading", &content_heading));
1344  std::string content;
1345  EXPECT_TRUE(status->GetString("content", &content));
1346  bool error;
1347  EXPECT_TRUE(status->GetBoolean("error", &error));
1348  bool accept_enabled;
1349  EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled));
1350
1351  // Verify that the screen's headings have been set correctly.
1352  EXPECT_EQ(
1353      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING,
1354                                base::UTF8ToUTF16(kDomain)),
1355      heading);
1356  EXPECT_EQ(
1357      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING,
1358                                base::UTF8ToUTF16(kDomain)),
1359      subheading);
1360  EXPECT_EQ(
1361      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING,
1362                                base::UTF8ToUTF16(kDomain)),
1363      content_heading);
1364
1365  if (!GetParam()) {
1366    // The Terms of Service URL was invalid. Verify that the screen is showing
1367    // an error and the accept button is disabled.
1368    EXPECT_TRUE(error);
1369    EXPECT_FALSE(accept_enabled);
1370    return;
1371  }
1372
1373  // The Terms of Service URL was valid. Verify that the screen is showing the
1374  // downloaded Terms of Service and the accept button is enabled.
1375  base::FilePath test_dir;
1376  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
1377  std::string terms_of_service;
1378  ASSERT_TRUE(base::ReadFileToString(
1379      test_dir.Append(kExistentTermsOfServicePath), &terms_of_service));
1380  EXPECT_EQ(terms_of_service, content);
1381  EXPECT_FALSE(error);
1382  EXPECT_TRUE(accept_enabled);
1383
1384  // Click the accept button.
1385  ASSERT_TRUE(content::ExecuteScript(contents,
1386                                     "$('tos-accept-button').click();"));
1387
1388  // Wait for the session to start.
1389  if (!IsSessionStarted()) {
1390    content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
1391                                          base::Bind(IsSessionStarted)).Wait();
1392  }
1393}
1394
1395INSTANTIATE_TEST_CASE_P(TermsOfServiceTestInstance,
1396                        TermsOfServiceTest, testing::Bool());
1397
1398}  // namespace policy
1399