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        &registry_,
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                                                 &registry_,
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