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 <set> 7 #include <string> 8 #include <vector> 9 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/files/file_path.h" 19 #include "base/files/file_util.h" 20 #include "base/json/json_reader.h" 21 #include "base/json/json_writer.h" 22 #include "base/location.h" 23 #include "base/macros.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_change_registrar.h" 30 #include "base/prefs/pref_service.h" 31 #include "base/run_loop.h" 32 #include "base/sequenced_task_runner.h" 33 #include "base/strings/string_number_conversions.h" 34 #include "base/strings/string_util.h" 35 #include "base/strings/stringprintf.h" 36 #include "base/strings/utf_string_conversions.h" 37 #include "base/threading/sequenced_worker_pool.h" 38 #include "base/values.h" 39 #include "chrome/browser/browser_process.h" 40 #include "chrome/browser/chrome_notification_types.h" 41 #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h" 42 #include "chrome/browser/chromeos/extensions/external_cache.h" 43 #include "chrome/browser/chromeos/input_method/input_method_util.h" 44 #include "chrome/browser/chromeos/login/existing_user_controller.h" 45 #include "chrome/browser/chromeos/login/screens/wizard_screen.h" 46 #include "chrome/browser/chromeos/login/ui/login_display_host.h" 47 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" 48 #include "chrome/browser/chromeos/login/ui/webui_login_view.h" 49 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h" 50 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h" 51 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.h" 52 #include "chrome/browser/chromeos/login/users/chrome_user_manager_impl.h" 53 #include "chrome/browser/chromeos/login/wizard_controller.h" 54 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" 55 #include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h" 56 #include "chrome/browser/chromeos/policy/device_local_account.h" 57 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h" 58 #include "chrome/browser/chromeos/policy/device_policy_builder.h" 59 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" 60 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" 61 #include "chrome/browser/extensions/crx_installer.h" 62 #include "chrome/browser/extensions/extension_service.h" 63 #include "chrome/browser/lifetime/application_lifetime.h" 64 #include "chrome/browser/policy/profile_policy_connector.h" 65 #include "chrome/browser/policy/profile_policy_connector_factory.h" 66 #include "chrome/browser/policy/test/local_policy_test_server.h" 67 #include "chrome/browser/prefs/session_startup_pref.h" 68 #include "chrome/browser/profiles/profile.h" 69 #include "chrome/browser/profiles/profile_manager.h" 70 #include "chrome/browser/ui/browser.h" 71 #include "chrome/browser/ui/browser_commands.h" 72 #include "chrome/browser/ui/browser_finder.h" 73 #include "chrome/browser/ui/browser_list.h" 74 #include "chrome/browser/ui/browser_list_observer.h" 75 #include "chrome/browser/ui/browser_window.h" 76 #include "chrome/browser/ui/extensions/application_launch.h" 77 #include "chrome/browser/ui/host_desktop.h" 78 #include "chrome/browser/ui/tabs/tab_strip_model.h" 79 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 80 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" 81 #include "chrome/common/chrome_paths.h" 82 #include "chrome/common/extensions/extension_constants.h" 83 #include "chrome/grit/chromium_strings.h" 84 #include "chrome/grit/generated_resources.h" 85 #include "chromeos/chromeos_paths.h" 86 #include "chromeos/chromeos_switches.h" 87 #include "chromeos/dbus/fake_session_manager_client.h" 88 #include "chromeos/ime/extension_ime_util.h" 89 #include "chromeos/ime/input_method_descriptor.h" 90 #include "chromeos/ime/input_method_manager.h" 91 #include "chromeos/login/auth/mock_auth_status_consumer.h" 92 #include "chromeos/login/auth/user_context.h" 93 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 94 #include "components/policy/core/common/cloud/cloud_policy_core.h" 95 #include "components/policy/core/common/cloud/cloud_policy_store.h" 96 #include "components/policy/core/common/cloud/policy_builder.h" 97 #include "components/policy/core/common/external_data_fetcher.h" 98 #include "components/policy/core/common/policy_map.h" 99 #include "components/policy/core/common/policy_namespace.h" 100 #include "components/policy/core/common/policy_service.h" 101 #include "components/policy/core/common/policy_switches.h" 102 #include "components/signin/core/common/signin_pref_names.h" 103 #include "components/user_manager/user.h" 104 #include "components/user_manager/user_manager.h" 105 #include "components/user_manager/user_type.h" 106 #include "content/public/browser/browser_thread.h" 107 #include "content/public/browser/notification_details.h" 108 #include "content/public/browser/notification_service.h" 109 #include "content/public/browser/notification_source.h" 110 #include "content/public/browser/web_contents.h" 111 #include "content/public/browser/web_ui.h" 112 #include "content/public/test/browser_test_utils.h" 113 #include "content/public/test/test_utils.h" 114 #include "crypto/rsa_private_key.h" 115 #include "extensions/browser/app_window/app_window.h" 116 #include "extensions/browser/app_window/app_window_registry.h" 117 #include "extensions/browser/app_window/native_app_window.h" 118 #include "extensions/browser/extension_system.h" 119 #include "extensions/browser/management_policy.h" 120 #include "extensions/browser/notification_types.h" 121 #include "extensions/common/extension.h" 122 #include "net/base/url_util.h" 123 #include "net/http/http_status_code.h" 124 #include "net/test/embedded_test_server/embedded_test_server.h" 125 #include "net/test/embedded_test_server/http_request.h" 126 #include "net/test/embedded_test_server/http_response.h" 127 #include "net/url_request/test_url_fetcher_factory.h" 128 #include "net/url_request/url_fetcher_delegate.h" 129 #include "net/url_request/url_request_status.h" 130 #include "policy/policy_constants.h" 131 #include "testing/gmock/include/gmock/gmock.h" 132 #include "third_party/icu/source/common/unicode/locid.h" 133 #include "ui/base/l10n/l10n_util.h" 134 #include "ui/base/window_open_disposition.h" 135 #include "ui/gfx/image/image_skia.h" 136 #include "ui/views/widget/widget.h" 137 #include "url/gurl.h" 138 139 namespace em = enterprise_management; 140 141 using chromeos::LoginScreenContext; 142 using testing::InvokeWithoutArgs; 143 using testing::Return; 144 using testing::_; 145 146 namespace policy { 147 148 namespace { 149 150 const char kDomain[] = "example.com"; 151 const char kAccountId1[] = "dla1 (at) example.com"; 152 const char kAccountId2[] = "dla2 (at) example.com"; 153 const char kDisplayName1[] = "display name 1"; 154 const char kDisplayName2[] = "display name 2"; 155 const char* kStartupURLs[] = { 156 "chrome://policy", 157 "chrome://about", 158 }; 159 const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt"; 160 const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt"; 161 const char kRelativeUpdateURL[] = "/service/update2/crx"; 162 const char kUpdateManifestHeader[] = 163 "<?xml version='1.0' encoding='UTF-8'?>\n" 164 "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>\n"; 165 const char kUpdateManifestTemplate[] = 166 " <app appid='%s'>\n" 167 " <updatecheck codebase='%s' version='%s' />\n" 168 " </app>\n"; 169 const char kUpdateManifestFooter[] = 170 "</gupdate>\n"; 171 const char kHostedAppID[] = "kbmnembihfiondgfjekmnmcbddelicoi"; 172 const char kHostedAppCRXPath[] = "extensions/hosted_app.crx"; 173 const char kHostedAppVersion[] = "1.0.0.0"; 174 const char kGoodExtensionID[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; 175 const char kGoodExtensionCRXPath[] = "extensions/good.crx"; 176 const char kGoodExtensionVersion[] = "1.0"; 177 const char kPackagedAppCRXPath[] = "extensions/platform_apps/app_window_2.crx"; 178 179 const char kExternalData[] = "External data"; 180 const char kExternalDataURL[] = "http://localhost/external_data"; 181 182 const char* kSingleRecommendedLocale[] = { 183 "el", 184 }; 185 const char* kRecommendedLocales1[] = { 186 "pl", 187 "et", 188 "en-US", 189 }; 190 const char* kRecommendedLocales2[] = { 191 "fr", 192 "nl", 193 }; 194 const char* kInvalidRecommendedLocale[] = { 195 "xx", 196 }; 197 const char kPublicSessionLocale[] = "de"; 198 const char kPublicSessionInputMethodIDTemplate[] = "_comp_ime_%sxkb:de:neo:ger"; 199 200 // The sequence token used by GetKeyboardLayoutsForLocale() for its background 201 // tasks. 202 const char kSequenceToken[] = "chromeos_login_l10n_util"; 203 204 // Helper that serves extension update manifests to Chrome. 205 class TestingUpdateManifestProvider { 206 public: 207 // Update manifests will be served at |relative_update_url|. 208 explicit TestingUpdateManifestProvider( 209 const std::string& relative_update_url); 210 ~TestingUpdateManifestProvider(); 211 212 // When an update manifest is requested for the given extension |id|, indicate 213 // that |version| of the extension can be downloaded at |crx_url|. 214 void AddUpdate(const std::string& id, 215 const std::string& version, 216 const GURL& crx_url); 217 218 // This method must be registered with the test's EmbeddedTestServer to start 219 // serving update manifests. 220 scoped_ptr<net::test_server::HttpResponse> HandleRequest( 221 const net::test_server::HttpRequest& request); 222 223 private: 224 struct Update { 225 public: 226 Update(const std::string& version, const GURL& crx_url); 227 Update(); 228 229 std::string version; 230 GURL crx_url; 231 }; 232 typedef std::map<std::string, Update> UpdateMap; 233 UpdateMap updates_; 234 235 const std::string relative_update_url_; 236 237 DISALLOW_COPY_AND_ASSIGN(TestingUpdateManifestProvider); 238 }; 239 240 // Helper that observes the dictionary |pref| in local state and waits until the 241 // value stored for |key| matches |expected_value|. 242 class DictionaryPrefValueWaiter { 243 public: 244 DictionaryPrefValueWaiter(const std::string& pref, 245 const std::string& key, 246 const std::string& expected_value); 247 ~DictionaryPrefValueWaiter(); 248 249 void Wait(); 250 251 private: 252 void QuitLoopIfExpectedValueFound(); 253 254 const std::string pref_; 255 const std::string key_; 256 const std::string expected_value_; 257 258 base::RunLoop run_loop_; 259 PrefChangeRegistrar pref_change_registrar_; 260 261 DISALLOW_COPY_AND_ASSIGN(DictionaryPrefValueWaiter); 262 }; 263 264 TestingUpdateManifestProvider::Update::Update(const std::string& version, 265 const GURL& crx_url) 266 : version(version), 267 crx_url(crx_url) { 268 } 269 270 TestingUpdateManifestProvider::Update::Update() { 271 } 272 273 TestingUpdateManifestProvider::TestingUpdateManifestProvider( 274 const std::string& relative_update_url) 275 : relative_update_url_(relative_update_url) { 276 } 277 278 TestingUpdateManifestProvider::~TestingUpdateManifestProvider() { 279 } 280 281 void TestingUpdateManifestProvider::AddUpdate(const std::string& id, 282 const std::string& version, 283 const GURL& crx_url) { 284 updates_[id] = Update(version, crx_url); 285 } 286 287 scoped_ptr<net::test_server::HttpResponse> 288 TestingUpdateManifestProvider::HandleRequest( 289 const net::test_server::HttpRequest& request) { 290 const GURL url("http://localhost" + request.relative_url); 291 if (url.path() != relative_update_url_) 292 return scoped_ptr<net::test_server::HttpResponse>(); 293 294 std::string content = kUpdateManifestHeader; 295 for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) { 296 if (it.GetKey() != "x") 297 continue; 298 // Extract the extension id from the subquery. Since GetValueForKeyInQuery() 299 // expects a complete URL, dummy scheme and host must be prepended. 300 std::string id; 301 net::GetValueForKeyInQuery(GURL("http://dummy?" + it.GetUnescapedValue()), 302 "id", &id); 303 UpdateMap::const_iterator entry = updates_.find(id); 304 if (entry != updates_.end()) { 305 content += base::StringPrintf(kUpdateManifestTemplate, 306 id.c_str(), 307 entry->second.crx_url.spec().c_str(), 308 entry->second.version.c_str()); 309 } 310 } 311 content += kUpdateManifestFooter; 312 scoped_ptr<net::test_server::BasicHttpResponse> 313 http_response(new net::test_server::BasicHttpResponse); 314 http_response->set_code(net::HTTP_OK); 315 http_response->set_content(content); 316 http_response->set_content_type("text/xml"); 317 return http_response.PassAs<net::test_server::HttpResponse>(); 318 } 319 320 DictionaryPrefValueWaiter::DictionaryPrefValueWaiter( 321 const std::string& pref, 322 const std::string& key, 323 const std::string& expected_value) 324 : pref_(pref), 325 key_(key), 326 expected_value_(expected_value) { 327 pref_change_registrar_.Init(g_browser_process->local_state()); 328 } 329 330 DictionaryPrefValueWaiter::~DictionaryPrefValueWaiter() { 331 } 332 333 void DictionaryPrefValueWaiter::Wait() { 334 pref_change_registrar_.Add( 335 pref_.c_str(), 336 base::Bind(&DictionaryPrefValueWaiter::QuitLoopIfExpectedValueFound, 337 base::Unretained(this))); 338 QuitLoopIfExpectedValueFound(); 339 run_loop_.Run(); 340 } 341 342 void DictionaryPrefValueWaiter::QuitLoopIfExpectedValueFound() { 343 const base::DictionaryValue* pref = 344 pref_change_registrar_.prefs()->GetDictionary(pref_.c_str()); 345 ASSERT_TRUE(pref); 346 std::string actual_value; 347 if (pref->GetStringWithoutPathExpansion(key_, &actual_value) && 348 actual_value == expected_value_) { 349 run_loop_.Quit(); 350 } 351 } 352 353 bool DoesInstallSuccessReferToId(const std::string& id, 354 const content::NotificationSource& source, 355 const content::NotificationDetails& details) { 356 return content::Details<const extensions::InstalledExtensionInfo>(details)-> 357 extension->id() == id; 358 } 359 360 bool DoesInstallFailureReferToId(const std::string& id, 361 const content::NotificationSource& source, 362 const content::NotificationDetails& details) { 363 return content::Details<const base::string16>(details)-> 364 find(base::UTF8ToUTF16(id)) != base::string16::npos; 365 } 366 367 scoped_ptr<net::FakeURLFetcher> RunCallbackAndReturnFakeURLFetcher( 368 scoped_refptr<base::SequencedTaskRunner> task_runner, 369 const base::Closure& callback, 370 const GURL& url, 371 net::URLFetcherDelegate* delegate, 372 const std::string& response_data, 373 net::HttpStatusCode response_code, 374 net::URLRequestStatus::Status status) { 375 task_runner->PostTask(FROM_HERE, callback); 376 return make_scoped_ptr(new net::FakeURLFetcher( 377 url, delegate, response_data, response_code, status)); 378 } 379 380 bool IsSessionStarted() { 381 return user_manager::UserManager::Get()->IsSessionStarted(); 382 } 383 384 } // namespace 385 386 class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest, 387 public user_manager::UserManager::Observer, 388 public chrome::BrowserListObserver, 389 public extensions::AppWindowRegistry::Observer { 390 protected: 391 DeviceLocalAccountTest() 392 : user_id_1_(GenerateDeviceLocalAccountUserId( 393 kAccountId1, DeviceLocalAccount::TYPE_PUBLIC_SESSION)), 394 user_id_2_(GenerateDeviceLocalAccountUserId( 395 kAccountId2, DeviceLocalAccount::TYPE_PUBLIC_SESSION)), 396 public_session_input_method_id_(base::StringPrintf( 397 kPublicSessionInputMethodIDTemplate, 398 chromeos::extension_ime_util::kXkbExtensionId)), 399 contents_(NULL) { 400 set_exit_when_last_browser_closes(false); 401 } 402 403 virtual ~DeviceLocalAccountTest() {} 404 405 virtual void SetUp() OVERRIDE { 406 // Configure and start the test server. 407 scoped_ptr<crypto::RSAPrivateKey> signing_key( 408 PolicyBuilder::CreateTestSigningKey()); 409 ASSERT_TRUE(test_server_.SetSigningKeyAndSignature( 410 signing_key.get(), PolicyBuilder::GetTestSigningKeySignature())); 411 signing_key.reset(); 412 test_server_.RegisterClient(PolicyBuilder::kFakeToken, 413 PolicyBuilder::kFakeDeviceId); 414 ASSERT_TRUE(test_server_.Start()); 415 416 BrowserList::AddObserver(this); 417 418 DevicePolicyCrosBrowserTest::SetUp(); 419 } 420 421 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 422 DevicePolicyCrosBrowserTest::SetUpCommandLine(command_line); 423 command_line->AppendSwitch(chromeos::switches::kLoginManager); 424 command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests); 425 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 426 command_line->AppendSwitchASCII(policy::switches::kDeviceManagementUrl, 427 test_server_.GetServiceURL().spec()); 428 } 429 430 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 431 DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture(); 432 433 // Clear command-line arguments (but keep command-line switches) so the 434 // startup pages policy takes effect. 435 CommandLine* command_line = CommandLine::ForCurrentProcess(); 436 CommandLine::StringVector argv(command_line->argv()); 437 argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(), 438 argv.end()); 439 command_line->InitFromArgv(argv); 440 441 InstallOwnerKey(); 442 MarkAsEnterpriseOwned(); 443 444 InitializePolicy(); 445 } 446 447 virtual void SetUpOnMainThread() OVERRIDE { 448 DevicePolicyCrosBrowserTest::SetUpOnMainThread(); 449 450 initial_locale_ = g_browser_process->GetApplicationLocale(); 451 initial_language_ = l10n_util::GetLanguage(initial_locale_); 452 453 content::WindowedNotificationObserver( 454 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 455 content::NotificationService::AllSources()).Wait(); 456 457 chromeos::LoginDisplayHostImpl* host = 458 reinterpret_cast<chromeos::LoginDisplayHostImpl*>( 459 chromeos::LoginDisplayHostImpl::default_host()); 460 ASSERT_TRUE(host); 461 chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView(); 462 ASSERT_TRUE(web_ui_login_view); 463 content::WebUI* web_ui = web_ui_login_view->GetWebUI(); 464 ASSERT_TRUE(web_ui); 465 contents_ = web_ui->GetWebContents(); 466 ASSERT_TRUE(contents_); 467 468 // Wait for the login UI to be ready. 469 chromeos::OobeUI* oobe_ui = host->GetOobeUI(); 470 ASSERT_TRUE(oobe_ui); 471 base::RunLoop run_loop; 472 const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure()); 473 if (!oobe_ui_ready) 474 run_loop.Run(); 475 476 // The network selection screen changes the application locale on load and 477 // once again on blur. Wait for the screen to load and blur it so that any 478 // locale changes caused by this screen happen now and do not affect any 479 // subsequent parts of the test. 480 bool done = false; 481 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 482 contents_, 483 "var languageSelect = document.getElementById('language-select');" 484 "var blurAndReportSuccess = function() {" 485 " languageSelect.blur();" 486 " domAutomationController.send(true);" 487 "};" 488 "var screenLoading = document.getElementById('outer-container')" 489 " .classList.contains('down');" 490 "if (document.activeElement == languageSelect || !screenLoading)" 491 " blurAndReportSuccess();" 492 "else" 493 " languageSelect.addEventListener('focus', blurAndReportSuccess);", 494 &done)); 495 496 // Skip to the login screen. 497 chromeos::WizardController* wizard_controller = 498 chromeos::WizardController::default_controller(); 499 ASSERT_TRUE(wizard_controller); 500 wizard_controller->SkipToLoginForTesting(LoginScreenContext()); 501 } 502 503 virtual void TearDownOnMainThread() OVERRIDE { 504 BrowserList::RemoveObserver(this); 505 506 // This shuts down the login UI. 507 base::MessageLoop::current()->PostTask(FROM_HERE, 508 base::Bind(&chrome::AttemptExit)); 509 base::RunLoop().RunUntilIdle(); 510 } 511 512 virtual void LocalStateChanged( 513 user_manager::UserManager* user_manager) OVERRIDE { 514 if (run_loop_) 515 run_loop_->Quit(); 516 } 517 518 virtual void OnBrowserRemoved(Browser* browser) OVERRIDE { 519 if (run_loop_) 520 run_loop_->Quit(); 521 } 522 523 virtual void OnAppWindowAdded(extensions::AppWindow* app_window) OVERRIDE { 524 if (run_loop_) 525 run_loop_->Quit(); 526 } 527 528 virtual void OnAppWindowRemoved(extensions::AppWindow* app_window) OVERRIDE { 529 if (run_loop_) 530 run_loop_->Quit(); 531 } 532 533 void InitializePolicy() { 534 device_policy()->policy_data().set_public_key_version(1); 535 em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); 536 proto.mutable_show_user_names()->set_show_user_names(true); 537 538 device_local_account_policy_.policy_data().set_policy_type( 539 dm_protocol::kChromePublicAccountPolicyType); 540 device_local_account_policy_.policy_data().set_username(kAccountId1); 541 device_local_account_policy_.policy_data().set_settings_entity_id( 542 kAccountId1); 543 device_local_account_policy_.policy_data().set_public_key_version(1); 544 device_local_account_policy_.payload().mutable_userdisplayname()->set_value( 545 kDisplayName1); 546 } 547 548 void BuildDeviceLocalAccountPolicy() { 549 device_local_account_policy_.SetDefaultSigningKey(); 550 device_local_account_policy_.Build(); 551 } 552 553 void UploadDeviceLocalAccountPolicy() { 554 BuildDeviceLocalAccountPolicy(); 555 test_server_.UpdatePolicy( 556 dm_protocol::kChromePublicAccountPolicyType, kAccountId1, 557 device_local_account_policy_.payload().SerializeAsString()); 558 } 559 560 void UploadAndInstallDeviceLocalAccountPolicy() { 561 UploadDeviceLocalAccountPolicy(); 562 session_manager_client()->set_device_local_account_policy( 563 kAccountId1, device_local_account_policy_.GetBlob()); 564 } 565 566 void SetRecommendedLocales(const char* recommended_locales[], 567 size_t array_size) { 568 em::StringListPolicyProto* session_locales_proto = 569 device_local_account_policy_.payload().mutable_sessionlocales(); 570 session_locales_proto->mutable_policy_options()->set_mode( 571 em::PolicyOptions_PolicyMode_RECOMMENDED); 572 session_locales_proto->mutable_value()->Clear(); 573 for (size_t i = 0; i < array_size; ++i) { 574 session_locales_proto->mutable_value()->add_entries( 575 recommended_locales[i]); 576 } 577 } 578 579 void AddPublicSessionToDevicePolicy(const std::string& username) { 580 em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); 581 em::DeviceLocalAccountInfoProto* account = 582 proto.mutable_device_local_accounts()->add_account(); 583 account->set_account_id(username); 584 account->set_type( 585 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); 586 RefreshDevicePolicy(); 587 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, 588 std::string(), proto.SerializeAsString()); 589 } 590 591 void EnableAutoLogin() { 592 em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); 593 em::DeviceLocalAccountsProto* device_local_accounts = 594 proto.mutable_device_local_accounts(); 595 device_local_accounts->set_auto_login_id(kAccountId1); 596 device_local_accounts->set_auto_login_delay(0); 597 RefreshDevicePolicy(); 598 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, 599 std::string(), proto.SerializeAsString()); 600 } 601 602 void CheckPublicSessionPresent(const std::string& id) { 603 const user_manager::User* user = 604 user_manager::UserManager::Get()->FindUser(id); 605 ASSERT_TRUE(user); 606 EXPECT_EQ(id, user->email()); 607 EXPECT_EQ(user_manager::USER_TYPE_PUBLIC_ACCOUNT, user->GetType()); 608 } 609 610 base::FilePath GetExtensionCacheDirectoryForAccountID( 611 const std::string& account_id) { 612 base::FilePath extension_cache_root_dir; 613 if (!PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS, 614 &extension_cache_root_dir)) { 615 ADD_FAILURE(); 616 } 617 return extension_cache_root_dir.Append( 618 base::HexEncode(account_id.c_str(), account_id.size())); 619 } 620 621 base::FilePath GetCacheCRXFile(const std::string& account_id, 622 const std::string& id, 623 const std::string& version) { 624 return GetExtensionCacheDirectoryForAccountID(account_id) 625 .Append(base::StringPrintf("%s-%s.crx", id.c_str(), version.c_str())); 626 } 627 628 // Returns a profile which can be used for testing. 629 Profile* GetProfileForTest() { 630 // Any profile can be used here since this test does not test multi profile. 631 return ProfileManager::GetActiveUserProfile(); 632 } 633 634 void WaitForDisplayName(const std::string& user_id, 635 const std::string& expected_display_name) { 636 DictionaryPrefValueWaiter("UserDisplayName", 637 user_id, 638 expected_display_name).Wait(); 639 } 640 641 void WaitForPolicy() { 642 // Wait for the display name becoming available as that indicates 643 // device-local account policy is fully loaded, which is a prerequisite for 644 // successful login. 645 WaitForDisplayName(user_id_1_, kDisplayName1); 646 } 647 648 void ExpandPublicSessionPod(bool expect_advanced) { 649 bool advanced = false; 650 // Click on the pod to expand it. 651 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 652 contents_, 653 base::StringPrintf( 654 "var pod =" 655 " document.getElementById('pod-row').getPodWithUsername_('%s');" 656 "pod.click();" 657 "domAutomationController.send(pod.classList.contains('advanced'));", 658 user_id_1_.c_str()), 659 &advanced)); 660 // Verify that the pod expanded to its basic/advanced form, as expected. 661 EXPECT_EQ(expect_advanced, advanced); 662 663 // Verify that the construction of the pod's language list did not affect 664 // the current ICU locale. 665 EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); 666 } 667 668 // GetKeyboardLayoutsForLocale() posts a task to a background task runner. 669 // This method flushes that task runner and the current thread's message loop 670 // to ensure that GetKeyboardLayoutsForLocale() is finished. 671 void WaitForGetKeyboardLayoutsForLocaleToFinish() { 672 base::SequencedWorkerPool* worker_pool = 673 content::BrowserThread::GetBlockingPool(); 674 scoped_refptr<base::SequencedTaskRunner> background_task_runner = 675 worker_pool->GetSequencedTaskRunner( 676 worker_pool->GetNamedSequenceToken(kSequenceToken)); 677 base::RunLoop run_loop; 678 background_task_runner->PostTaskAndReply(FROM_HERE, 679 base::Bind(&base::DoNothing), 680 run_loop.QuitClosure()); 681 run_loop.Run(); 682 base::RunLoop().RunUntilIdle(); 683 684 // Verify that the construction of the keyboard layout list did not affect 685 // the current ICU locale. 686 EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); 687 } 688 689 void StartLogin(const std::string& locale, 690 const std::string& input_method) { 691 // Start login into the device-local account. 692 chromeos::LoginDisplayHostImpl* host = 693 reinterpret_cast<chromeos::LoginDisplayHostImpl*>( 694 chromeos::LoginDisplayHostImpl::default_host()); 695 ASSERT_TRUE(host); 696 host->StartSignInScreen(LoginScreenContext()); 697 chromeos::ExistingUserController* controller = 698 chromeos::ExistingUserController::current_controller(); 699 ASSERT_TRUE(controller); 700 701 chromeos::UserContext user_context(user_manager::USER_TYPE_PUBLIC_ACCOUNT, 702 user_id_1_); 703 user_context.SetPublicSessionLocale(locale); 704 user_context.SetPublicSessionInputMethod(input_method); 705 controller->LoginAsPublicSession(user_context); 706 } 707 708 void WaitForSessionStart() { 709 if (IsSessionStarted()) 710 return; 711 content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED, 712 base::Bind(IsSessionStarted)).Wait(); 713 } 714 715 void VerifyKeyboardLayoutMatchesLocale() { 716 chromeos::input_method::InputMethodManager* input_method_manager = 717 chromeos::input_method::InputMethodManager::Get(); 718 std::vector<std::string> layouts_from_locale; 719 input_method_manager->GetInputMethodUtil()-> 720 GetInputMethodIdsFromLanguageCode( 721 g_browser_process->GetApplicationLocale(), 722 chromeos::input_method::kKeyboardLayoutsOnly, 723 &layouts_from_locale); 724 ASSERT_FALSE(layouts_from_locale.empty()); 725 EXPECT_EQ(layouts_from_locale.front(), 726 input_method_manager->GetActiveIMEState() 727 ->GetCurrentInputMethod() 728 .id()); 729 } 730 731 const std::string user_id_1_; 732 const std::string user_id_2_; 733 const std::string public_session_input_method_id_; 734 735 std::string initial_locale_; 736 std::string initial_language_; 737 738 scoped_ptr<base::RunLoop> run_loop_; 739 740 UserPolicyBuilder device_local_account_policy_; 741 LocalPolicyTestServer test_server_; 742 743 content::WebContents* contents_; 744 745 private: 746 DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountTest); 747 }; 748 749 static bool IsKnownUser(const std::string& account_id) { 750 return user_manager::UserManager::Get()->IsKnownUser(account_id); 751 } 752 753 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) { 754 AddPublicSessionToDevicePolicy(kAccountId1); 755 AddPublicSessionToDevicePolicy(kAccountId2); 756 757 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED, 758 base::Bind(&IsKnownUser, user_id_1_)) 759 .Wait(); 760 EXPECT_TRUE(IsKnownUser(user_id_2_)); 761 762 CheckPublicSessionPresent(user_id_1_); 763 CheckPublicSessionPresent(user_id_2_); 764 } 765 766 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) { 767 UploadAndInstallDeviceLocalAccountPolicy(); 768 AddPublicSessionToDevicePolicy(kAccountId1); 769 770 WaitForPolicy(); 771 772 // Verify that the display name is shown in the UI. 773 const std::string get_compact_pod_display_name = base::StringPrintf( 774 "domAutomationController.send(document.getElementById('pod-row')" 775 " .getPodWithUsername_('%s').nameElement.textContent);", 776 user_id_1_.c_str()); 777 std::string display_name; 778 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 779 contents_, 780 get_compact_pod_display_name, 781 &display_name)); 782 EXPECT_EQ(kDisplayName1, display_name); 783 const std::string get_expanded_pod_display_name = base::StringPrintf( 784 "domAutomationController.send(document.getElementById('pod-row')" 785 " .getPodWithUsername_('%s').querySelector('.expanded-pane-name')" 786 " .textContent);", 787 user_id_1_.c_str()); 788 display_name.clear(); 789 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 790 contents_, 791 get_expanded_pod_display_name, 792 &display_name)); 793 EXPECT_EQ(kDisplayName1, display_name); 794 795 // Click on the pod to expand it. 796 ASSERT_TRUE(content::ExecuteScript( 797 contents_, 798 base::StringPrintf( 799 "document.getElementById('pod-row').getPodWithUsername_('%s')" 800 " .click();", 801 user_id_1_.c_str()))); 802 803 // Change the display name. 804 device_local_account_policy_.payload().mutable_userdisplayname()->set_value( 805 kDisplayName2); 806 UploadAndInstallDeviceLocalAccountPolicy(); 807 policy::BrowserPolicyConnectorChromeOS* connector = 808 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 809 DeviceLocalAccountPolicyBroker* broker = 810 connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser( 811 user_id_1_); 812 ASSERT_TRUE(broker); 813 broker->core()->store()->Load(); 814 WaitForDisplayName(user_id_1_, kDisplayName2); 815 816 // Verify that the new display name is shown in the UI. 817 display_name.clear(); 818 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 819 contents_, 820 get_compact_pod_display_name, 821 &display_name)); 822 EXPECT_EQ(kDisplayName2, display_name); 823 display_name.clear(); 824 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 825 contents_, 826 get_expanded_pod_display_name, 827 &display_name)); 828 EXPECT_EQ(kDisplayName2, display_name); 829 830 // Verify that the pod is still expanded. This indicates that the UI updated 831 // without reloading and losing state. 832 bool expanded = false; 833 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 834 contents_, 835 base::StringPrintf( 836 "domAutomationController.send(document.getElementById('pod-row')" 837 " .getPodWithUsername_('%s').expanded);", 838 user_id_1_.c_str()), 839 &expanded)); 840 EXPECT_TRUE(expanded); 841 } 842 843 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) { 844 UploadDeviceLocalAccountPolicy(); 845 AddPublicSessionToDevicePolicy(kAccountId1); 846 847 WaitForPolicy(); 848 849 // Sanity check: The policy should be present now. 850 ASSERT_FALSE(session_manager_client()->device_local_account_policy( 851 kAccountId1).empty()); 852 } 853 854 static bool IsNotKnownUser(const std::string& account_id) { 855 return !IsKnownUser(account_id); 856 } 857 858 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, AccountListChange) { 859 AddPublicSessionToDevicePolicy(kAccountId1); 860 AddPublicSessionToDevicePolicy(kAccountId2); 861 862 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED, 863 base::Bind(&IsKnownUser, user_id_1_)) 864 .Wait(); 865 EXPECT_TRUE(IsKnownUser(user_id_2_)); 866 867 // Update policy to remove kAccountId2. 868 em::ChromeDeviceSettingsProto& proto(device_policy()->payload()); 869 proto.mutable_device_local_accounts()->clear_account(); 870 AddPublicSessionToDevicePolicy(kAccountId1); 871 872 em::ChromeDeviceSettingsProto policy; 873 policy.mutable_show_user_names()->set_show_user_names(true); 874 em::DeviceLocalAccountInfoProto* account1 = 875 policy.mutable_device_local_accounts()->add_account(); 876 account1->set_account_id(kAccountId1); 877 account1->set_type( 878 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); 879 880 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(), 881 policy.SerializeAsString()); 882 g_browser_process->policy_service()->RefreshPolicies(base::Closure()); 883 884 // Make sure the second device-local account disappears. 885 content::WindowedNotificationObserver(chrome::NOTIFICATION_USER_LIST_CHANGED, 886 base::Bind(&IsNotKnownUser, user_id_2_)) 887 .Wait(); 888 } 889 890 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) { 891 // Specify startup pages. 892 device_local_account_policy_.payload().mutable_restoreonstartup()->set_value( 893 SessionStartupPref::kPrefValueURLs); 894 em::StringListPolicyProto* startup_urls_proto = 895 device_local_account_policy_.payload().mutable_restoreonstartupurls(); 896 for (size_t i = 0; i < arraysize(kStartupURLs); ++i) 897 startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]); 898 UploadAndInstallDeviceLocalAccountPolicy(); 899 AddPublicSessionToDevicePolicy(kAccountId1); 900 901 WaitForPolicy(); 902 903 ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); 904 WaitForSessionStart(); 905 906 // Check that the startup pages specified in policy were opened. 907 BrowserList* browser_list = 908 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 909 EXPECT_EQ(1U, browser_list->size()); 910 Browser* browser = browser_list->get(0); 911 ASSERT_TRUE(browser); 912 913 TabStripModel* tabs = browser->tab_strip_model(); 914 ASSERT_TRUE(tabs); 915 int expected_tab_count = static_cast<int>(arraysize(kStartupURLs)); 916 EXPECT_EQ(expected_tab_count, tabs->count()); 917 for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) { 918 EXPECT_EQ(GURL(kStartupURLs[i]), 919 tabs->GetWebContentsAt(i)->GetVisibleURL()); 920 } 921 922 // Verify that the session is not considered to be logged in with a GAIA 923 // account. 924 Profile* profile = GetProfileForTest(); 925 ASSERT_TRUE(profile); 926 EXPECT_FALSE(profile->GetPrefs()->HasPrefPath( 927 prefs::kGoogleServicesUsername)); 928 } 929 930 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, FullscreenDisallowed) { 931 UploadAndInstallDeviceLocalAccountPolicy(); 932 AddPublicSessionToDevicePolicy(kAccountId1); 933 934 WaitForPolicy(); 935 936 ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); 937 WaitForSessionStart(); 938 939 BrowserList* browser_list = 940 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 941 EXPECT_EQ(1U, browser_list->size()); 942 Browser* browser = browser_list->get(0); 943 ASSERT_TRUE(browser); 944 BrowserWindow* browser_window = browser->window(); 945 ASSERT_TRUE(browser_window); 946 947 // Verify that an attempt to enter fullscreen mode is denied. 948 EXPECT_FALSE(browser_window->IsFullscreen()); 949 chrome::ToggleFullscreenMode(browser); 950 EXPECT_FALSE(browser_window->IsFullscreen()); 951 } 952 953 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsUncached) { 954 // Make it possible to force-install a hosted app and an extension. 955 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 956 TestingUpdateManifestProvider testing_update_manifest_provider( 957 kRelativeUpdateURL); 958 testing_update_manifest_provider.AddUpdate( 959 kHostedAppID, 960 kHostedAppVersion, 961 embedded_test_server()->GetURL(std::string("/") + kHostedAppCRXPath)); 962 testing_update_manifest_provider.AddUpdate( 963 kGoodExtensionID, 964 kGoodExtensionVersion, 965 embedded_test_server()->GetURL(std::string("/") + kGoodExtensionCRXPath)); 966 embedded_test_server()->RegisterRequestHandler( 967 base::Bind(&TestingUpdateManifestProvider::HandleRequest, 968 base::Unretained(&testing_update_manifest_provider))); 969 970 // Specify policy to force-install the hosted app and the extension. 971 em::StringList* forcelist = device_local_account_policy_.payload() 972 .mutable_extensioninstallforcelist()->mutable_value(); 973 forcelist->add_entries(base::StringPrintf( 974 "%s;%s", 975 kHostedAppID, 976 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); 977 forcelist->add_entries(base::StringPrintf( 978 "%s;%s", 979 kGoodExtensionID, 980 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); 981 982 UploadAndInstallDeviceLocalAccountPolicy(); 983 AddPublicSessionToDevicePolicy(kAccountId1); 984 985 WaitForPolicy(); 986 987 // Start listening for app/extension installation results. 988 content::WindowedNotificationObserver hosted_app_observer( 989 extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED, 990 base::Bind(DoesInstallSuccessReferToId, kHostedAppID)); 991 content::WindowedNotificationObserver extension_observer( 992 extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR, 993 base::Bind(DoesInstallFailureReferToId, kGoodExtensionID)); 994 995 ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); 996 997 // Wait for the hosted app installation to succeed and the extension 998 // installation to fail (because hosted apps are whitelisted for use in 999 // device-local accounts and extensions are not). 1000 hosted_app_observer.Wait(); 1001 extension_observer.Wait(); 1002 1003 // Verify that the hosted app was installed. 1004 Profile* profile = GetProfileForTest(); 1005 ASSERT_TRUE(profile); 1006 ExtensionService* extension_service = 1007 extensions::ExtensionSystem::Get(profile)->extension_service(); 1008 EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true)); 1009 1010 // Verify that the extension was not installed. 1011 EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true)); 1012 1013 // Verify that the app was downloaded to the account's extension cache. 1014 base::FilePath test_dir; 1015 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 1016 EXPECT_TRUE(ContentsEqual( 1017 GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion), 1018 test_dir.Append(kHostedAppCRXPath))); 1019 1020 // Verify that the extension was removed from the account's extension cache 1021 // after the installation failure. 1022 DeviceLocalAccountPolicyBroker* broker = 1023 g_browser_process->platform_part()->browser_policy_connector_chromeos()-> 1024 GetDeviceLocalAccountPolicyService()->GetBrokerForUser(user_id_1_); 1025 ASSERT_TRUE(broker); 1026 chromeos::ExternalCache* cache = 1027 broker->extension_loader()->GetExternalCacheForTesting(); 1028 ASSERT_TRUE(cache); 1029 EXPECT_FALSE(cache->GetExtension(kGoodExtensionID, NULL, NULL)); 1030 } 1031 1032 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExtensionsCached) { 1033 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 1034 1035 // Pre-populate the device local account's extension cache with a hosted app 1036 // and an extension. 1037 EXPECT_TRUE(base::CreateDirectory( 1038 GetExtensionCacheDirectoryForAccountID(kAccountId1))); 1039 base::FilePath test_dir; 1040 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 1041 const base::FilePath cached_hosted_app = 1042 GetCacheCRXFile(kAccountId1, kHostedAppID, kHostedAppVersion); 1043 EXPECT_TRUE(CopyFile(test_dir.Append(kHostedAppCRXPath), 1044 cached_hosted_app)); 1045 EXPECT_TRUE(CopyFile( 1046 test_dir.Append(kGoodExtensionCRXPath), 1047 GetCacheCRXFile(kAccountId1, kGoodExtensionID, kGoodExtensionVersion))); 1048 1049 // Specify policy to force-install the hosted app. 1050 em::StringList* forcelist = device_local_account_policy_.payload() 1051 .mutable_extensioninstallforcelist()->mutable_value(); 1052 forcelist->add_entries(base::StringPrintf( 1053 "%s;%s", 1054 kHostedAppID, 1055 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); 1056 forcelist->add_entries(base::StringPrintf( 1057 "%s;%s", 1058 kGoodExtensionID, 1059 embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); 1060 1061 UploadAndInstallDeviceLocalAccountPolicy(); 1062 AddPublicSessionToDevicePolicy(kAccountId1); 1063 1064 WaitForPolicy(); 1065 1066 // Start listening for app/extension installation results. 1067 content::WindowedNotificationObserver hosted_app_observer( 1068 extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED, 1069 base::Bind(DoesInstallSuccessReferToId, kHostedAppID)); 1070 content::WindowedNotificationObserver extension_observer( 1071 extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR, 1072 base::Bind(DoesInstallFailureReferToId, kGoodExtensionID)); 1073 1074 ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); 1075 1076 // Wait for the hosted app installation to succeed and the extension 1077 // installation to fail. 1078 hosted_app_observer.Wait(); 1079 extension_observer.Wait(); 1080 1081 // Verify that the hosted app was installed. 1082 Profile* profile = GetProfileForTest(); 1083 ASSERT_TRUE(profile); 1084 ExtensionService* extension_service = 1085 extensions::ExtensionSystem::Get(profile)->extension_service(); 1086 EXPECT_TRUE(extension_service->GetExtensionById(kHostedAppID, true)); 1087 1088 // Verify that the extension was not installed. 1089 EXPECT_FALSE(extension_service->GetExtensionById(kGoodExtensionID, true)); 1090 1091 // Verify that the app is still in the account's extension cache. 1092 EXPECT_TRUE(PathExists(cached_hosted_app)); 1093 1094 // Verify that the extension was removed from the account's extension cache. 1095 DeviceLocalAccountPolicyBroker* broker = 1096 g_browser_process->platform_part()->browser_policy_connector_chromeos()-> 1097 GetDeviceLocalAccountPolicyService()->GetBrokerForUser(user_id_1_); 1098 ASSERT_TRUE(broker); 1099 chromeos::ExternalCache* cache = 1100 broker->extension_loader()->GetExternalCacheForTesting(); 1101 ASSERT_TRUE(cache); 1102 EXPECT_FALSE(cache->GetExtension(kGoodExtensionID, NULL, NULL)); 1103 } 1104 1105 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, ExternalData) { 1106 // user_manager::UserManager requests an external data fetch whenever 1107 // the key::kUserAvatarImage policy is set. Since this test wants to 1108 // verify that the underlying policy subsystem will start a fetch 1109 // without this request as well, the user_manager::UserManager must be 1110 // prevented from seeing the policy change. 1111 reinterpret_cast<chromeos::ChromeUserManagerImpl*>( 1112 user_manager::UserManager::Get())->StopPolicyObserverForTesting(); 1113 1114 UploadDeviceLocalAccountPolicy(); 1115 AddPublicSessionToDevicePolicy(kAccountId1); 1116 1117 WaitForPolicy(); 1118 1119 // Start serving external data at |kExternalDataURL|. 1120 scoped_ptr<base::RunLoop> run_loop(new base::RunLoop); 1121 scoped_ptr<net::FakeURLFetcherFactory> fetcher_factory( 1122 new net::FakeURLFetcherFactory( 1123 NULL, 1124 base::Bind(&RunCallbackAndReturnFakeURLFetcher, 1125 base::MessageLoopProxy::current(), 1126 run_loop->QuitClosure()))); 1127 fetcher_factory->SetFakeResponse(GURL(kExternalDataURL), 1128 kExternalData, 1129 net::HTTP_OK, 1130 net::URLRequestStatus::SUCCESS); 1131 1132 // Specify an external data reference for the key::kUserAvatarImage policy. 1133 scoped_ptr<base::DictionaryValue> metadata = 1134 test::ConstructExternalDataReference(kExternalDataURL, kExternalData); 1135 std::string policy; 1136 base::JSONWriter::Write(metadata.get(), &policy); 1137 device_local_account_policy_.payload().mutable_useravatarimage()->set_value( 1138 policy); 1139 UploadAndInstallDeviceLocalAccountPolicy(); 1140 policy::BrowserPolicyConnectorChromeOS* connector = 1141 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 1142 DeviceLocalAccountPolicyBroker* broker = 1143 connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser( 1144 user_id_1_); 1145 ASSERT_TRUE(broker); 1146 broker->core()->store()->Load(); 1147 1148 // The external data should be fetched and cached automatically. Wait for this 1149 // fetch. 1150 run_loop->Run(); 1151 1152 // Stop serving external data at |kExternalDataURL|. 1153 fetcher_factory.reset(); 1154 1155 const PolicyMap::Entry* policy_entry = 1156 broker->core()->store()->policy_map().Get(key::kUserAvatarImage); 1157 ASSERT_TRUE(policy_entry); 1158 ASSERT_TRUE(policy_entry->external_data_fetcher); 1159 1160 // Retrieve the external data. Although the data is no longer being served at 1161 // |kExternalDataURL|, the retrieval should succeed because the data has been 1162 // cached. 1163 run_loop.reset(new base::RunLoop); 1164 scoped_ptr<std::string> fetched_external_data; 1165 policy_entry->external_data_fetcher->Fetch(base::Bind( 1166 &test::ExternalDataFetchCallback, 1167 &fetched_external_data, 1168 run_loop->QuitClosure())); 1169 run_loop->Run(); 1170 1171 ASSERT_TRUE(fetched_external_data); 1172 EXPECT_EQ(kExternalData, *fetched_external_data); 1173 1174 ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); 1175 WaitForSessionStart(); 1176 1177 // Verify that the external data reference has propagated to the device-local 1178 // account's ProfilePolicyConnector. 1179 ProfilePolicyConnector* policy_connector = 1180 ProfilePolicyConnectorFactory::GetForProfile(GetProfileForTest()); 1181 ASSERT_TRUE(policy_connector); 1182 const PolicyMap& policies = policy_connector->policy_service()->GetPolicies( 1183 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); 1184 policy_entry = policies.Get(key::kUserAvatarImage); 1185 ASSERT_TRUE(policy_entry); 1186 EXPECT_TRUE(base::Value::Equals(metadata.get(), policy_entry->value)); 1187 ASSERT_TRUE(policy_entry->external_data_fetcher); 1188 1189 // Retrieve the external data via the ProfilePolicyConnector. The retrieval 1190 // should succeed because the data has been cached. 1191 run_loop.reset(new base::RunLoop); 1192 fetched_external_data.reset(); 1193 policy_entry->external_data_fetcher->Fetch(base::Bind( 1194 &test::ExternalDataFetchCallback, 1195 &fetched_external_data, 1196 run_loop->QuitClosure())); 1197 run_loop->Run(); 1198 1199 ASSERT_TRUE(fetched_external_data); 1200 EXPECT_EQ(kExternalData, *fetched_external_data); 1201 } 1202 1203 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, UserAvatarImage) { 1204 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 1205 1206 UploadDeviceLocalAccountPolicy(); 1207 AddPublicSessionToDevicePolicy(kAccountId1); 1208 1209 WaitForPolicy(); 1210 1211 base::FilePath test_dir; 1212 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 1213 std::string image_data; 1214 ASSERT_TRUE(base::ReadFileToString( 1215 test_dir.Append(chromeos::test::kUserAvatarImage1RelativePath), 1216 &image_data)); 1217 1218 std::string policy; 1219 base::JSONWriter::Write(test::ConstructExternalDataReference( 1220 embedded_test_server()->GetURL(std::string("/") + 1221 chromeos::test::kUserAvatarImage1RelativePath).spec(), 1222 image_data).get(), 1223 &policy); 1224 device_local_account_policy_.payload().mutable_useravatarimage()->set_value( 1225 policy); 1226 UploadAndInstallDeviceLocalAccountPolicy(); 1227 policy::BrowserPolicyConnectorChromeOS* connector = 1228 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 1229 DeviceLocalAccountPolicyBroker* broker = 1230 connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser( 1231 user_id_1_); 1232 ASSERT_TRUE(broker); 1233 1234 run_loop_.reset(new base::RunLoop); 1235 user_manager::UserManager::Get()->AddObserver(this); 1236 broker->core()->store()->Load(); 1237 run_loop_->Run(); 1238 user_manager::UserManager::Get()->RemoveObserver(this); 1239 1240 scoped_ptr<gfx::ImageSkia> policy_image = chromeos::test::ImageLoader( 1241 test_dir.Append(chromeos::test::kUserAvatarImage1RelativePath)).Load(); 1242 ASSERT_TRUE(policy_image); 1243 1244 const user_manager::User* user = 1245 user_manager::UserManager::Get()->FindUser(user_id_1_); 1246 ASSERT_TRUE(user); 1247 1248 base::FilePath user_data_dir; 1249 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)); 1250 const base::FilePath saved_image_path = 1251 user_data_dir.Append(user_id_1_).AddExtension("jpg"); 1252 1253 EXPECT_FALSE(user->HasDefaultImage()); 1254 EXPECT_EQ(user_manager::User::USER_IMAGE_EXTERNAL, user->image_index()); 1255 EXPECT_TRUE(chromeos::test::AreImagesEqual(*policy_image, user->GetImage())); 1256 const base::DictionaryValue* images_pref = 1257 g_browser_process->local_state()->GetDictionary("user_image_info"); 1258 ASSERT_TRUE(images_pref); 1259 const base::DictionaryValue* image_properties; 1260 ASSERT_TRUE(images_pref->GetDictionaryWithoutPathExpansion( 1261 user_id_1_, 1262 &image_properties)); 1263 int image_index; 1264 std::string image_path; 1265 ASSERT_TRUE(image_properties->GetInteger("index", &image_index)); 1266 ASSERT_TRUE(image_properties->GetString("path", &image_path)); 1267 EXPECT_EQ(user_manager::User::USER_IMAGE_EXTERNAL, image_index); 1268 EXPECT_EQ(saved_image_path.value(), image_path); 1269 1270 scoped_ptr<gfx::ImageSkia> saved_image = 1271 chromeos::test::ImageLoader(saved_image_path).Load(); 1272 ASSERT_TRUE(saved_image); 1273 1274 // Check image dimensions. Images can't be compared since JPEG is lossy. 1275 EXPECT_EQ(policy_image->width(), saved_image->width()); 1276 EXPECT_EQ(policy_image->height(), saved_image->height()); 1277 } 1278 1279 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LastWindowClosedLogoutReminder) { 1280 UploadAndInstallDeviceLocalAccountPolicy(); 1281 AddPublicSessionToDevicePolicy(kAccountId1); 1282 1283 WaitForPolicy(); 1284 1285 ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); 1286 WaitForSessionStart(); 1287 1288 Profile* profile = GetProfileForTest(); 1289 ASSERT_TRUE(profile); 1290 extensions::AppWindowRegistry* app_window_registry = 1291 extensions::AppWindowRegistry::Get(profile); 1292 app_window_registry->AddObserver(this); 1293 1294 // Verify that the logout confirmation dialog is not showing. 1295 ash::LogoutConfirmationController* logout_confirmation_controller = 1296 ash::Shell::GetInstance()->logout_confirmation_controller(); 1297 ASSERT_TRUE(logout_confirmation_controller); 1298 EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing()); 1299 1300 // Remove policy that allows only explicitly whitelisted apps to be installed 1301 // in a public session. 1302 extensions::ExtensionSystem* extension_system = 1303 extensions::ExtensionSystem::Get(profile); 1304 ASSERT_TRUE(extension_system); 1305 extension_system->management_policy()->UnregisterAllProviders(); 1306 1307 // Install and a platform app. 1308 scoped_refptr<extensions::CrxInstaller> installer = 1309 extensions::CrxInstaller::CreateSilent( 1310 extension_system->extension_service()); 1311 installer->set_allow_silent_install(true); 1312 installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD); 1313 installer->set_creation_flags(extensions::Extension::FROM_WEBSTORE); 1314 content::WindowedNotificationObserver app_install_observer( 1315 extensions::NOTIFICATION_CRX_INSTALLER_DONE, 1316 content::NotificationService::AllSources()); 1317 base::FilePath test_dir; 1318 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 1319 installer->InstallCrx(test_dir.Append(kPackagedAppCRXPath)); 1320 app_install_observer.Wait(); 1321 const extensions::Extension* app = 1322 content::Details<const extensions::Extension>( 1323 app_install_observer.details()).ptr(); 1324 1325 // Start the platform app, causing it to open a window. 1326 run_loop_.reset(new base::RunLoop); 1327 OpenApplication(AppLaunchParams( 1328 profile, app, extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW)); 1329 run_loop_->Run(); 1330 EXPECT_EQ(1U, app_window_registry->app_windows().size()); 1331 1332 // Close the only open browser window. 1333 BrowserList* browser_list = 1334 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 1335 EXPECT_EQ(1U, browser_list->size()); 1336 Browser* browser = browser_list->get(0); 1337 ASSERT_TRUE(browser); 1338 BrowserWindow* browser_window = browser->window(); 1339 ASSERT_TRUE(browser_window); 1340 run_loop_.reset(new base::RunLoop); 1341 browser_window->Close(); 1342 browser_window = NULL; 1343 run_loop_->Run(); 1344 browser = NULL; 1345 EXPECT_TRUE(browser_list->empty()); 1346 1347 // Verify that the logout confirmation dialog is not showing because an app 1348 // window is still open. 1349 EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing()); 1350 1351 // Open a browser window. 1352 Browser* first_browser = CreateBrowser(profile); 1353 EXPECT_EQ(1U, browser_list->size()); 1354 1355 // Close the app window. 1356 run_loop_.reset(new base::RunLoop); 1357 ASSERT_EQ(1U, app_window_registry->app_windows().size()); 1358 app_window_registry->app_windows().front()->GetBaseWindow()->Close(); 1359 run_loop_->Run(); 1360 EXPECT_TRUE(app_window_registry->app_windows().empty()); 1361 1362 // Verify that the logout confirmation dialog is not showing because a browser 1363 // window is still open. 1364 EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing()); 1365 1366 // Open a second browser window. 1367 Browser* second_browser = CreateBrowser(profile); 1368 EXPECT_EQ(2U, browser_list->size()); 1369 1370 // Close the first browser window. 1371 browser_window = first_browser->window(); 1372 ASSERT_TRUE(browser_window); 1373 run_loop_.reset(new base::RunLoop); 1374 browser_window->Close(); 1375 browser_window = NULL; 1376 run_loop_->Run(); 1377 first_browser = NULL; 1378 EXPECT_EQ(1U, browser_list->size()); 1379 1380 // Verify that the logout confirmation dialog is not showing because a browser 1381 // window is still open. 1382 EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing()); 1383 1384 // Close the second browser window. 1385 browser_window = second_browser->window(); 1386 ASSERT_TRUE(browser_window); 1387 run_loop_.reset(new base::RunLoop); 1388 browser_window->Close(); 1389 browser_window = NULL; 1390 run_loop_->Run(); 1391 second_browser = NULL; 1392 EXPECT_TRUE(browser_list->empty()); 1393 1394 // Verify that the logout confirmation dialog is showing. 1395 ash::LogoutConfirmationDialog* dialog = 1396 logout_confirmation_controller->dialog_for_testing(); 1397 ASSERT_TRUE(dialog); 1398 1399 // Deny the logout. 1400 dialog->GetWidget()->Close(); 1401 dialog = NULL; 1402 base::RunLoop().RunUntilIdle(); 1403 1404 // Verify that the logout confirmation dialog is no longer showing. 1405 EXPECT_FALSE(logout_confirmation_controller->dialog_for_testing()); 1406 1407 // Open a browser window. 1408 browser = CreateBrowser(profile); 1409 EXPECT_EQ(1U, browser_list->size()); 1410 1411 // Close the browser window. 1412 browser_window = browser->window(); 1413 ASSERT_TRUE(browser_window); 1414 run_loop_.reset(new base::RunLoop); 1415 browser_window->Close(); 1416 browser_window = NULL; 1417 run_loop_->Run(); 1418 browser = NULL; 1419 EXPECT_TRUE(browser_list->empty()); 1420 1421 // Verify that the logout confirmation dialog is showing again. 1422 dialog = logout_confirmation_controller->dialog_for_testing(); 1423 ASSERT_TRUE(dialog); 1424 1425 // Deny the logout. 1426 dialog->GetWidget()->Close(); 1427 dialog = NULL; 1428 base::RunLoop().RunUntilIdle(); 1429 1430 app_window_registry->RemoveObserver(this); 1431 }; 1432 1433 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleNoSwitch) { 1434 UploadAndInstallDeviceLocalAccountPolicy(); 1435 AddPublicSessionToDevicePolicy(kAccountId1); 1436 1437 WaitForPolicy(); 1438 1439 ExpandPublicSessionPod(false); 1440 1441 // Click the enter button to start the session. 1442 ASSERT_TRUE(content::ExecuteScript( 1443 contents_, 1444 base::StringPrintf( 1445 "document.getElementById('pod-row').getPodWithUsername_('%s')" 1446 " .querySelector('.enter-button').click();", 1447 user_id_1_.c_str()))); 1448 1449 WaitForSessionStart(); 1450 1451 // Verify that the locale has not changed and the first keyboard layout 1452 // applicable to the locale was chosen. 1453 EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale()); 1454 EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); 1455 VerifyKeyboardLayoutMatchesLocale(); 1456 } 1457 1458 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleSwitch) { 1459 UploadAndInstallDeviceLocalAccountPolicy(); 1460 AddPublicSessionToDevicePolicy(kAccountId1); 1461 1462 WaitForPolicy(); 1463 1464 ExpandPublicSessionPod(false); 1465 1466 // Click the link that switches the pod to its advanced form. Verify that the 1467 // pod switches from basic to advanced. 1468 bool advanced = false; 1469 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 1470 contents_, 1471 base::StringPrintf( 1472 "var pod =" 1473 " document.getElementById('pod-row').getPodWithUsername_('%s');" 1474 "pod.querySelector('.language-and-input').click();" 1475 "domAutomationController.send(pod.classList.contains('advanced'));", 1476 user_id_1_.c_str()), 1477 &advanced)); 1478 EXPECT_FALSE(advanced); 1479 1480 // Manually select a different locale. 1481 ASSERT_TRUE(content::ExecuteScript( 1482 contents_, 1483 base::StringPrintf( 1484 "var languageSelect = document.getElementById('pod-row')" 1485 " .getPodWithUsername_('%s').querySelector('.language-select');" 1486 "languageSelect.value = '%s';" 1487 "var event = document.createEvent('HTMLEvents');" 1488 "event.initEvent('change', false, true);" 1489 "languageSelect.dispatchEvent(event);", 1490 user_id_1_.c_str(), 1491 kPublicSessionLocale))); 1492 1493 // The UI will have requested an updated list of keyboard layouts at this 1494 // point. Wait for the constructions of this list to finish. 1495 WaitForGetKeyboardLayoutsForLocaleToFinish(); 1496 1497 // Manually select a different keyboard layout and click the enter button to 1498 // start the session. 1499 ASSERT_TRUE(content::ExecuteScript( 1500 contents_, 1501 base::StringPrintf( 1502 "var pod =" 1503 " document.getElementById('pod-row').getPodWithUsername_('%s');" 1504 "pod.querySelector('.keyboard-select').value = '%s';" 1505 "pod.querySelector('.enter-button').click();", 1506 user_id_1_.c_str(), 1507 public_session_input_method_id_.c_str()))); 1508 1509 WaitForSessionStart(); 1510 1511 // Verify that the locale and keyboard layout have been applied. 1512 EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); 1513 EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), 1514 icu::Locale::getDefault().getLanguage()); 1515 EXPECT_EQ(public_session_input_method_id_, 1516 chromeos::input_method::InputMethodManager::Get() 1517 ->GetActiveIMEState() 1518 ->GetCurrentInputMethod() 1519 .id()); 1520 } 1521 1522 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, OneRecommendedLocale) { 1523 // Specify a recommended locale. 1524 SetRecommendedLocales(kSingleRecommendedLocale, 1525 arraysize(kSingleRecommendedLocale)); 1526 UploadAndInstallDeviceLocalAccountPolicy(); 1527 AddPublicSessionToDevicePolicy(kAccountId1); 1528 1529 WaitForPolicy(); 1530 1531 ExpandPublicSessionPod(false); 1532 1533 // Click the enter button to start the session. 1534 ASSERT_TRUE(content::ExecuteScript( 1535 contents_, 1536 base::StringPrintf( 1537 "document.getElementById('pod-row').getPodWithUsername_('%s')" 1538 " .querySelector('.enter-button').click();", 1539 user_id_1_.c_str()))); 1540 1541 WaitForSessionStart(); 1542 1543 // Verify that the recommended locale has been applied and the first keyboard 1544 // layout applicable to the locale was chosen. 1545 EXPECT_EQ(kSingleRecommendedLocale[0], 1546 g_browser_process->GetApplicationLocale()); 1547 EXPECT_EQ(l10n_util::GetLanguage(kSingleRecommendedLocale[0]), 1548 icu::Locale::getDefault().getLanguage()); 1549 VerifyKeyboardLayoutMatchesLocale(); 1550 } 1551 1552 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MultipleRecommendedLocales) { 1553 // Specify recommended locales. 1554 SetRecommendedLocales(kRecommendedLocales1, arraysize(kRecommendedLocales1)); 1555 UploadAndInstallDeviceLocalAccountPolicy(); 1556 AddPublicSessionToDevicePolicy(kAccountId1); 1557 AddPublicSessionToDevicePolicy(kAccountId2); 1558 1559 WaitForPolicy(); 1560 1561 ExpandPublicSessionPod(true); 1562 1563 // Verify that the pod shows a list of locales beginning with the recommended 1564 // ones, followed by others. 1565 const std::string get_locale_list = base::StringPrintf( 1566 "var languageSelect = document.getElementById('pod-row')" 1567 " .getPodWithUsername_('%s').querySelector('.language-select');" 1568 "var locales = [];" 1569 "for (var i = 0; i < languageSelect.length; ++i)" 1570 " locales.push(languageSelect.options[i].value);" 1571 "domAutomationController.send(JSON.stringify(locales));", 1572 user_id_1_.c_str()); 1573 std::string json; 1574 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_, 1575 get_locale_list, 1576 &json)); 1577 scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json)); 1578 const base::ListValue* locales = NULL; 1579 ASSERT_TRUE(value_ptr); 1580 ASSERT_TRUE(value_ptr->GetAsList(&locales)); 1581 EXPECT_LT(arraysize(kRecommendedLocales1), locales->GetSize()); 1582 1583 // Verify that the list starts with the recommended locales, in correct order. 1584 for (size_t i = 0; i < arraysize(kRecommendedLocales1); ++i) { 1585 std::string locale; 1586 EXPECT_TRUE(locales->GetString(i, &locale)); 1587 EXPECT_EQ(kRecommendedLocales1[i], locale); 1588 } 1589 1590 // Verify that the recommended locales do not appear again in the remainder of 1591 // the list. 1592 std::set<std::string> recommended_locales; 1593 for (size_t i = 0; i < arraysize(kRecommendedLocales1); ++i) 1594 recommended_locales.insert(kRecommendedLocales1[i]); 1595 for (size_t i = arraysize(kRecommendedLocales1); i < locales->GetSize(); 1596 ++i) { 1597 std::string locale; 1598 EXPECT_TRUE(locales->GetString(i, &locale)); 1599 EXPECT_EQ(recommended_locales.end(), recommended_locales.find(locale)); 1600 } 1601 1602 // Verify that the first recommended locale is selected. 1603 const std::string get_selected_locale = 1604 base::StringPrintf( 1605 "domAutomationController.send(document.getElementById('pod-row')" 1606 " .getPodWithUsername_('%s').querySelector('.language-select')" 1607 " .value);", 1608 user_id_1_.c_str()); 1609 std::string selected_locale; 1610 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_, 1611 get_selected_locale, 1612 &selected_locale)); 1613 EXPECT_EQ(kRecommendedLocales1[0], selected_locale); 1614 1615 // Change the list of recommended locales. 1616 SetRecommendedLocales(kRecommendedLocales2, arraysize(kRecommendedLocales2)); 1617 1618 // Also change the display name as it is easy to ensure that policy has been 1619 // updated by waiting for a display name change. 1620 device_local_account_policy_.payload().mutable_userdisplayname()->set_value( 1621 kDisplayName2); 1622 UploadAndInstallDeviceLocalAccountPolicy(); 1623 policy::BrowserPolicyConnectorChromeOS* connector = 1624 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 1625 DeviceLocalAccountPolicyBroker* broker = 1626 connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser( 1627 user_id_1_); 1628 ASSERT_TRUE(broker); 1629 broker->core()->store()->Load(); 1630 WaitForDisplayName(user_id_1_, kDisplayName2); 1631 1632 // Verify that the new list of locales is shown in the UI. 1633 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_, 1634 get_locale_list, 1635 &json)); 1636 value_ptr.reset(base::JSONReader::Read(json)); 1637 locales = NULL; 1638 ASSERT_TRUE(value_ptr); 1639 ASSERT_TRUE(value_ptr->GetAsList(&locales)); 1640 EXPECT_LT(arraysize(kRecommendedLocales2), locales->GetSize()); 1641 for (size_t i = 0; i < arraysize(kRecommendedLocales2); ++i) { 1642 std::string locale; 1643 EXPECT_TRUE(locales->GetString(i, &locale)); 1644 EXPECT_EQ(kRecommendedLocales2[i], locale); 1645 } 1646 1647 // Verify that the first new recommended locale is selected. 1648 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_, 1649 get_selected_locale, 1650 &selected_locale)); 1651 EXPECT_EQ(kRecommendedLocales2[0], selected_locale); 1652 1653 // Manually select a different locale. 1654 ASSERT_TRUE(content::ExecuteScript( 1655 contents_, 1656 base::StringPrintf( 1657 "var languageSelect = document.getElementById('pod-row')" 1658 " .getPodWithUsername_('%s').querySelector('.language-select');" 1659 "languageSelect.value = '%s';" 1660 "var event = document.createEvent('HTMLEvents');" 1661 "event.initEvent('change', false, true);" 1662 "languageSelect.dispatchEvent(event);", 1663 user_id_1_.c_str(), 1664 kPublicSessionLocale))); 1665 1666 // Change the list of recommended locales. 1667 SetRecommendedLocales(kRecommendedLocales2, arraysize(kRecommendedLocales2)); 1668 device_local_account_policy_.payload().mutable_userdisplayname()->set_value( 1669 kDisplayName1); 1670 UploadAndInstallDeviceLocalAccountPolicy(); 1671 broker->core()->store()->Load(); 1672 WaitForDisplayName(user_id_1_, kDisplayName1); 1673 1674 // Verify that the manually selected locale is still selected. 1675 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_, 1676 get_selected_locale, 1677 &selected_locale)); 1678 EXPECT_EQ(kPublicSessionLocale, selected_locale); 1679 1680 // The UI will request an updated list of keyboard layouts at this point. Wait 1681 // for the constructions of this list to finish. 1682 WaitForGetKeyboardLayoutsForLocaleToFinish(); 1683 1684 // Manually select a different keyboard layout. 1685 ASSERT_TRUE(content::ExecuteScript( 1686 contents_, 1687 base::StringPrintf( 1688 "document.getElementById('pod-row').getPodWithUsername_('%s')" 1689 " .querySelector('.keyboard-select').value = '%s';", 1690 user_id_1_.c_str(), 1691 public_session_input_method_id_.c_str()))); 1692 1693 // Click on a different pod, causing focus to shift away and the pod to 1694 // contract. 1695 ASSERT_TRUE(content::ExecuteScript( 1696 contents_, 1697 base::StringPrintf( 1698 "document.getElementById('pod-row').getPodWithUsername_('%s')" 1699 " .click();", 1700 user_id_2_.c_str()))); 1701 1702 // Click on the pod again, causing it to expand again. Verify that the pod has 1703 // kept all its state (the advanced form is being shown, the manually selected 1704 // locale and keyboard layout are selected). 1705 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 1706 contents_, 1707 base::StringPrintf( 1708 "var pod =" 1709 " document.getElementById('pod-row').getPodWithUsername_('%s');" 1710 "pod.click();" 1711 "var state = {};" 1712 "state.advanced = pod.classList.contains('advanced');" 1713 "state.locale = pod.querySelector('.language-select').value;" 1714 "state.keyboardLayout = pod.querySelector('.keyboard-select').value;" 1715 "console.log(JSON.stringify(state));" 1716 "domAutomationController.send(JSON.stringify(state));", 1717 user_id_1_.c_str()), 1718 &json)); 1719 LOG(ERROR) << json; 1720 value_ptr.reset(base::JSONReader::Read(json)); 1721 const base::DictionaryValue* state = NULL; 1722 ASSERT_TRUE(value_ptr); 1723 ASSERT_TRUE(value_ptr->GetAsDictionary(&state)); 1724 bool advanced = false; 1725 EXPECT_TRUE(state->GetBoolean("advanced", &advanced)); 1726 EXPECT_TRUE(advanced); 1727 EXPECT_TRUE(state->GetString("locale", &selected_locale)); 1728 EXPECT_EQ(kPublicSessionLocale, selected_locale); 1729 std::string selected_keyboard_layout; 1730 EXPECT_TRUE(state->GetString("keyboardLayout", &selected_keyboard_layout)); 1731 EXPECT_EQ(public_session_input_method_id_, selected_keyboard_layout); 1732 1733 // Click the enter button to start the session. 1734 ASSERT_TRUE(content::ExecuteScript( 1735 contents_, 1736 base::StringPrintf( 1737 "document.getElementById('pod-row').getPodWithUsername_('%s')" 1738 " .querySelector('.enter-button').click();", 1739 user_id_1_.c_str()))); 1740 1741 WaitForSessionStart(); 1742 1743 // Verify that the locale and keyboard layout have been applied. 1744 EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); 1745 EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), 1746 icu::Locale::getDefault().getLanguage()); 1747 EXPECT_EQ(public_session_input_method_id_, 1748 chromeos::input_method::InputMethodManager::Get() 1749 ->GetActiveIMEState() 1750 ->GetCurrentInputMethod() 1751 .id()); 1752 } 1753 1754 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, InvalidRecommendedLocale) { 1755 // Specify an invalid recommended locale. 1756 SetRecommendedLocales(kInvalidRecommendedLocale, 1757 arraysize(kInvalidRecommendedLocale)); 1758 UploadAndInstallDeviceLocalAccountPolicy(); 1759 AddPublicSessionToDevicePolicy(kAccountId1); 1760 1761 WaitForPolicy(); 1762 1763 // Click on the pod to expand it. Verify that the pod expands to its basic 1764 // form as there is only one recommended locale. 1765 bool advanced = false; 1766 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 1767 contents_, 1768 base::StringPrintf( 1769 "var pod =" 1770 " document.getElementById('pod-row').getPodWithUsername_('%s');" 1771 "pod.click();" 1772 "domAutomationController.send(pod.classList.contains('advanced'));", 1773 user_id_1_.c_str()), 1774 &advanced)); 1775 EXPECT_FALSE(advanced); 1776 EXPECT_EQ(l10n_util::GetLanguage(initial_locale_), 1777 icu::Locale::getDefault().getLanguage()); 1778 1779 // Click the enter button to start the session. 1780 ASSERT_TRUE(content::ExecuteScript( 1781 contents_, 1782 base::StringPrintf( 1783 "document.getElementById('pod-row').getPodWithUsername_('%s')" 1784 " .querySelector('.enter-button').click();", 1785 user_id_1_.c_str()))); 1786 1787 WaitForSessionStart(); 1788 1789 // Verify that since the recommended locale was invalid, the locale has not 1790 // changed and the first keyboard layout applicable to the locale was chosen. 1791 EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale()); 1792 EXPECT_EQ(l10n_util::GetLanguage(initial_locale_), 1793 icu::Locale::getDefault().getLanguage()); 1794 VerifyKeyboardLayoutMatchesLocale(); 1795 } 1796 1797 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, 1798 AutoLoginWithoutRecommendedLocales) { 1799 UploadAndInstallDeviceLocalAccountPolicy(); 1800 AddPublicSessionToDevicePolicy(kAccountId1); 1801 EnableAutoLogin(); 1802 1803 WaitForPolicy(); 1804 1805 WaitForSessionStart(); 1806 1807 // Verify that the locale has not changed and the first keyboard layout 1808 // applicable to the locale was chosen. 1809 EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale()); 1810 EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage()); 1811 VerifyKeyboardLayoutMatchesLocale(); 1812 } 1813 1814 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, 1815 AutoLoginWithRecommendedLocales) { 1816 // Specify recommended locales. 1817 SetRecommendedLocales(kRecommendedLocales1, arraysize(kRecommendedLocales1)); 1818 UploadAndInstallDeviceLocalAccountPolicy(); 1819 AddPublicSessionToDevicePolicy(kAccountId1); 1820 EnableAutoLogin(); 1821 1822 WaitForPolicy(); 1823 1824 WaitForSessionStart(); 1825 1826 // Verify that the first recommended locale has been applied and the first 1827 // keyboard layout applicable to the locale was chosen. 1828 EXPECT_EQ(kRecommendedLocales1[0], g_browser_process->GetApplicationLocale()); 1829 EXPECT_EQ(l10n_util::GetLanguage(kRecommendedLocales1[0]), 1830 icu::Locale::getDefault().getLanguage()); 1831 VerifyKeyboardLayoutMatchesLocale(); 1832 } 1833 1834 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, TermsOfServiceWithLocaleSwitch) { 1835 // Specify Terms of Service URL. 1836 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 1837 device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value( 1838 embedded_test_server()->GetURL( 1839 std::string("/") + kExistentTermsOfServicePath).spec()); 1840 UploadAndInstallDeviceLocalAccountPolicy(); 1841 AddPublicSessionToDevicePolicy(kAccountId1); 1842 1843 WaitForPolicy(); 1844 1845 // Select a different locale. 1846 ASSERT_TRUE(content::ExecuteScript( 1847 contents_, 1848 base::StringPrintf( 1849 "var languageSelect = document.getElementById('pod-row')" 1850 " .getPodWithUsername_('%s').querySelector('.language-select');" 1851 "languageSelect.value = '%s';" 1852 "var event = document.createEvent('HTMLEvents');" 1853 "event.initEvent('change', false, true);" 1854 "languageSelect.dispatchEvent(event);", 1855 user_id_1_.c_str(), 1856 kPublicSessionLocale))); 1857 1858 // The UI will have requested an updated list of keyboard layouts at this 1859 // point. Wait for the constructions of this list to finish. 1860 WaitForGetKeyboardLayoutsForLocaleToFinish(); 1861 1862 // Set up an observer that will quit the message loop when login has succeeded 1863 // and the first wizard screen, if any, is being shown. 1864 base::RunLoop login_wait_run_loop; 1865 chromeos::MockAuthStatusConsumer login_status_consumer; 1866 EXPECT_CALL(login_status_consumer, OnAuthSuccess(_)).Times(1).WillOnce( 1867 InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit)); 1868 chromeos::ExistingUserController* controller = 1869 chromeos::ExistingUserController::current_controller(); 1870 ASSERT_TRUE(controller); 1871 controller->set_login_status_consumer(&login_status_consumer); 1872 1873 // Manually select a different keyboard layout and click the enter button to 1874 // start the session. 1875 ASSERT_TRUE(content::ExecuteScript( 1876 contents_, 1877 base::StringPrintf( 1878 "var pod =" 1879 " document.getElementById('pod-row').getPodWithUsername_('%s');" 1880 "pod.querySelector('.keyboard-select').value = '%s';" 1881 "pod.querySelector('.enter-button').click();", 1882 user_id_1_.c_str(), 1883 public_session_input_method_id_.c_str()))); 1884 1885 // Spin the loop until the login observer fires. Then, unregister the 1886 // observer. 1887 login_wait_run_loop.Run(); 1888 controller->set_login_status_consumer(NULL); 1889 1890 // Verify that the Terms of Service screen is being shown. 1891 chromeos::WizardController* wizard_controller = 1892 chromeos::WizardController::default_controller(); 1893 ASSERT_TRUE(wizard_controller); 1894 ASSERT_TRUE(wizard_controller->current_screen()); 1895 EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName, 1896 wizard_controller->current_screen()->GetName()); 1897 1898 // Wait for the Terms of Service to finish downloading. 1899 bool done = false; 1900 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(contents_, 1901 "var screenElement = document.getElementById('terms-of-service');" 1902 "function SendReplyIfDownloadDone() {" 1903 " if (screenElement.classList.contains('tos-loading'))" 1904 " return false;" 1905 " domAutomationController.send(true);" 1906 " observer.disconnect();" 1907 " return true;" 1908 "}" 1909 "var observer = new MutationObserver(SendReplyIfDownloadDone);" 1910 "if (!SendReplyIfDownloadDone()) {" 1911 " var options = { attributes: true, attributeFilter: [ 'class' ] };" 1912 " observer.observe(screenElement, options);" 1913 "}", 1914 &done)); 1915 1916 // Verify that the locale and keyboard layout have been applied. 1917 EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); 1918 EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), 1919 icu::Locale::getDefault().getLanguage()); 1920 EXPECT_EQ(public_session_input_method_id_, 1921 chromeos::input_method::InputMethodManager::Get() 1922 ->GetActiveIMEState() 1923 ->GetCurrentInputMethod() 1924 .id()); 1925 1926 // Click the accept button. 1927 ASSERT_TRUE(content::ExecuteScript(contents_, 1928 "$('tos-accept-button').click();")); 1929 1930 WaitForSessionStart(); 1931 1932 // Verify that the locale and keyboard layout are still in force. 1933 EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale()); 1934 EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale), 1935 icu::Locale::getDefault().getLanguage()); 1936 EXPECT_EQ(public_session_input_method_id_, 1937 chromeos::input_method::InputMethodManager::Get() 1938 ->GetActiveIMEState() 1939 ->GetCurrentInputMethod() 1940 .id()); 1941 } 1942 1943 class TermsOfServiceDownloadTest : public DeviceLocalAccountTest, 1944 public testing::WithParamInterface<bool> { 1945 }; 1946 1947 IN_PROC_BROWSER_TEST_P(TermsOfServiceDownloadTest, TermsOfServiceScreen) { 1948 // Specify Terms of Service URL. 1949 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 1950 device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value( 1951 embedded_test_server()->GetURL( 1952 std::string("/") + 1953 (GetParam() ? kExistentTermsOfServicePath 1954 : kNonexistentTermsOfServicePath)).spec()); 1955 UploadAndInstallDeviceLocalAccountPolicy(); 1956 AddPublicSessionToDevicePolicy(kAccountId1); 1957 1958 WaitForPolicy(); 1959 1960 ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); 1961 1962 // Set up an observer that will quit the message loop when login has succeeded 1963 // and the first wizard screen, if any, is being shown. 1964 base::RunLoop login_wait_run_loop; 1965 chromeos::MockAuthStatusConsumer login_status_consumer; 1966 EXPECT_CALL(login_status_consumer, OnAuthSuccess(_)).Times(1).WillOnce( 1967 InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit)); 1968 1969 // Spin the loop until the observer fires. Then, unregister the observer. 1970 chromeos::ExistingUserController* controller = 1971 chromeos::ExistingUserController::current_controller(); 1972 ASSERT_TRUE(controller); 1973 controller->set_login_status_consumer(&login_status_consumer); 1974 login_wait_run_loop.Run(); 1975 controller->set_login_status_consumer(NULL); 1976 1977 // Verify that the Terms of Service screen is being shown. 1978 chromeos::WizardController* wizard_controller = 1979 chromeos::WizardController::default_controller(); 1980 ASSERT_TRUE(wizard_controller); 1981 ASSERT_TRUE(wizard_controller->current_screen()); 1982 EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName, 1983 wizard_controller->current_screen()->GetName()); 1984 1985 // Wait for the Terms of Service to finish downloading, then get the status of 1986 // the screen's UI elements. 1987 std::string json; 1988 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_, 1989 "var screenElement = document.getElementById('terms-of-service');" 1990 "function SendReplyIfDownloadDone() {" 1991 " if (screenElement.classList.contains('tos-loading'))" 1992 " return false;" 1993 " var status = {};" 1994 " status.heading = document.getElementById('tos-heading').textContent;" 1995 " status.subheading =" 1996 " document.getElementById('tos-subheading').textContent;" 1997 " status.contentHeading =" 1998 " document.getElementById('tos-content-heading').textContent;" 1999 " status.content =" 2000 " document.getElementById('tos-content-main').textContent;" 2001 " status.error = screenElement.classList.contains('error');" 2002 " status.acceptEnabled =" 2003 " !document.getElementById('tos-accept-button').disabled;" 2004 " domAutomationController.send(JSON.stringify(status));" 2005 " observer.disconnect();" 2006 " return true;" 2007 "}" 2008 "var observer = new MutationObserver(SendReplyIfDownloadDone);" 2009 "if (!SendReplyIfDownloadDone()) {" 2010 " var options = { attributes: true, attributeFilter: [ 'class' ] };" 2011 " observer.observe(screenElement, options);" 2012 "}", 2013 &json)); 2014 scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json)); 2015 const base::DictionaryValue* status = NULL; 2016 ASSERT_TRUE(value_ptr); 2017 ASSERT_TRUE(value_ptr->GetAsDictionary(&status)); 2018 std::string heading; 2019 EXPECT_TRUE(status->GetString("heading", &heading)); 2020 std::string subheading; 2021 EXPECT_TRUE(status->GetString("subheading", &subheading)); 2022 std::string content_heading; 2023 EXPECT_TRUE(status->GetString("contentHeading", &content_heading)); 2024 std::string content; 2025 EXPECT_TRUE(status->GetString("content", &content)); 2026 bool error; 2027 EXPECT_TRUE(status->GetBoolean("error", &error)); 2028 bool accept_enabled; 2029 EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled)); 2030 2031 // Verify that the screen's headings have been set correctly. 2032 EXPECT_EQ( 2033 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING, 2034 base::UTF8ToUTF16(kDomain)), 2035 heading); 2036 EXPECT_EQ( 2037 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING, 2038 base::UTF8ToUTF16(kDomain)), 2039 subheading); 2040 EXPECT_EQ( 2041 l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING, 2042 base::UTF8ToUTF16(kDomain)), 2043 content_heading); 2044 2045 if (!GetParam()) { 2046 // The Terms of Service URL was invalid. Verify that the screen is showing 2047 // an error and the accept button is disabled. 2048 EXPECT_TRUE(error); 2049 EXPECT_FALSE(accept_enabled); 2050 return; 2051 } 2052 2053 // The Terms of Service URL was valid. Verify that the screen is showing the 2054 // downloaded Terms of Service and the accept button is enabled. 2055 base::FilePath test_dir; 2056 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 2057 std::string terms_of_service; 2058 ASSERT_TRUE(base::ReadFileToString( 2059 test_dir.Append(kExistentTermsOfServicePath), &terms_of_service)); 2060 EXPECT_EQ(terms_of_service, content); 2061 EXPECT_FALSE(error); 2062 EXPECT_TRUE(accept_enabled); 2063 2064 // Click the accept button. 2065 ASSERT_TRUE(content::ExecuteScript(contents_, 2066 "$('tos-accept-button').click();")); 2067 2068 WaitForSessionStart(); 2069 } 2070 2071 INSTANTIATE_TEST_CASE_P(TermsOfServiceDownloadTestInstance, 2072 TermsOfServiceDownloadTest, testing::Bool()); 2073 2074 } // namespace policy 2075