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