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.
5 #include "components/policy/core/common/cloud/component_cloud_policy_service.h"
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"
37 namespace em = enterprise_management;
45 const char kTestExtension[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
46 const char kTestExtension2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
47 const char kTestDownload[] = "http://example.com/getpolicy?id=123";
49 const char kTestPolicy[] =
52 " \"Value\": \"disabled\""
55 " \"Value\": \"maybe\","
56 " \"Level\": \"Recommended\""
60 const char kInvalidTestPolicy[] =
63 " \"Value\": \"published\""
65 " \"Undeclared Name\": {"
66 " \"Value\": \"not published\""
70 const char kTestSchema[] =
72 " \"type\": \"object\","
74 " \"Name\": { \"type\": \"string\" },"
75 " \"Second\": { \"type\": \"string\" }"
79 class MockComponentCloudPolicyDelegate
80 : public ComponentCloudPolicyService::Delegate {
82 virtual ~MockComponentCloudPolicyDelegate() {}
84 MOCK_METHOD0(OnComponentCloudPolicyUpdated, void());
87 class TestURLRequestContextGetter : public net::URLRequestContextGetter {
89 explicit TestURLRequestContextGetter(
90 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
91 : task_runner_(task_runner) {}
92 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
95 virtual scoped_refptr<base::SingleThreadTaskRunner>
96 GetNetworkTaskRunner() const OVERRIDE {
101 virtual ~TestURLRequestContextGetter() {}
103 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
108 class ComponentCloudPolicyServiceTest : public testing::Test {
110 ComponentCloudPolicyServiceTest()
112 core_(PolicyNamespaceKey(GetChromeUserPolicyType(), ""),
114 loop_.message_loop_proxy()) {}
116 virtual void SetUp() OVERRIDE {
117 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
119 cache_ = new ResourceCache(temp_dir_.path(), loop_.message_loop_proxy());
121 new TestURLRequestContextGetter(loop_.message_loop_proxy());
122 service_.reset(new ComponentCloudPolicyService(
126 make_scoped_ptr(cache_),
128 loop_.message_loop_proxy(),
129 loop_.message_loop_proxy()));
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));
137 expected_policy_.Set("Name",
138 POLICY_LEVEL_MANDATORY,
140 new base::StringValue("disabled"),
142 expected_policy_.Set("Second",
143 POLICY_LEVEL_RECOMMENDED,
145 new base::StringValue("maybe"),
149 virtual void TearDown() OVERRIDE {
150 // The service cleans up its backend on the background thread.
155 void RunUntilIdle() {
156 base::RunLoop().RunUntilIdle();
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());
164 core_.Connect(scoped_ptr<CloudPolicyClient>(client_));
166 // |expected_namespaces_in_client| is the expected number of components
167 // that the ComponentCloudPolicyService will set at the |client_| at
169 EXPECT_EQ(expected_namespaces_in_client,
170 client_->namespaces_to_fetch_.size());
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();
178 Mock::VerifyAndClearExpectations(client_);
182 EXPECT_FALSE(store_.is_initialized());
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);
189 store_.NotifyStoreLoaded();
191 EXPECT_TRUE(store_.is_initialized());
194 void InitializeRegistry() {
195 registry_.RegisterComponent(
196 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension),
198 registry_.SetReady(POLICY_DOMAIN_CHROME);
199 registry_.SetReady(POLICY_DOMAIN_EXTENSIONS);
202 void PopulateCache() {
203 EXPECT_TRUE(cache_->Store(
204 "extension-policy", kTestExtension, CreateSerializedResponse()));
206 cache_->Store("extension-policy-data", kTestExtension, kTestPolicy));
208 builder_.policy_data().set_settings_entity_id(kTestExtension2);
209 EXPECT_TRUE(cache_->Store(
210 "extension-policy", kTestExtension2, CreateSerializedResponse()));
212 cache_->Store("extension-policy-data", kTestExtension2, kTestPolicy));
215 scoped_ptr<em::PolicyFetchResponse> CreateResponse() {
217 return make_scoped_ptr(new em::PolicyFetchResponse(builder_.policy()));
220 std::string CreateSerializedResponse() {
222 return builder_.GetBlob();
225 Schema CreateTestSchema() {
227 Schema schema = Schema::Parse(kTestSchema, &error);
228 EXPECT_TRUE(schema.valid()) << error;
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_|
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_;
249 TEST_F(ComponentCloudPolicyServiceTest, InitializedAtConstructionTime) {
253 InitializeRegistry();
255 cache_ = new ResourceCache(temp_dir_.path(), loop_.message_loop_proxy());
256 service_.reset(new ComponentCloudPolicyService(&delegate_,
259 make_scoped_ptr(cache_),
261 loop_.message_loop_proxy(),
262 loop_.message_loop_proxy()));
263 EXPECT_FALSE(service_->is_initialized());
265 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
266 EXPECT_CALL(*client_, FetchPolicy()).Times(0);
268 Mock::VerifyAndClearExpectations(&client_);
269 Mock::VerifyAndClearExpectations(&delegate_);
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));
277 TEST_F(ComponentCloudPolicyServiceTest, InitializeStoreThenRegistry) {
280 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()).Times(0);
281 EXPECT_CALL(*client_, FetchPolicy()).Times(0);
283 Mock::VerifyAndClearExpectations(client_);
284 Mock::VerifyAndClearExpectations(&delegate_);
285 EXPECT_FALSE(service_->is_initialized());
287 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
288 EXPECT_CALL(*client_, FetchPolicy()).Times(0);
289 InitializeRegistry();
291 Mock::VerifyAndClearExpectations(client_);
292 Mock::VerifyAndClearExpectations(&delegate_);
293 EXPECT_TRUE(service_->is_initialized());
295 const PolicyBundle empty_bundle;
296 EXPECT_TRUE(service_->policy().Equals(empty_bundle));
299 TEST_F(ComponentCloudPolicyServiceTest, InitializeRegistryThenStore) {
302 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()).Times(0);
303 EXPECT_CALL(*client_, FetchPolicy()).Times(0);
304 InitializeRegistry();
306 Mock::VerifyAndClearExpectations(client_);
307 Mock::VerifyAndClearExpectations(&delegate_);
308 EXPECT_FALSE(service_->is_initialized());
310 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
311 EXPECT_CALL(*client_, FetchPolicy()).Times(0);
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));
321 TEST_F(ComponentCloudPolicyServiceTest, InitializeWithCachedPolicy) {
325 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
326 EXPECT_CALL(*client_, FetchPolicy()).Times(0);
327 InitializeRegistry();
329 Mock::VerifyAndClearExpectations(client_);
330 Mock::VerifyAndClearExpectations(&delegate_);
332 EXPECT_TRUE(service_->is_initialized());
333 EXPECT_EQ(2u, client_->namespaces_to_fetch_.size());
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);
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));
347 TEST_F(ComponentCloudPolicyServiceTest, FetchPolicy) {
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);
356 Mock::VerifyAndClearExpectations(client_);
357 Mock::VerifyAndClearExpectations(&delegate_);
358 EXPECT_TRUE(service_->is_initialized());
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),
368 Mock::VerifyAndClearExpectations(client_);
369 Mock::VerifyAndClearExpectations(&delegate_);
371 // Send back a fake policy fetch response.
372 client_->SetPolicy(PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType,
375 service_->OnPolicyFetched(client_);
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);
386 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
388 Mock::VerifyAndClearExpectations(&delegate_);
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));
397 TEST_F(ComponentCloudPolicyServiceTest, LoadAndPurgeCache) {
399 // Insert data in the cache.
401 registry_.RegisterComponent(
402 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension2),
404 InitializeRegistry();
406 // Load the initial cache.
407 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
408 EXPECT_CALL(*client_, FetchPolicy()).Times(0);
410 Mock::VerifyAndClearExpectations(client_);
411 Mock::VerifyAndClearExpectations(&delegate_);
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));
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));
427 Mock::VerifyAndClearExpectations(&delegate_);
429 ns.component_id = kTestExtension;
430 expected_bundle.Get(ns).Clear();
431 EXPECT_TRUE(service_->policy().Equals(expected_bundle));
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));
439 TEST_F(ComponentCloudPolicyServiceTest, SignInAfterStartup) {
440 registry_.SetReady(POLICY_DOMAIN_CHROME);
441 registry_.SetReady(POLICY_DOMAIN_EXTENSIONS);
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();
449 Mock::VerifyAndClearExpectations(&delegate_);
450 EXPECT_TRUE(service_->is_initialized());
452 // Register an extension.
453 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
454 registry_.RegisterComponent(
455 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension),
458 Mock::VerifyAndClearExpectations(&delegate_);
460 // Now signin. A fetch will be requested for the new extension.
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,
468 service_->OnPolicyFetched(client_);
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);
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();
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);
493 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
495 Mock::VerifyAndClearExpectations(&delegate_);
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));
504 TEST_F(ComponentCloudPolicyServiceTest, SignOut) {
505 // Initialize everything and serve policy for a component.
508 InitializeRegistry();
510 // The initial, cached policy will be served once the backend is initialized.
511 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
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());
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());
529 store_.policy_.reset();
530 store_.NotifyStoreLoaded();
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());
539 TEST_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));
550 InitializeRegistry();
552 // The initial, cached policy will be served once the backend is initialized.
553 EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated());
555 Mock::VerifyAndClearExpectations(&delegate_);
557 PolicyBundle expected_bundle;
558 const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension);
559 expected_bundle.Get(ns).Set("Name",
560 POLICY_LEVEL_MANDATORY,
562 new base::StringValue("published"),
564 EXPECT_TRUE(service_->policy().Equals(expected_bundle));
567 } // namespace policy