• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_store.h"
6 
7 #include <map>
8 #include <string>
9 
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/sha1.h"
16 #include "base/test/test_simple_task_runner.h"
17 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
18 #include "components/policy/core/common/cloud/policy_builder.h"
19 #include "components/policy/core/common/cloud/resource_cache.h"
20 #include "components/policy/core/common/external_data_fetcher.h"
21 #include "policy/proto/chrome_extension_policy.pb.h"
22 #include "policy/proto/device_management_backend.pb.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace em = enterprise_management;
27 
28 using testing::Mock;
29 
30 namespace policy {
31 
32 namespace {
33 
34 const char kTestExtension[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
35 const char kTestDownload[] = "http://example.com/getpolicy?id=123";
36 const char kTestPolicy[] =
37     "{"
38     "  \"Name\": {"
39     "    \"Value\": \"disabled\""
40     "  },"
41     "  \"Second\": {"
42     "    \"Value\": \"maybe\","
43     "    \"Level\": \"Recommended\""
44     "  }"
45     "}";
46 
TestPolicyHash()47 std::string TestPolicyHash() {
48   return base::SHA1HashString(kTestPolicy);
49 }
50 
NotEqual(const std::string & expected,const std::string & key)51 bool NotEqual(const std::string& expected, const std::string& key) {
52   return key != expected;
53 }
54 
True(const std::string & ignored)55 bool True(const std::string& ignored) {
56   return true;
57 }
58 
59 class MockComponentCloudPolicyStoreDelegate
60     : public ComponentCloudPolicyStore::Delegate {
61  public:
~MockComponentCloudPolicyStoreDelegate()62   virtual ~MockComponentCloudPolicyStoreDelegate() {}
63 
64   MOCK_METHOD0(OnComponentCloudPolicyStoreUpdated, void());
65 };
66 
67 }  // namespace
68 
69 class ComponentCloudPolicyStoreTest : public testing::Test {
70  protected:
SetUp()71   virtual void SetUp() OVERRIDE {
72     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
73     cache_.reset(new ResourceCache(
74         temp_dir_.path(),
75         make_scoped_refptr(new base::TestSimpleTaskRunner)));
76     store_.reset(new ComponentCloudPolicyStore(&store_delegate_, cache_.get()));
77     store_->SetCredentials(ComponentPolicyBuilder::kFakeUsername,
78                            ComponentPolicyBuilder::kFakeToken);
79 
80     builder_.policy_data().set_policy_type(
81         dm_protocol::kChromeExtensionPolicyType);
82     builder_.policy_data().set_settings_entity_id(kTestExtension);
83     builder_.payload().set_download_url(kTestDownload);
84     builder_.payload().set_secure_hash(TestPolicyHash());
85 
86     PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension);
87     PolicyMap& policy = expected_bundle_.Get(ns);
88     policy.Set("Name", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
89                base::Value::CreateStringValue("disabled"), NULL);
90     policy.Set("Second", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
91                base::Value::CreateStringValue("maybe"), NULL);
92   }
93 
94   // Returns true if the policy exposed by the |store_| is empty.
IsEmpty()95   bool IsEmpty() {
96     return store_->policy().begin() == store_->policy().end();
97   }
98 
CreateResponse()99   scoped_ptr<em::PolicyFetchResponse> CreateResponse() {
100     builder_.Build();
101     return make_scoped_ptr(new em::PolicyFetchResponse(builder_.policy()));
102   }
103 
CreateSerializedResponse()104   std::string CreateSerializedResponse() {
105     builder_.Build();
106     return builder_.GetBlob();
107   }
108 
109   base::ScopedTempDir temp_dir_;
110   scoped_ptr<ResourceCache> cache_;
111   scoped_ptr<ComponentCloudPolicyStore> store_;
112   MockComponentCloudPolicyStoreDelegate store_delegate_;
113   ComponentPolicyBuilder builder_;
114   PolicyBundle expected_bundle_;
115 };
116 
TEST_F(ComponentCloudPolicyStoreTest,ValidatePolicy)117 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicy) {
118   em::ExternalPolicyData payload;
119   PolicyNamespace ns;
120   EXPECT_TRUE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
121   EXPECT_EQ(POLICY_DOMAIN_EXTENSIONS, ns.domain);
122   EXPECT_EQ(kTestExtension, ns.component_id);
123   EXPECT_EQ(kTestDownload, payload.download_url());
124   EXPECT_EQ(TestPolicyHash(), payload.secure_hash());
125 }
126 
TEST_F(ComponentCloudPolicyStoreTest,ValidatePolicyWrongUsername)127 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongUsername) {
128   builder_.policy_data().set_username("anotheruser@example.com");
129   em::ExternalPolicyData payload;
130   PolicyNamespace ns;
131   EXPECT_FALSE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
132 }
133 
TEST_F(ComponentCloudPolicyStoreTest,ValidatePolicyWrongDMToken)134 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyWrongDMToken) {
135   builder_.policy_data().set_request_token("notmytoken");
136   em::ExternalPolicyData payload;
137   PolicyNamespace ns;
138   EXPECT_FALSE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
139 }
140 
TEST_F(ComponentCloudPolicyStoreTest,ValidatePolicyBadType)141 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyBadType) {
142   builder_.policy_data().set_policy_type(dm_protocol::kChromeUserPolicyType);
143   em::ExternalPolicyData payload;
144   PolicyNamespace ns;
145   EXPECT_FALSE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
146 }
147 
TEST_F(ComponentCloudPolicyStoreTest,ValidatePolicyBadDownloadUrl)148 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyBadDownloadUrl) {
149   builder_.payload().set_download_url("invalidurl");
150   em::ExternalPolicyData payload;
151   PolicyNamespace ns;
152   EXPECT_FALSE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
153 }
154 
TEST_F(ComponentCloudPolicyStoreTest,ValidatePolicyEmptyDownloadUrl)155 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyEmptyDownloadUrl) {
156   builder_.payload().clear_download_url();
157   builder_.payload().clear_secure_hash();
158   em::ExternalPolicyData payload;
159   PolicyNamespace ns;
160   // This is valid; it's how "no policy" is signalled to the client.
161   EXPECT_TRUE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
162 }
163 
TEST_F(ComponentCloudPolicyStoreTest,ValidatePolicyBadPayload)164 TEST_F(ComponentCloudPolicyStoreTest, ValidatePolicyBadPayload) {
165   builder_.clear_payload();
166   builder_.policy_data().set_policy_value("broken");
167   em::ExternalPolicyData payload;
168   PolicyNamespace ns;
169   EXPECT_FALSE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
170 }
171 
TEST_F(ComponentCloudPolicyStoreTest,ValidateNoCredentials)172 TEST_F(ComponentCloudPolicyStoreTest, ValidateNoCredentials) {
173   store_.reset(new ComponentCloudPolicyStore(&store_delegate_, cache_.get()));
174   em::ExternalPolicyData payload;
175   PolicyNamespace ns;
176   EXPECT_FALSE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
177 }
178 
TEST_F(ComponentCloudPolicyStoreTest,ValidateWrongCredentials)179 TEST_F(ComponentCloudPolicyStoreTest, ValidateWrongCredentials) {
180   em::ExternalPolicyData payload;
181   PolicyNamespace ns;
182   // Verify that the default response validates with the right credentials.
183   EXPECT_TRUE(store_->ValidatePolicy(CreateResponse(), &ns, &payload));
184   // Now store that response.
185   EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
186   EXPECT_TRUE(store_->Store(
187       ns, CreateSerializedResponse(), TestPolicyHash(), kTestPolicy));
188   Mock::VerifyAndClearExpectations(&store_delegate_);
189   EXPECT_TRUE(store_->policy().Equals(expected_bundle_));
190   // And verify that the response data in the cache.
191   std::map<std::string, std::string> contents;
192   cache_->LoadAllSubkeys("extension-policy", &contents);
193   EXPECT_FALSE(contents.empty());
194 
195   // Try loading the cached response data with wrong credentials.
196   ComponentCloudPolicyStore another_store(&store_delegate_, cache_.get());
197   another_store.SetCredentials("wrongdude@example.com", "wrongtoken");
198   another_store.Load();
199   const PolicyBundle empty_bundle;
200   EXPECT_TRUE(another_store.policy().Equals(empty_bundle));
201 
202   // The failure to read wiped the cache.
203   cache_->LoadAllSubkeys("extension-policy", &contents);
204   EXPECT_TRUE(contents.empty());
205 }
206 
TEST_F(ComponentCloudPolicyStoreTest,StoreAndLoad)207 TEST_F(ComponentCloudPolicyStoreTest, StoreAndLoad) {
208   // Initially empty.
209   EXPECT_TRUE(IsEmpty());
210   store_->Load();
211   EXPECT_TRUE(IsEmpty());
212 
213   // Store policy for an unsupported domain.
214   PolicyNamespace ns(POLICY_DOMAIN_CHROME, kTestExtension);
215   builder_.policy_data().set_policy_type(dm_protocol::kChromeUserPolicyType);
216   EXPECT_FALSE(store_->Store(
217       ns, CreateSerializedResponse(), TestPolicyHash(), kTestPolicy));
218 
219   // Store policy with the wrong hash.
220   builder_.policy_data().set_policy_type(
221       dm_protocol::kChromeExtensionPolicyType);
222   ns.domain = POLICY_DOMAIN_EXTENSIONS;
223   builder_.payload().set_secure_hash("badash");
224   EXPECT_FALSE(store_->Store(
225       ns, CreateSerializedResponse(), "badash", kTestPolicy));
226 
227   // Store policy without a hash.
228   builder_.payload().clear_secure_hash();
229   EXPECT_FALSE(store_->Store(
230       ns, CreateSerializedResponse(), std::string(), kTestPolicy));
231 
232   // Store policy with invalid JSON data.
233   static const char kInvalidData[] = "{ not json }";
234   const std::string invalid_data_hash = base::SHA1HashString(kInvalidData);
235   builder_.payload().set_secure_hash(invalid_data_hash);
236   EXPECT_FALSE(store_->Store(
237       ns, CreateSerializedResponse(), invalid_data_hash, kInvalidData));
238 
239   // All of those failed.
240   EXPECT_TRUE(IsEmpty());
241   EXPECT_EQ(std::string(), store_->GetCachedHash(ns));
242 
243   // Now store a valid policy.
244   builder_.payload().set_secure_hash(TestPolicyHash());
245   EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
246   EXPECT_TRUE(store_->Store(
247       ns, CreateSerializedResponse(), TestPolicyHash(), kTestPolicy));
248   Mock::VerifyAndClearExpectations(&store_delegate_);
249   EXPECT_FALSE(IsEmpty());
250   EXPECT_TRUE(store_->policy().Equals(expected_bundle_));
251   EXPECT_EQ(TestPolicyHash(), store_->GetCachedHash(ns));
252 
253   // Loading from the cache validates the policy data again.
254   ComponentCloudPolicyStore another_store(&store_delegate_, cache_.get());
255   another_store.SetCredentials(ComponentPolicyBuilder::kFakeUsername,
256                                ComponentPolicyBuilder::kFakeToken);
257   another_store.Load();
258   EXPECT_TRUE(another_store.policy().Equals(expected_bundle_));
259   EXPECT_EQ(TestPolicyHash(), another_store.GetCachedHash(ns));
260 }
261 
TEST_F(ComponentCloudPolicyStoreTest,Updates)262 TEST_F(ComponentCloudPolicyStoreTest, Updates) {
263   // Store some policies.
264   PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension);
265   EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
266   EXPECT_TRUE(store_->Store(
267       ns, CreateSerializedResponse(), TestPolicyHash(), kTestPolicy));
268   Mock::VerifyAndClearExpectations(&store_delegate_);
269   EXPECT_FALSE(IsEmpty());
270   EXPECT_TRUE(store_->policy().Equals(expected_bundle_));
271 
272   // Deleting a non-existant namespace doesn't trigger updates.
273   PolicyNamespace ns_fake(POLICY_DOMAIN_EXTENSIONS, "nosuchid");
274   store_->Delete(ns_fake);
275   Mock::VerifyAndClearExpectations(&store_delegate_);
276 
277   // Deleting a namespace that has policies triggers an update.
278   EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
279   store_->Delete(ns);
280   Mock::VerifyAndClearExpectations(&store_delegate_);
281 }
282 
TEST_F(ComponentCloudPolicyStoreTest,Purge)283 TEST_F(ComponentCloudPolicyStoreTest, Purge) {
284   // Store a valid policy.
285   EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
286   PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension);
287   EXPECT_TRUE(store_->Store(
288       ns, CreateSerializedResponse(), TestPolicyHash(), kTestPolicy));
289   Mock::VerifyAndClearExpectations(&store_delegate_);
290   EXPECT_FALSE(IsEmpty());
291   EXPECT_TRUE(store_->policy().Equals(expected_bundle_));
292 
293   // Purge other components.
294   store_->Purge(POLICY_DOMAIN_EXTENSIONS,
295                 base::Bind(&NotEqual, kTestExtension));
296 
297   // The policy for |ns| is still served.
298   EXPECT_TRUE(store_->policy().Equals(expected_bundle_));
299 
300   // Loading the store again will still see |ns|.
301   ComponentCloudPolicyStore another_store(&store_delegate_, cache_.get());
302   const PolicyBundle empty_bundle;
303   EXPECT_TRUE(another_store.policy().Equals(empty_bundle));
304   another_store.SetCredentials(ComponentPolicyBuilder::kFakeUsername,
305                                ComponentPolicyBuilder::kFakeToken);
306   another_store.Load();
307   EXPECT_TRUE(another_store.policy().Equals(expected_bundle_));
308 
309   // Now purge everything.
310   EXPECT_CALL(store_delegate_, OnComponentCloudPolicyStoreUpdated());
311   store_->Purge(POLICY_DOMAIN_EXTENSIONS, base::Bind(&True));
312   Mock::VerifyAndClearExpectations(&store_delegate_);
313 
314   // No policies are served anymore.
315   EXPECT_TRUE(store_->policy().Equals(empty_bundle));
316 
317   // And they aren't loaded anymore either.
318   ComponentCloudPolicyStore yet_another_store(&store_delegate_, cache_.get());
319   yet_another_store.SetCredentials(ComponentPolicyBuilder::kFakeUsername,
320                                    ComponentPolicyBuilder::kFakeToken);
321   yet_another_store.Load();
322   EXPECT_TRUE(yet_another_store.policy().Equals(empty_bundle));
323 }
324 
325 }  // namespace policy
326