Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: remoting/host/policy_watcher.cc

Issue 966433002: Malformed PortRange or ThirdPartyAuthConfig trigger OnPolicyError. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing a Windows-specific, pre-processor-related build break. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/host/policy_watcher.h ('k') | remoting/host/policy_watcher_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 kPolicyNameSubstring[] = "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(kPolicyNameSubstring) != std::string::npos) {
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 policy.
121 ThirdPartyAuthConfig not_used;
122 switch (ThirdPartyAuthConfig::Parse(changed_policies, &not_used)) {
123 case ThirdPartyAuthConfig::NoPolicy:
124 case ThirdPartyAuthConfig::ParsingSuccess:
125 break; // Well-formed.
126 case ThirdPartyAuthConfig::InvalidPolicy:
127 return false; // Malformed.
128 default:
129 NOTREACHED();
130 return false;
131 }
132
133 // Verify UdpPortRange policy.
134 std::string udp_port_range_string;
135 PortRange udp_port_range;
136 if (changed_policies.GetString(policy::key::kRemoteAccessHostUdpPortRange,
137 &udp_port_range_string)) {
138 if (!PortRange::Parse(udp_port_range_string, &udp_port_range)) {
139 return false;
140 }
141 }
142
143 // Report that all the policies were well-formed.
144 return true;
145 }
146
95 } // namespace 147 } // namespace
96 148
97 void PolicyWatcher::StartWatching( 149 void PolicyWatcher::StartWatching(
98 const PolicyUpdatedCallback& policy_updated_callback, 150 const PolicyUpdatedCallback& policy_updated_callback,
99 const PolicyErrorCallback& policy_error_callback) { 151 const PolicyErrorCallback& policy_error_callback) {
100 DCHECK(CalledOnValidThread()); 152 DCHECK(CalledOnValidThread());
101 DCHECK(!policy_updated_callback.is_null()); 153 DCHECK(!policy_updated_callback.is_null());
102 DCHECK(!policy_error_callback.is_null()); 154 DCHECK(!policy_error_callback.is_null());
103 DCHECK(policy_updated_callback_.is_null()); 155 DCHECK(policy_updated_callback_.is_null());
104 156
105 policy_updated_callback_ = policy_updated_callback; 157 policy_updated_callback_ = policy_updated_callback;
106 policy_error_callback_ = policy_error_callback; 158 policy_error_callback_ = policy_error_callback;
107 159
108 // Listen for future policy changes. 160 // Listen for future policy changes.
109 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this); 161 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
110 162
111 // Process current policy state. 163 // Process current policy state.
112 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) { 164 if (policy_service_->IsInitializationComplete(policy::POLICY_DOMAIN_CHROME)) {
113 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME); 165 OnPolicyServiceInitialized(policy::POLICY_DOMAIN_CHROME);
114 } 166 }
115 } 167 }
116 168
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() { 169 void PolicyWatcher::SignalPolicyError() {
148 old_policies_->Clear(); 170 old_policies_->Clear();
149 policy_error_callback_.Run(); 171 policy_error_callback_.Run();
150 } 172 }
151 173
152 PolicyWatcher::PolicyWatcher( 174 PolicyWatcher::PolicyWatcher(
153 policy::PolicyService* policy_service, 175 policy::PolicyService* policy_service,
154 scoped_ptr<policy::PolicyService> owned_policy_service, 176 scoped_ptr<policy::PolicyService> owned_policy_service,
155 scoped_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider, 177 scoped_ptr<policy::ConfigurationPolicyProvider> owned_policy_provider,
156 scoped_ptr<policy::SchemaRegistry> owned_schema_registry) 178 scoped_ptr<policy::SchemaRegistry> owned_schema_registry)
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 216
195 if (owned_policy_provider_) { 217 if (owned_policy_provider_) {
196 owned_policy_provider_->Shutdown(); 218 owned_policy_provider_->Shutdown();
197 } 219 }
198 } 220 }
199 221
200 const policy::Schema* PolicyWatcher::GetPolicySchema() const { 222 const policy::Schema* PolicyWatcher::GetPolicySchema() const {
201 return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace()); 223 return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace());
202 } 224 }
203 225
204 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, 226 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 227 // Allowing unrecognized policy names allows presence of
223 // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }), 228 // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }),
224 // 2) policies intended for future/newer versions of the host, 229 // 2) policies intended for future/newer versions of the host,
225 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername 230 // 3) policies not supported on all OS-s (i.e. RemoteAccessHostMatchUsername
226 // is not supported on Windows and therefore policy_templates.json omits 231 // is not supported on Windows and therefore policy_templates.json omits
227 // schema for this policy on this particular platform). 232 // schema for this policy on this particular platform).
228 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN_TOPLEVEL; 233 auto strategy = policy::SCHEMA_ALLOW_UNKNOWN_TOPLEVEL;
229 234
230 std::string path; 235 std::string path;
231 std::string error; 236 std::string error;
232 bool changed = false; 237 bool changed = false;
233 const policy::Schema* schema = GetPolicySchema(); 238 const policy::Schema* schema = GetPolicySchema();
234 if (schema->Normalize(policy_dict.get(), strategy, &path, &error, &changed)) { 239 if (schema->Normalize(policy_dict, strategy, &path, &error, &changed)) {
235 if (changed) { 240 if (changed) {
236 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path 241 LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path
237 << ": " << error; 242 << ": " << error;
238 } 243 }
239 UpdatePolicies(policy_dict.get()); 244 return true;
240 } else { 245 } else {
241 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error; 246 LOG(ERROR) << "Invalid policy contents: " << path << ": " << error;
242 SignalPolicyError(); 247 return false;
243 } 248 }
244 } 249 }
245 250
251 namespace {
252 void CopyDictionaryValue(const base::DictionaryValue& from,
253 base::DictionaryValue& to,
254 std::string key) {
255 const base::Value* value;
256 if (from.Get(key, &value)) {
257 to.Set(key, value->DeepCopy());
258 }
259 }
260 } // namespace
261
262 scoped_ptr<base::DictionaryValue>
263 PolicyWatcher::StoreNewAndReturnChangedPolicies(
264 scoped_ptr<base::DictionaryValue> new_policies) {
265 // Find the changed policies.
266 scoped_ptr<base::DictionaryValue> changed_policies(
267 new base::DictionaryValue());
268 base::DictionaryValue::Iterator iter(*new_policies);
269 while (!iter.IsAtEnd()) {
270 base::Value* old_policy;
271 if (!(old_policies_->Get(iter.key(), &old_policy) &&
272 old_policy->Equals(&iter.value()))) {
273 changed_policies->Set(iter.key(), iter.value().DeepCopy());
274 }
275 iter.Advance();
276 }
277
278 // If one of ThirdPartyAuthConfig policies changed, we need to include all.
279 if (changed_policies->HasKey(key::kRemoteAccessHostTokenUrl) ||
280 changed_policies->HasKey(key::kRemoteAccessHostTokenValidationUrl) ||
281 changed_policies->HasKey(
282 key::kRemoteAccessHostTokenValidationCertificateIssuer)) {
283 CopyDictionaryValue(*new_policies, *changed_policies,
284 key::kRemoteAccessHostTokenUrl);
285 CopyDictionaryValue(*new_policies, *changed_policies,
286 key::kRemoteAccessHostTokenValidationUrl);
287 CopyDictionaryValue(*new_policies, *changed_policies,
288 key::kRemoteAccessHostTokenValidationCertificateIssuer);
289 }
290
291 // Save the new policies.
292 old_policies_.swap(new_policies);
293
294 return changed_policies.Pass();
295 }
296
297 void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns,
298 const policy::PolicyMap& previous,
299 const policy::PolicyMap& current) {
300 scoped_ptr<base::DictionaryValue> new_policies =
301 CopyChromotingPoliciesIntoDictionary(current);
302
303 // Check for mistyped values and get rid of unknown policies.
304 if (!NormalizePolicies(new_policies.get())) {
305 SignalPolicyError();
306 return;
307 }
308
309 // Use default values for any missing policies.
310 scoped_ptr<base::DictionaryValue> filled_policies =
311 CopyValuesAndAddDefaults(*new_policies, *default_values_);
312
313 // Limit reporting to only the policies that were changed.
314 scoped_ptr<base::DictionaryValue> changed_policies =
315 StoreNewAndReturnChangedPolicies(filled_policies.Pass());
316 if (changed_policies->empty()) {
317 return;
318 }
319
320 // Verify that we are calling the callback with valid policies.
321 if (!VerifyWellformedness(*changed_policies)) {
322 SignalPolicyError();
323 return;
324 }
325
326 // Notify our client of the changed policies.
327 policy_updated_callback_.Run(changed_policies.Pass());
328 }
329
246 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) { 330 void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) {
247 policy::PolicyNamespace ns = GetPolicyNamespace(); 331 policy::PolicyNamespace ns = GetPolicyNamespace();
248 const policy::PolicyMap& current = policy_service_->GetPolicies(ns); 332 const policy::PolicyMap& current = policy_service_->GetPolicies(ns);
249 OnPolicyUpdated(ns, current, current); 333 OnPolicyUpdated(ns, current, current);
250 } 334 }
251 335
252 scoped_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader( 336 scoped_ptr<PolicyWatcher> PolicyWatcher::CreateFromPolicyLoader(
253 scoped_ptr<policy::AsyncPolicyLoader> async_policy_loader) { 337 scoped_ptr<policy::AsyncPolicyLoader> async_policy_loader) {
254 scoped_ptr<policy::SchemaRegistry> schema_registry = CreateSchemaRegistry(); 338 scoped_ptr<policy::SchemaRegistry> schema_registry = CreateSchemaRegistry();
255 scoped_ptr<policy::AsyncPolicyProvider> policy_provider( 339 scoped_ptr<policy::AsyncPolicyProvider> policy_provider(
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 policy::POLICY_SCOPE_MACHINE)); 384 policy::POLICY_SCOPE_MACHINE));
301 #else 385 #else
302 #error OS that is not yet supported by PolicyWatcher code. 386 #error OS that is not yet supported by PolicyWatcher code.
303 #endif 387 #endif
304 388
305 return PolicyWatcher::CreateFromPolicyLoader(policy_loader.Pass()); 389 return PolicyWatcher::CreateFromPolicyLoader(policy_loader.Pass());
306 #endif // !(OS_CHROMEOS) 390 #endif // !(OS_CHROMEOS)
307 } 391 }
308 392
309 } // namespace remoting 393 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/policy_watcher.h ('k') | remoting/host/policy_watcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698