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 "components/policy/core/common/cloud/component_cloud_policy_service.h" | 5 #include "components/policy/core/common/cloud/component_cloud_policy_service.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 93 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
94 | 94 |
95 // The thread that the |service_| runs on. Used to post policy changes to the | 95 // The thread that the |service_| runs on. Used to post policy changes to the |
96 // right thread. | 96 // right thread. |
97 scoped_refptr<base::SequencedTaskRunner> service_task_runner_; | 97 scoped_refptr<base::SequencedTaskRunner> service_task_runner_; |
98 | 98 |
99 scoped_ptr<ResourceCache> cache_; | 99 scoped_ptr<ResourceCache> cache_; |
100 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher_; | 100 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher_; |
101 ComponentCloudPolicyStore store_; | 101 ComponentCloudPolicyStore store_; |
102 scoped_ptr<ComponentCloudPolicyUpdater> updater_; | 102 scoped_ptr<ComponentCloudPolicyUpdater> updater_; |
103 scoped_refptr<SchemaMap> schema_map_; | 103 bool initialized_; |
104 | 104 |
105 DISALLOW_COPY_AND_ASSIGN(Backend); | 105 DISALLOW_COPY_AND_ASSIGN(Backend); |
106 }; | 106 }; |
107 | 107 |
108 ComponentCloudPolicyService::Backend::Backend( | 108 ComponentCloudPolicyService::Backend::Backend( |
109 base::WeakPtr<ComponentCloudPolicyService> service, | 109 base::WeakPtr<ComponentCloudPolicyService> service, |
110 scoped_refptr<base::SequencedTaskRunner> task_runner, | 110 scoped_refptr<base::SequencedTaskRunner> task_runner, |
111 scoped_refptr<base::SequencedTaskRunner> service_task_runner, | 111 scoped_refptr<base::SequencedTaskRunner> service_task_runner, |
112 scoped_ptr<ResourceCache> cache, | 112 scoped_ptr<ResourceCache> cache, |
113 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher) | 113 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher) |
114 : service_(service), | 114 : service_(service), |
115 task_runner_(task_runner), | 115 task_runner_(task_runner), |
116 service_task_runner_(service_task_runner), | 116 service_task_runner_(service_task_runner), |
117 cache_(cache.Pass()), | 117 cache_(cache.Pass()), |
118 external_policy_data_fetcher_(external_policy_data_fetcher.Pass()), | 118 external_policy_data_fetcher_(external_policy_data_fetcher.Pass()), |
119 store_(this, cache_.get()) {} | 119 store_(this, cache_.get()), |
| 120 initialized_(false) {} |
120 | 121 |
121 ComponentCloudPolicyService::Backend::~Backend() {} | 122 ComponentCloudPolicyService::Backend::~Backend() {} |
122 | 123 |
123 void ComponentCloudPolicyService::Backend::SetCredentials( | 124 void ComponentCloudPolicyService::Backend::SetCredentials( |
124 const std::string& username, | 125 const std::string& username, |
125 const std::string& dm_token) { | 126 const std::string& dm_token) { |
126 if (username.empty() || dm_token.empty()) { | 127 if (username.empty() || dm_token.empty()) { |
127 // No sign-in credentials, so drop any cached policy. | 128 // No sign-in credentials, so drop any cached policy. |
128 store_.Clear(); | 129 store_.Clear(); |
129 } else { | 130 } else { |
130 store_.SetCredentials(username, dm_token); | 131 store_.SetCredentials(username, dm_token); |
131 } | 132 } |
132 } | 133 } |
133 | 134 |
134 void ComponentCloudPolicyService::Backend::Init( | 135 void ComponentCloudPolicyService::Backend::Init( |
135 scoped_refptr<SchemaMap> schema_map) { | 136 scoped_refptr<SchemaMap> schema_map) { |
136 DCHECK(!schema_map_); | 137 DCHECK(!initialized_); |
137 | 138 |
138 OnSchemasUpdated(schema_map, scoped_ptr<PolicyNamespaceList>()); | 139 OnSchemasUpdated(schema_map, scoped_ptr<PolicyNamespaceList>()); |
139 | 140 |
140 // Read the initial policy. Note that this does not trigger notifications | 141 // Read the initial policy. Note that this does not trigger notifications |
141 // through OnComponentCloudPolicyStoreUpdated. Note also that the cached | 142 // through OnComponentCloudPolicyStoreUpdated. Note also that the cached |
142 // data may contain names or values that don't match the schema for that | 143 // data may contain names or values that don't match the schema for that |
143 // component; the data must be cached without modifications so that its | 144 // component; the data must be cached without modifications so that its |
144 // integrity can be verified using the hash, but it must also be filtered | 145 // integrity can be verified using the hash, but it must also be filtered |
145 // right after a Load(). | 146 // right after a Load(). |
146 store_.Load(); | 147 store_.Load(); |
147 scoped_ptr<PolicyBundle> bundle(new PolicyBundle); | 148 scoped_ptr<PolicyBundle> bundle(new PolicyBundle); |
148 bundle->CopyFrom(store_.policy()); | 149 bundle->CopyFrom(store_.policy()); |
149 schema_map_->FilterBundle(bundle.get()); | |
150 | 150 |
151 // Start downloading any pending data. | 151 // Start downloading any pending data. |
152 updater_.reset(new ComponentCloudPolicyUpdater( | 152 updater_.reset(new ComponentCloudPolicyUpdater( |
153 task_runner_, external_policy_data_fetcher_.Pass(), &store_)); | 153 task_runner_, external_policy_data_fetcher_.Pass(), &store_)); |
154 | 154 |
155 service_task_runner_->PostTask( | 155 service_task_runner_->PostTask( |
156 FROM_HERE, | 156 FROM_HERE, |
157 base::Bind(&ComponentCloudPolicyService::OnBackendInitialized, | 157 base::Bind(&ComponentCloudPolicyService::OnBackendInitialized, |
158 service_, | 158 service_, |
159 base::Passed(&bundle))); | 159 base::Passed(&bundle))); |
| 160 |
| 161 initialized_ = true; |
160 } | 162 } |
161 | 163 |
162 void ComponentCloudPolicyService::Backend::UpdateExternalPolicy( | 164 void ComponentCloudPolicyService::Backend::UpdateExternalPolicy( |
163 scoped_ptr<em::PolicyFetchResponse> response) { | 165 scoped_ptr<em::PolicyFetchResponse> response) { |
164 updater_->UpdateExternalPolicy(response.Pass()); | 166 updater_->UpdateExternalPolicy(response.Pass()); |
165 } | 167 } |
166 | 168 |
167 void ComponentCloudPolicyService::Backend:: | 169 void ComponentCloudPolicyService::Backend:: |
168 OnComponentCloudPolicyStoreUpdated() { | 170 OnComponentCloudPolicyStoreUpdated() { |
169 if (!schema_map_) { | 171 if (!initialized_) { |
170 // Ignore notifications triggered by the initial Purge or Clear. | 172 // Ignore notifications triggered by the initial Purge or Clear. |
171 return; | 173 return; |
172 } | 174 } |
173 | 175 |
174 scoped_ptr<PolicyBundle> bundle(new PolicyBundle); | 176 scoped_ptr<PolicyBundle> bundle(new PolicyBundle); |
175 bundle->CopyFrom(store_.policy()); | 177 bundle->CopyFrom(store_.policy()); |
176 schema_map_->FilterBundle(bundle.get()); | |
177 service_task_runner_->PostTask( | 178 service_task_runner_->PostTask( |
178 FROM_HERE, | 179 FROM_HERE, |
179 base::Bind(&ComponentCloudPolicyService::OnPolicyUpdated, | 180 base::Bind(&ComponentCloudPolicyService::OnPolicyUpdated, |
180 service_, | 181 service_, |
181 base::Passed(&bundle))); | 182 base::Passed(&bundle))); |
182 } | 183 } |
183 | 184 |
184 void ComponentCloudPolicyService::Backend::OnSchemasUpdated( | 185 void ComponentCloudPolicyService::Backend::OnSchemasUpdated( |
185 scoped_refptr<SchemaMap> schema_map, | 186 scoped_refptr<SchemaMap> schema_map, |
186 scoped_ptr<PolicyNamespaceList> removed) { | 187 scoped_ptr<PolicyNamespaceList> removed) { |
187 // Purge any components that have been removed. | 188 // Purge any components that have been removed. |
188 const DomainMap& domains = schema_map->GetDomains(); | 189 const DomainMap& domains = schema_map->GetDomains(); |
189 for (DomainMap::const_iterator domain = domains.begin(); | 190 for (DomainMap::const_iterator domain = domains.begin(); |
190 domain != domains.end(); ++domain) { | 191 domain != domains.end(); ++domain) { |
191 store_.Purge(domain->first, | 192 store_.Purge(domain->first, |
192 base::Bind(&NotInSchemaMap, schema_map, domain->first)); | 193 base::Bind(&NotInSchemaMap, schema_map, domain->first)); |
193 } | 194 } |
194 | 195 |
195 // Set |schema_map_| after purging so that the notifications from the store | |
196 // are ignored on the first OnSchemasUpdated() call from Init(). | |
197 schema_map_ = schema_map; | |
198 | |
199 if (removed) { | 196 if (removed) { |
200 for (size_t i = 0; i < removed->size(); ++i) | 197 for (size_t i = 0; i < removed->size(); ++i) |
201 updater_->CancelUpdate((*removed)[i]); | 198 updater_->CancelUpdate((*removed)[i]); |
202 } | 199 } |
203 } | 200 } |
204 | 201 |
205 ComponentCloudPolicyService::ComponentCloudPolicyService( | 202 ComponentCloudPolicyService::ComponentCloudPolicyService( |
206 Delegate* delegate, | 203 Delegate* delegate, |
207 SchemaRegistry* schema_registry, | 204 SchemaRegistry* schema_registry, |
208 CloudPolicyCore* core, | 205 CloudPolicyCore* core, |
209 scoped_ptr<ResourceCache> cache, | 206 scoped_ptr<ResourceCache> cache, |
210 scoped_refptr<net::URLRequestContextGetter> request_context, | 207 scoped_refptr<net::URLRequestContextGetter> request_context, |
211 scoped_refptr<base::SequencedTaskRunner> backend_task_runner, | 208 scoped_refptr<base::SequencedTaskRunner> backend_task_runner, |
212 scoped_refptr<base::SequencedTaskRunner> io_task_runner) | 209 scoped_refptr<base::SequencedTaskRunner> io_task_runner) |
213 : delegate_(delegate), | 210 : delegate_(delegate), |
214 schema_registry_(schema_registry), | 211 schema_registry_(schema_registry), |
215 core_(core), | 212 core_(core), |
216 request_context_(request_context), | 213 request_context_(request_context), |
217 backend_task_runner_(backend_task_runner), | 214 backend_task_runner_(backend_task_runner), |
218 io_task_runner_(io_task_runner), | 215 io_task_runner_(io_task_runner), |
219 current_schema_map_(new SchemaMap), | 216 current_schema_map_(new SchemaMap), |
| 217 unfiltered_policy_(new PolicyBundle), |
220 started_loading_initial_policy_(false), | 218 started_loading_initial_policy_(false), |
221 loaded_initial_policy_(false), | 219 loaded_initial_policy_(false), |
222 is_registered_for_cloud_policy_(false), | 220 is_registered_for_cloud_policy_(false), |
223 weak_ptr_factory_(this) { | 221 weak_ptr_factory_(this) { |
224 external_policy_data_fetcher_backend_.reset( | 222 external_policy_data_fetcher_backend_.reset( |
225 new ExternalPolicyDataFetcherBackend(io_task_runner_, request_context)); | 223 new ExternalPolicyDataFetcherBackend(io_task_runner_, request_context)); |
226 | 224 |
227 backend_.reset( | 225 backend_.reset( |
228 new Backend(weak_ptr_factory_.GetWeakPtr(), | 226 new Backend(weak_ptr_factory_.GetWeakPtr(), |
229 backend_task_runner_, | 227 backend_task_runner_, |
230 base::MessageLoopProxy::current(), | 228 base::MessageLoopProxy::current(), |
231 cache.Pass(), | 229 cache.Pass(), |
232 external_policy_data_fetcher_backend_->CreateFrontend( | 230 external_policy_data_fetcher_backend_->CreateFrontend( |
233 backend_task_runner_))); | 231 backend_task_runner_))); |
234 | 232 |
235 schema_registry_->AddObserver(this); | 233 schema_registry_->AddObserver(this); |
236 core_->store()->AddObserver(this); | 234 core_->store()->AddObserver(this); |
237 | 235 |
238 // Wait for the store and the schema registry to become ready before | 236 // Wait for the store and the schema registry to become ready before |
239 // initializing the backend, so that it can get the initial list of | 237 // initializing the backend, so that it can get the initial list of |
240 // components and the cached credentials (if any) to validate the cached | 238 // components and the cached credentials (if any) to validate the cached |
241 // policies. | 239 // policies. |
242 if (core_->store()->is_initialized()) | 240 if (core_->store()->is_initialized()) |
243 OnStoreLoaded(core_->store()); | 241 OnStoreLoaded(core_->store()); |
| 242 |
| 243 // Start observing the core and tracking the state of the client. |
| 244 core_->AddObserver(this); |
| 245 if (core_->client()) |
| 246 OnCoreConnected(core_); |
244 } | 247 } |
245 | 248 |
246 ComponentCloudPolicyService::~ComponentCloudPolicyService() { | 249 ComponentCloudPolicyService::~ComponentCloudPolicyService() { |
247 DCHECK(CalledOnValidThread()); | 250 DCHECK(CalledOnValidThread()); |
248 | 251 |
249 schema_registry_->RemoveObserver(this); | 252 schema_registry_->RemoveObserver(this); |
250 core_->store()->RemoveObserver(this); | 253 core_->store()->RemoveObserver(this); |
251 core_->RemoveObserver(this); | 254 core_->RemoveObserver(this); |
252 if (core_->client()) | 255 if (core_->client()) |
253 OnCoreDisconnecting(core_); | 256 OnCoreDisconnecting(core_); |
(...skipping 26 matching lines...) Expand all Loading... |
280 bool has_new_schemas) { | 283 bool has_new_schemas) { |
281 DCHECK(CalledOnValidThread()); | 284 DCHECK(CalledOnValidThread()); |
282 | 285 |
283 // Ignore schema updates until the backend is initialized. | 286 // Ignore schema updates until the backend is initialized. |
284 // OnBackendInitialized() will send the current schema to the backend again, | 287 // OnBackendInitialized() will send the current schema to the backend again, |
285 // in case it was updated before the backend initialized. | 288 // in case it was updated before the backend initialized. |
286 if (!loaded_initial_policy_) | 289 if (!loaded_initial_policy_) |
287 return; | 290 return; |
288 | 291 |
289 ReloadSchema(); | 292 ReloadSchema(); |
| 293 |
| 294 // Filter the |unfiltered_policy_| again, now that |current_schema_map_| has |
| 295 // been updated. We must make sure we never serve invalid policy; we must |
| 296 // also filter again if an invalid Schema has now been loaded. |
| 297 OnPolicyUpdated(unfiltered_policy_.Pass()); |
290 } | 298 } |
291 | 299 |
292 void ComponentCloudPolicyService::OnCoreConnected(CloudPolicyCore* core) { | 300 void ComponentCloudPolicyService::OnCoreConnected(CloudPolicyCore* core) { |
293 DCHECK(CalledOnValidThread()); | 301 DCHECK(CalledOnValidThread()); |
294 DCHECK_EQ(core_, core); | 302 DCHECK_EQ(core_, core); |
295 | 303 |
296 core_->client()->AddObserver(this); | 304 core_->client()->AddObserver(this); |
297 | 305 |
298 // Register the supported policy domains at the client. | 306 // Register the supported policy domains at the client. |
299 core_->client()->AddNamespaceToFetch( | 307 core_->client()->AddNamespaceToFetch( |
300 PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "")); | 308 PolicyNamespaceKey(dm_protocol::kChromeExtensionPolicyType, "")); |
301 | 309 |
302 // Immediately load any PolicyFetchResponses that the client may already | 310 // Immediately load any PolicyFetchResponses that the client may already |
303 // have. | 311 // have if the backend is ready. |
304 OnPolicyFetched(core_->client()); | 312 if (loaded_initial_policy_) |
| 313 OnPolicyFetched(core_->client()); |
305 } | 314 } |
306 | 315 |
307 void ComponentCloudPolicyService::OnCoreDisconnecting(CloudPolicyCore* core) { | 316 void ComponentCloudPolicyService::OnCoreDisconnecting(CloudPolicyCore* core) { |
308 DCHECK(CalledOnValidThread()); | 317 DCHECK(CalledOnValidThread()); |
309 DCHECK_EQ(core_, core); | 318 DCHECK_EQ(core_, core); |
310 | 319 |
311 core_->client()->RemoveObserver(this); | 320 core_->client()->RemoveObserver(this); |
312 | 321 |
313 // Remove all the namespaces from the client. | 322 // Remove all the namespaces from the client. |
314 core_->client()->RemoveNamespaceToFetch( | 323 core_->client()->RemoveNamespaceToFetch( |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 DCHECK(CalledOnValidThread()); | 423 DCHECK(CalledOnValidThread()); |
415 // Ignored. | 424 // Ignored. |
416 } | 425 } |
417 | 426 |
418 void ComponentCloudPolicyService::InitializeIfReady() { | 427 void ComponentCloudPolicyService::InitializeIfReady() { |
419 DCHECK(CalledOnValidThread()); | 428 DCHECK(CalledOnValidThread()); |
420 if (started_loading_initial_policy_ || !schema_registry_->IsReady() || | 429 if (started_loading_initial_policy_ || !schema_registry_->IsReady() || |
421 !core_->store()->is_initialized()) { | 430 !core_->store()->is_initialized()) { |
422 return; | 431 return; |
423 } | 432 } |
| 433 |
424 // The initial list of components is ready. Initialize the backend now, which | 434 // The initial list of components is ready. Initialize the backend now, which |
425 // will call back to OnBackendInitialized. | 435 // will call back to OnBackendInitialized. |
426 backend_task_runner_->PostTask(FROM_HERE, | 436 backend_task_runner_->PostTask(FROM_HERE, |
427 base::Bind(&Backend::Init, | 437 base::Bind(&Backend::Init, |
428 base::Unretained(backend_.get()), | 438 base::Unretained(backend_.get()), |
429 schema_registry_->schema_map())); | 439 schema_registry_->schema_map())); |
430 started_loading_initial_policy_ = true; | 440 started_loading_initial_policy_ = true; |
431 } | 441 } |
432 | 442 |
433 void ComponentCloudPolicyService::OnBackendInitialized( | 443 void ComponentCloudPolicyService::OnBackendInitialized( |
434 scoped_ptr<PolicyBundle> initial_policy) { | 444 scoped_ptr<PolicyBundle> initial_policy) { |
435 DCHECK(CalledOnValidThread()); | 445 DCHECK(CalledOnValidThread()); |
436 DCHECK(!loaded_initial_policy_); | 446 DCHECK(!loaded_initial_policy_); |
437 | 447 |
438 loaded_initial_policy_ = true; | 448 loaded_initial_policy_ = true; |
439 | 449 |
440 // We're now ready to serve the initial policy; notify the policy observers. | |
441 OnPolicyUpdated(initial_policy.Pass()); | |
442 | |
443 // Send the current schema to the backend, in case it has changed while the | 450 // Send the current schema to the backend, in case it has changed while the |
444 // backend was initializing. | 451 // backend was initializing. |
445 ReloadSchema(); | 452 ReloadSchema(); |
446 | 453 |
447 // Start observing the core and tracking the state of the client. | 454 // We're now ready to serve the initial policy; notify the policy observers. |
448 core_->AddObserver(this); | 455 OnPolicyUpdated(initial_policy.Pass()); |
449 | |
450 if (core_->client()) | |
451 OnCoreConnected(core_); | |
452 } | 456 } |
453 | 457 |
454 void ComponentCloudPolicyService::ReloadSchema() { | 458 void ComponentCloudPolicyService::ReloadSchema() { |
455 DCHECK(CalledOnValidThread()); | 459 DCHECK(CalledOnValidThread()); |
456 | 460 |
457 scoped_ptr<PolicyNamespaceList> removed(new PolicyNamespaceList); | 461 scoped_ptr<PolicyNamespaceList> removed(new PolicyNamespaceList); |
458 PolicyNamespaceList added; | 462 PolicyNamespaceList added; |
459 const scoped_refptr<SchemaMap>& new_schema_map = | 463 const scoped_refptr<SchemaMap>& new_schema_map = |
460 schema_registry_->schema_map(); | 464 schema_registry_->schema_map(); |
461 new_schema_map->GetChanges(current_schema_map_, removed.get(), &added); | 465 new_schema_map->GetChanges(current_schema_map_, removed.get(), &added); |
462 | 466 |
463 current_schema_map_ = new_schema_map; | 467 current_schema_map_ = new_schema_map; |
464 | 468 |
465 // Schedule a policy refresh if a new managed component was added. | |
466 if (core_->client() && !added.empty()) | |
467 core_->RefreshSoon(); | |
468 | |
469 // Send the updated SchemaMap and a list of removed components to the | 469 // Send the updated SchemaMap and a list of removed components to the |
470 // backend. | 470 // backend. |
471 backend_task_runner_->PostTask(FROM_HERE, | 471 backend_task_runner_->PostTask(FROM_HERE, |
472 base::Bind(&Backend::OnSchemasUpdated, | 472 base::Bind(&Backend::OnSchemasUpdated, |
473 base::Unretained(backend_.get()), | 473 base::Unretained(backend_.get()), |
474 current_schema_map_, | 474 current_schema_map_, |
475 base::Passed(&removed))); | 475 base::Passed(&removed))); |
| 476 |
| 477 // Have another look at the client if the core is already connected. |
| 478 // The client may have already fetched policy for some component and it was |
| 479 // previously ignored because the component wasn't listed in the schema map. |
| 480 // There's no point in fetching policy from the server again; the server |
| 481 // always pushes all the components it knows about. |
| 482 if (core_->client()) |
| 483 OnPolicyFetched(core_->client()); |
476 } | 484 } |
477 | 485 |
478 void ComponentCloudPolicyService::OnPolicyUpdated( | 486 void ComponentCloudPolicyService::OnPolicyUpdated( |
479 scoped_ptr<PolicyBundle> policy) { | 487 scoped_ptr<PolicyBundle> policy) { |
480 DCHECK(CalledOnValidThread()); | 488 DCHECK(CalledOnValidThread()); |
481 policy_.Swap(policy.get()); | 489 |
| 490 // Store the current unfiltered policies. |
| 491 unfiltered_policy_ = policy.Pass(); |
| 492 |
| 493 // Make a copy in |policy_| and filter it; this is what's passed to the |
| 494 // outside world. |
| 495 policy_.CopyFrom(*unfiltered_policy_); |
| 496 current_schema_map_->FilterBundle(&policy_); |
| 497 |
482 delegate_->OnComponentCloudPolicyUpdated(); | 498 delegate_->OnComponentCloudPolicyUpdated(); |
483 } | 499 } |
484 | 500 |
485 } // namespace policy | 501 } // namespace policy |
OLD | NEW |