device_local_account_browsertest.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <map> 6#include <string> 7 8#include "base/basictypes.h" 9#include "base/bind.h" 10#include "base/callback.h" 11#include "base/command_line.h" 12#include "base/file_util.h" 13#include "base/files/file_path.h" 14#include "base/files/scoped_temp_dir.h" 15#include "base/message_loop.h" 16#include "base/path_service.h" 17#include "base/run_loop.h" 18#include "base/stl_util.h" 19#include "base/string_util.h" 20#include "base/utf_string_conversions.h" 21#include "chrome/browser/browser_process.h" 22#include "chrome/browser/chromeos/login/existing_user_controller.h" 23#include "chrome/browser/chromeos/login/user.h" 24#include "chrome/browser/chromeos/login/user_manager.h" 25#include "chrome/browser/chromeos/login/wizard_controller.h" 26#include "chrome/browser/chromeos/policy/device_policy_builder.h" 27#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h" 28#include "chrome/browser/lifetime/application_lifetime.h" 29#include "chrome/browser/policy/cloud/cloud_policy_constants.h" 30#include "chrome/browser/policy/cloud/policy_builder.h" 31#include "chrome/browser/policy/policy_service.h" 32#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h" 33#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h" 34#include "chrome/browser/policy/test/local_policy_test_server.h" 35#include "chrome/browser/prefs/session_startup_pref.h" 36#include "chrome/browser/ui/browser.h" 37#include "chrome/browser/ui/browser_finder.h" 38#include "chrome/browser/ui/host_desktop.h" 39#include "chrome/browser/ui/tabs/tab_strip_model.h" 40#include "chrome/common/chrome_notification_types.h" 41#include "chrome/common/chrome_switches.h" 42#include "chrome/test/base/in_process_browser_test.h" 43#include "chromeos/chromeos_paths.h" 44#include "chromeos/chromeos_switches.h" 45#include "chromeos/dbus/cryptohome_client.h" 46#include "chromeos/dbus/dbus_method_call_status.h" 47#include "chromeos/dbus/dbus_thread_manager.h" 48#include "chromeos/dbus/fake_cryptohome_client.h" 49#include "chromeos/dbus/fake_session_manager_client.h" 50#include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h" 51#include "chromeos/dbus/session_manager_client.h" 52#include "content/public/browser/notification_observer.h" 53#include "content/public/browser/notification_registrar.h" 54#include "content/public/browser/notification_service.h" 55#include "content/public/browser/web_contents.h" 56#include "testing/gmock/include/gmock/gmock.h" 57#include "third_party/cros_system_api/dbus/service_constants.h" 58 59namespace em = enterprise_management; 60 61using testing::Return; 62 63namespace policy { 64 65namespace { 66 67const char kAccountId1[] = "dla1@example.com"; 68const char kAccountId2[] = "dla2@example.com"; 69const char kDisplayName1[] = "display name for account 1"; 70const char kDisplayName2[] = "display name for account 2"; 71const char* kStartupURLs[] = { 72 "chrome://policy", 73 "chrome://about", 74}; 75 76// Observes a specific notification type and quits the message loop once a 77// condition holds. 78class NotificationWatcher : public content::NotificationObserver { 79 public: 80 // Callback invoked on notifications. Should return true when the condition 81 // that the caller is waiting for is satisfied. 82 typedef base::Callback<bool(void)> ConditionTestCallback; 83 84 explicit NotificationWatcher(int notification_type, 85 const ConditionTestCallback& callback) 86 : type_(notification_type), 87 callback_(callback) {} 88 89 void Run() { 90 if (callback_.Run()) 91 return; 92 93 content::NotificationRegistrar registrar; 94 registrar.Add(this, type_, content::NotificationService::AllSources()); 95 run_loop_.Run(); 96 } 97 98 // content::NotificationObserver: 99 virtual void Observe(int type, 100 const content::NotificationSource& source, 101 const content::NotificationDetails& details) OVERRIDE { 102 if (callback_.Run()) 103 run_loop_.Quit(); 104 } 105 106 private: 107 int type_; 108 ConditionTestCallback callback_; 109 base::RunLoop run_loop_; 110 111 DISALLOW_COPY_AND_ASSIGN(NotificationWatcher); 112}; 113 114} // namespace 115 116class DeviceLocalAccountTest : public InProcessBrowserTest { 117 protected: 118 DeviceLocalAccountTest() {} 119 virtual ~DeviceLocalAccountTest() {} 120 121 virtual void SetUp() OVERRIDE { 122 // Configure and start the test server. 123 scoped_ptr<crypto::RSAPrivateKey> signing_key( 124 PolicyBuilder::CreateTestSigningKey()); 125 ASSERT_TRUE(test_server_.SetSigningKey(signing_key.get())); 126 signing_key.reset(); 127 test_server_.RegisterClient(PolicyBuilder::kFakeToken, 128 PolicyBuilder::kFakeDeviceId); 129 ASSERT_TRUE(test_server_.Start()); 130 131 InProcessBrowserTest::SetUp(); 132 } 133 134 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 135 command_line->AppendSwitch(chromeos::switches::kLoginManager); 136 command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests); 137 command_line->AppendSwitchASCII( 138 chromeos::switches::kLoginScreen, 139 chromeos::WizardController::kLoginScreenName); 140 command_line->AppendSwitchASCII( 141 switches::kDeviceManagementUrl, test_server_.GetServiceURL().spec()); 142 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 143 } 144 145 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 146 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 147 148 // Clear command-line arguments (but keep command-line switches) so the 149 // startup pages policy takes effect. 150 CommandLine* command_line = CommandLine::ForCurrentProcess(); 151 CommandLine::StringVector argv(command_line->argv()); 152 argv.erase(argv.begin() + argv.size() - command_line->GetArgs().size(), 153 argv.end()); 154 command_line->InitFromArgv(argv); 155 156 // Mark the device enterprise-enrolled. 157 SetUpInstallAttributes(); 158 159 // Redirect session_manager DBus calls to FakeSessionManagerClient. 160 chromeos::MockDBusThreadManagerWithoutGMock* dbus_thread_manager = 161 new chromeos::MockDBusThreadManagerWithoutGMock(); 162 session_manager_client_ = 163 dbus_thread_manager->fake_session_manager_client(); 164 chromeos::DBusThreadManager::InitializeForTesting(dbus_thread_manager); 165 166 SetUpPolicy(); 167 } 168 169 virtual void CleanUpOnMainThread() OVERRIDE { 170 // This shuts down the login UI. 171 MessageLoop::current()->PostTask(FROM_HERE, 172 base::Bind(&chrome::AttemptExit)); 173 base::RunLoop().RunUntilIdle(); 174 } 175 176 void SetUpInstallAttributes() { 177 cryptohome::SerializedInstallAttributes install_attrs_proto; 178 cryptohome::SerializedInstallAttributes::Attribute* attribute = NULL; 179 180 attribute = install_attrs_proto.add_attributes(); 181 attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseOwned); 182 attribute->set_value("true"); 183 184 attribute = install_attrs_proto.add_attributes(); 185 attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseUser); 186 attribute->set_value(PolicyBuilder::kFakeUsername); 187 188 base::FilePath install_attrs_file = 189 temp_dir_.path().AppendASCII("install_attributes.pb"); 190 const std::string install_attrs_blob( 191 install_attrs_proto.SerializeAsString()); 192 ASSERT_EQ(static_cast<int>(install_attrs_blob.size()), 193 file_util::WriteFile(install_attrs_file, 194 install_attrs_blob.c_str(), 195 install_attrs_blob.size())); 196 ASSERT_TRUE(PathService::Override(chromeos::FILE_INSTALL_ATTRIBUTES, 197 install_attrs_file)); 198 } 199 200 void SetUpPolicy() { 201 // Configure two device-local accounts in device settings. 202 DevicePolicyBuilder device_policy; 203 device_policy.policy_data().set_public_key_version(1); 204 em::ChromeDeviceSettingsProto& proto(device_policy.payload()); 205 proto.mutable_show_user_names()->set_show_user_names(true); 206 em::DeviceLocalAccountInfoProto* account1 = 207 proto.mutable_device_local_accounts()->add_account(); 208 account1->set_account_id(kAccountId1); 209 account1->set_type( 210 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); 211 em::DeviceLocalAccountInfoProto* account2 = 212 proto.mutable_device_local_accounts()->add_account(); 213 account2->set_account_id(kAccountId2); 214 account2->set_type( 215 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); 216 device_policy.Build(); 217 session_manager_client_->set_device_policy(device_policy.GetBlob()); 218 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, 219 std::string(), proto.SerializeAsString()); 220 221 // Install the owner key. 222 base::FilePath owner_key_file = temp_dir_.path().AppendASCII("owner.key"); 223 std::vector<uint8> owner_key_bits; 224 ASSERT_TRUE(device_policy.signing_key()->ExportPublicKey(&owner_key_bits)); 225 ASSERT_EQ( 226 static_cast<int>(owner_key_bits.size()), 227 file_util::WriteFile( 228 owner_key_file, 229 reinterpret_cast<const char*>(vector_as_array(&owner_key_bits)), 230 owner_key_bits.size())); 231 ASSERT_TRUE( 232 PathService::Override(chromeos::FILE_OWNER_KEY, owner_key_file)); 233 234 // Configure device-local account policy for the first device-local account. 235 UserPolicyBuilder device_local_account_policy; 236 device_local_account_policy.policy_data().set_policy_type( 237 dm_protocol::kChromePublicAccountPolicyType); 238 device_local_account_policy.policy_data().set_username(kAccountId1); 239 device_local_account_policy.policy_data().set_settings_entity_id( 240 kAccountId1); 241 device_local_account_policy.policy_data().set_public_key_version(1); 242 device_local_account_policy.payload().mutable_restoreonstartup()->set_value( 243 SessionStartupPref::kPrefValueURLs); 244 em::StringListPolicyProto* startup_urls_proto = 245 device_local_account_policy.payload().mutable_restoreonstartupurls(); 246 for (size_t i = 0; i < arraysize(kStartupURLs); ++i) 247 startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]); 248 device_local_account_policy.payload().mutable_userdisplayname()->set_value( 249 kDisplayName1); 250 device_local_account_policy.Build(); 251 session_manager_client_->set_device_local_account_policy( 252 kAccountId1, device_local_account_policy.GetBlob()); 253 test_server_.UpdatePolicy( 254 dm_protocol::kChromePublicAccountPolicyType, kAccountId1, 255 device_local_account_policy.payload().SerializeAsString()); 256 257 // Make policy for the second account available from the server. 258 device_local_account_policy.payload().mutable_userdisplayname()->set_value( 259 kDisplayName2); 260 test_server_.UpdatePolicy( 261 dm_protocol::kChromePublicAccountPolicyType, kAccountId2, 262 device_local_account_policy.payload().SerializeAsString()); 263 264 // Don't install policy for |kAccountId2| yet so initial download gets 265 // test coverage. 266 ASSERT_TRUE(session_manager_client_->device_local_account_policy( 267 kAccountId2).empty()); 268 } 269 270 void CheckPublicSessionPresent(const std::string& id) { 271 const chromeos::User* user = chromeos::UserManager::Get()->FindUser(id); 272 ASSERT_TRUE(user); 273 EXPECT_EQ(id, user->email()); 274 EXPECT_EQ(chromeos::User::USER_TYPE_PUBLIC_ACCOUNT, user->GetType()); 275 } 276 277 LocalPolicyTestServer test_server_; 278 base::ScopedTempDir temp_dir_; 279 280 chromeos::FakeSessionManagerClient* session_manager_client_; 281}; 282 283static bool IsKnownUser(const std::string& account_id) { 284 return chromeos::UserManager::Get()->IsKnownUser(account_id); 285} 286 287IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LoginScreen) { 288 NotificationWatcher(chrome::NOTIFICATION_USER_LIST_CHANGED, 289 base::Bind(&IsKnownUser, kAccountId1)).Run(); 290 NotificationWatcher(chrome::NOTIFICATION_USER_LIST_CHANGED, 291 base::Bind(&IsKnownUser, kAccountId2)).Run(); 292 293 CheckPublicSessionPresent(kAccountId1); 294 CheckPublicSessionPresent(kAccountId2); 295} 296 297static bool DisplayNameMatches(const std::string& account_id, 298 const std::string& display_name) { 299 const chromeos::User* user = 300 chromeos::UserManager::Get()->FindUser(account_id); 301 if (!user || user->display_name().empty()) 302 return false; 303 EXPECT_EQ(UTF8ToUTF16(display_name), user->display_name()); 304 return true; 305} 306 307IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) { 308 NotificationWatcher( 309 chrome::NOTIFICATION_USER_LIST_CHANGED, 310 base::Bind(&DisplayNameMatches, kAccountId1, kDisplayName1)).Run(); 311} 312 313IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, PolicyDownload) { 314 // Policy for kAccountId2 is not installed in session_manager_client, make 315 // sure it gets fetched from the server. Note that the test setup doesn't set 316 // up policy for kAccountId2, so the presence of the display name can be used 317 // as signal to indicate successful policy download. 318 NotificationWatcher( 319 chrome::NOTIFICATION_USER_LIST_CHANGED, 320 base::Bind(&DisplayNameMatches, kAccountId2, kDisplayName2)).Run(); 321 322 // Sanity check: The policy should be present now. 323 ASSERT_FALSE(session_manager_client_->device_local_account_policy( 324 kAccountId2).empty()); 325} 326 327static bool IsNotKnownUser(const std::string& account_id) { 328 return !IsKnownUser(account_id); 329} 330 331IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DevicePolicyChange) { 332 // Wait until the login screen is up. 333 NotificationWatcher(chrome::NOTIFICATION_USER_LIST_CHANGED, 334 base::Bind(&IsKnownUser, kAccountId1)).Run(); 335 NotificationWatcher(chrome::NOTIFICATION_USER_LIST_CHANGED, 336 base::Bind(&IsKnownUser, kAccountId2)).Run(); 337 338 // Update policy to remove kAccountId2. 339 em::ChromeDeviceSettingsProto policy; 340 policy.mutable_show_user_names()->set_show_user_names(true); 341 em::DeviceLocalAccountInfoProto* account1 = 342 policy.mutable_device_local_accounts()->add_account(); 343 account1->set_account_id(kAccountId1); 344 account1->set_type( 345 em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); 346 347 test_server_.UpdatePolicy(dm_protocol::kChromeDevicePolicyType, std::string(), 348 policy.SerializeAsString()); 349 g_browser_process->policy_service()->RefreshPolicies(base::Closure()); 350 351 // Make sure the second device-local account disappears. 352 NotificationWatcher(chrome::NOTIFICATION_USER_LIST_CHANGED, 353 base::Bind(&IsNotKnownUser, kAccountId2)).Run(); 354} 355 356static bool IsSessionStarted() { 357 return chromeos::UserManager::Get()->IsSessionStarted(); 358} 359 360IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, StartSession) { 361 // This observes the display name becoming available as this indicates 362 // device-local account policy is fully loaded, which is a prerequisite for 363 // successful login. 364 NotificationWatcher( 365 chrome::NOTIFICATION_USER_LIST_CHANGED, 366 base::Bind(&DisplayNameMatches, kAccountId1, kDisplayName1)).Run(); 367 368 chromeos::ExistingUserController* controller = 369 chromeos::ExistingUserController::current_controller(); 370 ASSERT_TRUE(controller); 371 controller->LoginAsPublicAccount(kAccountId1); 372 373 // Wait for the session to start. 374 NotificationWatcher(chrome::NOTIFICATION_SESSION_STARTED, 375 base::Bind(IsSessionStarted)).Run(); 376 377 // Check that the startup pages specified in policy were opened. 378 EXPECT_EQ(1U, chrome::GetTotalBrowserCount()); 379 Browser* browser = 380 chrome::FindLastActiveWithHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH); 381 ASSERT_TRUE(browser); 382 383 TabStripModel* tabs = browser->tab_strip_model(); 384 ASSERT_TRUE(tabs); 385 int expected_tab_count = static_cast<int>(arraysize(kStartupURLs)); 386 EXPECT_EQ(expected_tab_count, tabs->count()); 387 for (int i = 0; i < expected_tab_count && i < tabs->count(); ++i) 388 EXPECT_EQ(GURL(kStartupURLs[i]), tabs->GetWebContentsAt(i)->GetURL()); 389} 390 391} // namespace policy 392