Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Side by Side Diff: chrome/browser/policy/cloud/component_cloud_policy_store.cc

Issue 109743002: Move policy code into components/policy. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: moar fixes Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "chrome/browser/policy/cloud/component_cloud_policy_store.h"
6
7 #include "base/callback.h"
8 #include "base/json/json_reader.h"
9 #include "base/logging.h"
10 #include "base/sha1.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
14 #include "chrome/browser/policy/cloud/cloud_policy_validator.h"
15 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
16 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
17 #include "components/policy/core/common/external_data_fetcher.h"
18 #include "components/policy/core/common/policy_map.h"
19 #include "url/gurl.h"
20
21 namespace em = enterprise_management;
22
23 namespace policy {
24
25 namespace {
26
27 const char kValue[] = "Value";
28 const char kLevel[] = "Level";
29 const char kRecommended[] = "Recommended";
30
31 const struct DomainConstants {
32 PolicyDomain domain;
33 const char* proto_cache_key;
34 const char* data_cache_key;
35 const char* policy_type;
36 } kDomains[] = {
37 {
38 POLICY_DOMAIN_EXTENSIONS,
39 "extension-policy",
40 "extension-policy-data",
41 dm_protocol::kChromeExtensionPolicyType,
42 },
43 };
44
45 const DomainConstants* GetDomainConstants(PolicyDomain domain) {
46 for (size_t i = 0; i < arraysize(kDomains); ++i) {
47 if (kDomains[i].domain == domain)
48 return &kDomains[i];
49 }
50 return NULL;
51 }
52
53 const DomainConstants* GetDomainConstantsForType(const std::string& type) {
54 for (size_t i = 0; i < arraysize(kDomains); ++i) {
55 if (kDomains[i].policy_type == type)
56 return &kDomains[i];
57 }
58 return NULL;
59 }
60
61 } // namespace
62
63 ComponentCloudPolicyStore::Delegate::~Delegate() {}
64
65 ComponentCloudPolicyStore::ComponentCloudPolicyStore(
66 Delegate* delegate,
67 ResourceCache* cache)
68 : delegate_(delegate),
69 cache_(cache) {
70 // Allow the store to be created on a different thread than the thread that
71 // will end up using it.
72 DetachFromThread();
73 }
74
75 ComponentCloudPolicyStore::~ComponentCloudPolicyStore() {
76 DCHECK(CalledOnValidThread());
77 }
78
79 // static
80 bool ComponentCloudPolicyStore::SupportsDomain(PolicyDomain domain) {
81 return GetDomainConstants(domain) != NULL;
82 }
83
84 // static
85 bool ComponentCloudPolicyStore::GetPolicyType(PolicyDomain domain,
86 std::string* policy_type) {
87 const DomainConstants* constants = GetDomainConstants(domain);
88 if (constants)
89 *policy_type = constants->policy_type;
90 return constants != NULL;
91 }
92
93 // static
94 bool ComponentCloudPolicyStore::GetPolicyDomain(const std::string& policy_type,
95 PolicyDomain* domain) {
96 const DomainConstants* constants = GetDomainConstantsForType(policy_type);
97 if (constants)
98 *domain = constants->domain;
99 return constants != NULL;
100 }
101
102 const std::string& ComponentCloudPolicyStore::GetCachedHash(
103 const PolicyNamespace& ns) const {
104 DCHECK(CalledOnValidThread());
105 std::map<PolicyNamespace, std::string>::const_iterator it =
106 cached_hashes_.find(ns);
107 return it == cached_hashes_.end() ? base::EmptyString() : it->second;
108 }
109
110 void ComponentCloudPolicyStore::SetCredentials(const std::string& username,
111 const std::string& dm_token) {
112 DCHECK(CalledOnValidThread());
113 DCHECK(username_.empty() || username == username_);
114 DCHECK(dm_token_.empty() || dm_token == dm_token_);
115 username_ = username;
116 dm_token_ = dm_token;
117 }
118
119 void ComponentCloudPolicyStore::Load() {
120 DCHECK(CalledOnValidThread());
121 typedef std::map<std::string, std::string> ContentMap;
122
123 // Load all cached policy protobufs for each domain.
124 for (size_t domain = 0; domain < arraysize(kDomains); ++domain) {
125 const DomainConstants& constants = kDomains[domain];
126 ContentMap protos;
127 cache_->LoadAllSubkeys(constants.proto_cache_key, &protos);
128 for (ContentMap::iterator it = protos.begin(); it != protos.end(); ++it) {
129 const std::string& id(it->first);
130 PolicyNamespace ns(constants.domain, id);
131
132 // Validate each protobuf.
133 scoped_ptr<em::PolicyFetchResponse> proto(new em::PolicyFetchResponse);
134 em::ExternalPolicyData payload;
135 if (!proto->ParseFromString(it->second) ||
136 !ValidateProto(
137 proto.Pass(), constants.policy_type, id, &payload, NULL)) {
138 Delete(ns);
139 continue;
140 }
141
142 // The protobuf looks good; load the policy data.
143 std::string data;
144 PolicyMap policy;
145 if (cache_->Load(constants.data_cache_key, id, &data) &&
146 ValidateData(data, payload.secure_hash(), &policy)) {
147 // The data is also good; expose the policies.
148 policy_bundle_.Get(ns).Swap(&policy);
149 cached_hashes_[ns] = payload.secure_hash();
150 } else {
151 // The data for this proto couldn't be loaded or is corrupted.
152 Delete(ns);
153 }
154 }
155 }
156 }
157
158 bool ComponentCloudPolicyStore::Store(const PolicyNamespace& ns,
159 const std::string& serialized_policy,
160 const std::string& secure_hash,
161 const std::string& data) {
162 DCHECK(CalledOnValidThread());
163 const DomainConstants* constants = GetDomainConstants(ns.domain);
164 PolicyMap policy;
165 // |serialized_policy| has already been validated; validate the data now.
166 if (!constants || !ValidateData(data, secure_hash, &policy))
167 return false;
168
169 // Flush the proto and the data to the cache.
170 cache_->Store(constants->proto_cache_key, ns.component_id, serialized_policy);
171 cache_->Store(constants->data_cache_key, ns.component_id, data);
172 // And expose the policy.
173 policy_bundle_.Get(ns).Swap(&policy);
174 cached_hashes_[ns] = secure_hash;
175 delegate_->OnComponentCloudPolicyStoreUpdated();
176 return true;
177 }
178
179 void ComponentCloudPolicyStore::Delete(const PolicyNamespace& ns) {
180 DCHECK(CalledOnValidThread());
181 const DomainConstants* constants = GetDomainConstants(ns.domain);
182 if (!constants)
183 return;
184
185 cache_->Delete(constants->proto_cache_key, ns.component_id);
186 cache_->Delete(constants->data_cache_key, ns.component_id);
187
188 if (!policy_bundle_.Get(ns).empty()) {
189 policy_bundle_.Get(ns).Clear();
190 delegate_->OnComponentCloudPolicyStoreUpdated();
191 }
192 }
193
194 void ComponentCloudPolicyStore::Purge(
195 PolicyDomain domain,
196 const ResourceCache::SubkeyFilter& filter) {
197 DCHECK(CalledOnValidThread());
198 const DomainConstants* constants = GetDomainConstants(domain);
199 if (!constants)
200 return;
201
202 cache_->FilterSubkeys(constants->proto_cache_key, filter);
203 cache_->FilterSubkeys(constants->data_cache_key, filter);
204
205 // Stop serving policies for purged namespaces.
206 bool purged_current_policies = false;
207 for (PolicyBundle::const_iterator it = policy_bundle_.begin();
208 it != policy_bundle_.end(); ++it) {
209 if (it->first.domain == domain &&
210 filter.Run(it->first.component_id) &&
211 !policy_bundle_.Get(it->first).empty()) {
212 policy_bundle_.Get(it->first).Clear();
213 purged_current_policies = true;
214 }
215 }
216
217 // Purge cached hashes, so that those namespaces can be fetched again if the
218 // policy state changes.
219 std::map<PolicyNamespace, std::string>::iterator it = cached_hashes_.begin();
220 while (it != cached_hashes_.end()) {
221 if (it->first.domain == domain && filter.Run(it->first.component_id)) {
222 std::map<PolicyNamespace, std::string>::iterator prev = it;
223 ++it;
224 cached_hashes_.erase(prev);
225 } else {
226 ++it;
227 }
228 }
229
230 if (purged_current_policies)
231 delegate_->OnComponentCloudPolicyStoreUpdated();
232 }
233
234 void ComponentCloudPolicyStore::Clear() {
235 for (size_t i = 0; i < arraysize(kDomains); ++i) {
236 cache_->Clear(kDomains[i].proto_cache_key);
237 cache_->Clear(kDomains[i].data_cache_key);
238 }
239 cached_hashes_.clear();
240 const PolicyBundle empty_bundle;
241 if (!policy_bundle_.Equals(empty_bundle)) {
242 policy_bundle_.Clear();
243 delegate_->OnComponentCloudPolicyStoreUpdated();
244 }
245 }
246
247 bool ComponentCloudPolicyStore::ValidatePolicy(
248 scoped_ptr<em::PolicyFetchResponse> proto,
249 PolicyNamespace* ns,
250 em::ExternalPolicyData* payload) {
251 em::PolicyData policy_data;
252 if (!ValidateProto(
253 proto.Pass(), std::string(), std::string(), payload, &policy_data)) {
254 return false;
255 }
256
257 if (!policy_data.has_policy_type())
258 return false;
259
260 const DomainConstants* constants =
261 GetDomainConstantsForType(policy_data.policy_type());
262 if (!constants || !policy_data.has_settings_entity_id())
263 return false;
264
265 ns->domain = constants->domain;
266 ns->component_id = policy_data.settings_entity_id();
267 return true;
268 }
269
270 bool ComponentCloudPolicyStore::ValidateProto(
271 scoped_ptr<em::PolicyFetchResponse> proto,
272 const std::string& policy_type,
273 const std::string& settings_entity_id,
274 em::ExternalPolicyData* payload,
275 em::PolicyData* policy_data) {
276 if (username_.empty() || dm_token_.empty())
277 return false;
278
279 scoped_ptr<ComponentCloudPolicyValidator> validator(
280 ComponentCloudPolicyValidator::Create(
281 proto.Pass(), scoped_refptr<base::SequencedTaskRunner>()));
282 validator->ValidateUsername(username_);
283 validator->ValidateDMToken(dm_token_,
284 ComponentCloudPolicyValidator::DM_TOKEN_REQUIRED);
285 if (!policy_type.empty())
286 validator->ValidatePolicyType(policy_type);
287 if (!settings_entity_id.empty())
288 validator->ValidateSettingsEntityId(settings_entity_id);
289 validator->ValidatePayload();
290 // TODO(joaodasilva): validate signature.
291 validator->RunValidation();
292 if (!validator->success())
293 return false;
294
295 em::ExternalPolicyData* data = validator->payload().get();
296 // The download URL must be empty, or must be a valid URL.
297 // An empty download URL signals that this component doesn't have cloud
298 // policy, or that the policy has been removed.
299 if (data->has_download_url() && !data->download_url().empty()) {
300 if (!GURL(data->download_url()).is_valid() ||
301 !data->has_secure_hash() ||
302 data->secure_hash().empty()) {
303 return false;
304 }
305 } else if (data->has_secure_hash()) {
306 return false;
307 }
308
309 if (payload)
310 payload->Swap(validator->payload().get());
311 if (policy_data)
312 policy_data->Swap(validator->policy_data().get());
313 return true;
314 }
315
316 bool ComponentCloudPolicyStore::ValidateData(
317 const std::string& data,
318 const std::string& secure_hash,
319 PolicyMap* policy) {
320 return base::SHA1HashString(data) == secure_hash && ParsePolicy(data, policy);
321 }
322
323 bool ComponentCloudPolicyStore::ParsePolicy(const std::string& data,
324 PolicyMap* policy) {
325 scoped_ptr<base::Value> json(base::JSONReader::Read(
326 data, base::JSON_PARSE_RFC | base::JSON_DETACHABLE_CHILDREN));
327 base::DictionaryValue* dict = NULL;
328 if (!json || !json->GetAsDictionary(&dict))
329 return false;
330
331 // Each top-level key maps a policy name to its description.
332 //
333 // Each description is an object that contains the policy value under the
334 // "Value" key. The optional "Level" key is either "Mandatory" (default) or
335 // "Recommended".
336 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
337 base::DictionaryValue* description = NULL;
338 if (!dict->GetDictionaryWithoutPathExpansion(it.key(), &description))
339 return false;
340
341 scoped_ptr<base::Value> value;
342 if (!description->RemoveWithoutPathExpansion(kValue, &value))
343 return false;
344
345 PolicyLevel level = POLICY_LEVEL_MANDATORY;
346 std::string level_string;
347 if (description->GetStringWithoutPathExpansion(kLevel, &level_string) &&
348 level_string == kRecommended) {
349 level = POLICY_LEVEL_RECOMMENDED;
350 }
351
352 // If policy for components is ever used for device-level settings then
353 // this must support a configurable scope; assuming POLICY_SCOPE_USER is
354 // fine for now.
355 policy->Set(it.key(), level, POLICY_SCOPE_USER, value.release(), NULL);
356 }
357
358 return true;
359 }
360
361 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698