- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / policy / cloud / component_cloud_policy_service.cc
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 "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/pickle.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/stl_util.h"
15 #include "chrome/browser/policy/cloud/component_cloud_policy_store.h"
16 #include "chrome/browser/policy/cloud/component_cloud_policy_updater.h"
17 #include "chrome/browser/policy/cloud/external_policy_data_fetcher.h"
18 #include "chrome/browser/policy/cloud/resource_cache.h"
19 #include "chrome/browser/policy/policy_domain_descriptor.h"
20 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
21 #include "net/url_request/url_request_context_getter.h"
22
23 namespace em = enterprise_management;
24
25 namespace policy {
26
27 namespace {
28
29 void GetComponentIds(scoped_refptr<const PolicyDomainDescriptor>& descriptor,
30                      std::set<std::string>* set) {
31   const PolicyDomainDescriptor::SchemaMap& map = descriptor->components();
32   for (PolicyDomainDescriptor::SchemaMap::const_iterator it = map.begin();
33        it != map.end(); ++it) {
34     set->insert(it->first);
35   }
36 }
37
38 }  // namespace
39
40 const char ComponentCloudPolicyService::kComponentNamespaceCache[] =
41     "component-namespace-cache";
42
43 ComponentCloudPolicyService::Delegate::~Delegate() {}
44
45 // Owns the objects that live on the background thread, and posts back to the
46 // thread that the ComponentCloudPolicyService runs on whenever the policy
47 // changes.
48 class ComponentCloudPolicyService::Backend
49     : public ComponentCloudPolicyStore::Delegate {
50  public:
51   // This class can be instantiated on any thread but from then on, may be
52   // accessed via the |task_runner_| only. Policy changes are posted to the
53   // |service| via the |service_task_runner|. The |cache| is used to load and
54   // store local copies of the downloaded policies.
55   Backend(base::WeakPtr<ComponentCloudPolicyService> service,
56           scoped_refptr<base::SequencedTaskRunner> task_runner,
57           scoped_refptr<base::SequencedTaskRunner> service_task_runner,
58           scoped_ptr<ResourceCache> cache);
59   virtual ~Backend();
60
61   // This is invoked right after the constructor but on the background thread.
62   // Used to create the store on the right thread.
63   void Init();
64
65   // Reads the initial list of components and the initial policy.
66   void FinalizeInit();
67
68   // Allows downloading of external data via the |external_policy_data_fetcher|.
69   void Connect(
70       scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher);
71
72   // Stops updating remote data. Cached policies are still served.
73   void Disconnect();
74
75   // Loads the initial policies from the store. |username| and |dm_token| are
76   // used to validate the cached policies.
77   void SetCredentials(const std::string& username, const std::string& dm_token);
78
79   // Passes a policy protobuf to the backend, to start its validation and
80   // eventual download of the policy data on the background thread.
81   // This is ignored if the backend isn't connected.
82   void UpdateExternalPolicy(scoped_ptr<em::PolicyFetchResponse> response);
83
84   // ComponentCloudPolicyStore::Delegate implementation:
85   virtual void OnComponentCloudPolicyStoreUpdated() OVERRIDE;
86
87   // Passes the current descriptor of a domain, so that the disk cache
88   // can purge components that aren't being tracked anymore.
89   void RegisterPolicyDomain(
90       scoped_refptr<const PolicyDomainDescriptor> descriptor);
91
92  private:
93   typedef std::map<PolicyDomain, scoped_refptr<const PolicyDomainDescriptor> >
94       DomainMap;
95
96   scoped_ptr<ComponentMap> ReadCachedComponents();
97
98   // The ComponentCloudPolicyService that owns |this|. Used to inform the
99   // |service_| when policy changes.
100   base::WeakPtr<ComponentCloudPolicyService> service_;
101
102   // The thread that |this| runs on. Used to post tasks to be run by |this|.
103   scoped_refptr<base::SequencedTaskRunner> task_runner_;
104
105   // The thread that the |service_| runs on. Used to post policy changes to the
106   // right thread.
107   scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
108
109   scoped_ptr<ResourceCache> cache_;
110   scoped_ptr<ComponentCloudPolicyStore> store_;
111   scoped_ptr<ComponentCloudPolicyUpdater> updater_;
112   DomainMap domain_map_;
113
114   DISALLOW_COPY_AND_ASSIGN(Backend);
115 };
116
117 ComponentCloudPolicyService::Backend::Backend(
118     base::WeakPtr<ComponentCloudPolicyService> service,
119     scoped_refptr<base::SequencedTaskRunner> task_runner,
120     scoped_refptr<base::SequencedTaskRunner> service_task_runner,
121     scoped_ptr<ResourceCache> cache)
122     : service_(service),
123       task_runner_(task_runner),
124       service_task_runner_(service_task_runner),
125       cache_(cache.Pass()) {}
126
127 ComponentCloudPolicyService::Backend::~Backend() {}
128
129 void ComponentCloudPolicyService::Backend::Init() {
130   DCHECK(!store_);
131   store_.reset(new ComponentCloudPolicyStore(this, cache_.get()));
132 }
133
134 void ComponentCloudPolicyService::Backend::FinalizeInit() {
135   // Read the components that were cached in the last RegisterPolicyDomain()
136   // calls for each domain.
137   scoped_ptr<ComponentMap> components = ReadCachedComponents();
138
139   // Read the initial policy.
140   store_->Load();
141   scoped_ptr<PolicyBundle> policy(new PolicyBundle);
142   policy->CopyFrom(store_->policy());
143
144   service_task_runner_->PostTask(
145       FROM_HERE,
146       base::Bind(&ComponentCloudPolicyService::OnBackendInitialized,
147                  service_,
148                  base::Passed(&components),
149                  base::Passed(&policy)));
150 }
151
152 void ComponentCloudPolicyService::Backend::SetCredentials(
153     const std::string& username,
154     const std::string& dm_token) {
155   store_->SetCredentials(username, dm_token);
156 }
157
158 void ComponentCloudPolicyService::Backend::Connect(
159     scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher) {
160   updater_.reset(new ComponentCloudPolicyUpdater(
161       task_runner_,
162       external_policy_data_fetcher.Pass(),
163       store_.get()));
164 }
165
166 void ComponentCloudPolicyService::Backend::Disconnect() {
167   updater_.reset();
168 }
169
170 void ComponentCloudPolicyService::Backend::UpdateExternalPolicy(
171     scoped_ptr<em::PolicyFetchResponse> response) {
172   if (updater_)
173     updater_->UpdateExternalPolicy(response.Pass());
174 }
175
176 void ComponentCloudPolicyService::Backend::
177     OnComponentCloudPolicyStoreUpdated() {
178   scoped_ptr<PolicyBundle> bundle(new PolicyBundle);
179   bundle->CopyFrom(store_->policy());
180   for (DomainMap::iterator it = domain_map_.begin();
181        it != domain_map_.end(); ++it) {
182     it->second->FilterBundle(bundle.get());
183   }
184
185   service_task_runner_->PostTask(
186       FROM_HERE,
187       base::Bind(&ComponentCloudPolicyService::OnPolicyUpdated,
188                  service_,
189                  base::Passed(&bundle)));
190 }
191
192 void ComponentCloudPolicyService::Backend::RegisterPolicyDomain(
193     scoped_refptr<const PolicyDomainDescriptor> descriptor) {
194   // Store the current list of components in the cache.
195   StringSet ids;
196   std::string policy_type;
197   if (ComponentCloudPolicyStore::GetPolicyType(descriptor->domain(),
198                                                &policy_type)) {
199     GetComponentIds(descriptor, &ids);
200     Pickle pickle;
201     for (StringSet::const_iterator it = ids.begin(); it != ids.end(); ++it)
202       pickle.WriteString(*it);
203     std::string data(reinterpret_cast<const char*>(pickle.data()),
204                      pickle.size());
205     cache_->Store(kComponentNamespaceCache, policy_type, data);
206   }
207
208   domain_map_[descriptor->domain()] = descriptor;
209
210   // Purge any components that have been removed.
211   if (store_)
212     store_->Purge(descriptor->domain(), ids);
213 }
214
215 scoped_ptr<ComponentCloudPolicyService::ComponentMap>
216     ComponentCloudPolicyService::Backend::ReadCachedComponents() {
217   scoped_ptr<ComponentMap> components(new ComponentMap);
218   std::map<std::string, std::string> contents;
219   cache_->LoadAllSubkeys(kComponentNamespaceCache, &contents);
220   for (std::map<std::string, std::string>::iterator it = contents.begin();
221        it != contents.end(); ++it) {
222     PolicyDomain domain;
223     if (ComponentCloudPolicyStore::GetPolicyDomain(it->first, &domain)) {
224       StringSet& set = (*components)[domain];
225       const Pickle pickle(it->second.data(), it->second.size());
226       PickleIterator pickit(pickle);
227       std::string id;
228       while (pickit.ReadString(&id))
229         set.insert(id);
230     } else {
231       cache_->Delete(kComponentNamespaceCache, it->first);
232     }
233   }
234   return components.Pass();
235 }
236
237 ComponentCloudPolicyService::ComponentCloudPolicyService(
238     Delegate* delegate,
239     CloudPolicyStore* store,
240     scoped_ptr<ResourceCache> cache,
241     scoped_refptr<base::SequencedTaskRunner> backend_task_runner,
242     scoped_refptr<base::SequencedTaskRunner> io_task_runner)
243     : delegate_(delegate),
244       backend_task_runner_(backend_task_runner),
245       io_task_runner_(io_task_runner),
246       client_(NULL),
247       store_(store),
248       is_initialized_(false),
249       weak_ptr_factory_(this) {
250   store_->AddObserver(this);
251
252   backend_.reset(new Backend(weak_ptr_factory_.GetWeakPtr(),
253                              backend_task_runner_,
254                              base::MessageLoopProxy::current(),
255                              cache.Pass()));
256   backend_task_runner_->PostTask(
257       FROM_HERE, base::Bind(&Backend::Init, base::Unretained(backend_.get())));
258
259   if (store_->is_initialized())
260     InitializeBackend();
261 }
262
263 ComponentCloudPolicyService::~ComponentCloudPolicyService() {
264   DCHECK(CalledOnValidThread());
265   store_->RemoveObserver(this);
266   if (client_)
267     client_->RemoveObserver(this);
268   io_task_runner_->DeleteSoon(FROM_HERE,
269                               external_policy_data_fetcher_backend_.release());
270   backend_task_runner_->DeleteSoon(FROM_HERE, backend_.release());
271 }
272
273 // static
274 bool ComponentCloudPolicyService::SupportsDomain(PolicyDomain domain) {
275   return ComponentCloudPolicyStore::SupportsDomain(domain);
276 }
277
278 void ComponentCloudPolicyService::Connect(
279     CloudPolicyClient* client,
280     scoped_refptr<net::URLRequestContextGetter> request_context) {
281   DCHECK(CalledOnValidThread());
282   DCHECK(!client_);
283   client_ = client;
284   client_->AddObserver(this);
285   DCHECK(!external_policy_data_fetcher_backend_);
286   external_policy_data_fetcher_backend_.reset(
287       new ExternalPolicyDataFetcherBackend(io_task_runner_,
288                                            request_context));
289   // Create the updater in the backend.
290   backend_task_runner_->PostTask(FROM_HERE, base::Bind(
291       &Backend::Connect,
292       base::Unretained(backend_.get()),
293       base::Passed(external_policy_data_fetcher_backend_->CreateFrontend(
294           backend_task_runner_))));
295   if (is_initialized())
296     InitializeClient();
297 }
298
299 void ComponentCloudPolicyService::Disconnect() {
300   DCHECK(CalledOnValidThread());
301   if (client_) {
302     // Unregister all the current components.
303     for (ComponentMap::iterator it = registered_components_.begin();
304          it != registered_components_.end(); ++it) {
305       RemoveNamespacesToFetch(it->first, it->second);
306     }
307
308     client_->RemoveObserver(this);
309     client_ = NULL;
310
311     io_task_runner_->DeleteSoon(
312         FROM_HERE, external_policy_data_fetcher_backend_.release());
313     backend_task_runner_->PostTask(
314         FROM_HERE,
315         base::Bind(&Backend::Disconnect, base::Unretained(backend_.get())));
316   }
317 }
318
319 void ComponentCloudPolicyService::RegisterPolicyDomain(
320     scoped_refptr<const PolicyDomainDescriptor> descriptor) {
321   DCHECK(CalledOnValidThread());
322   DCHECK(SupportsDomain(descriptor->domain()));
323
324   // Send the new descriptor to the backend, to purge the cache.
325   backend_task_runner_->PostTask(FROM_HERE,
326                                  base::Bind(&Backend::RegisterPolicyDomain,
327                                             base::Unretained(backend_.get()),
328                                             descriptor));
329
330   // Register the current list of components for |domain| at the |client_|.
331   StringSet current_ids;
332   GetComponentIds(descriptor, &current_ids);
333   StringSet& registered_ids = registered_components_[descriptor->domain()];
334   if (client_ && is_initialized()) {
335     if (UpdateClientNamespaces(
336             descriptor->domain(), registered_ids, current_ids)) {
337       delegate_->OnComponentCloudPolicyRefreshNeeded();
338     }
339   }
340
341   registered_ids = current_ids;
342 }
343
344 void ComponentCloudPolicyService::OnPolicyFetched(CloudPolicyClient* client) {
345   DCHECK(CalledOnValidThread());
346   DCHECK_EQ(client_, client);
347   // Pass each PolicyFetchResponse whose policy type is registered to the
348   // Backend.
349   const CloudPolicyClient::ResponseMap& responses = client_->responses();
350   for (CloudPolicyClient::ResponseMap::const_iterator it = responses.begin();
351        it != responses.end(); ++it) {
352     const PolicyNamespaceKey& key(it->first);
353     PolicyDomain domain;
354     if (ComponentCloudPolicyStore::GetPolicyDomain(key.first, &domain) &&
355         ContainsKey(registered_components_[domain], key.second)) {
356       scoped_ptr<em::PolicyFetchResponse> response(
357           new em::PolicyFetchResponse(*it->second));
358       backend_task_runner_->PostTask(
359           FROM_HERE,
360           base::Bind(&Backend::UpdateExternalPolicy,
361                      base::Unretained(backend_.get()),
362                      base::Passed(&response)));
363     }
364   }
365 }
366
367 void ComponentCloudPolicyService::OnRegistrationStateChanged(
368     CloudPolicyClient* client) {
369   DCHECK(CalledOnValidThread());
370   // Ignored.
371 }
372
373 void ComponentCloudPolicyService::OnClientError(CloudPolicyClient* client) {
374   DCHECK(CalledOnValidThread());
375   // Ignored.
376 }
377
378 void ComponentCloudPolicyService::OnStoreLoaded(CloudPolicyStore* store) {
379   DCHECK(CalledOnValidThread());
380   DCHECK_EQ(store_, store);
381   if (store_->is_initialized()) {
382     if (is_initialized()) {
383       // The backend is already initialized; update the credentials, in case
384       // a new dmtoken or server key became available.
385       SetCredentialsAndReloadClient();
386     } else {
387       // The |store_| just became ready; initialize the backend now.
388       InitializeBackend();
389     }
390   }
391 }
392
393 void ComponentCloudPolicyService::OnStoreError(CloudPolicyStore* store) {
394   DCHECK(CalledOnValidThread());
395   OnStoreLoaded(store);
396 }
397
398 void ComponentCloudPolicyService::InitializeBackend() {
399   DCHECK(CalledOnValidThread());
400   DCHECK(!is_initialized());
401   DCHECK(store_->is_initialized());
402
403   // Set the credentials for the initial policy load, if available.
404   SetCredentialsAndReloadClient();
405
406   backend_task_runner_->PostTask(
407       FROM_HERE,
408       base::Bind(&Backend::FinalizeInit, base::Unretained(backend_.get())));
409 }
410
411 void ComponentCloudPolicyService::OnBackendInitialized(
412     scoped_ptr<ComponentMap> cached_components,
413     scoped_ptr<PolicyBundle> initial_policy) {
414   DCHECK(CalledOnValidThread());
415   // InitializeBackend() may be called multiple times if the |store_| fires
416   // events while the backend is loading.
417   if (is_initialized())
418     return;
419
420   // RegisterPolicyDomain() may have been called while the backend was
421   // initializing; only update |registered_components_| from |cached_components|
422   // for domains that haven't registered yet.
423   for (ComponentMap::iterator it = cached_components->begin();
424        it != cached_components->end(); ++it) {
425     // Lookup without inserting an empty set.
426     if (registered_components_.find(it->first) != registered_components_.end())
427       continue;  // Ignore the cached list if a more recent one was registered.
428     registered_components_[it->first].swap(it->second);
429   }
430
431   // A client may have already connected while the backend was initializing.
432   if (client_)
433     InitializeClient();
434
435   // Set the initial policy, and send the initial update callback.
436   is_initialized_ = true;
437   OnPolicyUpdated(initial_policy.Pass());
438 }
439
440 void ComponentCloudPolicyService::InitializeClient() {
441   DCHECK(CalledOnValidThread());
442   // Register all the current components.
443   bool added = false;
444   for (ComponentMap::iterator it = registered_components_.begin();
445        it != registered_components_.end(); ++it) {
446     added |= !it->second.empty();
447     AddNamespacesToFetch(it->first, it->second);
448   }
449   // The client may already have PolicyFetchResponses for registered components;
450   // load them now.
451   OnPolicyFetched(client_);
452   if (added && is_initialized())
453     delegate_->OnComponentCloudPolicyRefreshNeeded();
454 }
455
456 void ComponentCloudPolicyService::OnPolicyUpdated(
457     scoped_ptr<PolicyBundle> policy) {
458   DCHECK(CalledOnValidThread());
459   policy_.Swap(policy.get());
460   // Don't propagate updates until the initial store Load() has been done.
461   if (is_initialized())
462     delegate_->OnComponentCloudPolicyUpdated();
463 }
464
465 void ComponentCloudPolicyService::SetCredentialsAndReloadClient() {
466   DCHECK(CalledOnValidThread());
467   const em::PolicyData* policy = store_->policy();
468   if (!policy || !policy->has_username() || !policy->has_request_token())
469     return;
470   backend_task_runner_->PostTask(FROM_HERE,
471                                  base::Bind(&Backend::SetCredentials,
472                                             base::Unretained(backend_.get()),
473                                             policy->username(),
474                                             policy->request_token()));
475   // If this was the initial register, or if the signing key changed, then the
476   // previous OnPolicyFetched() call had its PolicyFetchResponses rejected
477   // because the credentials weren't updated yet. Reload all the responses in
478   // the client now to handle those cases; if those responses have already been
479   // validated then they will be ignored.
480   if (client_)
481     OnPolicyFetched(client_);
482 }
483
484 bool ComponentCloudPolicyService::UpdateClientNamespaces(
485     PolicyDomain domain,
486     const StringSet& old_set,
487     const StringSet& new_set) {
488   DCHECK(CalledOnValidThread());
489   StringSet added = base::STLSetDifference<StringSet>(new_set, old_set);
490   StringSet removed = base::STLSetDifference<StringSet>(old_set, new_set);
491   AddNamespacesToFetch(domain, added);
492   RemoveNamespacesToFetch(domain, removed);
493   return !added.empty();
494 }
495
496 void ComponentCloudPolicyService::AddNamespacesToFetch(PolicyDomain domain,
497                                                        const StringSet& set) {
498   DCHECK(CalledOnValidThread());
499   std::string policy_type;
500   if (ComponentCloudPolicyStore::GetPolicyType(domain, &policy_type)) {
501     for (StringSet::const_iterator it = set.begin(); it != set.end(); ++it)
502       client_->AddNamespaceToFetch(PolicyNamespaceKey(policy_type, *it));
503   }
504 }
505
506 void ComponentCloudPolicyService::RemoveNamespacesToFetch(
507     PolicyDomain domain,
508     const StringSet& set) {
509   DCHECK(CalledOnValidThread());
510   std::string policy_type;
511   if (ComponentCloudPolicyStore::GetPolicyType(domain, &policy_type)) {
512     for (StringSet::const_iterator it = set.begin(); it != set.end(); ++it)
513       client_->RemoveNamespaceToFetch(PolicyNamespaceKey(policy_type, *it));
514   }
515 }
516
517 }  // namespace policy