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 "chrome/browser/policy/cloud/component_cloud_policy_service.h" 6 7 #include "base/callback.h" 8 #include "base/files/scoped_temp_dir.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/pickle.h" 11 #include "base/run_loop.h" 12 #include "base/sha1.h" 13 #include "base/single_thread_task_runner.h" 14 #include "base/stl_util.h" 15 #include "base/values.h" 16 #include "chrome/browser/policy/cloud/cloud_policy_constants.h" 17 #include "chrome/browser/policy/cloud/mock_cloud_policy_client.h" 18 #include "chrome/browser/policy/cloud/mock_cloud_policy_store.h" 19 #include "chrome/browser/policy/cloud/policy_builder.h" 20 #include "chrome/browser/policy/cloud/resource_cache.h" 21 #include "chrome/browser/policy/external_data_fetcher.h" 22 #include "chrome/browser/policy/policy_domain_descriptor.h" 23 #include "chrome/browser/policy/policy_map.h" 24 #include "chrome/browser/policy/policy_types.h" 25 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h" 26 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h" 27 #include "chrome/common/policy/policy_schema.h" 28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/test/test_browser_thread.h" 30 #include "net/url_request/test_url_fetcher_factory.h" 31 #include "net/url_request/url_fetcher_delegate.h" 32 #include "net/url_request/url_request_context.h" 33 #include "net/url_request/url_request_context_getter.h" 34 #include "testing/gmock/include/gmock/gmock.h" 35 #include "testing/gtest/include/gtest/gtest.h" 36 37 namespace em = enterprise_management; 38 39 using testing::Mock; 40 41 namespace policy { 42 43 namespace { 44 45 const char kTestExtension[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 46 const char kTestExtension2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; 47 const char kTestExtension3[] = "cccccccccccccccccccccccccccccccc"; 48 const char kTestDownload[] = "http://example.com/getpolicy?id=123"; 49 const char kTestDownload2[] = "http://example.com/getpolicy?id=456"; 50 51 const char kTestPolicy[] = 52 "{" 53 " \"Name\": {" 54 " \"Value\": \"disabled\"" 55 " }," 56 " \"Second\": {" 57 " \"Value\": \"maybe\"," 58 " \"Level\": \"Recommended\"" 59 " }" 60 "}"; 61 62 const char kTestSchema[] = 63 "{" 64 " \"$schema\": \"http://json-schema.org/draft-03/schema#\"," 65 " \"type\": \"object\"," 66 " \"properties\": {" 67 " \"Name\": { \"type\": \"string\" }," 68 " \"Second\": { \"type\": \"string\" }" 69 " }" 70 "}"; 71 72 class MockComponentCloudPolicyDelegate 73 : public ComponentCloudPolicyService::Delegate { 74 public: 75 virtual ~MockComponentCloudPolicyDelegate() {} 76 77 MOCK_METHOD0(OnComponentCloudPolicyRefreshNeeded, void()); 78 MOCK_METHOD0(OnComponentCloudPolicyUpdated, void()); 79 }; 80 81 class TestURLRequestContextGetter : public net::URLRequestContextGetter { 82 public: 83 explicit TestURLRequestContextGetter( 84 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 85 : task_runner_(task_runner) {} 86 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { 87 return NULL; 88 } 89 virtual scoped_refptr<base::SingleThreadTaskRunner> 90 GetNetworkTaskRunner() const OVERRIDE { 91 return task_runner_; 92 } 93 94 private: 95 virtual ~TestURLRequestContextGetter() {} 96 97 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 98 }; 99 100 } // namespace 101 102 class ComponentCloudPolicyServiceTest : public testing::Test { 103 protected: 104 ComponentCloudPolicyServiceTest() 105 : ui_thread_(content::BrowserThread::UI, &loop_), 106 file_thread_(content::BrowserThread::FILE, &loop_) {} 107 108 virtual void SetUp() OVERRIDE { 109 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 110 cache_ = new ResourceCache(temp_dir_.path()); 111 service_.reset(new ComponentCloudPolicyService( 112 &delegate_, &store_, make_scoped_ptr(cache_))); 113 114 builder_.policy_data().set_policy_type( 115 dm_protocol::kChromeExtensionPolicyType); 116 builder_.policy_data().set_settings_entity_id(kTestExtension); 117 builder_.payload().set_download_url(kTestDownload); 118 builder_.payload().set_secure_hash(base::SHA1HashString(kTestPolicy)); 119 120 expected_policy_.Set("Name", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, 121 base::Value::CreateStringValue("disabled"), NULL); 122 expected_policy_.Set("Second", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, 123 base::Value::CreateStringValue("maybe"), NULL); 124 125 // A NULL |request_context_| is enough to construct the updater, but 126 // ComponentCloudPolicyService::Backend::LoadStore() tests the pointer when 127 // Connect() is called before the store was loaded. 128 request_context_ = 129 new TestURLRequestContextGetter(loop_.message_loop_proxy()); 130 } 131 132 virtual void TearDown() OVERRIDE { 133 // The service cleans up its backend on the FILE thread. 134 service_.reset(); 135 RunUntilIdle(); 136 } 137 138 void RunUntilIdle() { 139 base::RunLoop().RunUntilIdle(); 140 } 141 142 void LoadStore() { 143 EXPECT_FALSE(store_.is_initialized()); 144 EXPECT_FALSE(service_->is_initialized()); 145 146 em::PolicyData* data = new em::PolicyData(); 147 data->set_username(ComponentPolicyBuilder::kFakeUsername); 148 data->set_request_token(ComponentPolicyBuilder::kFakeToken); 149 store_.policy_.reset(data); 150 151 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 152 store_.NotifyStoreLoaded(); 153 RunUntilIdle(); 154 Mock::VerifyAndClearExpectations(&delegate_); 155 EXPECT_TRUE(service_->is_initialized()); 156 } 157 158 void PopulateCache() { 159 Pickle pickle; 160 pickle.WriteString(kTestExtension); 161 pickle.WriteString(kTestExtension2); 162 std::string data(reinterpret_cast<const char*>(pickle.data()), 163 pickle.size()); 164 EXPECT_TRUE( 165 cache_->Store(ComponentCloudPolicyService::kComponentNamespaceCache, 166 dm_protocol::kChromeExtensionPolicyType, 167 data)); 168 169 EXPECT_TRUE(cache_->Store( 170 "extension-policy", kTestExtension, CreateSerializedResponse())); 171 EXPECT_TRUE( 172 cache_->Store("extension-policy-data", kTestExtension, kTestPolicy)); 173 174 builder_.policy_data().set_settings_entity_id(kTestExtension2); 175 EXPECT_TRUE(cache_->Store( 176 "extension-policy", kTestExtension2, CreateSerializedResponse())); 177 EXPECT_TRUE( 178 cache_->Store("extension-policy-data", kTestExtension2, kTestPolicy)); 179 180 EXPECT_TRUE(cache_->Store("unrelated", "stuff", "here")); 181 } 182 183 scoped_ptr<em::PolicyFetchResponse> CreateResponse() { 184 builder_.Build(); 185 return make_scoped_ptr(new em::PolicyFetchResponse(builder_.policy())); 186 } 187 188 std::string CreateSerializedResponse() { 189 builder_.Build(); 190 return builder_.GetBlob(); 191 } 192 193 scoped_ptr<PolicySchema> CreateTestSchema() { 194 std::string error; 195 scoped_ptr<PolicySchema> schema = PolicySchema::Parse(kTestSchema, &error); 196 EXPECT_TRUE(schema) << error; 197 return schema.Pass(); 198 } 199 200 base::MessageLoop loop_; 201 content::TestBrowserThread ui_thread_; 202 content::TestBrowserThread file_thread_; 203 base::ScopedTempDir temp_dir_; 204 scoped_refptr<TestURLRequestContextGetter> request_context_; 205 net::TestURLFetcherFactory fetcher_factory_; 206 MockComponentCloudPolicyDelegate delegate_; 207 // |cache_| is owned by the |service_| and is invalid once the |service_| 208 // is destroyed. 209 ResourceCache* cache_; 210 MockCloudPolicyClient client_; 211 MockCloudPolicyStore store_; 212 scoped_ptr<ComponentCloudPolicyService> service_; 213 ComponentPolicyBuilder builder_; 214 PolicyMap expected_policy_; 215 }; 216 217 TEST_F(ComponentCloudPolicyServiceTest, InitializeWithoutCredentials) { 218 EXPECT_FALSE(service_->is_initialized()); 219 // Run the background task to initialize the backend. 220 RunUntilIdle(); 221 // Still waiting for the |store_|. 222 EXPECT_FALSE(service_->is_initialized()); 223 224 // Initialize with a store without credentials. 225 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 226 store_.NotifyStoreLoaded(); 227 RunUntilIdle(); 228 EXPECT_TRUE(service_->is_initialized()); 229 Mock::VerifyAndClearExpectations(&delegate_); 230 const PolicyBundle empty_bundle; 231 EXPECT_TRUE(service_->policy().Equals(empty_bundle)); 232 } 233 234 TEST_F(ComponentCloudPolicyServiceTest, InitializationWithCachedComponents) { 235 // Store a previous list of components. 236 Pickle pickle; 237 pickle.WriteString("aa"); 238 pickle.WriteString("bb"); 239 pickle.WriteString("cc"); 240 std::string data(reinterpret_cast<const char*>(pickle.data()), pickle.size()); 241 EXPECT_TRUE( 242 cache_->Store(ComponentCloudPolicyService::kComponentNamespaceCache, 243 dm_protocol::kChromeExtensionPolicyType, 244 data)); 245 // Store some garbage in another domain; it won't be fetched. 246 EXPECT_TRUE(cache_->Store( 247 ComponentCloudPolicyService::kComponentNamespaceCache, "garbage", data)); 248 249 // Connect a client before initialization is complete. 250 service_->Connect(&client_, request_context_); 251 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); 252 253 // Now load the backend. 254 LoadStore(); 255 256 // The cached namespaces were added to the client. 257 std::set<PolicyNamespaceKey> set; 258 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "aa")); 259 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "bb")); 260 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "cc")); 261 EXPECT_EQ(set, client_.namespaces_to_fetch_); 262 263 // And the bad components were wiped from the cache. 264 std::map<std::string, std::string> contents; 265 cache_->LoadAllSubkeys(ComponentCloudPolicyService::kComponentNamespaceCache, 266 &contents); 267 ASSERT_EQ(1u, contents.size()); 268 EXPECT_EQ(std::string(dm_protocol::kChromeExtensionPolicyType), 269 contents.begin()->first); 270 } 271 272 TEST_F(ComponentCloudPolicyServiceTest, ConnectAfterRegister) { 273 // Add some components. 274 scoped_refptr<PolicyDomainDescriptor> descriptor = new PolicyDomainDescriptor( 275 POLICY_DOMAIN_EXTENSIONS); 276 descriptor->RegisterComponent(kTestExtension, CreateTestSchema()); 277 descriptor->RegisterComponent(kTestExtension2, CreateTestSchema()); 278 service_->RegisterPolicyDomain(descriptor); 279 280 // Now connect the client. 281 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); 282 service_->Connect(&client_, request_context_); 283 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); 284 285 // It receives the namespaces once the backend is initialized. 286 LoadStore(); 287 std::set<PolicyNamespaceKey> set; 288 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 289 kTestExtension)); 290 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 291 kTestExtension2)); 292 EXPECT_EQ(set, client_.namespaces_to_fetch_); 293 294 // The current components were also persisted to the cache. 295 std::map<std::string, std::string> contents; 296 cache_->LoadAllSubkeys(ComponentCloudPolicyService::kComponentNamespaceCache, 297 &contents); 298 ASSERT_EQ(1u, contents.size()); 299 EXPECT_EQ(std::string(dm_protocol::kChromeExtensionPolicyType), 300 contents.begin()->first); 301 const std::string data(contents.begin()->second); 302 Pickle pickle(data.data(), data.size()); 303 PickleIterator pickit(pickle); 304 std::string value0; 305 std::string value1; 306 std::string tmp; 307 ASSERT_TRUE(pickit.ReadString(&value0)); 308 ASSERT_TRUE(pickit.ReadString(&value1)); 309 EXPECT_FALSE(pickit.ReadString(&tmp)); 310 std::set<std::string> unpickled; 311 unpickled.insert(value0); 312 unpickled.insert(value1); 313 314 std::set<std::string> expected_components; 315 expected_components.insert(kTestExtension); 316 expected_components.insert(kTestExtension2); 317 318 EXPECT_EQ(expected_components, unpickled); 319 } 320 321 TEST_F(ComponentCloudPolicyServiceTest, StoreReadyAfterConnectAndRegister) { 322 // Add some previous data to the cache. 323 PopulateCache(); 324 325 // Add some components. 326 scoped_refptr<PolicyDomainDescriptor> descriptor = new PolicyDomainDescriptor( 327 POLICY_DOMAIN_EXTENSIONS); 328 descriptor->RegisterComponent(kTestExtension, CreateTestSchema()); 329 service_->RegisterPolicyDomain(descriptor); 330 331 // And connect the client. Make the client have some policies, with a new 332 // download_url. 333 builder_.payload().set_download_url(kTestDownload2); 334 client_.SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 335 kTestExtension), 336 *CreateResponse()); 337 service_->Connect(&client_, request_context_); 338 339 // Now make the store ready. 340 LoadStore(); 341 342 // The components that were registed before have their caches purged. 343 std::map<std::string, std::string> contents; 344 cache_->LoadAllSubkeys("extension-policy", &contents); 345 EXPECT_EQ(1u, contents.size()); // kTestExtension2 was purged. 346 EXPECT_TRUE(ContainsKey(contents, kTestExtension)); 347 cache_->LoadAllSubkeys("unrelated", &contents); 348 EXPECT_EQ(1u, contents.size()); // unrelated keys are not purged. 349 EXPECT_TRUE(ContainsKey(contents, "stuff")); 350 351 // The policy responses that the client already had start updating. 352 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); 353 ASSERT_TRUE(fetcher); 354 // Expect the URL of the client's PolicyFetchResponse, not the cached URL. 355 EXPECT_EQ(GURL(kTestDownload2), fetcher->GetOriginalURL()); 356 } 357 358 TEST_F(ComponentCloudPolicyServiceTest, ConnectThenRegisterThenStoreReady) { 359 // Connect right after creating the service. 360 service_->Connect(&client_, request_context_); 361 362 // Now register the current components, before the backend has been 363 // initialized. 364 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); 365 scoped_refptr<PolicyDomainDescriptor> descriptor = new PolicyDomainDescriptor( 366 POLICY_DOMAIN_EXTENSIONS); 367 descriptor->RegisterComponent(kTestExtension, CreateTestSchema()); 368 service_->RegisterPolicyDomain(descriptor); 369 EXPECT_TRUE(client_.namespaces_to_fetch_.empty()); 370 371 // Now load the store. The client gets the namespaces. 372 LoadStore(); 373 std::set<PolicyNamespaceKey> set; 374 set.insert(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 375 kTestExtension)); 376 EXPECT_EQ(set, client_.namespaces_to_fetch_); 377 } 378 379 TEST_F(ComponentCloudPolicyServiceTest, FetchPolicy) { 380 // Initialize the store and create the backend, and connect the client. 381 LoadStore(); 382 // A refresh is not needed, because no components were found. 383 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()).Times(0); 384 service_->Connect(&client_, request_context_); 385 Mock::VerifyAndClearExpectations(&delegate_); 386 387 // Register the components to fetch. 388 scoped_refptr<PolicyDomainDescriptor> descriptor = new PolicyDomainDescriptor( 389 POLICY_DOMAIN_EXTENSIONS); 390 descriptor->RegisterComponent(kTestExtension, CreateTestSchema()); 391 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()); 392 service_->RegisterPolicyDomain(descriptor); 393 Mock::VerifyAndClearExpectations(&delegate_); 394 395 // Send back a fake policy fetch response. 396 client_.SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 397 kTestExtension), 398 *CreateResponse()); 399 service_->OnPolicyFetched(&client_); 400 RunUntilIdle(); 401 402 // That should have triggered the download fetch. 403 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); 404 ASSERT_TRUE(fetcher); 405 EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL()); 406 fetcher->set_response_code(200); 407 fetcher->SetResponseString(kTestPolicy); 408 fetcher->delegate()->OnURLFetchComplete(fetcher); 409 410 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 411 RunUntilIdle(); 412 Mock::VerifyAndClearExpectations(&delegate_); 413 414 // The policy is now being served. 415 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 416 PolicyBundle expected_bundle; 417 expected_bundle.Get(ns).CopyFrom(expected_policy_); 418 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 419 } 420 421 TEST_F(ComponentCloudPolicyServiceTest, LoadAndPurgeCache) { 422 // Insert data in the cache. 423 PopulateCache(); 424 425 // Load the initial cache. 426 LoadStore(); 427 428 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()); 429 service_->Connect(&client_, request_context_); 430 Mock::VerifyAndClearExpectations(&delegate_); 431 432 PolicyBundle expected_bundle; 433 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 434 expected_bundle.Get(ns).CopyFrom(expected_policy_); 435 ns.component_id = kTestExtension2; 436 expected_bundle.Get(ns).CopyFrom(expected_policy_); 437 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 438 439 // Now purge one of the extensions. 440 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 441 // The service will start updating the components that are registered, which 442 // starts by fetching policy for them. 443 scoped_refptr<PolicyDomainDescriptor> descriptor = new PolicyDomainDescriptor( 444 POLICY_DOMAIN_EXTENSIONS); 445 descriptor->RegisterComponent(kTestExtension2, CreateTestSchema()); 446 service_->RegisterPolicyDomain(descriptor); 447 RunUntilIdle(); 448 Mock::VerifyAndClearExpectations(&delegate_); 449 450 ns.component_id = kTestExtension; 451 expected_bundle.Get(ns).Clear(); 452 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 453 454 std::map<std::string, std::string> contents; 455 cache_->LoadAllSubkeys("extension-policy", &contents); 456 EXPECT_EQ(1u, contents.size()); 457 EXPECT_TRUE(ContainsKey(contents, kTestExtension2)); 458 cache_->LoadAllSubkeys("unrelated", &contents); 459 EXPECT_EQ(1u, contents.size()); 460 EXPECT_TRUE(ContainsKey(contents, "stuff")); 461 } 462 463 TEST_F(ComponentCloudPolicyServiceTest, UpdateCredentials) { 464 // Do the same as LoadStore() but without the initial credentials. 465 EXPECT_FALSE(store_.is_initialized()); 466 EXPECT_FALSE(service_->is_initialized()); 467 store_.policy_.reset(new em::PolicyData()); // No credentials. 468 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 469 store_.NotifyStoreLoaded(); 470 RunUntilIdle(); 471 Mock::VerifyAndClearExpectations(&delegate_); 472 EXPECT_TRUE(service_->is_initialized()); 473 474 // Connect the client and register an extension. 475 service_->Connect(&client_, request_context_); 476 EXPECT_CALL(delegate_, OnComponentCloudPolicyRefreshNeeded()); 477 scoped_refptr<PolicyDomainDescriptor> descriptor = new PolicyDomainDescriptor( 478 POLICY_DOMAIN_EXTENSIONS); 479 descriptor->RegisterComponent(kTestExtension, CreateTestSchema()); 480 service_->RegisterPolicyDomain(descriptor); 481 Mock::VerifyAndClearExpectations(&delegate_); 482 483 // Send the response to the service. The response data will be rejected, 484 // because the store doesn't have the updated credentials yet. 485 client_.SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 486 kTestExtension), 487 *CreateResponse()); 488 service_->OnPolicyFetched(&client_); 489 RunUntilIdle(); 490 491 // The policy was not verified, and no download is started. 492 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); 493 EXPECT_FALSE(fetcher); 494 495 // Now update the |store_| with the updated policy, which includes 496 // credentials. The responses in the |client_| will be reloaded. 497 em::PolicyData* data = new em::PolicyData(); 498 data->set_username(ComponentPolicyBuilder::kFakeUsername); 499 data->set_request_token(ComponentPolicyBuilder::kFakeToken); 500 store_.policy_.reset(data); 501 store_.NotifyStoreLoaded(); 502 RunUntilIdle(); 503 504 // The extension policy was validated this time, and the download is started. 505 fetcher = fetcher_factory_.GetFetcherByID(0); 506 ASSERT_TRUE(fetcher); 507 EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL()); 508 fetcher->set_response_code(200); 509 fetcher->SetResponseString(kTestPolicy); 510 fetcher->delegate()->OnURLFetchComplete(fetcher); 511 512 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 513 RunUntilIdle(); 514 Mock::VerifyAndClearExpectations(&delegate_); 515 516 // The policy is now being served. 517 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 518 PolicyBundle expected_bundle; 519 expected_bundle.Get(ns).CopyFrom(expected_policy_); 520 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 521 } 522 523 } // namespace policy 524