1 // Copyright (c) 2012 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 "base/callback.h" 6 #include "base/command_line.h" 7 #include "base/file_util.h" 8 #include "base/files/file_path.h" 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/path_service.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/run_loop.h" 14 #include "base/strings/stringprintf.h" 15 #include "base/time/time.h" 16 #include "chrome/browser/browser_process.h" 17 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/invalidation/fake_invalidation_service.h" 19 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h" 20 #include "chrome/browser/policy/profile_policy_connector.h" 21 #include "chrome/browser/policy/profile_policy_connector_factory.h" 22 #include "chrome/browser/policy/test/local_policy_test_server.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/ui/browser.h" 25 #include "chrome/test/base/in_process_browser_test.h" 26 #include "components/invalidation/invalidation_service.h" 27 #include "components/invalidation/profile_invalidation_provider.h" 28 #include "components/keyed_service/core/keyed_service.h" 29 #include "components/policy/core/browser/browser_policy_connector.h" 30 #include "components/policy/core/common/cloud/cloud_policy_client.h" 31 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 32 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" 33 #include "components/policy/core/common/external_data_fetcher.h" 34 #include "components/policy/core/common/policy_map.h" 35 #include "components/policy/core/common/policy_service.h" 36 #include "components/policy/core/common/policy_switches.h" 37 #include "components/policy/core/common/policy_test_utils.h" 38 #include "content/public/browser/notification_service.h" 39 #include "content/public/browser/notification_source.h" 40 #include "content/public/test/test_utils.h" 41 #include "net/url_request/url_request_context_getter.h" 42 #include "policy/policy_constants.h" 43 #include "policy/proto/chrome_settings.pb.h" 44 #include "policy/proto/cloud_policy.pb.h" 45 #include "sync/internal_api/public/base/invalidation.h" 46 #include "testing/gmock/include/gmock/gmock.h" 47 #include "testing/gtest/include/gtest/gtest.h" 48 #include "url/gurl.h" 49 50 #if defined(OS_CHROMEOS) 51 #include "chrome/browser/chromeos/login/users/user_manager.h" 52 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h" 53 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h" 54 #include "chromeos/chromeos_paths.h" 55 #include "chromeos/dbus/cryptohome_client.h" 56 #else 57 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h" 58 #include "chrome/browser/signin/signin_manager_factory.h" 59 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" 60 #include "components/signin/core/browser/signin_manager.h" 61 #endif 62 63 using testing::AnyNumber; 64 using testing::InvokeWithoutArgs; 65 using testing::Mock; 66 using testing::Return; 67 using testing::_; 68 69 namespace content { 70 class BrowserContext; 71 } 72 73 namespace em = enterprise_management; 74 75 namespace policy { 76 77 namespace { 78 79 KeyedService* BuildFakeProfileInvalidationProvider( 80 content::BrowserContext* context) { 81 return new invalidation::ProfileInvalidationProvider( 82 scoped_ptr<invalidation::InvalidationService>( 83 new invalidation::FakeInvalidationService)); 84 } 85 86 const char* GetTestUser() { 87 #if defined(OS_CHROMEOS) 88 return chromeos::UserManager::kStubUser; 89 #else 90 return "user (at) example.com"; 91 #endif 92 } 93 94 std::string GetEmptyPolicy() { 95 const char kEmptyPolicy[] = 96 "{" 97 " \"%s\": {" 98 " \"mandatory\": {}," 99 " \"recommended\": {}" 100 " }," 101 " \"managed_users\": [ \"*\" ]," 102 " \"policy_user\": \"%s\"," 103 " \"current_key_index\": 0" 104 "}"; 105 106 return base::StringPrintf( 107 kEmptyPolicy, dm_protocol::kChromeUserPolicyType, GetTestUser()); 108 } 109 110 std::string GetTestPolicy(const char* homepage, int key_version) { 111 const char kTestPolicy[] = 112 "{" 113 " \"%s\": {" 114 " \"mandatory\": {" 115 " \"ShowHomeButton\": true," 116 " \"RestoreOnStartup\": 4," 117 " \"URLBlacklist\": [ \"dev.chromium.org\", \"youtube.com\" ]," 118 " \"MaxInvalidationFetchDelay\": 1000" 119 " }," 120 " \"recommended\": {" 121 " \"HomepageLocation\": \"%s\"" 122 " }" 123 " }," 124 " \"managed_users\": [ \"*\" ]," 125 " \"policy_user\": \"%s\"," 126 " \"current_key_index\": %d," 127 " \"invalidation_source\": 16," 128 " \"invalidation_name\": \"test_policy\"" 129 "}"; 130 131 return base::StringPrintf(kTestPolicy, 132 dm_protocol::kChromeUserPolicyType, 133 homepage, 134 GetTestUser(), 135 key_version); 136 } 137 138 void GetExpectedDefaultPolicy(PolicyMap* policy_map) { 139 #if defined(OS_CHROMEOS) 140 policy_map->Set( 141 key::kChromeOsMultiProfileUserBehavior, POLICY_LEVEL_MANDATORY, 142 POLICY_SCOPE_USER, base::Value::CreateStringValue("not-allowed"), NULL); 143 #endif 144 } 145 146 void GetExpectedTestPolicy(PolicyMap* expected, const char* homepage) { 147 expected->Set(key::kShowHomeButton, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, 148 base::Value::CreateBooleanValue(true), NULL); 149 expected->Set(key::kRestoreOnStartup, POLICY_LEVEL_MANDATORY, 150 POLICY_SCOPE_USER, base::Value::CreateIntegerValue(4), NULL); 151 base::ListValue list; 152 list.AppendString("dev.chromium.org"); 153 list.AppendString("youtube.com"); 154 expected->Set( 155 key::kURLBlacklist, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, 156 list.DeepCopy(), NULL); 157 expected->Set( 158 key::kMaxInvalidationFetchDelay, POLICY_LEVEL_MANDATORY, 159 POLICY_SCOPE_USER, base::Value::CreateIntegerValue(1000), NULL); 160 expected->Set( 161 key::kHomepageLocation, POLICY_LEVEL_RECOMMENDED, 162 POLICY_SCOPE_USER, base::Value::CreateStringValue(homepage), NULL); 163 #if defined(OS_CHROMEOS) 164 expected->Set( 165 key::kChromeOsMultiProfileUserBehavior, POLICY_LEVEL_MANDATORY, 166 POLICY_SCOPE_USER, base::Value::CreateStringValue("not-allowed"), NULL); 167 #endif 168 } 169 170 } // namespace 171 172 // Tests the cloud policy stack(s). 173 class CloudPolicyTest : public InProcessBrowserTest, 174 public PolicyService::Observer { 175 protected: 176 CloudPolicyTest() {} 177 virtual ~CloudPolicyTest() {} 178 179 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 180 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 181 ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetEmptyPolicy())); 182 183 test_server_.reset(new LocalPolicyTestServer(policy_file_path())); 184 ASSERT_TRUE(test_server_->Start()); 185 186 std::string url = test_server_->GetServiceURL().spec(); 187 188 CommandLine* command_line = CommandLine::ForCurrentProcess(); 189 command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, url); 190 191 invalidation::ProfileInvalidationProviderFactory::GetInstance()-> 192 RegisterTestingFactory(BuildFakeProfileInvalidationProvider); 193 } 194 195 virtual void SetUpOnMainThread() OVERRIDE { 196 ASSERT_TRUE(PolicyServiceIsEmpty(g_browser_process->policy_service())) 197 << "Pre-existing policies in this machine will make this test fail."; 198 199 BrowserPolicyConnector* connector = 200 g_browser_process->browser_policy_connector(); 201 connector->ScheduleServiceInitialization(0); 202 203 #if defined(OS_CHROMEOS) 204 UserCloudPolicyManagerChromeOS* policy_manager = 205 UserCloudPolicyManagerFactoryChromeOS::GetForProfile( 206 browser()->profile()); 207 ASSERT_TRUE(policy_manager); 208 #else 209 // Mock a signed-in user. This is used by the UserCloudPolicyStore to pass 210 // the username to the UserCloudPolicyValidator. 211 SigninManager* signin_manager = 212 SigninManagerFactory::GetForProfile(browser()->profile()); 213 ASSERT_TRUE(signin_manager); 214 signin_manager->SetAuthenticatedUsername(GetTestUser()); 215 216 UserCloudPolicyManager* policy_manager = 217 UserCloudPolicyManagerFactory::GetForBrowserContext( 218 browser()->profile()); 219 ASSERT_TRUE(policy_manager); 220 policy_manager->Connect( 221 g_browser_process->local_state(), 222 g_browser_process->system_request_context(), 223 UserCloudPolicyManager::CreateCloudPolicyClient( 224 connector->device_management_service(), 225 g_browser_process->system_request_context()).Pass()); 226 #endif // defined(OS_CHROMEOS) 227 228 ASSERT_TRUE(policy_manager->core()->client()); 229 base::RunLoop run_loop; 230 MockCloudPolicyClientObserver observer; 231 EXPECT_CALL(observer, OnRegistrationStateChanged(_)).WillOnce( 232 InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); 233 policy_manager->core()->client()->AddObserver(&observer); 234 235 // Give a bogus OAuth token to the |policy_manager|. This should make its 236 // CloudPolicyClient fetch the DMToken. 237 ASSERT_FALSE(policy_manager->core()->client()->is_registered()); 238 em::DeviceRegisterRequest::Type registration_type = 239 #if defined(OS_CHROMEOS) 240 em::DeviceRegisterRequest::USER; 241 #else 242 em::DeviceRegisterRequest::BROWSER; 243 #endif 244 policy_manager->core()->client()->Register( 245 registration_type, "bogus", std::string(), false, std::string(), 246 std::string()); 247 run_loop.Run(); 248 Mock::VerifyAndClearExpectations(&observer); 249 policy_manager->core()->client()->RemoveObserver(&observer); 250 EXPECT_TRUE(policy_manager->core()->client()->is_registered()); 251 252 #if defined(OS_CHROMEOS) 253 // Get the path to the user policy key file. 254 base::FilePath user_policy_key_dir; 255 ASSERT_TRUE( 256 PathService::Get(chromeos::DIR_USER_POLICY_KEYS, &user_policy_key_dir)); 257 std::string sanitized_username = 258 chromeos::CryptohomeClient::GetStubSanitizedUsername(GetTestUser()); 259 user_policy_key_file_ = user_policy_key_dir.AppendASCII(sanitized_username) 260 .AppendASCII("policy.pub"); 261 #endif 262 } 263 264 PolicyService* GetPolicyService() { 265 ProfilePolicyConnector* profile_connector = 266 ProfilePolicyConnectorFactory::GetForProfile(browser()->profile()); 267 return profile_connector->policy_service(); 268 } 269 270 invalidation::FakeInvalidationService* GetInvalidationService() { 271 return static_cast<invalidation::FakeInvalidationService*>( 272 static_cast<invalidation::ProfileInvalidationProvider*>( 273 invalidation::ProfileInvalidationProviderFactory::GetInstance()-> 274 GetForProfile(browser()->profile()))->GetInvalidationService()); 275 } 276 277 void SetServerPolicy(const std::string& policy) { 278 int result = base::WriteFile(policy_file_path(), policy.data(), 279 policy.size()); 280 ASSERT_EQ(static_cast<int>(policy.size()), result); 281 } 282 283 base::FilePath policy_file_path() const { 284 return temp_dir_.path().AppendASCII("policy.json"); 285 } 286 287 virtual void OnPolicyUpdated(const PolicyNamespace& ns, 288 const PolicyMap& previous, 289 const PolicyMap& current) OVERRIDE { 290 if (!on_policy_updated_.is_null()) { 291 on_policy_updated_.Run(); 292 on_policy_updated_.Reset(); 293 } 294 } 295 296 virtual void OnPolicyServiceInitialized(PolicyDomain domain) OVERRIDE {} 297 298 base::ScopedTempDir temp_dir_; 299 scoped_ptr<LocalPolicyTestServer> test_server_; 300 base::FilePath user_policy_key_file_; 301 base::Closure on_policy_updated_; 302 }; 303 304 IN_PROC_BROWSER_TEST_F(CloudPolicyTest, FetchPolicy) { 305 PolicyService* policy_service = GetPolicyService(); 306 { 307 base::RunLoop run_loop; 308 // This does the initial fetch and stores the initial key. 309 policy_service->RefreshPolicies(run_loop.QuitClosure()); 310 run_loop.Run(); 311 } 312 313 PolicyMap default_policy; 314 GetExpectedDefaultPolicy(&default_policy); 315 EXPECT_TRUE(default_policy.Equals(policy_service->GetPolicies( 316 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())))); 317 318 ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("google.com", 0))); 319 PolicyMap expected; 320 GetExpectedTestPolicy(&expected, "google.com"); 321 { 322 base::RunLoop run_loop; 323 // This fetches the new policies, using the same key. 324 policy_service->RefreshPolicies(run_loop.QuitClosure()); 325 run_loop.Run(); 326 } 327 EXPECT_TRUE(expected.Equals(policy_service->GetPolicies( 328 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())))); 329 } 330 331 IN_PROC_BROWSER_TEST_F(CloudPolicyTest, InvalidatePolicy) { 332 PolicyService* policy_service = GetPolicyService(); 333 policy_service->AddObserver(POLICY_DOMAIN_CHROME, this); 334 335 // Perform the initial fetch. 336 ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("google.com", 0))); 337 { 338 base::RunLoop run_loop; 339 policy_service->RefreshPolicies(run_loop.QuitClosure()); 340 run_loop.Run(); 341 } 342 343 // Update the homepage in the policy and trigger an invalidation. 344 ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("youtube.com", 0))); 345 base::TimeDelta now = 346 base::Time::NowFromSystemTime() - base::Time::UnixEpoch(); 347 GetInvalidationService()->EmitInvalidationForTest( 348 syncer::Invalidation::Init( 349 invalidation::ObjectId(16, "test_policy"), 350 now.InMicroseconds() /* version */, 351 "payload")); 352 { 353 base::RunLoop run_loop; 354 on_policy_updated_ = run_loop.QuitClosure(); 355 run_loop.Run(); 356 } 357 358 // Check that the updated policy was fetched. 359 PolicyMap expected; 360 GetExpectedTestPolicy(&expected, "youtube.com"); 361 EXPECT_TRUE(expected.Equals(policy_service->GetPolicies( 362 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())))); 363 364 policy_service->RemoveObserver(POLICY_DOMAIN_CHROME, this); 365 } 366 367 #if defined(OS_CHROMEOS) 368 IN_PROC_BROWSER_TEST_F(CloudPolicyTest, FetchPolicyWithRotatedKey) { 369 PolicyService* policy_service = GetPolicyService(); 370 { 371 base::RunLoop run_loop; 372 // This does the initial fetch and stores the initial key. 373 policy_service->RefreshPolicies(run_loop.QuitClosure()); 374 run_loop.Run(); 375 } 376 377 // Read the initial key. 378 std::string initial_key; 379 ASSERT_TRUE(base::ReadFileToString(user_policy_key_file_, &initial_key)); 380 381 PolicyMap default_policy; 382 GetExpectedDefaultPolicy(&default_policy); 383 EXPECT_TRUE(default_policy.Equals(policy_service->GetPolicies( 384 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())))); 385 386 // Set the new policies and a new key at the server. 387 ASSERT_NO_FATAL_FAILURE(SetServerPolicy(GetTestPolicy("google.com", 1))); 388 PolicyMap expected; 389 GetExpectedTestPolicy(&expected, "google.com"); 390 { 391 base::RunLoop run_loop; 392 // This fetches the new policies and does a key rotation. 393 policy_service->RefreshPolicies(run_loop.QuitClosure()); 394 run_loop.Run(); 395 } 396 EXPECT_TRUE(expected.Equals(policy_service->GetPolicies( 397 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())))); 398 399 // Verify that the key was rotated. 400 std::string rotated_key; 401 ASSERT_TRUE(base::ReadFileToString(user_policy_key_file_, &rotated_key)); 402 EXPECT_NE(rotated_key, initial_key); 403 404 // Another refresh using the same key won't rotate it again. 405 { 406 base::RunLoop run_loop; 407 policy_service->RefreshPolicies(run_loop.QuitClosure()); 408 run_loop.Run(); 409 } 410 EXPECT_TRUE(expected.Equals(policy_service->GetPolicies( 411 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())))); 412 std::string current_key; 413 ASSERT_TRUE(base::ReadFileToString(user_policy_key_file_, ¤t_key)); 414 EXPECT_EQ(rotated_key, current_key); 415 } 416 #endif 417 418 TEST(CloudPolicyProtoTest, VerifyProtobufEquivalence) { 419 // There are 2 protobufs that can be used for user cloud policy: 420 // cloud_policy.proto and chrome_settings.proto. chrome_settings.proto is the 421 // version used by the server, but generates one proto message per policy; to 422 // save binary size on the client, the other version shares proto messages for 423 // policies of the same type. They generate the same bytes on the wire though, 424 // so they are compatible. This test verifies that that stays true. 425 426 // Build a ChromeSettingsProto message with one policy of each supported type. 427 em::ChromeSettingsProto chrome_settings; 428 chrome_settings.mutable_homepagelocation()->set_homepagelocation( 429 "chromium.org"); 430 chrome_settings.mutable_showhomebutton()->set_showhomebutton(true); 431 chrome_settings.mutable_restoreonstartup()->set_restoreonstartup(4); 432 em::StringList* list = 433 chrome_settings.mutable_disabledschemes()->mutable_disabledschemes(); 434 list->add_entries("ftp"); 435 list->add_entries("mailto"); 436 // Try explicitly setting a policy mode too. 437 chrome_settings.mutable_disablespdy()->set_disablespdy(false); 438 chrome_settings.mutable_disablespdy()->mutable_policy_options()->set_mode( 439 em::PolicyOptions::MANDATORY); 440 chrome_settings.mutable_syncdisabled()->set_syncdisabled(true); 441 chrome_settings.mutable_syncdisabled()->mutable_policy_options()->set_mode( 442 em::PolicyOptions::RECOMMENDED); 443 444 // Build an equivalent CloudPolicySettings message. 445 em::CloudPolicySettings cloud_policy; 446 cloud_policy.mutable_homepagelocation()->set_value("chromium.org"); 447 cloud_policy.mutable_showhomebutton()->set_value(true); 448 cloud_policy.mutable_restoreonstartup()->set_value(4); 449 list = cloud_policy.mutable_disabledschemes()->mutable_value(); 450 list->add_entries("ftp"); 451 list->add_entries("mailto"); 452 cloud_policy.mutable_disablespdy()->set_value(false); 453 cloud_policy.mutable_disablespdy()->mutable_policy_options()->set_mode( 454 em::PolicyOptions::MANDATORY); 455 cloud_policy.mutable_syncdisabled()->set_value(true); 456 cloud_policy.mutable_syncdisabled()->mutable_policy_options()->set_mode( 457 em::PolicyOptions::RECOMMENDED); 458 459 // They should now serialize to the same bytes. 460 std::string chrome_settings_serialized; 461 std::string cloud_policy_serialized; 462 ASSERT_TRUE(chrome_settings.SerializeToString(&chrome_settings_serialized)); 463 ASSERT_TRUE(cloud_policy.SerializeToString(&cloud_policy_serialized)); 464 EXPECT_EQ(chrome_settings_serialized, cloud_policy_serialized); 465 } 466 467 } // namespace policy 468