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 "components/policy/core/common/cloud/component_cloud_policy_service.h" 6 7#include <map> 8#include <string> 9 10#include "base/callback.h" 11#include "base/files/scoped_temp_dir.h" 12#include "base/message_loop/message_loop.h" 13#include "base/run_loop.h" 14#include "base/single_thread_task_runner.h" 15#include "base/stl_util.h" 16#include "base/values.h" 17#include "components/policy/core/common/cloud/cloud_policy_constants.h" 18#include "components/policy/core/common/cloud/mock_cloud_policy_client.h" 19#include "components/policy/core/common/cloud/mock_cloud_policy_store.h" 20#include "components/policy/core/common/cloud/policy_builder.h" 21#include "components/policy/core/common/cloud/resource_cache.h" 22#include "components/policy/core/common/external_data_fetcher.h" 23#include "components/policy/core/common/policy_map.h" 24#include "components/policy/core/common/policy_types.h" 25#include "components/policy/core/common/schema.h" 26#include "components/policy/core/common/schema_map.h" 27#include "crypto/sha2.h" 28#include "net/url_request/test_url_fetcher_factory.h" 29#include "net/url_request/url_fetcher_delegate.h" 30#include "net/url_request/url_request_context.h" 31#include "net/url_request/url_request_context_getter.h" 32#include "policy/proto/chrome_extension_policy.pb.h" 33#include "policy/proto/device_management_backend.pb.h" 34#include "testing/gmock/include/gmock/gmock.h" 35#include "testing/gtest/include/gtest/gtest.h" 36 37namespace em = enterprise_management; 38 39using testing::Mock; 40 41namespace policy { 42 43namespace { 44 45const char kTestExtension[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 46const char kTestExtension2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; 47const char kTestDownload[] = "http://example.com/getpolicy?id=123"; 48 49const char kTestPolicy[] = 50 "{" 51 " \"Name\": {" 52 " \"Value\": \"disabled\"" 53 " }," 54 " \"Second\": {" 55 " \"Value\": \"maybe\"," 56 " \"Level\": \"Recommended\"" 57 " }" 58 "}"; 59 60const char kInvalidTestPolicy[] = 61 "{" 62 " \"Name\": {" 63 " \"Value\": \"published\"" 64 " }," 65 " \"Undeclared Name\": {" 66 " \"Value\": \"not published\"" 67 " }" 68 "}"; 69 70const char kTestSchema[] = 71 "{" 72 " \"type\": \"object\"," 73 " \"properties\": {" 74 " \"Name\": { \"type\": \"string\" }," 75 " \"Second\": { \"type\": \"string\" }" 76 " }" 77 "}"; 78 79class MockComponentCloudPolicyDelegate 80 : public ComponentCloudPolicyService::Delegate { 81 public: 82 virtual ~MockComponentCloudPolicyDelegate() {} 83 84 MOCK_METHOD0(OnComponentCloudPolicyUpdated, void()); 85}; 86 87class TestURLRequestContextGetter : public net::URLRequestContextGetter { 88 public: 89 explicit TestURLRequestContextGetter( 90 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 91 : task_runner_(task_runner) {} 92 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE { 93 return NULL; 94 } 95 virtual scoped_refptr<base::SingleThreadTaskRunner> 96 GetNetworkTaskRunner() const OVERRIDE { 97 return task_runner_; 98 } 99 100 private: 101 virtual ~TestURLRequestContextGetter() {} 102 103 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 104}; 105 106} // namespace 107 108class ComponentCloudPolicyServiceTest : public testing::Test { 109 protected: 110 ComponentCloudPolicyServiceTest() 111 : client_(NULL), 112 core_(PolicyNamespaceKey(GetChromeUserPolicyType(), ""), 113 &store_, 114 loop_.message_loop_proxy()) {} 115 116 virtual void SetUp() OVERRIDE { 117 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 118 119 cache_ = new ResourceCache(temp_dir_.path(), loop_.message_loop_proxy()); 120 request_context_ = 121 new TestURLRequestContextGetter(loop_.message_loop_proxy()); 122 service_.reset(new ComponentCloudPolicyService( 123 &delegate_, 124 ®istry_, 125 &core_, 126 make_scoped_ptr(cache_), 127 request_context_, 128 loop_.message_loop_proxy(), 129 loop_.message_loop_proxy())); 130 131 builder_.policy_data().set_policy_type( 132 dm_protocol::kChromeExtensionPolicyType); 133 builder_.policy_data().set_settings_entity_id(kTestExtension); 134 builder_.payload().set_download_url(kTestDownload); 135 builder_.payload().set_secure_hash(crypto::SHA256HashString(kTestPolicy)); 136 137 expected_policy_.Set("Name", 138 POLICY_LEVEL_MANDATORY, 139 POLICY_SCOPE_USER, 140 new base::StringValue("disabled"), 141 NULL); 142 expected_policy_.Set("Second", 143 POLICY_LEVEL_RECOMMENDED, 144 POLICY_SCOPE_USER, 145 new base::StringValue("maybe"), 146 NULL); 147 } 148 149 virtual void TearDown() OVERRIDE { 150 // The service cleans up its backend on the background thread. 151 service_.reset(); 152 RunUntilIdle(); 153 } 154 155 void RunUntilIdle() { 156 base::RunLoop().RunUntilIdle(); 157 } 158 159 void Connect(size_t expected_namespaces_in_client) { 160 client_ = new MockCloudPolicyClient(); 161 client_->SetDMToken(ComponentPolicyBuilder::kFakeToken); 162 EXPECT_EQ(0u, client_->namespaces_to_fetch_.size()); 163 164 core_.Connect(scoped_ptr<CloudPolicyClient>(client_)); 165 166 // |expected_namespaces_in_client| is the expected number of components 167 // that the ComponentCloudPolicyService will set at the |client_| at 168 // OnCoreConnected. 169 EXPECT_EQ(expected_namespaces_in_client, 170 client_->namespaces_to_fetch_.size()); 171 172 // Also initialize the refresh scheduler, so that calls to 173 // core()->RefreshSoon() trigger a FetchPolicy() call on the mock |client_|. 174 // The |service_| should never trigger new fetches. 175 EXPECT_CALL(*client_, FetchPolicy()); 176 core_.StartRefreshScheduler(); 177 RunUntilIdle(); 178 Mock::VerifyAndClearExpectations(client_); 179 } 180 181 void LoadStore() { 182 EXPECT_FALSE(store_.is_initialized()); 183 184 em::PolicyData* data = new em::PolicyData(); 185 data->set_username(ComponentPolicyBuilder::kFakeUsername); 186 data->set_request_token(ComponentPolicyBuilder::kFakeToken); 187 store_.policy_.reset(data); 188 189 store_.NotifyStoreLoaded(); 190 RunUntilIdle(); 191 EXPECT_TRUE(store_.is_initialized()); 192 } 193 194 void InitializeRegistry() { 195 registry_.RegisterComponent( 196 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension), 197 CreateTestSchema()); 198 registry_.SetReady(POLICY_DOMAIN_CHROME); 199 registry_.SetReady(POLICY_DOMAIN_EXTENSIONS); 200 } 201 202 void PopulateCache() { 203 EXPECT_TRUE(cache_->Store( 204 "extension-policy", kTestExtension, CreateSerializedResponse())); 205 EXPECT_TRUE( 206 cache_->Store("extension-policy-data", kTestExtension, kTestPolicy)); 207 208 builder_.policy_data().set_settings_entity_id(kTestExtension2); 209 EXPECT_TRUE(cache_->Store( 210 "extension-policy", kTestExtension2, CreateSerializedResponse())); 211 EXPECT_TRUE( 212 cache_->Store("extension-policy-data", kTestExtension2, kTestPolicy)); 213 } 214 215 scoped_ptr<em::PolicyFetchResponse> CreateResponse() { 216 builder_.Build(); 217 return make_scoped_ptr(new em::PolicyFetchResponse(builder_.policy())); 218 } 219 220 std::string CreateSerializedResponse() { 221 builder_.Build(); 222 return builder_.GetBlob(); 223 } 224 225 Schema CreateTestSchema() { 226 std::string error; 227 Schema schema = Schema::Parse(kTestSchema, &error); 228 EXPECT_TRUE(schema.valid()) << error; 229 return schema; 230 } 231 232 base::MessageLoop loop_; 233 base::ScopedTempDir temp_dir_; 234 scoped_refptr<TestURLRequestContextGetter> request_context_; 235 net::TestURLFetcherFactory fetcher_factory_; 236 MockComponentCloudPolicyDelegate delegate_; 237 // |cache_| is owned by the |service_| and is invalid once the |service_| 238 // is destroyed. 239 ResourceCache* cache_; 240 MockCloudPolicyClient* client_; 241 MockCloudPolicyStore store_; 242 CloudPolicyCore core_; 243 SchemaRegistry registry_; 244 scoped_ptr<ComponentCloudPolicyService> service_; 245 ComponentPolicyBuilder builder_; 246 PolicyMap expected_policy_; 247}; 248 249TEST_F(ComponentCloudPolicyServiceTest, InitializedAtConstructionTime) { 250 service_.reset(); 251 Connect(1u); 252 LoadStore(); 253 InitializeRegistry(); 254 255 cache_ = new ResourceCache(temp_dir_.path(), loop_.message_loop_proxy()); 256 service_.reset(new ComponentCloudPolicyService(&delegate_, 257 ®istry_, 258 &core_, 259 make_scoped_ptr(cache_), 260 request_context_, 261 loop_.message_loop_proxy(), 262 loop_.message_loop_proxy())); 263 EXPECT_FALSE(service_->is_initialized()); 264 265 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 266 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 267 RunUntilIdle(); 268 Mock::VerifyAndClearExpectations(&client_); 269 Mock::VerifyAndClearExpectations(&delegate_); 270 271 EXPECT_TRUE(service_->is_initialized()); 272 EXPECT_EQ(2u, client_->namespaces_to_fetch_.size()); 273 const PolicyBundle empty_bundle; 274 EXPECT_TRUE(service_->policy().Equals(empty_bundle)); 275} 276 277TEST_F(ComponentCloudPolicyServiceTest, InitializeStoreThenRegistry) { 278 Connect(2u); 279 280 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()).Times(0); 281 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 282 LoadStore(); 283 Mock::VerifyAndClearExpectations(client_); 284 Mock::VerifyAndClearExpectations(&delegate_); 285 EXPECT_FALSE(service_->is_initialized()); 286 287 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 288 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 289 InitializeRegistry(); 290 RunUntilIdle(); 291 Mock::VerifyAndClearExpectations(client_); 292 Mock::VerifyAndClearExpectations(&delegate_); 293 EXPECT_TRUE(service_->is_initialized()); 294 295 const PolicyBundle empty_bundle; 296 EXPECT_TRUE(service_->policy().Equals(empty_bundle)); 297} 298 299TEST_F(ComponentCloudPolicyServiceTest, InitializeRegistryThenStore) { 300 Connect(2u); 301 302 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()).Times(0); 303 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 304 InitializeRegistry(); 305 RunUntilIdle(); 306 Mock::VerifyAndClearExpectations(client_); 307 Mock::VerifyAndClearExpectations(&delegate_); 308 EXPECT_FALSE(service_->is_initialized()); 309 310 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 311 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 312 LoadStore(); 313 Mock::VerifyAndClearExpectations(client_); 314 Mock::VerifyAndClearExpectations(&delegate_); 315 EXPECT_TRUE(service_->is_initialized()); 316 EXPECT_EQ(2u, client_->namespaces_to_fetch_.size()); 317 const PolicyBundle empty_bundle; 318 EXPECT_TRUE(service_->policy().Equals(empty_bundle)); 319} 320 321TEST_F(ComponentCloudPolicyServiceTest, InitializeWithCachedPolicy) { 322 PopulateCache(); 323 Connect(2u); 324 325 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 326 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 327 InitializeRegistry(); 328 LoadStore(); 329 Mock::VerifyAndClearExpectations(client_); 330 Mock::VerifyAndClearExpectations(&delegate_); 331 332 EXPECT_TRUE(service_->is_initialized()); 333 EXPECT_EQ(2u, client_->namespaces_to_fetch_.size()); 334 335 // kTestExtension2 is not in the registry so it was dropped. 336 std::map<std::string, std::string> contents; 337 cache_->LoadAllSubkeys("extension-policy", &contents); 338 ASSERT_EQ(1u, contents.size()); 339 EXPECT_EQ(kTestExtension, contents.begin()->first); 340 341 PolicyBundle expected_bundle; 342 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 343 expected_bundle.Get(ns).CopyFrom(expected_policy_); 344 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 345} 346 347TEST_F(ComponentCloudPolicyServiceTest, FetchPolicy) { 348 Connect(2u); 349 // Initialize the store and create the backend. 350 // A refresh is not needed, because no components are registered yet. 351 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 352 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 353 registry_.SetReady(POLICY_DOMAIN_CHROME); 354 registry_.SetReady(POLICY_DOMAIN_EXTENSIONS); 355 LoadStore(); 356 Mock::VerifyAndClearExpectations(client_); 357 Mock::VerifyAndClearExpectations(&delegate_); 358 EXPECT_TRUE(service_->is_initialized()); 359 360 // Register the components to fetch. The |service_| issues a new update 361 // because the new schema may filter different policies from the store. 362 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 363 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 364 registry_.RegisterComponent( 365 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension), 366 CreateTestSchema()); 367 RunUntilIdle(); 368 Mock::VerifyAndClearExpectations(client_); 369 Mock::VerifyAndClearExpectations(&delegate_); 370 371 // Send back a fake policy fetch response. 372 client_->SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 373 kTestExtension), 374 *CreateResponse()); 375 service_->OnPolicyFetched(client_); 376 RunUntilIdle(); 377 378 // That should have triggered the download fetch. 379 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); 380 ASSERT_TRUE(fetcher); 381 EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL()); 382 fetcher->set_response_code(200); 383 fetcher->SetResponseString(kTestPolicy); 384 fetcher->delegate()->OnURLFetchComplete(fetcher); 385 386 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 387 RunUntilIdle(); 388 Mock::VerifyAndClearExpectations(&delegate_); 389 390 // The policy is now being served. 391 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 392 PolicyBundle expected_bundle; 393 expected_bundle.Get(ns).CopyFrom(expected_policy_); 394 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 395} 396 397TEST_F(ComponentCloudPolicyServiceTest, LoadAndPurgeCache) { 398 Connect(2u); 399 // Insert data in the cache. 400 PopulateCache(); 401 registry_.RegisterComponent( 402 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension2), 403 CreateTestSchema()); 404 InitializeRegistry(); 405 406 // Load the initial cache. 407 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 408 EXPECT_CALL(*client_, FetchPolicy()).Times(0); 409 LoadStore(); 410 Mock::VerifyAndClearExpectations(client_); 411 Mock::VerifyAndClearExpectations(&delegate_); 412 413 PolicyBundle expected_bundle; 414 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 415 expected_bundle.Get(ns).CopyFrom(expected_policy_); 416 ns.component_id = kTestExtension2; 417 expected_bundle.Get(ns).CopyFrom(expected_policy_); 418 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 419 420 // Now purge one of the extensions. This generates 2 notifications: one for 421 // the new, immediate filtering, and another once the backend comes back 422 // after purging the cache. 423 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()).Times(2); 424 registry_.UnregisterComponent( 425 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension)); 426 RunUntilIdle(); 427 Mock::VerifyAndClearExpectations(&delegate_); 428 429 ns.component_id = kTestExtension; 430 expected_bundle.Get(ns).Clear(); 431 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 432 433 std::map<std::string, std::string> contents; 434 cache_->LoadAllSubkeys("extension-policy", &contents); 435 EXPECT_EQ(1u, contents.size()); 436 EXPECT_TRUE(ContainsKey(contents, kTestExtension2)); 437} 438 439TEST_F(ComponentCloudPolicyServiceTest, SignInAfterStartup) { 440 registry_.SetReady(POLICY_DOMAIN_CHROME); 441 registry_.SetReady(POLICY_DOMAIN_EXTENSIONS); 442 443 // Initialize the store without credentials. 444 EXPECT_FALSE(store_.is_initialized()); 445 EXPECT_FALSE(service_->is_initialized()); 446 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 447 store_.NotifyStoreLoaded(); 448 RunUntilIdle(); 449 Mock::VerifyAndClearExpectations(&delegate_); 450 EXPECT_TRUE(service_->is_initialized()); 451 452 // Register an extension. 453 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 454 registry_.RegisterComponent( 455 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension), 456 CreateTestSchema()); 457 RunUntilIdle(); 458 Mock::VerifyAndClearExpectations(&delegate_); 459 460 // Now signin. A fetch will be requested for the new extension. 461 Connect(2u); 462 463 // Send the response to the service. The response data will be ignored, 464 // because the store doesn't have the updated credentials yet. 465 client_->SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, 466 kTestExtension), 467 *CreateResponse()); 468 service_->OnPolicyFetched(client_); 469 RunUntilIdle(); 470 471 // The policy was ignored and no download is started because the store 472 // doesn't have credentials. 473 net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); 474 EXPECT_FALSE(fetcher); 475 476 // Now update the |store_| with the updated policy, which includes 477 // credentials. The responses in the |client_| will be reloaded. 478 em::PolicyData* data = new em::PolicyData(); 479 data->set_username(ComponentPolicyBuilder::kFakeUsername); 480 data->set_request_token(ComponentPolicyBuilder::kFakeToken); 481 store_.policy_.reset(data); 482 store_.NotifyStoreLoaded(); 483 RunUntilIdle(); 484 485 // The extension policy was validated this time, and the download is started. 486 fetcher = fetcher_factory_.GetFetcherByID(0); 487 ASSERT_TRUE(fetcher); 488 EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL()); 489 fetcher->set_response_code(200); 490 fetcher->SetResponseString(kTestPolicy); 491 fetcher->delegate()->OnURLFetchComplete(fetcher); 492 493 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 494 RunUntilIdle(); 495 Mock::VerifyAndClearExpectations(&delegate_); 496 497 // The policy is now being served. 498 PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 499 PolicyBundle expected_bundle; 500 expected_bundle.Get(ns).CopyFrom(expected_policy_); 501 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 502} 503 504TEST_F(ComponentCloudPolicyServiceTest, SignOut) { 505 // Initialize everything and serve policy for a component. 506 PopulateCache(); 507 LoadStore(); 508 InitializeRegistry(); 509 510 // The initial, cached policy will be served once the backend is initialized. 511 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 512 RunUntilIdle(); 513 Mock::VerifyAndClearExpectations(&delegate_); 514 PolicyBundle expected_bundle; 515 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 516 expected_bundle.Get(ns).CopyFrom(expected_policy_); 517 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 518 std::map<std::string, std::string> contents; 519 cache_->LoadAllSubkeys("extension-policy", &contents); 520 ASSERT_EQ(1u, contents.size()); 521 522 // Now sign in. 523 Connect(2u); 524 525 // Signing out removes all of the component policies from the service and 526 // from the cache. It does not trigger a refresh. 527 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 528 core_.Disconnect(); 529 store_.policy_.reset(); 530 store_.NotifyStoreLoaded(); 531 RunUntilIdle(); 532 Mock::VerifyAndClearExpectations(&delegate_); 533 const PolicyBundle empty_bundle; 534 EXPECT_TRUE(service_->policy().Equals(empty_bundle)); 535 cache_->LoadAllSubkeys("extension-policy", &contents); 536 ASSERT_EQ(0u, contents.size()); 537} 538 539TEST_F(ComponentCloudPolicyServiceTest, LoadInvalidPolicyFromCache) { 540 // Put the invalid test policy in the cache. One of its policies will be 541 // loaded, the other should be filtered out by the schema. 542 builder_.payload().set_secure_hash( 543 crypto::SHA256HashString(kInvalidTestPolicy)); 544 EXPECT_TRUE(cache_->Store( 545 "extension-policy", kTestExtension, CreateSerializedResponse())); 546 EXPECT_TRUE(cache_->Store( 547 "extension-policy-data", kTestExtension, kInvalidTestPolicy)); 548 549 LoadStore(); 550 InitializeRegistry(); 551 552 // The initial, cached policy will be served once the backend is initialized. 553 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); 554 RunUntilIdle(); 555 Mock::VerifyAndClearExpectations(&delegate_); 556 557 PolicyBundle expected_bundle; 558 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); 559 expected_bundle.Get(ns).Set("Name", 560 POLICY_LEVEL_MANDATORY, 561 POLICY_SCOPE_USER, 562 new base::StringValue("published"), 563 NULL); 564 EXPECT_TRUE(service_->policy().Equals(expected_bundle)); 565} 566 567} // namespace policy 568