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

Side by Side Diff: chrome/browser/chromeos/network_settings/onc_validator.cc

Issue 10944009: Implementation of ONC signature, validator and normalizer. (Closed) Base URL: http://git.chromium.org/chromium/src.git@gperffix
Patch Set: Addressed comments. Created 8 years, 1 month 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/network_settings/onc_validator.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/logging.h"
11 #include "base/string_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/chromeos/cros/onc_constants.h"
14 #include "chrome/browser/chromeos/network_settings/onc_signature.h"
15
16 namespace chromeos {
17 namespace onc {
18
19 Validator::Validator(
20 bool error_on_unknown_field,
21 bool error_on_wrong_recommended,
22 bool error_on_missing_field,
23 bool managed_onc)
24 : error_on_unknown_field_(error_on_unknown_field),
25 error_on_wrong_recommended_(error_on_wrong_recommended),
26 error_on_missing_field_(error_on_missing_field),
27 managed_onc_(managed_onc) {
28 }
29
30 Validator::~Validator() {
31 }
32
33 scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
34 const OncValueSignature* object_signature,
35 const base::DictionaryValue& onc_object) {
36 CHECK(object_signature != NULL);
37 scoped_ptr<base::Value> result_value =
38 MapValue(*object_signature, onc_object);
39 base::DictionaryValue* result_dict = NULL;
40 if (result_value.get() != NULL) {
41 result_value.release()->GetAsDictionary(&result_dict);
42 CHECK(result_dict != NULL);
43 }
44
45 return make_scoped_ptr(result_dict);
46 }
47
48 scoped_ptr<base::Value> Validator::MapValue(
49 const OncValueSignature& signature,
50 const base::Value& onc_value) {
51 if (onc_value.GetType() != signature.onc_type) {
52 DVLOG(1) << "Wrong type. Expected " << signature.onc_type
53 << ", but found " << onc_value.GetType();
54 return scoped_ptr<base::Value>();
55 }
56
57 scoped_ptr<base::Value> repaired = Mapper::MapValue(signature, onc_value);
58 if (repaired.get() != NULL)
59 CHECK_EQ(repaired->GetType(), signature.onc_type);
60 return repaired.Pass();
61 }
62
63 scoped_ptr<base::DictionaryValue> Validator::MapObject(
64 const OncValueSignature& signature,
65 const base::DictionaryValue& onc_object) {
66 scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
67
68 bool valid;
69 if (&signature == &kNetworkConfigurationSignature)
70 valid = ValidateNetworkConfiguration(onc_object, repaired.get());
71 else if (&signature == &kEthernetSignature)
72 valid = ValidateEthernet(onc_object, repaired.get());
73 else if (&signature == &kIPConfigSignature)
74 valid = ValidateIPConfig(onc_object, repaired.get());
75 else if (&signature == &kWiFiSignature)
76 valid = ValidateWiFi(onc_object, repaired.get());
77 else if (&signature == &kVPNSignature)
78 valid = ValidateVPN(onc_object, repaired.get());
79 else if (&signature == &kIPsecSignature)
80 valid = ValidateIPsec(onc_object, repaired.get());
81 else if (&signature == &kOpenVPNSignature)
82 valid = ValidateOpenVPN(onc_object, repaired.get());
83 else if (&signature == &kCertificatePatternSignature)
84 valid = ValidateCertificatePattern(onc_object, repaired.get());
85 else if (&signature == &kProxySettingsSignature)
86 valid = ValidateProxySettings(onc_object, repaired.get());
87 else if (&signature == &kProxyLocationSignature)
88 valid = ValidateProxyLocation(onc_object, repaired.get());
89 else if (&signature == &kEAPSignature)
90 valid = ValidateEAP(onc_object, repaired.get());
91 else if (&signature == &kCertificateSignature)
92 valid = ValidateCertificate(onc_object, repaired.get());
93 else
94 valid = ValidateObjectDefault(signature, onc_object, repaired.get());
95
96 if (valid)
97 return repaired.Pass();
98 else
99 return scoped_ptr<base::DictionaryValue>();
100 }
101
102 bool Validator::ValidateObjectDefault(
103 const OncValueSignature& signature,
104 const base::DictionaryValue& onc_object,
105 base::DictionaryValue* result) {
106 bool found_unknown_field = false;
107 bool nested_error_occured = false;
108 MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
109 result);
110 if (nested_error_occured)
111 return false;
112
113 if (found_unknown_field) {
114 if (error_on_unknown_field_) {
115 DVLOG(1) << "Unknown field name. Aborting.";
116 return false;
117 }
118 DVLOG(1) << "Unknown field name. Ignoring.";
119 }
120
121 return ValidateRecommendedField(signature, result);
122 }
123
124 bool Validator::ValidateRecommendedField(
125 const OncValueSignature& object_signature,
126 base::DictionaryValue* result) {
127 CHECK(result != NULL);
128
129 scoped_ptr<base::ListValue> recommended;
130 {
Mattias Nissler (ping if slow) 2012/11/06 09:30:56 what is this scope good for?
pneubeck (no reviews) 2012/11/06 13:32:22 Done.
131 base::Value* recommended_value;
132 // This remove passes ownership to |recommended_value|.
133 if (!result->RemoveWithoutPathExpansion(onc::kRecommended,
134 &recommended_value)) {
135 return true;
136 }
137 base::ListValue* recommended_list;
138 recommended_value->GetAsList(&recommended_list);
139 CHECK(recommended_list != NULL);
140
141 recommended.reset(recommended_list);
142 }
143
144 if (!managed_onc_) {
145 DVLOG(1) << "Found a " << onc::kRecommended
146 << " field in unmanaged ONC. Removing it.";
147 return true;
148 }
149
150 scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue);
151 for (base::ListValue::iterator it = recommended->begin();
152 it != recommended->end(); ++it) {
153 std::string field_name;
154 if (!(*it)->GetAsString(&field_name)) {
155 NOTREACHED();
156 continue;
157 }
158
159 const OncFieldSignature* field_signature =
160 GetFieldSignature(object_signature, field_name);
161
162 bool found_error = false;
163 std::string error_cause;
164 if (field_signature == NULL) {
165 found_error = true;
166 error_cause = "unknown";
167 } else if (field_signature->value_signature->onc_type ==
168 base::Value::TYPE_DICTIONARY) {
169 found_error = true;
170 error_cause = "dictionary-typed";
171 }
172
173 if (found_error) {
174 DVLOG(1) << "Found " << error_cause << " field name '" << field_name
175 << "' in kRecommended array. "
176 << (error_on_wrong_recommended_ ? "Aborting." : "Ignoring.");
177 if (error_on_wrong_recommended_)
178 return false;
179 else
180 continue;
181 }
182
183 repaired_recommended->Append((*it)->DeepCopy());
184 }
185
186 result->Set(onc::kRecommended, repaired_recommended.release());
187 return true;
188 }
189
190 namespace {
191
192 std::string JoinStringRange(const char** range_begin,
193 const char** range_end,
194 const std::string& separator) {
195 std::vector<std::string> string_vector;
196 std::copy(range_begin, range_end, std::back_inserter(string_vector));
197 return JoinString(string_vector, separator);
198 }
199
200 bool RequireAnyOf(const std::string &actual, const char** valid_values) {
201 const char** it = valid_values;
202 for (; *it != NULL; ++it) {
203 if (actual == *it)
204 return true;
205 }
206 DVLOG(1) << "Found " << actual << ", but expected one of "
207 << JoinStringRange(valid_values, it, ", ");
208 return false;
209 }
210
211 bool IsInRange(int actual, int lower_bound, int upper_bound) {
212 if (lower_bound <= actual && actual <= upper_bound)
213 return true;
214 DVLOG(1) << "Found " << actual << ", which is out of range [" << lower_bound
215 << ", " << upper_bound << "]";
216 return false;
217 }
218
219 bool RequireField(const base::DictionaryValue& dict, std::string key) {
220 if (dict.HasKey(key))
221 return true;
222 DVLOG(1) << "Required field " << key << " missing.";
223 return false;
224 }
225
226 } // namespace
227
228 bool Validator::ValidateNetworkConfiguration(
229 const base::DictionaryValue& onc_object,
230 base::DictionaryValue* result) {
231 if (!ValidateObjectDefault(kNetworkConfigurationSignature,
232 onc_object, result)) {
233 return false;
234 }
235
236 std::string type;
237 static const char* valid_types[] = { kEthernet, kVPN, kWiFi, NULL };
Mattias Nissler (ping if slow) 2012/11/06 09:30:56 This should be named kValidTypes per the style gui
pneubeck (no reviews) 2012/11/06 13:32:22 Done.
238 if (result->GetStringWithoutPathExpansion(kType, &type) &&
239 !RequireAnyOf(type, valid_types)) {
240 return false;
241 }
242
243 bool allRequiredExist = RequireField(*result, kGUID);
244
245 bool remove = false;
246 result->GetBooleanWithoutPathExpansion(kRemove, &remove);
247 if (!remove) {
248 allRequiredExist &= RequireField(*result, kName);
249 allRequiredExist &= RequireField(*result, kType);
250 allRequiredExist &= type.empty() || RequireField(*result, type);
251 }
252
253 return !error_on_missing_field_ || allRequiredExist;
254 }
255
256 bool Validator::ValidateEthernet(
257 const base::DictionaryValue& onc_object,
258 base::DictionaryValue* result) {
259 using namespace onc::ethernet;
260 if (!ValidateObjectDefault(kEthernetSignature, onc_object, result))
261 return false;
262
263 std::string auth;
264 static const char* valid_authentications[] = { kNone, k8021X, NULL };
265 if (result->GetStringWithoutPathExpansion(kAuthentication, &auth) &&
266 !RequireAnyOf(auth, valid_authentications)) {
267 return false;
268 }
269
270 bool allRequiredExist = true;
271 if (auth == k8021X)
272 allRequiredExist &= RequireField(*result, kEAP);
273
274 return !error_on_missing_field_ || allRequiredExist;
275 }
276
277 bool Validator::ValidateIPConfig(
278 const base::DictionaryValue& onc_object,
279 base::DictionaryValue* result) {
280 using namespace onc::ipconfig;
281 if (!ValidateObjectDefault(kIPConfigSignature, onc_object, result))
282 return false;
283
284 std::string type;
285 static const char* valid_types[] = { kIPv4, kIPv6, NULL };
286 if (result->GetStringWithoutPathExpansion(ipconfig::kType, &type) &&
287 !RequireAnyOf(type, valid_types)) {
288 return false;
289 }
290
291 int routing_prefix;
292 int lower_bound = 1;
293 // In case of missing type, choose higher upper_bound.
294 int upper_bound = (type == kIPv4) ? 32 : 128;
295 if (result->GetIntegerWithoutPathExpansion(kRoutingPrefix, &routing_prefix) &&
296 !IsInRange(routing_prefix, lower_bound, upper_bound)) {
297 return false;
298 }
299
300 bool allRequiredExist = RequireField(*result, kIPAddress) &
301 RequireField(*result, kRoutingPrefix) &
302 RequireField(*result, ipconfig::kType);
303
304 return !error_on_missing_field_ || allRequiredExist;
305 }
306
307 bool Validator::ValidateWiFi(
308 const base::DictionaryValue& onc_object,
309 base::DictionaryValue* result) {
310 using namespace onc::wifi;
311 if (!ValidateObjectDefault(kWiFiSignature, onc_object, result))
312 return false;
313
314 std::string security;
315 static const char* valid_securities[] =
316 { kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL };
317 if (result->GetStringWithoutPathExpansion(kSecurity, &security) &&
318 !RequireAnyOf(security, valid_securities)) {
319 return false;
320 }
321
322 bool allRequiredExist = RequireField(*result, kSecurity) &
323 RequireField(*result, kSSID);
324 if (security == kWEP_8021X || security == kWPA_EAP)
325 allRequiredExist &= RequireField(*result, kEAP);
326 else if (security == kWEP_PSK || security == kWPA_PSK)
327 allRequiredExist &= RequireField(*result, kPassphrase);
328
329 return !error_on_missing_field_ || allRequiredExist;
330 }
331
332 bool Validator::ValidateVPN(
333 const base::DictionaryValue& onc_object,
334 base::DictionaryValue* result) {
335 using namespace vpn;
336 if (!ValidateObjectDefault(kVPNSignature, onc_object, result))
337 return false;
338
339 std::string type;
340 static const char* valid_types[] =
341 { kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL };
342 if (result->GetStringWithoutPathExpansion(vpn::kType, &type) &&
343 !RequireAnyOf(type, valid_types)) {
344 return false;
345 }
346
347 bool allRequiredExist = RequireField(*result, vpn::kType);
348
349 if (type == kOpenVPN) {
350 allRequiredExist &= RequireField(*result, kOpenVPN);
351 } else if (type == kIPsec) {
352 allRequiredExist &= RequireField(*result, kIPsec);
353 } else if (type == kTypeL2TP_IPsec) {
354 allRequiredExist &= RequireField(*result, kIPsec) &
355 RequireField(*result, kL2TP);
356 }
357
358 return !error_on_missing_field_ || allRequiredExist;
359 }
360
361 bool Validator::ValidateIPsec(
362 const base::DictionaryValue& onc_object,
363 base::DictionaryValue* result) {
364 using namespace onc::vpn;
365 using namespace onc::certificate;
366 if (!ValidateObjectDefault(kIPsecSignature, onc_object, result))
367 return false;
368
369 std::string auth;
370 static const char* valid_authentications[] = { kPSK, kCert, NULL };
371 if (result->GetStringWithoutPathExpansion(kAuthenticationType, &auth) &&
372 !RequireAnyOf(auth, valid_authentications)) {
373 return false;
374 }
375
376 std::string cert_type;
377 static const char* valid_cert_types[] = { kRef, kPattern, NULL };
378 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
379 !RequireAnyOf(cert_type, valid_cert_types)) {
380 return false;
381 }
382
383 bool allRequiredExist = RequireField(*result, kAuthenticationType) &
384 RequireField(*result, kIKEVersion);
385 if (auth == kCert) {
386 allRequiredExist &= RequireField(*result, kClientCertType) &
387 RequireField(*result, kServerCARef);
388 }
389 if (cert_type == kPattern)
390 allRequiredExist &= RequireField(*result, kClientCertPattern);
391 else if (cert_type == kRef)
392 allRequiredExist &= RequireField(*result, kClientCertRef);
393
394 return !error_on_missing_field_ || allRequiredExist;
395 }
396
397 bool Validator::ValidateOpenVPN(
398 const base::DictionaryValue& onc_object,
399 base::DictionaryValue* result) {
400 using namespace onc::vpn;
401 using namespace onc::openvpn;
402 using namespace onc::certificate;
403 if (!ValidateObjectDefault(kOpenVPNSignature, onc_object, result))
404 return false;
405
406 std::string auth_retry;
407 static const char* valid_auth_retry_values[] =
408 { openvpn::kNone, kInteract, kNoInteract, NULL };
409 if (result->GetStringWithoutPathExpansion(kAuthRetry, &auth_retry) &&
410 !RequireAnyOf(auth_retry, valid_auth_retry_values)) {
411 return false;
412 }
413
414 std::string cert_type;
415 static const char* valid_cert_types[] =
416 { certificate::kNone, kRef, kPattern, NULL };
417 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
418 !RequireAnyOf(cert_type, valid_cert_types)) {
419 return false;
420 }
421
422 std::string cert_tls;
423 static const char* valid_cert_tls_values[] =
424 { openvpn::kNone, openvpn::kServer, NULL };
425 if (result->GetStringWithoutPathExpansion(kRemoteCertTLS, &cert_tls) &&
426 !RequireAnyOf(cert_tls, valid_cert_tls_values)) {
427 return false;
428 }
429
430 bool allRequiredExist = RequireField(*result, kClientCertType);
431 if (cert_type == kPattern)
432 allRequiredExist &= RequireField(*result, kClientCertPattern);
433 else if (cert_type == kRef)
434 allRequiredExist &= RequireField(*result, kClientCertRef);
435
436 return !error_on_missing_field_ || allRequiredExist;
437 }
438
439 bool Validator::ValidateCertificatePattern(
440 const base::DictionaryValue& onc_object,
441 base::DictionaryValue* result) {
442 using namespace onc::certificate;
443 if (!ValidateObjectDefault(kCertificatePatternSignature, onc_object, result))
444 return false;
445
446 bool allRequiredExist = true;
447 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
448 !result->HasKey(kIssuerCARef)) {
449 allRequiredExist = false;
450 DVLOG(1) << "None of the fields " << kSubject << ", " << kIssuer << ", and "
451 << kIssuerCARef << " exists, but at least one is required.";
452 }
453
454 return !error_on_missing_field_ || allRequiredExist;
455 }
456
457 bool Validator::ValidateProxySettings(const base::DictionaryValue& onc_object,
458 base::DictionaryValue* result) {
459 using namespace onc::proxy;
460 if (!ValidateObjectDefault(kProxySettingsSignature, onc_object, result))
461 return false;
462
463 std::string type;
464 const char* valid_types[] = { kDirect, kManual, kPAC, kWPAD, NULL };
465 if (result->GetStringWithoutPathExpansion(proxy::kType, &type) &&
466 !RequireAnyOf(type, valid_types)) {
467 return false;
468 }
469
470 bool allRequiredExist = RequireField(*result, proxy::kType);
471
472 if (type == kManual)
473 allRequiredExist &= RequireField(*result, kManual);
474 else if (type == kPAC)
475 allRequiredExist &= RequireField(*result, kPAC);
476
477 return !error_on_missing_field_ || allRequiredExist;
478 }
479
480 bool Validator::ValidateProxyLocation(const base::DictionaryValue& onc_object,
481 base::DictionaryValue* result) {
482 using namespace onc::proxy;
483 if (!ValidateObjectDefault(kProxyLocationSignature, onc_object, result))
484 return false;
485
486 bool allRequiredExist = RequireField(*result, kHost) &
487 RequireField(*result, kPort);
488
489 return !error_on_missing_field_ || allRequiredExist;
490 }
491
492 bool Validator::ValidateEAP(const base::DictionaryValue& onc_object,
493 base::DictionaryValue* result) {
494 using namespace onc::eap;
495 using namespace onc::certificate;
496 if (!ValidateObjectDefault(kEAPSignature, onc_object, result))
497 return false;
498
499 std::string inner;
500 const char* valid_inner_values[] =
501 { kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL };
502 if (result->GetStringWithoutPathExpansion(kInner, &inner) &&
503 !RequireAnyOf(inner, valid_inner_values)) {
504 return false;
505 }
506
507 std::string outer;
508 const char* valid_outer_values[] = { kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP,
509 kEAP_SIM, kEAP_FAST, kEAP_AKA, NULL };
510 if (result->GetStringWithoutPathExpansion(kOuter, &outer) &&
511 !RequireAnyOf(outer, valid_outer_values)) {
512 return false;
513 }
514
515 std::string cert_type;
516 const char* valid_cert_types[] = { kRef, kPattern, NULL };
517 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
518 !RequireAnyOf(cert_type, valid_cert_types )) {
519 return false;
520 }
521
522 bool allRequiredExist = RequireField(*result, kOuter);
523
524 if (cert_type == kPattern)
525 allRequiredExist &= RequireField(*result, kClientCertPattern);
526 else if (cert_type == kRef)
527 allRequiredExist &= RequireField(*result, kClientCertRef);
528
529 return !error_on_missing_field_ || allRequiredExist;
530 }
531
532 bool Validator::ValidateCertificate(
533 const base::DictionaryValue& onc_object,
534 base::DictionaryValue* result) {
535 using namespace onc::certificate;
536 if (!ValidateObjectDefault(kCertificateSignature, onc_object, result))
537 return false;
538
539 std::string type;
540 const char* valid_types[] = { kClient, kServer, kAuthority, NULL };
541 if (result->GetStringWithoutPathExpansion(certificate::kType, &type) &&
542 !RequireAnyOf(type, valid_types)) {
543 return false;
544 }
545
546 bool allRequiredExist = RequireField(*result, kGUID);
547
548 bool remove = false;
549 result->GetBooleanWithoutPathExpansion(kRemove, &remove);
550 if (!remove) {
551 allRequiredExist &= RequireField(*result, certificate::kType);
552
553 if (type == kClient)
554 allRequiredExist &= RequireField(*result, kPKCS12);
555 else if (type == kServer || type == kAuthority)
556 allRequiredExist &= RequireField(*result, kX509);
557 }
558
559 return !error_on_missing_field_ || allRequiredExist;
560 }
561
562 } // namespace onc
563 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698