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