OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 // Most of this code is copied from: | 5 // Most of this code is copied from: |
6 // src/chrome/browser/policy/asynchronous_policy_loader.{h,cc} | 6 // src/chrome/browser/policy/asynchronous_policy_loader.{h,cc} |
7 | 7 |
8 #include "remoting/host/policy_watcher.h" | 8 #include "remoting/host/policy_watcher.h" |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
15 #include "base/values.h" | 15 #include "base/values.h" |
16 #include "components/policy/core/common/async_policy_loader.h" | 16 #include "components/policy/core/common/async_policy_loader.h" |
17 #include "components/policy/core/common/async_policy_provider.h" | 17 #include "components/policy/core/common/async_policy_provider.h" |
18 #include "components/policy/core/common/policy_namespace.h" | 18 #include "components/policy/core/common/policy_namespace.h" |
19 #include "components/policy/core/common/policy_service_impl.h" | 19 #include "components/policy/core/common/policy_service_impl.h" |
20 #include "components/policy/core/common/schema.h" | 20 #include "components/policy/core/common/schema.h" |
21 #include "components/policy/core/common/schema_registry.h" | 21 #include "components/policy/core/common/schema_registry.h" |
22 #include "policy/policy_constants.h" | 22 #include "policy/policy_constants.h" |
23 #include "remoting/host/dns_blackhole_checker.h" | 23 #include "remoting/host/dns_blackhole_checker.h" |
24 #include "remoting/host/third_party_auth_config.h" | |
25 #include "remoting/protocol/port_range.h" | |
24 | 26 |
25 #if !defined(NDEBUG) | 27 #if !defined(NDEBUG) |
26 #include "base/json/json_reader.h" | 28 #include "base/json/json_reader.h" |
27 #endif | 29 #endif |
28 | 30 |
29 #if defined(OS_WIN) | 31 #if defined(OS_WIN) |
30 #include "components/policy/core/common/policy_loader_win.h" | 32 #include "components/policy/core/common/policy_loader_win.h" |
31 #elif defined(OS_MACOSX) | 33 #elif defined(OS_MACOSX) |
32 #include "components/policy/core/common/policy_loader_mac.h" | 34 #include "components/policy/core/common/policy_loader_mac.h" |
33 #include "components/policy/core/common/preferences_mac.h" | 35 #include "components/policy/core/common/preferences_mac.h" |
34 #elif defined(OS_POSIX) && !defined(OS_ANDROID) | 36 #elif defined(OS_POSIX) && !defined(OS_ANDROID) |
35 #include "components/policy/core/common/config_dir_policy_loader.h" | 37 #include "components/policy/core/common/config_dir_policy_loader.h" |
36 #endif | 38 #endif |
37 | 39 |
38 namespace remoting { | 40 namespace remoting { |
39 | 41 |
40 namespace key = ::policy::key; | 42 namespace key = ::policy::key; |
41 | 43 |
42 namespace { | 44 namespace { |
43 | 45 |
44 // Copies all policy values from one dictionary to another, using values from | 46 // Copies all policy values from one dictionary to another, using values from |
45 // |default_values| if they are not set in |from|. | 47 // |default_values| if they are not set in |from|. |
46 scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults( | 48 scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults( |
47 const base::DictionaryValue* from, | 49 const base::DictionaryValue& from, |
48 const base::DictionaryValue* default_values) { | 50 const base::DictionaryValue& default_values) { |
49 scoped_ptr<base::DictionaryValue> to(default_values->DeepCopy()); | 51 scoped_ptr<base::DictionaryValue> to(default_values.DeepCopy()); |
50 for (base::DictionaryValue::Iterator i(*default_values); !i.IsAtEnd(); | 52 for (base::DictionaryValue::Iterator i(default_values); !i.IsAtEnd(); |
51 i.Advance()) { | 53 i.Advance()) { |
52 const base::Value* value = nullptr; | 54 const base::Value* value = nullptr; |
53 | 55 |
54 // If the policy isn't in |from|, use the default. | 56 // If the policy isn't in |from|, use the default. |
55 if (!from->Get(i.key(), &value)) { | 57 if (!from.Get(i.key(), &value)) { |
56 continue; | 58 continue; |
57 } | 59 } |
58 | 60 |
59 CHECK(value->IsType(i.value().GetType())); | 61 CHECK(value->IsType(i.value().GetType())); |
60 to->Set(i.key(), value->DeepCopy()); | 62 to->Set(i.key(), value->DeepCopy()); |
61 } | 63 } |
62 | 64 |
63 #if !defined(NDEBUG) | 65 #if !defined(NDEBUG) |
64 // Replace values with those specified in DebugOverridePolicies, if present. | 66 // Replace values with those specified in DebugOverridePolicies, if present. |
65 std::string policy_overrides; | 67 std::string policy_overrides; |
66 if (from->GetString(key::kRemoteAccessHostDebugOverridePolicies, | 68 if (from.GetString(key::kRemoteAccessHostDebugOverridePolicies, |
67 &policy_overrides)) { | 69 &policy_overrides)) { |
68 scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides)); | 70 scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides)); |
69 const base::DictionaryValue* override_values; | 71 const base::DictionaryValue* override_values; |
70 if (value && value->GetAsDictionary(&override_values)) { | 72 if (value && value->GetAsDictionary(&override_values)) { |
71 to->MergeDictionary(override_values); | 73 to->MergeDictionary(override_values); |
72 } | 74 } |
73 } | 75 } |
74 #endif // defined(NDEBUG) | 76 #endif // defined(NDEBUG) |
75 | 77 |
76 return to.Pass(); | 78 return to.Pass(); |
77 } | 79 } |
78 | 80 |
79 policy::PolicyNamespace GetPolicyNamespace() { | 81 policy::PolicyNamespace GetPolicyNamespace() { |
80 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()); | 82 return policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()); |
81 } | 83 } |
82 | 84 |
83 scoped_ptr<policy::SchemaRegistry> CreateSchemaRegistry() { | 85 scoped_ptr<policy::SchemaRegistry> CreateSchemaRegistry() { |
84 // TODO(lukasza): Schema below should ideally only cover Chromoting-specific | 86 // TODO(lukasza): Schema below should ideally only cover Chromoting-specific |
85 // policies (expecting perf and maintanability improvement, but no functional | 87 // policies (expecting perf and maintanability improvement, but no functional |
86 // impact). | 88 // impact). |
87 policy::Schema schema = policy::Schema::Wrap(policy::GetChromeSchemaData()); | 89 policy::Schema schema = policy::Schema::Wrap(policy::GetChromeSchemaData()); |
88 | 90 |
89 scoped_ptr<policy::SchemaRegistry> schema_registry( | 91 scoped_ptr<policy::SchemaRegistry> schema_registry( |
90 new policy::SchemaRegistry()); | 92 new policy::SchemaRegistry()); |
91 schema_registry->RegisterComponent(GetPolicyNamespace(), schema); | 93 schema_registry->RegisterComponent(GetPolicyNamespace(), schema); |
92 return schema_registry.Pass(); | 94 return schema_registry.Pass(); |
93 } | 95 } |
94 | 96 |
97 scoped_ptr<base::DictionaryValue> CopyChromotingPoliciesIntoDictionary( | |
98 const policy::PolicyMap& current) { | |
99 const char kPolicyNamePrefix[] = "RemoteAccessHost"; | |
100 scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue()); | |
101 for (auto it = current.begin(); it != current.end(); ++it) { | |
102 const std::string& key = it->first; | |
103 const base::Value* value = it->second.value; | |
104 | |
105 // Copying only Chromoting-specific policies helps avoid false alarms | |
106 // raised by NormalizePolicies below (such alarms shutdown the host). | |
107 // TODO(lukasza): Removing this somewhat brittle filtering will be possible | |
108 // after having separate, Chromoting-specific schema. | |
109 if (key.find(kPolicyNamePrefix) != std::string::npos) { | |
rmsousa
2015/02/27 23:56:14
doesn't prefix imply key.find must be 0?
Łukasz Anforowicz
2015/03/02 17:34:47
I'll rename "prefix" to "substring". This is real
| |
110 policy_dict->Set(key, value->DeepCopy()); | |
111 } | |
112 } | |
113 | |
114 return policy_dict.Pass(); | |
115 } | |
116 | |
117 // Takes a dictionary containing only 1) recognized policy names and 2) | |
118 // well-typed policy values and further verifies policy contents. | |
119 bool VerifyWellformedness(const base::DictionaryValue& changed_policies) { | |
120 // Verify ThirdPartyAuthConfig policies. | |
121 std::string token_url; | |
122 std::string token_validation_url; | |
123 std::string token_validation_cert_issuer; | |
124 bool changed_entries_present = ThirdPartyAuthConfig::ExtractPolicyValues( | |
125 changed_policies, &token_url, &token_validation_url, | |
126 &token_validation_cert_issuer); | |
127 ThirdPartyAuthConfig third_party_auth_config; | |
128 if (changed_entries_present && | |
129 !ThirdPartyAuthConfig::Parse(token_url, token_validation_url, | |
130 token_validation_cert_issuer, | |
131 &third_party_auth_config)) { | |
132 return false; | |
133 } | |
134 | |
135 // Verify UdpPortRange policy. | |
136 std::string udp_port_range_string; | |
137 PortRange udp_port_range; | |
138 if (changed_policies.GetString(policy::key::kRemoteAccessHostUdpPortRange, | |
139 &udp_port_range_string)) { | |
140 if (!PortRange::Parse(udp_port_range_string, &udp_port_range)) { | |
141 return false; | |
142 } | |
143 } | |
144 | |
145 // Report that all the policies were well-formed. | |
146 return true; | |
147 } | |
148 | |
95 } // namespace | 149 } // namespace |
96 | 150 |
97 void PolicyWatcher::StartWatching( | 151 void PolicyWatcher::StartWatching( |
98 const PolicyUpdatedCallback& policy_updated_callback, | 152 const PolicyUpdatedCallback& policy_updated_callback, |
99 const PolicyErrorCallback& policy_error_callback) { | 153 const PolicyErrorCallback& policy_error_callback) { |
100 DCHECK(CalledOnValidThread()); | 154 DCHECK(CalledOnValidThread()); |
101 DCHECK(!policy_updated_callback.is_null()); | 155 DCHECK(!policy_updated_callback.is_null()); |
102 DCHECK(!policy_error_callback.is_null()); | 156 DCHECK(!policy_error_callback.is_null()); |
103 DCHECK(policy_updated_callback_.is_null()); | 157 DCHECK(policy_updated_callback_.is_null()); |
104 | 158 |
105 policy_updated_callback_ = policy_updated_callback; | 159 policy_updated_callback_ = policy_updated_callback; |
106 policy_error_callback_ = policy_error_callback; | 160 policy_error_callback_ = policy_error_callback; |
107 | 161 |
108 // Listen for future policy changes. | 162 // Listen for future policy changes. |
109 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this); | 163 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this); |
110 | 164 |
111 // Process current policy state. | 165 // Process current policy state. |
112 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) { | 166 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) { |
113 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME); | 167 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME); |
114 } | 168 } |
115 } | 169 } |
116 | 170 |
117 void PolicyWatcher::UpdatePolicies( | |
118 const base::DictionaryValue* new_policies_raw) { | |
119 DCHECK(CalledOnValidThread()); | |
120 | |
121 // Use default values for any missing policies. | |
122 scoped_ptr<base::DictionaryValue> new_policies = | |
123 CopyValuesAndAddDefaults(new_policies_raw, default_values_.get()); | |
124 | |
125 // Find the changed policies. | |
126 scoped_ptr<base::DictionaryValue> changed_policies( | |
127 new base::DictionaryValue()); | |
128 base::DictionaryValue::Iterator iter(*new_policies); | |
129 while (!iter.IsAtEnd()) { | |
130 base::Value* old_policy; | |
131 if (!(old_policies_->Get(iter.key(), &old_policy) && | |
132 old_policy->Equals(&iter.value()))) { | |
133 changed_policies->Set(iter.key(), iter.value().DeepCopy()); | |
134 } | |
135 iter.Advance(); | |
136 } | |
137 | |
138 // Save the new policies. | |
139 old_policies_.swap(new_policies); | |
140 | |
141 // Notify our client of the changed policies. | |
142 if (!changed_policies->empty()) { | |
143 policy_updated_callback_.Run(changed_policies.Pass()); | |
144 } | |
145 } | |
146 | |
147 void PolicyWatcher::SignalPolicyError() { | 171 void PolicyWatcher::SignalPolicyError() { |
148 old_policies_->Clear(); | 172 old_policies_->Clear(); |
149 policy_error_callback_.Run(); | 173 policy_error_callback_.Run(); |
150 } | 174 } |
151 | 175 |
152 PolicyWatcher::PolicyWatcher( | 176 PolicyWatcher::PolicyWatcher( |
153 policy::PolicyService* policy_service, | 177 policy::PolicyService* policy_service, |
154 scoped_ptr<policy::PolicyService> owned_policy_service, | 178 scoped_ptr<policy::PolicyService> owned_policy_service, |
155 scoped_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider, | 179 scoped_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider, |
156 scoped_ptr<policy::SchemaRegistry> owned_schema_registry) | 180 scoped_ptr<policy::SchemaRegistry> owned_schema_registry) |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
194 | 218 |
195 if (owned_policy_provider_) { | 219 if (owned_policy_provider_) { |
196 owned_policy_provider_->Shutdown(); | 220 owned_policy_provider_->Shutdown(); |
197 } | 221 } |
198 } | 222 } |
199 | 223 |
200 const policy::Schema* PolicyWatcher::GetPolicySchema() const { | 224 const policy::Schema* PolicyWatcher::GetPolicySchema() const { |
201 return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace()); | 225 return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace()); |
202 } | 226 } |
203 | 227 |
204 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, | 228 bool PolicyWatcher::NormalizePolicies(base::DictionaryValue* policy_dict) { |
205 const policy::PolicyMap& previous, | |
206 const policy::PolicyMap& current) { | |
207 const char kPolicyNamePrefix[] = "RemoteAccessHost"; | |
208 scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue()); | |
209 for (auto it = current.begin(); it != current.end(); ++it) { | |
210 const std::string& key = it->first; | |
211 const base::Value* value = it->second.value; | |
212 | |
213 // Copying only Chromoting-specific policies helps avoid false alarms | |
214 // raised by Schema::Normalize below (such alarms shutdown the host). | |
215 // TODO(lukasza): Removing this somewhat brittle filtering will be possible | |
216 // after having separate, Chromoting-specific schema. | |
217 if (key.find(kPolicyNamePrefix) != std::string::npos) { | |
218 policy_dict->Set(key, value->DeepCopy()); | |
219 } | |
220 } | |
221 | |
222 // Allowing unrecognized policy names allows presence of | 229 // Allowing unrecognized policy names allows presence of |
223 // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }), | 230 // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }), |
224 // 2) policies intended for future/newer versions of the host, | 231 // 2) policies intended for future/newer versions of the host, |
225 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername | 232 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername |
226 // is not supported on Windows and therefore policy_templates.json omits | 233 // is not supported on Windows and therefore policy_templates.json omits |
227 // schema for this policy on this particular platform). | 234 // schema for this policy on this particular platform). |
228 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN_TOPLEVEL; | 235 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN_TOPLEVEL; |
229 | 236 |
230 std::string path; | 237 std::string path; |
231 std::string error; | 238 std::string error; |
232 bool changed = false; | 239 bool changed = false; |
233 const policy::Schema* schema = GetPolicySchema(); | 240 const policy::Schema* schema = GetPolicySchema(); |
234 if (schema->Normalize(policy_dict.get(), strategy, &path, &error, &changed)) { | 241 if (schema->Normalize(policy_dict, strategy, &path, &error, &changed)) { |
235 if (changed) { | 242 if (changed) { |
236 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path | 243 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path |
237 << ": " << error; | 244 << ": " << error; |
238 } | 245 } |
239 UpdatePolicies(policy_dict.get()); | 246 return true; |
240 } else { | 247 } else { |
241 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error; | 248 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error; |
242 SignalPolicyError(); | 249 return false; |
243 } | 250 } |
244 } | 251 } |
245 | 252 |
253 namespace { | |
254 void CopyDictionaryValue(const base::DictionaryValue& from, | |
255 base::DictionaryValue& to, | |
256 std::string key) { | |
257 const base::Value* value; | |
258 if (from.Get(key, &value)) { | |
259 to.Set(key, value->DeepCopy()); | |
260 } | |
261 } | |
262 } // namespace | |
263 | |
264 scoped_ptr<base::DictionaryValue> | |
265 PolicyWatcher::StoreNewAndReturnChangedPolicies( | |
266 scoped_ptr<base::DictionaryValue> new_policies) { | |
267 // Find the changed policies. | |
268 scoped_ptr<base::DictionaryValue> changed_policies( | |
269 new base::DictionaryValue()); | |
270 base::DictionaryValue::Iterator iter(*new_policies); | |
271 while (!iter.IsAtEnd()) { | |
272 base::Value* old_policy; | |
273 if (!(old_policies_->Get(iter.key(), &old_policy) && | |
274 old_policy->Equals(&iter.value()))) { | |
275 changed_policies->Set(iter.key(), iter.value().DeepCopy()); | |
276 } | |
277 iter.Advance(); | |
278 } | |
279 | |
280 // If one of ThirdPartyAuthConfig policies changed, we need to include all. | |
281 if (changed_policies->HasKey(key::kRemoteAccessHostTokenUrl) || | |
282 changed_policies->HasKey(key::kRemoteAccessHostTokenValidationUrl) || | |
283 changed_policies->HasKey( | |
284 key::kRemoteAccessHostTokenValidationCertificateIssuer)) { | |
285 CopyDictionaryValue(*new_policies, *changed_policies, | |
286 key::kRemoteAccessHostTokenUrl); | |
287 CopyDictionaryValue(*new_policies, *changed_policies, | |
288 key::kRemoteAccessHostTokenValidationUrl); | |
289 CopyDictionaryValue(*new_policies, *changed_policies, | |
290 key::kRemoteAccessHostTokenValidationCertificateIssuer); | |
291 } | |
292 | |
293 // Save the new policies. | |
294 old_policies_.swap(new_policies); | |
295 | |
296 return changed_policies.Pass(); | |
297 } | |
298 | |
299 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, | |
300 const policy::PolicyMap& previous, | |
301 const policy::PolicyMap& current) { | |
302 scoped_ptr<base::DictionaryValue> new_policies = | |
303 CopyChromotingPoliciesIntoDictionary(current); | |
304 | |
305 // Check for mistyped values and get rid of unknown policies. | |
306 if (!NormalizePolicies(new_policies.get())) { | |
307 SignalPolicyError(); | |
308 return; | |
309 } | |
310 | |
311 // Use default values for any missing policies. | |
312 scoped_ptr<base::DictionaryValue> filled_policies = | |
313 CopyValuesAndAddDefaults(*new_policies, *default_values_); | |
314 | |
315 // Limit reporting to only the policies that were changed. | |
316 scoped_ptr<base::DictionaryValue> changed_policies = | |
317 StoreNewAndReturnChangedPolicies(filled_policies.Pass()); | |
318 if (changed_policies->empty()) { | |
319 return; | |
320 } | |
321 | |
322 // Verify that we are calling the callback with valid policies. | |
323 if (!VerifyWellformedness(*changed_policies)) { | |
324 SignalPolicyError(); | |
325 return; | |
326 } | |
327 | |
328 // Notify our client of the changed policies. | |
329 policy_updated_callback_.Run(changed_policies.Pass()); | |
330 } | |
331 | |
246 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) { | 332 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) { |
247 policy::PolicyNamespace ns = GetPolicyNamespace(); | 333 policy::PolicyNamespace ns = GetPolicyNamespace(); |
248 const policy::PolicyMap& current = policy_service_->GetPolicies(ns); | 334 const policy::PolicyMap& current = policy_service_->GetPolicies(ns); |
249 OnPolicyUpdated(ns, current, current); | 335 OnPolicyUpdated(ns, current, current); |
250 } | 336 } |
251 | 337 |
252 scoped_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader( | 338 scoped_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader( |
253 scoped_ptr<policy::AsyncPolicyLoader> async_policy_loader) { | 339 scoped_ptr<policy::AsyncPolicyLoader> async_policy_loader) { |
254 scoped_ptr<policy::SchemaRegistry> schema_registry = CreateSchemaRegistry(); | 340 scoped_ptr<policy::SchemaRegistry> schema_registry = CreateSchemaRegistry(); |
255 scoped_ptr<policy::AsyncPolicyProvider> policy_provider( | 341 scoped_ptr<policy::AsyncPolicyProvider> policy_provider( |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
300 policy::POLICY_SCOPE_MACHINE)); | 386 policy::POLICY_SCOPE_MACHINE)); |
301 #else | 387 #else |
302 #error OS that is not yet supported by PolicyWatcher code. | 388 #error OS that is not yet supported by PolicyWatcher code. |
303 #endif | 389 #endif |
304 | 390 |
305 return PolicyWatcher::CreateFromPolicyLoader(policy_loader.Pass()); | 391 return PolicyWatcher::CreateFromPolicyLoader(policy_loader.Pass()); |
306 #endif // !(OS_CHROMEOS) | 392 #endif // !(OS_CHROMEOS) |
307 } | 393 } |
308 | 394 |
309 } // namespace remoting | 395 } // namespace remoting |
OLD | NEW |