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), | |
259 is_initialized_(false), | 219 is_initialized_(false), |
260 has_initial_keys_(false), | 220 has_credentials_(false), |
261 weak_ptr_factory_(this) { | 221 weak_ptr_factory_(this) { |
| 222 schema_registry_->AddObserver(this); |
262 store_->AddObserver(this); | 223 store_->AddObserver(this); |
| 224 client_->AddObserver(this); |
263 | 225 |
264 backend_.reset(new Backend(weak_ptr_factory_.GetWeakPtr(), | 226 external_policy_data_fetcher_backend_.reset( |
265 backend_task_runner_, | 227 new ExternalPolicyDataFetcherBackend(io_task_runner_, request_context)); |
266 base::MessageLoopProxy::current(), | 228 |
267 cache.Pass())); | 229 backend_.reset( |
268 backend_task_runner_->PostTask( | 230 new Backend(weak_ptr_factory_.GetWeakPtr(), |
269 FROM_HERE, base::Bind(&Backend::Init, base::Unretained(backend_.get()))); | 231 backend_task_runner_, |
| 232 base::MessageLoopProxy::current(), |
| 233 cache.Pass(), |
| 234 external_policy_data_fetcher_backend_->CreateFrontend( |
| 235 backend_task_runner_))); |
270 | 236 |
271 if (store_->is_initialized()) | 237 if (store_->is_initialized()) |
272 InitializeBackend(); | 238 OnStoreLoaded(store_); |
273 } | 239 } |
274 | 240 |
275 ComponentCloudPolicyService::~ComponentCloudPolicyService() { | 241 ComponentCloudPolicyService::~ComponentCloudPolicyService() { |
276 DCHECK(CalledOnValidThread()); | 242 DCHECK(CalledOnValidThread()); |
| 243 schema_registry_->RemoveObserver(this); |
277 store_->RemoveObserver(this); | 244 store_->RemoveObserver(this); |
278 if (client_) | 245 client_->RemoveObserver(this); |
279 client_->RemoveObserver(this); | 246 |
| 247 // Remove all the namespaces from |client_| but don't send this empty schema |
| 248 // to the backend, to avoid dropping the caches. |
| 249 if (is_initialized()) { |
| 250 scoped_refptr<SchemaMap> empty(new SchemaMap); |
| 251 SetCurrentSchema(empty, false); |
| 252 } |
| 253 |
280 io_task_runner_->DeleteSoon(FROM_HERE, | 254 io_task_runner_->DeleteSoon(FROM_HERE, |
281 external_policy_data_fetcher_backend_.release()); | 255 external_policy_data_fetcher_backend_.release()); |
282 backend_task_runner_->DeleteSoon(FROM_HERE, backend_.release()); | 256 backend_task_runner_->DeleteSoon(FROM_HERE, backend_.release()); |
283 } | 257 } |
284 | 258 |
285 // static | 259 // static |
286 bool ComponentCloudPolicyService::SupportsDomain(PolicyDomain domain) { | 260 bool ComponentCloudPolicyService::SupportsDomain(PolicyDomain domain) { |
287 return ComponentCloudPolicyStore::SupportsDomain(domain); | 261 return ComponentCloudPolicyStore::SupportsDomain(domain); |
288 } | 262 } |
289 | 263 |
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) { | 264 void ComponentCloudPolicyService::OnPolicyFetched(CloudPolicyClient* client) { |
364 DCHECK(CalledOnValidThread()); | 265 DCHECK(CalledOnValidThread()); |
365 DCHECK_EQ(client_, client); | 266 DCHECK_EQ(client_, client); |
| 267 |
| 268 if (!is_initialized() || !has_credentials_) |
| 269 return; |
| 270 |
366 // Pass each PolicyFetchResponse whose policy type is registered to the | 271 // Pass each PolicyFetchResponse whose policy type is registered to the |
367 // Backend. | 272 // Backend. |
368 const CloudPolicyClient::ResponseMap& responses = client_->responses(); | 273 const CloudPolicyClient::ResponseMap& responses = client_->responses(); |
369 for (CloudPolicyClient::ResponseMap::const_iterator it = responses.begin(); | 274 for (CloudPolicyClient::ResponseMap::const_iterator it = responses.begin(); |
370 it != responses.end(); ++it) { | 275 it != responses.end(); ++it) { |
371 const PolicyNamespaceKey& key(it->first); | 276 PolicyNamespace ns; |
372 if (ContainsKey(keys_, key)) { | 277 if (ToPolicyNamespace(it->first, &ns) && |
| 278 current_schema_map_->GetSchema(ns)) { |
373 scoped_ptr<em::PolicyFetchResponse> response( | 279 scoped_ptr<em::PolicyFetchResponse> response( |
374 new em::PolicyFetchResponse(*it->second)); | 280 new em::PolicyFetchResponse(*it->second)); |
375 backend_task_runner_->PostTask( | 281 backend_task_runner_->PostTask( |
376 FROM_HERE, | 282 FROM_HERE, |
377 base::Bind(&Backend::UpdateExternalPolicy, | 283 base::Bind(&Backend::UpdateExternalPolicy, |
378 base::Unretained(backend_.get()), | 284 base::Unretained(backend_.get()), |
379 base::Passed(&response))); | 285 base::Passed(&response))); |
380 } | 286 } |
381 } | 287 } |
382 } | 288 } |
383 | 289 |
384 void ComponentCloudPolicyService::OnRegistrationStateChanged( | 290 void ComponentCloudPolicyService::OnRegistrationStateChanged( |
385 CloudPolicyClient* client) { | 291 CloudPolicyClient* client) { |
386 DCHECK(CalledOnValidThread()); | 292 DCHECK(CalledOnValidThread()); |
387 // Ignored. | 293 // Ignored. |
388 } | 294 } |
389 | 295 |
390 void ComponentCloudPolicyService::OnClientError(CloudPolicyClient* client) { | 296 void ComponentCloudPolicyService::OnClientError(CloudPolicyClient* client) { |
391 DCHECK(CalledOnValidThread()); | 297 DCHECK(CalledOnValidThread()); |
392 // Ignored. | 298 // Ignored. |
393 } | 299 } |
394 | 300 |
395 void ComponentCloudPolicyService::OnStoreLoaded(CloudPolicyStore* store) { | 301 void ComponentCloudPolicyService::OnStoreLoaded(CloudPolicyStore* store) { |
396 DCHECK(CalledOnValidThread()); | 302 DCHECK(CalledOnValidThread()); |
397 DCHECK_EQ(store_, store); | 303 DCHECK_EQ(store_, store); |
398 if (store_->is_initialized()) { | 304 |
| 305 if (!store_->is_initialized()) |
| 306 return; |
| 307 |
| 308 const em::PolicyData* policy = store_->policy(); |
| 309 if (!has_credentials_ && policy && policy->has_username() && |
| 310 policy->has_request_token()) { |
| 311 // Send the current credentials to the backend, if they haven't been sent |
| 312 // before. Usually this happens at startup if the user already had a cached |
| 313 // cloud policy; otherwise it happens right after the initial registration |
| 314 // for cloud policy. |
| 315 backend_task_runner_->PostTask(FROM_HERE, |
| 316 base::Bind(&Backend::SetCredentials, |
| 317 base::Unretained(backend_.get()), |
| 318 policy->username(), |
| 319 policy->request_token())); |
| 320 has_credentials_ = true; |
399 if (is_initialized()) { | 321 if (is_initialized()) { |
400 // The backend is already initialized; update the credentials, in case | 322 // This was the first policy fetch for this client. Process any |
401 // a new dmtoken or server key became available. | 323 // PolicyFetchResponses that the client may have now; processing them |
402 SetCredentialsAndReloadClient(); | 324 // before the credentials were sent to the backend would fail validation. |
403 } else { | 325 OnPolicyFetched(client_); |
404 // The |store_| just became ready; initialize the backend now. | |
405 InitializeBackend(); | |
406 } | 326 } |
407 } | 327 } |
| 328 |
| 329 if (!is_initialized()) |
| 330 InitializeIfReady(); |
408 } | 331 } |
409 | 332 |
410 void ComponentCloudPolicyService::OnStoreError(CloudPolicyStore* store) { | 333 void ComponentCloudPolicyService::OnStoreError(CloudPolicyStore* store) { |
411 DCHECK(CalledOnValidThread()); | 334 DCHECK(CalledOnValidThread()); |
412 OnStoreLoaded(store); | 335 OnStoreLoaded(store); |
413 } | 336 } |
414 | 337 |
415 void ComponentCloudPolicyService::InitializeBackend() { | 338 void ComponentCloudPolicyService::OnSchemaRegistryReady() { |
416 DCHECK(CalledOnValidThread()); | 339 DCHECK(CalledOnValidThread()); |
417 DCHECK(!is_initialized()); | 340 InitializeIfReady(); |
418 DCHECK(store_->is_initialized()); | 341 } |
419 | 342 |
420 // Set the credentials for the initial policy load, if available. | 343 void ComponentCloudPolicyService::OnSchemaRegistryUpdated( |
421 SetCredentialsAndReloadClient(); | 344 bool has_new_schemas) { |
| 345 DCHECK(CalledOnValidThread()); |
422 | 346 |
423 backend_task_runner_->PostTask( | 347 if (!is_initialized()) |
| 348 return; |
| 349 |
| 350 // When an extension is reloaded or updated, it triggers an unregister quickly |
| 351 // followed by a register in the SchemaRegistry. If the intermediate version |
| 352 // of the SchemaMap is passed to the backend then it will drop the cached |
| 353 // policy for that extension and will trigger a new policy fetch soon after. |
| 354 // Delaying the schema update here coalesces both updates into one, and the |
| 355 // new schema will equal the older version in case of extension updates. |
| 356 // |
| 357 // TODO(joaodasilva): Increase this delay to 10 seconds. For now it's |
| 358 // immediate so that tests don't get delayed. |
| 359 schema_update_timer_.Start( |
424 FROM_HERE, | 360 FROM_HERE, |
425 base::Bind(&Backend::FinalizeInit, base::Unretained(backend_.get()))); | 361 base::TimeDelta::FromSeconds(0), |
| 362 base::Bind(&ComponentCloudPolicyService::SetCurrentSchema, |
| 363 base::Unretained(this), |
| 364 schema_registry_->schema_map(), |
| 365 true)); |
| 366 } |
| 367 |
| 368 void ComponentCloudPolicyService::InitializeIfReady() { |
| 369 DCHECK(CalledOnValidThread()); |
| 370 if (!schema_registry_->IsReady() || !store_->is_initialized()) |
| 371 return; |
| 372 backend_task_runner_->PostTask(FROM_HERE, |
| 373 base::Bind(&Backend::Init, |
| 374 base::Unretained(backend_.get()), |
| 375 schema_registry_->schema_map())); |
426 } | 376 } |
427 | 377 |
428 void ComponentCloudPolicyService::OnBackendInitialized( | 378 void ComponentCloudPolicyService::OnBackendInitialized( |
429 scoped_ptr<PolicyNamespaceKeys> initial_keys, | |
430 scoped_ptr<PolicyBundle> initial_policy) { | 379 scoped_ptr<PolicyBundle> initial_policy) { |
431 DCHECK(CalledOnValidThread()); | 380 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 | 381 |
437 // OnSchemasUpdated() may have been called while the backend was initializing; | 382 is_initialized_ = true; |
438 // in that case ignore the cached keys. | |
439 if (!has_initial_keys_) | |
440 keys_.swap(*initial_keys); | |
441 | 383 |
442 // A client may have already connected while the backend was initializing. | 384 // Send the current schema to the backend, in case it has changed while the |
443 if (client_) | 385 // backend was initializing. |
444 InitializeClient(); | 386 SetCurrentSchema(schema_registry_->schema_map(), true); |
445 | 387 |
446 // Set the initial policy, and send the initial update callback. | 388 // Process any PolicyFetchResponses that the client may already have, or that |
447 is_initialized_ = true; | 389 // may have been received while the backend was initializing. |
| 390 OnPolicyFetched(client_); |
| 391 |
| 392 // Finally tell the Delegate that the initial policy is available. |
448 OnPolicyUpdated(initial_policy.Pass()); | 393 OnPolicyUpdated(initial_policy.Pass()); |
449 } | 394 } |
450 | 395 |
451 void ComponentCloudPolicyService::InitializeClient() { | 396 void ComponentCloudPolicyService::SetCurrentSchema( |
| 397 const scoped_refptr<SchemaMap>& new_schema_map, |
| 398 bool send_to_backend) { |
452 DCHECK(CalledOnValidThread()); | 399 DCHECK(CalledOnValidThread()); |
453 // Register all the current components. | 400 DCHECK(is_initialized()); |
454 AddNamespacesToFetch(keys_); | 401 |
455 // The client may already have PolicyFetchResponses for registered components; | 402 scoped_ptr<PolicyNamespaceList> removed(new PolicyNamespaceList); |
456 // load them now. | 403 PolicyNamespaceList added; |
457 OnPolicyFetched(client_); | 404 new_schema_map->GetChanges(current_schema_map_, removed.get(), &added); |
458 if (!keys_.empty() && is_initialized()) | 405 |
| 406 current_schema_map_ = new_schema_map; |
| 407 |
| 408 for (size_t i = 0; i < removed->size(); ++i) { |
| 409 PolicyNamespaceKey key; |
| 410 if (ToPolicyNamespaceKey((*removed)[i], &key)) |
| 411 client_->RemoveNamespaceToFetch(key); |
| 412 } |
| 413 |
| 414 bool added_namespaces_to_client = false; |
| 415 for (size_t i = 0; i < added.size(); ++i) { |
| 416 PolicyNamespaceKey key; |
| 417 if (ToPolicyNamespaceKey(added[i], &key)) { |
| 418 client_->AddNamespaceToFetch(key); |
| 419 added_namespaces_to_client = true; |
| 420 } |
| 421 } |
| 422 |
| 423 if (added_namespaces_to_client) |
459 delegate_->OnComponentCloudPolicyRefreshNeeded(); | 424 delegate_->OnComponentCloudPolicyRefreshNeeded(); |
| 425 |
| 426 if (send_to_backend) { |
| 427 backend_task_runner_->PostTask(FROM_HERE, |
| 428 base::Bind(&Backend::OnSchemasUpdated, |
| 429 base::Unretained(backend_.get()), |
| 430 current_schema_map_, |
| 431 base::Passed(&removed))); |
| 432 } |
460 } | 433 } |
461 | 434 |
462 void ComponentCloudPolicyService::OnPolicyUpdated( | 435 void ComponentCloudPolicyService::OnPolicyUpdated( |
463 scoped_ptr<PolicyBundle> policy) { | 436 scoped_ptr<PolicyBundle> policy) { |
464 DCHECK(CalledOnValidThread()); | 437 DCHECK(CalledOnValidThread()); |
465 policy_.Swap(policy.get()); | 438 policy_.Swap(policy.get()); |
466 // Don't propagate updates until the initial store Load() has been done. | 439 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 } | 440 } |
520 | 441 |
521 } // namespace policy | 442 } // namespace policy |
OLD | NEW |