1 // Copyright 2014 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 <string> 6 #include <vector> 7 8 #include "ash/desktop_background/desktop_background_controller.h" 9 #include "ash/desktop_background/desktop_background_controller_observer.h" 10 #include "ash/shell.h" 11 #include "base/basictypes.h" 12 #include "base/command_line.h" 13 #include "base/compiler_specific.h" 14 #include "base/file_util.h" 15 #include "base/files/file_path.h" 16 #include "base/json/json_writer.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/path_service.h" 19 #include "base/run_loop.h" 20 #include "chrome/browser/chromeos/login/login_manager_test.h" 21 #include "chrome/browser/chromeos/login/startup_utils.h" 22 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" 23 #include "chrome/browser/chromeos/login/users/user.h" 24 #include "chrome/browser/chromeos/login/users/user_manager.h" 25 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" 26 #include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h" 27 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h" 28 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h" 29 #include "chrome/browser/profiles/profile.h" 30 #include "chrome/common/chrome_paths.h" 31 #include "chromeos/chromeos_paths.h" 32 #include "chromeos/chromeos_switches.h" 33 #include "chromeos/dbus/cryptohome_client.h" 34 #include "chromeos/dbus/dbus_thread_manager.h" 35 #include "chromeos/dbus/fake_dbus_thread_manager.h" 36 #include "chromeos/dbus/fake_session_manager_client.h" 37 #include "chromeos/dbus/session_manager_client.h" 38 #include "components/policy/core/common/cloud/cloud_policy_core.h" 39 #include "components/policy/core/common/cloud/cloud_policy_store.h" 40 #include "components/policy/core/common/cloud/cloud_policy_validator.h" 41 #include "components/policy/core/common/cloud/policy_builder.h" 42 #include "content/public/test/browser_test_utils.h" 43 #include "crypto/rsa_private_key.h" 44 #include "net/test/embedded_test_server/embedded_test_server.h" 45 #include "policy/proto/cloud_policy.pb.h" 46 #include "testing/gtest/include/gtest/gtest.h" 47 #include "third_party/skia/include/core/SkBitmap.h" 48 #include "third_party/skia/include/core/SkColor.h" 49 #include "ui/gfx/image/image_skia.h" 50 #include "url/gurl.h" 51 52 namespace chromeos { 53 54 namespace { 55 56 const char kTestUsers[2][19] = { "test-0 (at) example.com", "test-1 (at) example.com" }; 57 58 const char kRedImageFileName[] = "chromeos/wallpapers/red.jpg"; 59 const char kGreenImageFileName[] = "chromeos/wallpapers/green.jpg"; 60 const char kBlueImageFileName[] = "chromeos/wallpapers/blue.jpg"; 61 62 const SkColor kRedImageColor = SkColorSetARGB(255, 199, 6, 7); 63 const SkColor kGreenImageColor = SkColorSetARGB(255, 38, 196, 15); 64 65 policy::CloudPolicyStore* GetStoreForUser(const User* user) { 66 Profile* profile = UserManager::Get()->GetProfileByUser(user); 67 if (!profile) { 68 ADD_FAILURE(); 69 return NULL; 70 } 71 policy::UserCloudPolicyManagerChromeOS* policy_manager = 72 policy::UserCloudPolicyManagerFactoryChromeOS::GetForProfile(profile); 73 if (!policy_manager) { 74 ADD_FAILURE(); 75 return NULL; 76 } 77 return policy_manager->core()->store(); 78 } 79 80 // Compute the average ARGB color of |bitmap|. 81 SkColor ComputeAverageColor(const SkBitmap& bitmap) { 82 if (bitmap.empty() || bitmap.width() < 1 || bitmap.height() < 1) { 83 ADD_FAILURE() << "Empty or invalid bitmap."; 84 return SkColorSetARGB(0, 0, 0, 0); 85 } 86 if (bitmap.isNull()) { 87 ADD_FAILURE() << "Bitmap has no pixelref."; 88 return SkColorSetARGB(0, 0, 0, 0); 89 } 90 if (bitmap.config() == SkBitmap::kNo_Config) { 91 ADD_FAILURE() << "Bitmap has not been configured."; 92 return SkColorSetARGB(0, 0, 0, 0); 93 } 94 uint64 a = 0, r = 0, g = 0, b = 0; 95 bitmap.lockPixels(); 96 for (int x = 0; x < bitmap.width(); ++x) { 97 for (int y = 0; y < bitmap.height(); ++y) { 98 const SkColor color = bitmap.getColor(x, y); 99 a += SkColorGetA(color); 100 r += SkColorGetR(color); 101 g += SkColorGetG(color); 102 b += SkColorGetB(color); 103 } 104 } 105 bitmap.unlockPixels(); 106 uint64 pixel_number = bitmap.width() * bitmap.height(); 107 return SkColorSetARGB((a + pixel_number / 2) / pixel_number, 108 (r + pixel_number / 2) / pixel_number, 109 (g + pixel_number / 2) / pixel_number, 110 (b + pixel_number / 2) / pixel_number); 111 } 112 113 // Obtain background image and return its average ARGB color. 114 SkColor GetAverageBackgroundColor() { 115 const gfx::ImageSkia image = 116 ash::Shell::GetInstance()->desktop_background_controller()-> 117 GetWallpaper(); 118 119 const gfx::ImageSkiaRep& representation = image.GetRepresentation(1.); 120 if (representation.is_null()) { 121 ADD_FAILURE() << "No image representation."; 122 return SkColorSetARGB(0, 0, 0, 0); 123 } 124 125 const SkBitmap& bitmap = representation.sk_bitmap(); 126 return ComputeAverageColor(bitmap); 127 } 128 129 } // namespace 130 131 class WallpaperManagerPolicyTest 132 : public LoginManagerTest, 133 public ash::DesktopBackgroundControllerObserver { 134 protected: 135 WallpaperManagerPolicyTest() 136 : LoginManagerTest(true), 137 wallpaper_change_count_(0), 138 fake_dbus_thread_manager_(new FakeDBusThreadManager), 139 fake_session_manager_client_(new FakeSessionManagerClient) { 140 fake_dbus_thread_manager_->SetFakeClients(); 141 fake_dbus_thread_manager_->SetSessionManagerClient( 142 scoped_ptr<SessionManagerClient>(fake_session_manager_client_)); 143 } 144 145 scoped_ptr<policy::UserPolicyBuilder> GetUserPolicyBuilder( 146 const std::string& user_id) { 147 scoped_ptr<policy::UserPolicyBuilder> 148 user_policy_builder(new policy::UserPolicyBuilder()); 149 base::FilePath user_keys_dir; 150 EXPECT_TRUE(PathService::Get(DIR_USER_POLICY_KEYS, &user_keys_dir)); 151 const std::string sanitized_user_id = 152 CryptohomeClient::GetStubSanitizedUsername(user_id); 153 const base::FilePath user_key_file = 154 user_keys_dir.AppendASCII(sanitized_user_id) 155 .AppendASCII("policy.pub"); 156 std::vector<uint8> user_key_bits; 157 EXPECT_TRUE(user_policy_builder->GetSigningKey()-> 158 ExportPublicKey(&user_key_bits)); 159 EXPECT_TRUE(base::CreateDirectory(user_key_file.DirName())); 160 EXPECT_EQ(base::WriteFile( 161 user_key_file, 162 reinterpret_cast<const char*>(user_key_bits.data()), 163 user_key_bits.size()), 164 static_cast<int>(user_key_bits.size())); 165 user_policy_builder->policy_data().set_username(user_id); 166 return user_policy_builder.Pass(); 167 } 168 169 // LoginManagerTest: 170 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 171 DBusThreadManager::SetInstanceForTesting(fake_dbus_thread_manager_); 172 LoginManagerTest::SetUpInProcessBrowserTestFixture(); 173 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_)); 174 } 175 176 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 177 // Set the same switches as LoginManagerTest, except that kMultiProfiles is 178 // only set when GetParam() is true and except that kLoginProfile is set 179 // when GetParam() is false. The latter seems to be required for the sane 180 // start-up of user profiles. 181 command_line->AppendSwitch(switches::kLoginManager); 182 command_line->AppendSwitch(switches::kForceLoginManagerInTests); 183 } 184 185 virtual void SetUpOnMainThread() OVERRIDE { 186 LoginManagerTest::SetUpOnMainThread(); 187 ash::Shell::GetInstance()-> 188 desktop_background_controller()->AddObserver(this); 189 190 // Set up policy signing. 191 user_policy_builders_[0] = GetUserPolicyBuilder(kTestUsers[0]); 192 user_policy_builders_[1] = GetUserPolicyBuilder(kTestUsers[1]); 193 194 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 195 } 196 197 virtual void TearDownOnMainThread() OVERRIDE { 198 ash::Shell::GetInstance()-> 199 desktop_background_controller()->RemoveObserver(this); 200 LoginManagerTest::TearDownOnMainThread(); 201 } 202 203 // ash::DesktopBackgroundControllerObserver: 204 virtual void OnWallpaperDataChanged() OVERRIDE { 205 ++wallpaper_change_count_; 206 if (run_loop_) 207 run_loop_->Quit(); 208 } 209 210 // Runs the loop until wallpaper has changed at least |count| times in total. 211 void RunUntilWallpaperChangeCount(int count) { 212 while (wallpaper_change_count_ < count) { 213 run_loop_.reset(new base::RunLoop); 214 run_loop_->Run(); 215 } 216 } 217 218 std::string ConstructPolicy(const std::string& relative_path) const { 219 std::string image_data; 220 if (!base::ReadFileToString(test_data_dir_.Append(relative_path), 221 &image_data)) { 222 ADD_FAILURE(); 223 } 224 std::string policy; 225 base::JSONWriter::Write(policy::test::ConstructExternalDataReference( 226 embedded_test_server()->GetURL(std::string("/") + relative_path).spec(), 227 image_data).get(), 228 &policy); 229 return policy; 230 } 231 232 // Inject |filename| as wallpaper policy for test user |user_number|. Set 233 // empty |filename| to clear policy. 234 void InjectPolicy(int user_number, const std::string& filename) { 235 ASSERT_TRUE(user_number == 0 || user_number == 1); 236 const std::string user_id = kTestUsers[user_number]; 237 policy::UserPolicyBuilder* builder = 238 user_policy_builders_[user_number].get(); 239 if (filename != "") { 240 builder->payload(). 241 mutable_wallpaperimage()->set_value(ConstructPolicy(filename)); 242 } else { 243 builder->payload().Clear(); 244 } 245 builder->Build(); 246 fake_session_manager_client_->set_user_policy(user_id, builder->GetBlob()); 247 const User* user = UserManager::Get()->FindUser(user_id); 248 ASSERT_TRUE(user); 249 policy::CloudPolicyStore* store = GetStoreForUser(user); 250 ASSERT_TRUE(store); 251 store->Load(); 252 ASSERT_EQ(policy::CloudPolicyStore::STATUS_OK, store->status()); 253 ASSERT_EQ(policy::CloudPolicyValidatorBase::VALIDATION_OK, 254 store->validation_status()); 255 } 256 257 // Obtain WallpaperInfo for |user_number| from WallpaperManager. 258 void GetUserWallpaperInfo(int user_number, WallpaperInfo* wallpaper_info) { 259 WallpaperManager::Get()-> 260 GetUserWallpaperInfo(kTestUsers[user_number], wallpaper_info); 261 } 262 263 base::FilePath test_data_dir_; 264 scoped_ptr<base::RunLoop> run_loop_; 265 int wallpaper_change_count_; 266 scoped_ptr<policy::UserPolicyBuilder> user_policy_builders_[2]; 267 FakeDBusThreadManager* fake_dbus_thread_manager_; 268 FakeSessionManagerClient* fake_session_manager_client_; 269 270 private: 271 DISALLOW_COPY_AND_ASSIGN(WallpaperManagerPolicyTest); 272 }; 273 274 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, PRE_SetResetClear) { 275 RegisterUser(kTestUsers[0]); 276 RegisterUser(kTestUsers[1]); 277 StartupUtils::MarkOobeCompleted(); 278 } 279 280 // Verifies that the wallpaper can be set and re-set through policy and that 281 // setting policy for a user that is not logged in doesn't affect the current 282 // user. Also verifies that after the policy has been cleared, the wallpaper 283 // reverts to default. 284 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, SetResetClear) { 285 WallpaperInfo info; 286 LoginUser(kTestUsers[0]); 287 base::RunLoop().RunUntilIdle(); 288 289 // First user: Wait until default wallpaper has been loaded (happens 290 // automatically) and store color to recognize it later. 291 RunUntilWallpaperChangeCount(1); 292 const SkColor original_background_color = GetAverageBackgroundColor(); 293 294 // Second user: Set wallpaper policy to blue image. This should not result in 295 // a wallpaper change, which is checked at the very end of this test. 296 InjectPolicy(1, kBlueImageFileName); 297 298 // First user: Set wallpaper policy to red image and verify average color. 299 InjectPolicy(0, kRedImageFileName); 300 RunUntilWallpaperChangeCount(2); 301 GetUserWallpaperInfo(0, &info); 302 ASSERT_EQ(User::POLICY, info.type); 303 ASSERT_EQ(kRedImageColor, GetAverageBackgroundColor()); 304 305 // First user: Set wallpaper policy to green image and verify average color. 306 InjectPolicy(0, kGreenImageFileName); 307 RunUntilWallpaperChangeCount(3); 308 GetUserWallpaperInfo(0, &info); 309 ASSERT_EQ(User::POLICY, info.type); 310 ASSERT_EQ(kGreenImageColor, GetAverageBackgroundColor()); 311 312 // First user: Clear wallpaper policy and verify that the default wallpaper is 313 // set again. 314 InjectPolicy(0, ""); 315 RunUntilWallpaperChangeCount(4); 316 GetUserWallpaperInfo(0, &info); 317 ASSERT_EQ(User::DEFAULT, info.type); 318 ASSERT_EQ(original_background_color, GetAverageBackgroundColor()); 319 320 // Check wallpaper change count to ensure that setting the second user's 321 // wallpaper didn't have any effect. 322 ASSERT_EQ(4, wallpaper_change_count_); 323 } 324 325 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, 326 DISABLED_PRE_PRE_PRE_WallpaperOnLoginScreen) { 327 RegisterUser(kTestUsers[0]); 328 RegisterUser(kTestUsers[1]); 329 StartupUtils::MarkOobeCompleted(); 330 } 331 332 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, 333 DISABLED_PRE_PRE_WallpaperOnLoginScreen) { 334 LoginUser(kTestUsers[0]); 335 336 // Wait until default wallpaper has been loaded. 337 RunUntilWallpaperChangeCount(1); 338 339 // Set wallpaper policy to red image. 340 InjectPolicy(0, kRedImageFileName); 341 342 // Run until wallpaper has changed. 343 RunUntilWallpaperChangeCount(2); 344 ASSERT_EQ(kRedImageColor, GetAverageBackgroundColor()); 345 } 346 347 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, 348 DISABLED_PRE_WallpaperOnLoginScreen) { 349 LoginUser(kTestUsers[1]); 350 351 // Wait until default wallpaper has been loaded. 352 RunUntilWallpaperChangeCount(1); 353 354 // Set wallpaper policy to green image. 355 InjectPolicy(1, kGreenImageFileName); 356 357 // Run until wallpaper has changed. 358 RunUntilWallpaperChangeCount(2); 359 ASSERT_EQ(kGreenImageColor, GetAverageBackgroundColor()); 360 } 361 362 // Disabled due to flakiness: http://crbug.com/385648. 363 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, 364 DISABLED_WallpaperOnLoginScreen) { 365 // Wait for active pod's wallpaper to be loaded. 366 RunUntilWallpaperChangeCount(1); 367 ASSERT_EQ(kGreenImageColor, GetAverageBackgroundColor()); 368 369 // Select the second pod (belonging to user 1). 370 ASSERT_TRUE(content::ExecuteScript( 371 static_cast<chromeos::LoginDisplayHostImpl*>( 372 chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI()-> 373 web_ui()->GetWebContents(), 374 "document.getElementsByClassName('pod')[1].focus();")); 375 RunUntilWallpaperChangeCount(2); 376 ASSERT_EQ(kRedImageColor, GetAverageBackgroundColor()); 377 } 378 379 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, PRE_PRE_PersistOverLogout) { 380 RegisterUser(kTestUsers[0]); 381 StartupUtils::MarkOobeCompleted(); 382 } 383 384 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, PRE_PersistOverLogout) { 385 LoginUser(kTestUsers[0]); 386 387 // Wait until default wallpaper has been loaded. 388 RunUntilWallpaperChangeCount(1); 389 390 // Set wallpaper policy to red image. 391 InjectPolicy(0, kRedImageFileName); 392 393 // Run until wallpaper has changed. 394 RunUntilWallpaperChangeCount(2); 395 ASSERT_EQ(kRedImageColor, GetAverageBackgroundColor()); 396 } 397 398 IN_PROC_BROWSER_TEST_F(WallpaperManagerPolicyTest, PersistOverLogout) { 399 LoginUser(kTestUsers[0]); 400 401 // Wait until wallpaper has been loaded. 402 RunUntilWallpaperChangeCount(1); 403 ASSERT_EQ(kRedImageColor, GetAverageBackgroundColor()); 404 } 405 406 } // namespace chromeos 407