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_updater.h"
6
7#include "base/callback.h"
8#include "base/compiler_specific.h"
9#include "base/files/scoped_temp_dir.h"
10#include "base/sequenced_task_runner.h"
11#include "base/sha1.h"
12#include "base/test/test_simple_task_runner.h"
13#include "base/values.h"
14#include "components/policy/core/common/cloud/cloud_policy_constants.h"
15#include "components/policy/core/common/cloud/component_cloud_policy_store.h"
16#include "components/policy/core/common/cloud/external_policy_data_fetcher.h"
17#include "components/policy/core/common/cloud/policy_builder.h"
18#include "components/policy/core/common/cloud/resource_cache.h"
19#include "components/policy/core/common/external_data_fetcher.h"
20#include "components/policy/core/common/policy_bundle.h"
21#include "components/policy/core/common/policy_map.h"
22#include "components/policy/core/common/policy_types.h"
23#include "net/url_request/test_url_fetcher_factory.h"
24#include "net/url_request/url_fetcher_delegate.h"
25#include "net/url_request/url_request_context_getter.h"
26#include "policy/proto/chrome_extension_policy.pb.h"
27#include "policy/proto/device_management_backend.pb.h"
28#include "testing/gmock/include/gmock/gmock.h"
29#include "testing/gtest/include/gtest/gtest.h"
30#include "url/gurl.h"
31
32namespace em = enterprise_management;
33
34using testing::Mock;
35
36namespace policy {
37
38namespace {
39
40const char kTestExtension[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
41const char kTestExtension2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
42const char kTestExtension3[] = "cccccccccccccccccccccccccccccccc";
43const char kTestDownload[] = "http://example.com/getpolicy?id=123";
44const char kTestDownload2[] = "http://example.com/getpolicy?id=456";
45const char kTestDownload3[] = "http://example.com/getpolicy?id=789";
46const char kTestPolicy[] =
47    "{"
48    "  \"Name\": {"
49    "    \"Value\": \"disabled\""
50    "  },"
51    "  \"Second\": {"
52    "    \"Value\": \"maybe\","
53    "    \"Level\": \"Recommended\""
54    "  }"
55    "}";
56
57class MockComponentCloudPolicyStoreDelegate
58    : public ComponentCloudPolicyStore::Delegate {
59 public:
60  virtual ~MockComponentCloudPolicyStoreDelegate() {}
61
62  MOCK_METHOD0(OnComponentCloudPolicyStoreUpdated, void());
63};
64
65}  // namespace
66
67class ComponentCloudPolicyUpdaterTest : public testing::Test {
68 protected:
69  virtual void SetUp() OVERRIDE;
70  virtual void TearDown() OVERRIDE;
71
72  scoped_ptr<em::PolicyFetchResponse> CreateResponse();
73
74  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
75  base::ScopedTempDir temp_dir_;
76  scoped_ptr<ResourceCache> cache_;
77  scoped_ptr<ComponentCloudPolicyStore> store_;
78  MockComponentCloudPolicyStoreDelegate store_delegate_;
79  net::TestURLFetcherFactory fetcher_factory_;
80  scoped_ptr<ExternalPolicyDataFetcherBackend> fetcher_backend_;
81  scoped_ptr<ComponentCloudPolicyUpdater> updater_;
82  ComponentPolicyBuilder builder_;
83  PolicyBundle expected_bundle_;
84};
85
86void ComponentCloudPolicyUpdaterTest::SetUp() {
87  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
88  task_runner_ = new base::TestSimpleTaskRunner();
89  cache_.reset(new ResourceCache(temp_dir_.path(), task_runner_));
90  store_.reset(new ComponentCloudPolicyStore(&store_delegate_, cache_.get()));
91  store_->SetCredentials(ComponentPolicyBuilder::kFakeUsername,
92                         ComponentPolicyBuilder::kFakeToken);
93  fetcher_factory_.set_remove_fetcher_on_delete(true);
94  fetcher_backend_.reset(new ExternalPolicyDataFetcherBackend(
95      task_runner_,
96      scoped_refptr<net::URLRequestContextGetter>()));
97  updater_.reset(new ComponentCloudPolicyUpdater(
98      task_runner_,
99      fetcher_backend_->CreateFrontend(task_runner_),
100      store_.get()));
101  ASSERT_EQ(store_->policy().end(), store_->policy().begin());
102
103  builder_.policy_data().set_policy_type(
104      dm_protocol::kChromeExtensionPolicyType);
105  builder_.policy_data().set_settings_entity_id(kTestExtension);
106  builder_.payload().set_download_url(kTestDownload);
107  builder_.payload().set_secure_hash(base::SHA1HashString(kTestPolicy));
108
109  PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension);
110  PolicyMap& policy = expected_bundle_.Get(ns);
111  policy.Set("Name", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
112             base::Value::CreateStringValue("disabled"), NULL);
113  policy.Set("Second", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
114             base::Value::CreateStringValue("maybe"), NULL);
115}
116
117void ComponentCloudPolicyUpdaterTest::TearDown() {
118  updater_.reset();
119  task_runner_->RunUntilIdle();
120}
121
122scoped_ptr<em::PolicyFetchResponse>
123    ComponentCloudPolicyUpdaterTest::CreateResponse() {
124  builder_.Build();
125  return make_scoped_ptr(new em::PolicyFetchResponse(builder_.policy()));
126}
127
128TEST_F(ComponentCloudPolicyUpdaterTest, FetchAndCache) {
129  // Submit a policy fetch response.
130  updater_->UpdateExternalPolicy(CreateResponse());
131  task_runner_->RunUntilIdle();
132
133  // Verify that a download has been started.
134  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
135  ASSERT_TRUE(fetcher);
136  EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL());
137
138  // Complete the download.
139  fetcher->set_response_code(200);
140  fetcher->SetResponseString(kTestPolicy);
141  fetcher->delegate()->OnURLFetchComplete(fetcher);
142  EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
143  task_runner_->RunUntilIdle();
144  Mock::VerifyAndClearExpectations(&store_delegate_);
145
146  // Verify that the downloaded policy is being served.
147  EXPECT_TRUE(store_->policy().Equals(expected_bundle_));
148}
149
150TEST_F(ComponentCloudPolicyUpdaterTest, PolicyFetchResponseTooLarge) {
151  // Submit a policy fetch response that exceeds the allowed maximum size.
152  std::string long_download("http://example.com/get?id=");
153  long_download.append(20 * 1024, '1');
154  builder_.payload().set_download_url(long_download);
155  updater_->UpdateExternalPolicy(CreateResponse());
156
157  // Submit two valid policy fetch responses.
158  builder_.policy_data().set_settings_entity_id(kTestExtension2);
159  builder_.payload().set_download_url(kTestDownload2);
160  updater_->UpdateExternalPolicy(CreateResponse());
161  builder_.policy_data().set_settings_entity_id(kTestExtension3);
162  builder_.payload().set_download_url(kTestDownload3);
163  updater_->UpdateExternalPolicy(CreateResponse());
164  task_runner_->RunUntilIdle();
165
166  // Verify that the first policy fetch response has been ignored and downloads
167  // have been started for the next two fetch responses instead.
168  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
169  ASSERT_TRUE(fetcher);
170  EXPECT_EQ(GURL(kTestDownload2), fetcher->GetOriginalURL());
171  fetcher = fetcher_factory_.GetFetcherByID(1);
172  ASSERT_TRUE(fetcher);
173  EXPECT_EQ(GURL(kTestDownload3), fetcher->GetOriginalURL());
174}
175
176TEST_F(ComponentCloudPolicyUpdaterTest, PolicyFetchResponseInvalid) {
177  // Submit an invalid policy fetch response.
178  builder_.policy_data().set_username("wronguser@example.com");
179  updater_->UpdateExternalPolicy(CreateResponse());
180
181  // Submit two valid policy fetch responses.
182  builder_.policy_data().set_username(ComponentPolicyBuilder::kFakeUsername);
183  builder_.policy_data().set_settings_entity_id(kTestExtension2);
184  builder_.payload().set_download_url(kTestDownload2);
185  updater_->UpdateExternalPolicy(CreateResponse());
186  builder_.policy_data().set_settings_entity_id(kTestExtension3);
187  builder_.payload().set_download_url(kTestDownload3);
188  updater_->UpdateExternalPolicy(CreateResponse());
189  task_runner_->RunUntilIdle();
190
191  // Verify that the first policy fetch response has been ignored and downloads
192  // have been started for the next two fetch responses instead.
193  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
194  ASSERT_TRUE(fetcher);
195  EXPECT_EQ(GURL(kTestDownload2), fetcher->GetOriginalURL());
196  fetcher = fetcher_factory_.GetFetcherByID(1);
197  ASSERT_TRUE(fetcher);
198  EXPECT_EQ(GURL(kTestDownload3), fetcher->GetOriginalURL());
199}
200
201TEST_F(ComponentCloudPolicyUpdaterTest, AlreadyCached) {
202  // Cache policy for an extension.
203  builder_.Build();
204  PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension);
205  EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
206  EXPECT_TRUE(store_->Store(ns,
207                            builder_.GetBlob(),
208                            base::SHA1HashString(kTestPolicy),
209                            kTestPolicy));
210  Mock::VerifyAndClearExpectations(&store_delegate_);
211
212  // Submit a policy fetch response whose extension ID and hash match the
213  // already cached policy.
214  updater_->UpdateExternalPolicy(CreateResponse());
215  task_runner_->RunUntilIdle();
216
217  // Verify that no download has been started.
218  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));
219}
220
221TEST_F(ComponentCloudPolicyUpdaterTest, PolicyDataInvalid) {
222  // Submit three policy fetch responses.
223  updater_->UpdateExternalPolicy(CreateResponse());
224  builder_.payload().set_download_url(kTestDownload2);
225  builder_.policy_data().set_settings_entity_id(kTestExtension2);
226  updater_->UpdateExternalPolicy(CreateResponse());
227  builder_.policy_data().set_settings_entity_id(kTestExtension3);
228  builder_.payload().set_download_url(kTestDownload3);
229  updater_->UpdateExternalPolicy(CreateResponse());
230  task_runner_->RunUntilIdle();
231
232  // Verify that the first download has been started.
233  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
234  ASSERT_TRUE(fetcher);
235  EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL());
236
237  // Verify that the second download has been started.
238  fetcher = fetcher_factory_.GetFetcherByID(1);
239  ASSERT_TRUE(fetcher);
240  EXPECT_EQ(GURL(kTestDownload2), fetcher->GetOriginalURL());
241
242  // Indicate that the policy data size will exceed allowed maximum.
243  fetcher->delegate()->OnURLFetchDownloadProgress(fetcher, 6 * 1024 * 1024, -1);
244  task_runner_->RunUntilIdle();
245
246  // Verify that the third download has been started.
247  fetcher = fetcher_factory_.GetFetcherByID(2);
248  ASSERT_TRUE(fetcher);
249  EXPECT_EQ(GURL(kTestDownload3), fetcher->GetOriginalURL());
250}
251
252TEST_F(ComponentCloudPolicyUpdaterTest, FetchUpdatedData) {
253  // Submit a policy fetch response.
254  updater_->UpdateExternalPolicy(CreateResponse());
255  task_runner_->RunUntilIdle();
256
257  // Verify that the first download has been started.
258  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
259  ASSERT_TRUE(fetcher);
260  EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL());
261
262  // Submit a second policy fetch response for the same extension with an
263  // updated download URL.
264  builder_.payload().set_download_url(kTestDownload2);
265  updater_->UpdateExternalPolicy(CreateResponse());
266  task_runner_->RunUntilIdle();
267
268  // Verify that the first download is no longer running.
269  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));
270
271  // Verify that the second download has been started.
272  fetcher = fetcher_factory_.GetFetcherByID(1);
273  ASSERT_TRUE(fetcher);
274  EXPECT_EQ(GURL(kTestDownload2), fetcher->GetOriginalURL());
275}
276
277TEST_F(ComponentCloudPolicyUpdaterTest, FetchUpdatedDataWithoutPolicy) {
278  // Submit a policy fetch response.
279  updater_->UpdateExternalPolicy(CreateResponse());
280  task_runner_->RunUntilIdle();
281
282  // Verify that the download has been started.
283  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
284  ASSERT_TRUE(fetcher);
285  EXPECT_EQ(GURL(kTestDownload), fetcher->GetOriginalURL());
286
287  // Complete the download.
288  fetcher->set_response_code(200);
289  fetcher->SetResponseString(kTestPolicy);
290  fetcher->delegate()->OnURLFetchComplete(fetcher);
291  EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
292  task_runner_->RunUntilIdle();
293  Mock::VerifyAndClearExpectations(&store_delegate_);
294
295  // Verify that the downloaded policy is being served.
296  EXPECT_TRUE(store_->policy().Equals(expected_bundle_));
297
298  // Submit a second policy fetch response for the same extension with no
299  // download URL, meaning that no policy should be provided for this extension.
300  builder_.payload().clear_download_url();
301  builder_.payload().clear_secure_hash();
302  EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
303  updater_->UpdateExternalPolicy(CreateResponse());
304  Mock::VerifyAndClearExpectations(&store_delegate_);
305  task_runner_->RunUntilIdle();
306
307  // Verify that no download has been started.
308  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));
309
310  // Verify that the policy is no longer being served.
311  const PolicyBundle empty_bundle;
312  EXPECT_TRUE(store_->policy().Equals(empty_bundle));
313}
314
315TEST_F(ComponentCloudPolicyUpdaterTest, NoPolicy) {
316  // Submit a policy fetch response with a valid download URL.
317  updater_->UpdateExternalPolicy(CreateResponse());
318  task_runner_->RunUntilIdle();
319
320  // Verify that the download has been started.
321  EXPECT_TRUE(fetcher_factory_.GetFetcherByID(0));
322
323  // Update the policy fetch response before the download has finished. The new
324  // policy fetch response has no download URL.
325  builder_.payload().Clear();
326  updater_->UpdateExternalPolicy(CreateResponse());
327  task_runner_->RunUntilIdle();
328
329  // Verify that the download is no longer running.
330  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));
331}
332
333TEST_F(ComponentCloudPolicyUpdaterTest, CancelUpdate) {
334  // Submit a policy fetch response with a valid download URL.
335  updater_->UpdateExternalPolicy(CreateResponse());
336  task_runner_->RunUntilIdle();
337
338  // Verify that the download has been started.
339  EXPECT_TRUE(fetcher_factory_.GetFetcherByID(0));
340
341  // Now cancel that update before the download completes.
342  EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated()).Times(0);
343  updater_->CancelUpdate(
344      PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension));
345  task_runner_->RunUntilIdle();
346  Mock::VerifyAndClearExpectations(&store_delegate_);
347  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));
348}
349
350}  // namespace policy
351