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

Side by Side Diff: chrome/browser/policy/cloud/component_cloud_policy_service.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_service.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/sequenced_task_runner.h"
15 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
16 #include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
17 #include "chrome/browser/policy/cloud/component_cloud_policy_store.h"
18 #include "chrome/browser/policy/cloud/component_cloud_policy_updater.h"
19 #include "chrome/browser/policy/cloud/external_policy_data_fetcher.h"
20 #include "chrome/browser/policy/cloud/resource_cache.h"
21 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
22 #include "components/policy/core/common/schema.h"
23 #include "components/policy/core/common/schema_map.h"
24 #include "net/url_request/url_request_context_getter.h"
25
26 namespace em = enterprise_management;
27
28 namespace policy {
29
30 namespace {
31
32 bool NotInSchemaMap(const scoped_refptr<SchemaMap> schema_map,
33 PolicyDomain domain,
34 const std::string& component_id) {
35 return schema_map->GetSchema(PolicyNamespace(domain, component_id)) == NULL;
36 }
37
38 bool ToPolicyNamespaceKey(const PolicyNamespace& ns, PolicyNamespaceKey* key) {
39 if (!ComponentCloudPolicyStore::GetPolicyType(ns.domain, &key->first))
40 return false;
41 key->second = ns.component_id;
42 return true;
43 }
44
45 bool ToPolicyNamespace(const PolicyNamespaceKey& key, PolicyNamespace* ns) {
46 if (!ComponentCloudPolicyStore::GetPolicyDomain(key.first, &ns->domain))
47 return false;
48 ns->component_id = key.second;
49 return true;
50 }
51
52 } // namespace
53
54 ComponentCloudPolicyService::Delegate::~Delegate() {}
55
56 // Owns the objects that live on the background thread, and posts back to the
57 // thread that the ComponentCloudPolicyService runs on whenever the policy
58 // changes.
59 class ComponentCloudPolicyService::Backend
60 : public ComponentCloudPolicyStore::Delegate {
61 public:
62 // This class can be instantiated on any thread but from then on, may be
63 // accessed via the |task_runner_| only. Policy changes are posted to the
64 // |service| via the |service_task_runner|. The |cache| is used to load and
65 // store local copies of the downloaded policies.
66 Backend(base::WeakPtr<ComponentCloudPolicyService> service,
67 scoped_refptr<base::SequencedTaskRunner> task_runner,
68 scoped_refptr<base::SequencedTaskRunner> service_task_runner,
69 scoped_ptr<ResourceCache> cache,
70 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher);
71
72 virtual ~Backend();
73
74 // |username| and |dm_token| will be used to validate the cached policies.
75 void SetCredentials(const std::string& username, const std::string& dm_token);
76
77 // Loads the |store_| and starts downloading updates.
78 void Init(scoped_refptr<SchemaMap> schema_map);
79
80 // Passes a policy protobuf to the backend, to start its validation and
81 // eventual download of the policy data on the background thread.
82 void UpdateExternalPolicy(scoped_ptr<em::PolicyFetchResponse> response);
83
84 // ComponentCloudPolicyStore::Delegate implementation:
85 virtual void OnComponentCloudPolicyStoreUpdated() OVERRIDE;
86
87 // Passes the current SchemaMap so that the disk cache can purge components
88 // that aren't being tracked anymore.
89 // |removed| is a list of namespaces that were present in the previous
90 // schema and have been removed in the updated version.
91 void OnSchemasUpdated(scoped_refptr<SchemaMap> schema_map,
92 scoped_ptr<PolicyNamespaceList> removed);
93
94 private:
95 // The ComponentCloudPolicyService that owns |this|. Used to inform the
96 // |service_| when policy changes.
97 base::WeakPtr<ComponentCloudPolicyService> service_;
98
99 // The thread that |this| runs on. Used to post tasks to be run by |this|.
100 scoped_refptr<base::SequencedTaskRunner> task_runner_;
101
102 // The thread that the |service_| runs on. Used to post policy changes to the
103 // right thread.
104 scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
105
106 scoped_ptr<ResourceCache> cache_;
107 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher_;
108 ComponentCloudPolicyStore store_;
109 scoped_ptr<ComponentCloudPolicyUpdater> updater_;
110 scoped_refptr<SchemaMap> schema_map_;
111
112 DISALLOW_COPY_AND_ASSIGN(Backend);
113 };
114
115 ComponentCloudPolicyService::Backend::Backend(
116 base::WeakPtr<ComponentCloudPolicyService> service,
117 scoped_refptr<base::SequencedTaskRunner> task_runner,
118 scoped_refptr<base::SequencedTaskRunner> service_task_runner,
119 scoped_ptr<ResourceCache> cache,
120 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher)
121 : service_(service),
122 task_runner_(task_runner),
123 service_task_runner_(service_task_runner),
124 cache_(cache.Pass()),
125 external_policy_data_fetcher_(external_policy_data_fetcher.Pass()),
126 store_(this, cache_.get()) {}
127
128 ComponentCloudPolicyService::Backend::~Backend() {}
129
130 void ComponentCloudPolicyService::Backend::SetCredentials(
131 const std::string& username,
132 const std::string& dm_token) {
133 if (username.empty() || dm_token.empty()) {
134 // No sign-in credentials, so drop any cached policy.
135 store_.Clear();
136 } else {
137 store_.SetCredentials(username, dm_token);
138 }
139 }
140
141 void ComponentCloudPolicyService::Backend::Init(
142 scoped_refptr<SchemaMap> schema_map) {
143 DCHECK(!schema_map_);
144
145 OnSchemasUpdated(schema_map, scoped_ptr<PolicyNamespaceList>());
146
147 // Read the initial policy. Note that this does not trigger notifications
148 // through OnComponentCloudPolicyStoreUpdated. Note also that the cached
149 // data may contain names or values that don't match the schema for that
150 // component; the data must be cached without modifications so that its
151 // integrity can be verified using the hash, but it must also be filtered
152 // right after a Load().
153 store_.Load();
154 scoped_ptr<PolicyBundle> bundle(new PolicyBundle);
155 bundle->CopyFrom(store_.policy());
156 schema_map_->FilterBundle(bundle.get());
157
158 // Start downloading any pending data.
159 updater_.reset(new ComponentCloudPolicyUpdater(
160 task_runner_, external_policy_data_fetcher_.Pass(), &store_));
161
162 service_task_runner_->PostTask(
163 FROM_HERE,
164 base::Bind(&ComponentCloudPolicyService::OnBackendInitialized,
165 service_,
166 base::Passed(&bundle)));
167 }
168
169 void ComponentCloudPolicyService::Backend::UpdateExternalPolicy(
170 scoped_ptr<em::PolicyFetchResponse> response) {
171 updater_->UpdateExternalPolicy(response.Pass());
172 }
173
174 void ComponentCloudPolicyService::Backend::
175 OnComponentCloudPolicyStoreUpdated() {
176 if (!schema_map_) {
177 // Ignore notifications triggered by the initial Purge or Clear.
178 return;
179 }
180
181 scoped_ptr<PolicyBundle> bundle(new PolicyBundle);
182 bundle->CopyFrom(store_.policy());
183 schema_map_->FilterBundle(bundle.get());
184 service_task_runner_->PostTask(
185 FROM_HERE,
186 base::Bind(&ComponentCloudPolicyService::OnPolicyUpdated,
187 service_,
188 base::Passed(&bundle)));
189 }
190
191 void ComponentCloudPolicyService::Backend::OnSchemasUpdated(
192 scoped_refptr<SchemaMap> schema_map,
193 scoped_ptr<PolicyNamespaceList> removed) {
194 // Purge any components that have been removed.
195 const DomainMap& domains = schema_map->GetDomains();
196 for (DomainMap::const_iterator domain = domains.begin();
197 domain != domains.end(); ++domain) {
198 store_.Purge(domain->first,
199 base::Bind(&NotInSchemaMap, schema_map, domain->first));
200 }
201
202 // Set |schema_map_| after purging so that the notifications from the store
203 // are ignored on the first OnSchemasUpdated() call from Init().
204 schema_map_ = schema_map;
205
206 if (removed) {
207 for (size_t i = 0; i < removed->size(); ++i)
208 updater_->CancelUpdate((*removed)[i]);
209 }
210 }
211
212 ComponentCloudPolicyService::ComponentCloudPolicyService(
213 Delegate* delegate,
214 SchemaRegistry* schema_registry,
215 CloudPolicyCore* core,
216 scoped_ptr<ResourceCache> cache,
217 scoped_refptr<net::URLRequestContextGetter> request_context,
218 scoped_refptr<base::SequencedTaskRunner> backend_task_runner,
219 scoped_refptr<base::SequencedTaskRunner> io_task_runner)
220 : delegate_(delegate),
221 schema_registry_(schema_registry),
222 core_(core),
223 request_context_(request_context),
224 backend_task_runner_(backend_task_runner),
225 io_task_runner_(io_task_runner),
226 current_schema_map_(new SchemaMap),
227 started_loading_initial_policy_(false),
228 loaded_initial_policy_(false),
229 is_registered_for_cloud_policy_(false),
230 weak_ptr_factory_(this) {
231 external_policy_data_fetcher_backend_.reset(
232 new ExternalPolicyDataFetcherBackend(io_task_runner_, request_context));
233
234 backend_.reset(
235 new Backend(weak_ptr_factory_.GetWeakPtr(),
236 backend_task_runner_,
237 base::MessageLoopProxy::current(),
238 cache.Pass(),
239 external_policy_data_fetcher_backend_->CreateFrontend(
240 backend_task_runner_)));
241
242 schema_registry_->AddObserver(this);
243 core_->store()->AddObserver(this);
244
245 // Wait for the store and the schema registry to become ready before
246 // initializing the backend, so that it can get the initial list of
247 // components and the cached credentials (if any) to validate the cached
248 // policies.
249 if (core_->store()->is_initialized())
250 OnStoreLoaded(core_->store());
251 }
252
253 ComponentCloudPolicyService::~ComponentCloudPolicyService() {
254 DCHECK(CalledOnValidThread());
255
256 schema_registry_->RemoveObserver(this);
257 core_->store()->RemoveObserver(this);
258 core_->RemoveObserver(this);
259 if (core_->client())
260 OnCoreDisconnecting(core_);
261
262 io_task_runner_->DeleteSoon(FROM_HERE,
263 external_policy_data_fetcher_backend_.release());
264 backend_task_runner_->DeleteSoon(FROM_HERE, backend_.release());
265 }
266
267 // static
268 bool ComponentCloudPolicyService::SupportsDomain(PolicyDomain domain) {
269 return ComponentCloudPolicyStore::SupportsDomain(domain);
270 }
271
272 void ComponentCloudPolicyService::ClearCache() {
273 DCHECK(CalledOnValidThread());
274 // Empty credentials will wipe the cache.
275 backend_task_runner_->PostTask(FROM_HERE,
276 base::Bind(&Backend::SetCredentials,
277 base::Unretained(backend_.get()),
278 std::string(), std::string()));
279 }
280
281 void ComponentCloudPolicyService::OnSchemaRegistryReady() {
282 DCHECK(CalledOnValidThread());
283 InitializeIfReady();
284 }
285
286 void ComponentCloudPolicyService::OnSchemaRegistryUpdated(
287 bool has_new_schemas) {
288 DCHECK(CalledOnValidThread());
289
290 // Ignore schema updates until the backend is initialized.
291 // OnBackendInitialized() will send the current schema to the backend again,
292 // in case it was updated before the backend initialized.
293 if (!loaded_initial_policy_)
294 return;
295
296 SetCurrentSchema();
297 }
298
299 void ComponentCloudPolicyService::OnCoreConnected(CloudPolicyCore* core) {
300 DCHECK(CalledOnValidThread());
301 DCHECK_EQ(core_, core);
302
303 core_->client()->AddObserver(this);
304
305 // Immediately load any PolicyFetchResponses that the client may already
306 // have.
307 OnPolicyFetched(core_->client());
308
309 // Register the current namespaces at the client.
310 current_schema_map_ = new SchemaMap();
311 SetCurrentSchema();
312 }
313
314 void ComponentCloudPolicyService::OnCoreDisconnecting(CloudPolicyCore* core) {
315 DCHECK(CalledOnValidThread());
316 DCHECK_EQ(core_, core);
317
318 core_->client()->RemoveObserver(this);
319
320 // Remove all the namespaces from the client.
321 scoped_refptr<SchemaMap> empty = new SchemaMap();
322 PolicyNamespaceList removed;
323 PolicyNamespaceList added;
324 empty->GetChanges(current_schema_map_, &removed, &added);
325 for (size_t i = 0; i < removed.size(); ++i) {
326 PolicyNamespaceKey key;
327 if (ToPolicyNamespaceKey(removed[i], &key))
328 core_->client()->RemoveNamespaceToFetch(key);
329 }
330 }
331
332 void ComponentCloudPolicyService::OnRefreshSchedulerStarted(
333 CloudPolicyCore* core) {
334 // Ignored.
335 }
336
337 void ComponentCloudPolicyService::OnStoreLoaded(CloudPolicyStore* store) {
338 DCHECK(CalledOnValidThread());
339 DCHECK_EQ(core_->store(), store);
340
341 const bool was_registered_before = is_registered_for_cloud_policy_;
342
343 // Send the current credentials to the backend; do this whenever the store
344 // updates, to handle the case of the user registering for policy after the
345 // session starts, or the user signing out.
346 const em::PolicyData* policy = core_->store()->policy();
347 std::string username;
348 std::string request_token;
349 if (policy && policy->has_username() && policy->has_request_token()) {
350 is_registered_for_cloud_policy_ = true;
351 username = policy->username();
352 request_token = policy->request_token();
353 } else {
354 is_registered_for_cloud_policy_ = false;
355 }
356
357 // Empty credentials will wipe the cache.
358 backend_task_runner_->PostTask(FROM_HERE,
359 base::Bind(&Backend::SetCredentials,
360 base::Unretained(backend_.get()),
361 username,
362 request_token));
363
364 if (!loaded_initial_policy_) {
365 // This is the initial load; check if we're ready to initialize the
366 // backend, regardless of the signin state.
367 InitializeIfReady();
368 } else if (!was_registered_before && is_registered_for_cloud_policy_) {
369 // We are already initialized, but just sent credentials to the backend for
370 // the first time; this means that the user was not registered for cloud
371 // policy on startup but registered during the session.
372 //
373 // When that happens, OnPolicyFetched() is sent to observers before the
374 // CloudPolicyStore gets a chance to verify the user policy. In those cases,
375 // the backend gets the PolicyFetchResponses before it has the credentials
376 // and therefore the validation of those responses fails.
377 // Reload any PolicyFetchResponses that the client may have now so that
378 // validation is retried with the credentials in place.
379 if (core_->client())
380 OnPolicyFetched(core_->client());
381 }
382 }
383
384 void ComponentCloudPolicyService::OnStoreError(CloudPolicyStore* store) {
385 DCHECK(CalledOnValidThread());
386 OnStoreLoaded(store);
387 }
388
389 void ComponentCloudPolicyService::OnPolicyFetched(CloudPolicyClient* client) {
390 DCHECK(CalledOnValidThread());
391 DCHECK_EQ(core_->client(), client);
392
393 if (!is_registered_for_cloud_policy_) {
394 // Trying to load any policies now will fail validation. An OnStoreLoaded()
395 // notification should follow soon, after the main user policy has been
396 // validated and stored.
397 return;
398 }
399
400 // Pass each PolicyFetchResponse whose policy type is registered to the
401 // Backend.
402 const CloudPolicyClient::ResponseMap& responses =
403 core_->client()->responses();
404 for (CloudPolicyClient::ResponseMap::const_iterator it = responses.begin();
405 it != responses.end(); ++it) {
406 PolicyNamespace ns;
407 if (ToPolicyNamespace(it->first, &ns) &&
408 current_schema_map_->GetSchema(ns)) {
409 scoped_ptr<em::PolicyFetchResponse> response(
410 new em::PolicyFetchResponse(*it->second));
411 backend_task_runner_->PostTask(
412 FROM_HERE,
413 base::Bind(&Backend::UpdateExternalPolicy,
414 base::Unretained(backend_.get()),
415 base::Passed(&response)));
416 }
417 }
418 }
419
420 void ComponentCloudPolicyService::OnRegistrationStateChanged(
421 CloudPolicyClient* client) {
422 DCHECK(CalledOnValidThread());
423 // Ignored; the registration state is tracked by looking at the
424 // CloudPolicyStore instead.
425 }
426
427 void ComponentCloudPolicyService::OnClientError(CloudPolicyClient* client) {
428 DCHECK(CalledOnValidThread());
429 // Ignored.
430 }
431
432 void ComponentCloudPolicyService::InitializeIfReady() {
433 DCHECK(CalledOnValidThread());
434 if (started_loading_initial_policy_ || !schema_registry_->IsReady() ||
435 !core_->store()->is_initialized()) {
436 return;
437 }
438 // The initial list of components is ready. Initialize the backend now, which
439 // will call back to OnBackendInitialized.
440 backend_task_runner_->PostTask(FROM_HERE,
441 base::Bind(&Backend::Init,
442 base::Unretained(backend_.get()),
443 schema_registry_->schema_map()));
444 started_loading_initial_policy_ = true;
445 }
446
447 void ComponentCloudPolicyService::OnBackendInitialized(
448 scoped_ptr<PolicyBundle> initial_policy) {
449 DCHECK(CalledOnValidThread());
450 DCHECK(!loaded_initial_policy_);
451
452 loaded_initial_policy_ = true;
453
454 // We're now ready to serve the initial policy; notify the policy observers.
455 OnPolicyUpdated(initial_policy.Pass());
456
457 // Start observing the core and tracking the state of the client.
458 core_->AddObserver(this);
459
460 if (core_->client()) {
461 OnCoreConnected(core_);
462 } else {
463 // Send the current schema to the backend, in case it has changed while the
464 // backend was initializing. OnCoreConnected() also does this if a client is
465 // already connected.
466 SetCurrentSchema();
467 }
468 }
469
470 void ComponentCloudPolicyService::SetCurrentSchema() {
471 DCHECK(CalledOnValidThread());
472
473 scoped_ptr<PolicyNamespaceList> removed(new PolicyNamespaceList);
474 PolicyNamespaceList added;
475 const scoped_refptr<SchemaMap>& new_schema_map =
476 schema_registry_->schema_map();
477 new_schema_map->GetChanges(current_schema_map_, removed.get(), &added);
478
479 current_schema_map_ = new_schema_map;
480
481 if (core_->client()) {
482 for (size_t i = 0; i < removed->size(); ++i) {
483 PolicyNamespaceKey key;
484 if (ToPolicyNamespaceKey((*removed)[i], &key))
485 core_->client()->RemoveNamespaceToFetch(key);
486 }
487
488 bool added_namespaces_to_client = false;
489 for (size_t i = 0; i < added.size(); ++i) {
490 PolicyNamespaceKey key;
491 if (ToPolicyNamespaceKey(added[i], &key)) {
492 core_->client()->AddNamespaceToFetch(key);
493 added_namespaces_to_client = true;
494 }
495 }
496
497 if (added_namespaces_to_client)
498 core_->RefreshSoon();
499 }
500
501 backend_task_runner_->PostTask(FROM_HERE,
502 base::Bind(&Backend::OnSchemasUpdated,
503 base::Unretained(backend_.get()),
504 current_schema_map_,
505 base::Passed(&removed)));
506 }
507
508 void ComponentCloudPolicyService::OnPolicyUpdated(
509 scoped_ptr<PolicyBundle> policy) {
510 DCHECK(CalledOnValidThread());
511 policy_.Swap(policy.get());
512 delegate_->OnComponentCloudPolicyUpdated();
513 }
514
515 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698