summaryrefslogtreecommitdiffstats
path: root/chromeos/network/onc
diff options
context:
space:
mode:
Diffstat (limited to 'chromeos/network/onc')
-rw-r--r--chromeos/network/onc/onc_constants.cc1
-rw-r--r--chromeos/network/onc/onc_mapper.cc92
-rw-r--r--chromeos/network/onc/onc_mapper.h72
-rw-r--r--chromeos/network/onc/onc_merger_unittest.cc4
-rw-r--r--chromeos/network/onc/onc_normalizer.cc11
-rw-r--r--chromeos/network/onc/onc_normalizer.h3
-rw-r--r--chromeos/network/onc/onc_signature.cc26
-rw-r--r--chromeos/network/onc/onc_signature.h4
-rw-r--r--chromeos/network/onc/onc_translator_unittest.cc2
-rw-r--r--chromeos/network/onc/onc_utils.cc6
-rw-r--r--chromeos/network/onc/onc_utils.h4
-rw-r--r--chromeos/network/onc/onc_validator.cc387
-rw-r--r--chromeos/network/onc/onc_validator.h126
-rw-r--r--chromeos/network/onc/onc_validator_unittest.cc72
14 files changed, 555 insertions, 255 deletions
diff --git a/chromeos/network/onc/onc_constants.cc b/chromeos/network/onc/onc_constants.cc
index f77e991..3798d64 100644
--- a/chromeos/network/onc/onc_constants.cc
+++ b/chromeos/network/onc/onc_constants.cc
@@ -99,7 +99,6 @@ const char kPBKDF2[] = "PBKDF2";
const char kSHA1[] = "SHA1";
const char kSalt[] = "Salt";
const char kStretch[] = "Stretch";
-const char kType[] = "Type";
} // namespace encrypted
namespace eap {
diff --git a/chromeos/network/onc/onc_mapper.cc b/chromeos/network/onc/onc_mapper.cc
index 8d5d723..768f0f6 100644
--- a/chromeos/network/onc/onc_mapper.cc
+++ b/chromeos/network/onc/onc_mapper.cc
@@ -17,28 +17,25 @@ Mapper::Mapper() {
Mapper::~Mapper() {
}
-scoped_ptr<base::Value> Mapper::MapValue(
- const OncValueSignature& signature,
- const base::Value& onc_value) {
+scoped_ptr<base::Value> Mapper::MapValue(const OncValueSignature& signature,
+ const base::Value& onc_value,
+ bool* error) {
scoped_ptr<base::Value> result_value;
switch (onc_value.GetType()) {
case base::Value::TYPE_DICTIONARY: {
const base::DictionaryValue* dict = NULL;
onc_value.GetAsDictionary(&dict);
- result_value = MapObject(signature, *dict);
+ result_value = MapObject(signature, *dict, error);
break;
}
case base::Value::TYPE_LIST: {
const base::ListValue* list = NULL;
onc_value.GetAsList(&list);
- bool nested_error_occured = false;
- result_value = MapArray(signature, *list, &nested_error_occured);
- if (nested_error_occured)
- result_value.reset();
+ result_value = MapArray(signature, *list, error);
break;
}
default: {
- result_value = MapPrimitive(signature, onc_value);
+ result_value = MapPrimitive(signature, onc_value, error);
break;
}
}
@@ -48,44 +45,44 @@ scoped_ptr<base::Value> Mapper::MapValue(
scoped_ptr<base::DictionaryValue> Mapper::MapObject(
const OncValueSignature& signature,
- const base::DictionaryValue& onc_object) {
+ const base::DictionaryValue& onc_object,
+ bool* error) {
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
bool found_unknown_field = false;
- bool nested_error_occured = false;
- MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
- result.get());
- if (!nested_error_occured && !found_unknown_field)
- return result.Pass();
- else
- return scoped_ptr<base::DictionaryValue>();
+ MapFields(signature, onc_object, &found_unknown_field, error, result.get());
+ if (found_unknown_field)
+ *error = true;
+ return result.Pass();
}
-scoped_ptr<base::Value> Mapper::MapPrimitive(
- const OncValueSignature& signature,
- const base::Value& onc_primitive) {
+scoped_ptr<base::Value> Mapper::MapPrimitive(const OncValueSignature& signature,
+ const base::Value& onc_primitive,
+ bool* error) {
return make_scoped_ptr(onc_primitive.DeepCopy());
}
-void Mapper::MapFields(
- const OncValueSignature& object_signature,
- const base::DictionaryValue& onc_object,
- bool* found_unknown_field,
- bool* nested_error_occured,
- base::DictionaryValue* result) {
+void Mapper::MapFields(const OncValueSignature& object_signature,
+ const base::DictionaryValue& onc_object,
+ bool* found_unknown_field,
+ bool* nested_error,
+ base::DictionaryValue* result) {
for (base::DictionaryValue::Iterator it(onc_object); it.HasNext();
it.Advance()) {
bool current_field_unknown = false;
- scoped_ptr<base::Value> result_value = MapField(
- it.key(), object_signature, it.value(), &current_field_unknown);
+ scoped_ptr<base::Value> result_value = MapField(it.key(),
+ object_signature,
+ it.value(),
+ &current_field_unknown,
+ nested_error);
if (current_field_unknown)
*found_unknown_field = true;
else if (result_value.get() != NULL)
result->SetWithoutPathExpansion(it.key(), result_value.release());
else
- *nested_error_occured = true;
+ DCHECK(*nested_error);
}
}
@@ -93,18 +90,16 @@ scoped_ptr<base::Value> Mapper::MapField(
const std::string& field_name,
const OncValueSignature& object_signature,
const base::Value& onc_value,
- bool* found_unknown_field) {
+ bool* found_unknown_field,
+ bool* error) {
const OncFieldSignature* field_signature =
GetFieldSignature(object_signature, field_name);
if (field_signature != NULL) {
- if (field_signature->value_signature == NULL) {
- NOTREACHED() << "Found missing value signature at field '"
- << field_name << "'.";
- return scoped_ptr<base::Value>();
- }
+ DCHECK(field_signature->value_signature != NULL)
+ << "Found missing value signature at field '" << field_name << "'.";
- return MapValue(*field_signature->value_signature, onc_value);
+ return MapValue(*field_signature->value_signature, onc_value, error);
} else {
DVLOG(1) << "Found unknown field name: '" << field_name << "'";
*found_unknown_field = true;
@@ -115,26 +110,35 @@ scoped_ptr<base::Value> Mapper::MapField(
scoped_ptr<base::ListValue> Mapper::MapArray(
const OncValueSignature& array_signature,
const base::ListValue& onc_array,
- bool* nested_error_occured) {
- if (array_signature.onc_array_entry_signature == NULL) {
- NOTREACHED() << "Found missing onc_array_entry_signature.";
- return scoped_ptr<base::ListValue>();
- }
+ bool* nested_error) {
+ DCHECK(array_signature.onc_array_entry_signature != NULL)
+ << "Found missing onc_array_entry_signature.";
scoped_ptr<base::ListValue> result_array(new base::ListValue);
+ int original_index = 0;
for (base::ListValue::const_iterator it = onc_array.begin();
- it != onc_array.end(); ++it) {
+ it != onc_array.end(); ++it, ++original_index) {
const base::Value* entry = *it;
scoped_ptr<base::Value> result_entry;
- result_entry = MapValue(*array_signature.onc_array_entry_signature, *entry);
+ result_entry = MapEntry(original_index,
+ *array_signature.onc_array_entry_signature,
+ *entry,
+ nested_error);
if (result_entry.get() != NULL)
result_array->Append(result_entry.release());
else
- *nested_error_occured = true;
+ DCHECK(*nested_error);
}
return result_array.Pass();
}
+scoped_ptr<base::Value> Mapper::MapEntry(int index,
+ const OncValueSignature& signature,
+ const base::Value& onc_value,
+ bool* error) {
+ return MapValue(signature, onc_value, error);
+}
+
} // namespace onc
} // namespace chromeos
diff --git a/chromeos/network/onc/onc_mapper.h b/chromeos/network/onc/onc_mapper.h
index e8d42a9..142af70 100644
--- a/chromeos/network/onc/onc_mapper.h
+++ b/chromeos/network/onc/onc_mapper.h
@@ -11,9 +11,9 @@
#include "chromeos/chromeos_export.h"
namespace base {
-class Value;
class DictionaryValue;
class ListValue;
+class Value;
}
namespace chromeos {
@@ -41,58 +41,66 @@ class Mapper {
protected:
// Calls |MapObject|, |MapArray| and |MapPrimitive| according to |onc_value|'s
- // type. By default aborts on nested errors in arrays. Result of the mapping
- // is returned. On error returns NULL.
- virtual scoped_ptr<base::Value> MapValue(
- const OncValueSignature& signature,
- const base::Value& onc_value);
+ // type, which always return an object of the according type. Result of the
+ // mapping is returned. On error sets |error| to true.
+ virtual scoped_ptr<base::Value> MapValue(const OncValueSignature& signature,
+ const base::Value& onc_value,
+ bool* error);
// Maps objects/dictionaries. By default calls |MapFields|, which recurses
- // into each field of |onc_object|, and aborts on unknown fields. Result of
- // the mapping is returned. On error returns NULL.
+ // into each field of |onc_object|, and drops unknown fields. Result of the
+ // mapping is returned. On error sets |error| to true. In this implementation
+ // only unknown fields are errors.
virtual scoped_ptr<base::DictionaryValue> MapObject(
const OncValueSignature& signature,
- const base::DictionaryValue& onc_object);
+ const base::DictionaryValue& onc_object,
+ bool* error);
// Maps primitive values like BinaryValue, StringValue, IntegerValue... (all
// but dictionaries and lists). By default copies |onc_primitive|. Result of
- // the mapping is returned. On error returns NULL.
+ // the mapping is returned. On error sets |error| to true.
virtual scoped_ptr<base::Value> MapPrimitive(
- const OncValueSignature& signature,
- const base::Value& onc_primitive);
-
- // Maps each field of the given |onc_object| according to
- // |object_signature|. Adds the mapping of each field to |result| using
- // |MapField| and drops unknown fields by default. Sets
- // |found_unknown_field| to true if this dictionary contains any unknown
- // fields. Set |nested_error_occured| to true if nested errors occured.
- virtual void MapFields(
- const OncValueSignature& object_signature,
- const base::DictionaryValue& onc_object,
- bool* found_unknown_field,
- bool* nested_error_occured,
- base::DictionaryValue* result);
+ const OncValueSignature& signature,
+ const base::Value& onc_primitive,
+ bool* error);
+
+ // Maps each field of the given |onc_object| according to |object_signature|.
+ // Adds the mapping of each field to |result| using |MapField| and drops
+ // unknown fields by default. Sets |found_unknown_field| to true if this
+ // dictionary contains any unknown fields. Set |nested_error| to true if
+ // nested errors occured.
+ virtual void MapFields(const OncValueSignature& object_signature,
+ const base::DictionaryValue& onc_object,
+ bool* found_unknown_field,
+ bool* nested_error,
+ base::DictionaryValue* result);
// Maps the value |onc_value| of field |field_name| according to its field
// signature in |object_signature| using |MapValue|. Sets
- // |found_unknown_field| to true if |field_name| cannot be found in
- // |object_signature|, which by default is an error. Result of the mapping is
- // returned. On error returns NULL.
+ // |found_unknown_field| to true and returns NULL if |field_name| cannot be
+ // found in |object_signature|. Otherwise returns the mapping of |onc_value|.
virtual scoped_ptr<base::Value> MapField(
const std::string& field_name,
const OncValueSignature& object_signature,
const base::Value& onc_value,
- bool* found_unknown_field);
+ bool* found_unknown_field,
+ bool* error);
// Maps the array |onc_array| according to |array_signature|, which defines
// the type of the entries. Maps each entry by calling |MapValue|. If any of
- // the nested mappings failed, the flag |nested_error_occured| is set to true
- // and the entry is dropped from the result. The resulting array is
- // returned. On error returns NULL.
+ // the nested mappings failed, the flag |nested_error| is set to true and the
+ // entry is dropped from the result. The resulting array is returned.
virtual scoped_ptr<base::ListValue> MapArray(
const OncValueSignature& array_signature,
const base::ListValue& onc_array,
- bool* nested_error_occured);
+ bool* nested_error);
+
+ // Calls |MapValue| and returns its result. Called by |MapArray| for each
+ // entry and its index in the enclosing array.
+ virtual scoped_ptr<base::Value> MapEntry(int index,
+ const OncValueSignature& signature,
+ const base::Value& onc_value,
+ bool* error);
private:
DISALLOW_COPY_AND_ASSIGN(Mapper);
diff --git a/chromeos/network/onc/onc_merger_unittest.cc b/chromeos/network/onc/onc_merger_unittest.cc
index c7d5190..21f8287 100644
--- a/chromeos/network/onc/onc_merger_unittest.cc
+++ b/chromeos/network/onc/onc_merger_unittest.cc
@@ -54,9 +54,9 @@ class ONCMergerTest : public testing::Test {
scoped_ptr<const base::DictionaryValue> device_policy_;
virtual void SetUp() {
- policy_ = test_utils::ReadTestDictionary("policy.onc");
+ policy_ = test_utils::ReadTestDictionary("managed_vpn.onc");
policy_without_recommended_ =
- test_utils::ReadTestDictionary("policy_without_recommended.onc");
+ test_utils::ReadTestDictionary("managed_vpn_without_recommended.onc");
user_ = test_utils::ReadTestDictionary("user.onc");
device_policy_ = test_utils::ReadTestDictionary("device_policy.onc");
}
diff --git a/chromeos/network/onc/onc_normalizer.cc b/chromeos/network/onc/onc_normalizer.cc
index 4f99867..a1f1743 100644
--- a/chromeos/network/onc/onc_normalizer.cc
+++ b/chromeos/network/onc/onc_normalizer.cc
@@ -25,14 +25,19 @@ scoped_ptr<base::DictionaryValue> Normalizer::NormalizeObject(
const OncValueSignature* object_signature,
const base::DictionaryValue& onc_object) {
CHECK(object_signature != NULL);
- return MapObject(*object_signature, onc_object);
+ bool error = false;
+ scoped_ptr<base::DictionaryValue> result =
+ MapObject(*object_signature, onc_object, &error);
+ DCHECK(!error);
+ return result.Pass();
}
scoped_ptr<base::DictionaryValue> Normalizer::MapObject(
const OncValueSignature& signature,
- const base::DictionaryValue& onc_object) {
+ const base::DictionaryValue& onc_object,
+ bool* error) {
scoped_ptr<base::DictionaryValue> normalized =
- Mapper::MapObject(signature, onc_object);
+ Mapper::MapObject(signature, onc_object, error);
if (normalized.get() == NULL)
return scoped_ptr<base::DictionaryValue>();
diff --git a/chromeos/network/onc/onc_normalizer.h b/chromeos/network/onc/onc_normalizer.h
index 5d00f00..0b4468b 100644
--- a/chromeos/network/onc/onc_normalizer.h
+++ b/chromeos/network/onc/onc_normalizer.h
@@ -33,7 +33,8 @@ class CHROMEOS_EXPORT Normalizer : public Mapper {
// Dispatch to the right normalization function according to |signature|.
virtual scoped_ptr<base::DictionaryValue> MapObject(
const OncValueSignature& signature,
- const base::DictionaryValue& onc_object) OVERRIDE;
+ const base::DictionaryValue& onc_object,
+ bool* error) OVERRIDE;
void NormalizeIPsec(base::DictionaryValue* ipsec);
void NormalizeVPN(base::DictionaryValue* vpn);
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index f71328c..974df42 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -28,12 +28,6 @@ const OncValueSignature kStringListSignature = {
const OncValueSignature kIPConfigListSignature = {
Value::TYPE_LIST, NULL, &kIPConfigSignature
};
-const OncValueSignature kCertificateListSignature = {
- Value::TYPE_LIST, NULL, &kCertificateSignature
-};
-const OncValueSignature kNetworkConfigurationListSignature = {
- Value::TYPE_LIST, NULL, &kNetworkConfigurationSignature
-};
const OncFieldSignature issuer_subject_pattern_fields[] = {
{ certificate::kCommonName, NULL, &kStringSignature },
@@ -236,10 +230,18 @@ const OncFieldSignature certificate_fields[] = {
{ NULL }
};
-const OncFieldSignature unencrypted_configuration_fields[] = {
+const OncFieldSignature toplevel_configuration_fields[] = {
{ kCertificates, NULL, &kCertificateListSignature },
{ kNetworkConfigurations, NULL, &kNetworkConfigurationListSignature },
{ kType, NULL, &kStringSignature },
+ { encrypted::kCipher, NULL, &kStringSignature },
+ { encrypted::kCiphertext, NULL, &kStringSignature },
+ { encrypted::kHMAC, NULL, &kStringSignature },
+ { encrypted::kHMACMethod, NULL, &kStringSignature },
+ { encrypted::kIV, NULL, &kStringSignature },
+ { encrypted::kIterations, NULL, &kIntegerSignature },
+ { encrypted::kSalt, NULL, &kStringSignature },
+ { encrypted::kStretch, NULL, &kStringSignature },
{ NULL }
};
@@ -293,8 +295,14 @@ const OncValueSignature kCertificateSignature = {
const OncValueSignature kNetworkConfigurationSignature = {
Value::TYPE_DICTIONARY, network_configuration_fields, NULL
};
-const OncValueSignature kUnencryptedConfigurationSignature = {
- Value::TYPE_DICTIONARY, unencrypted_configuration_fields, NULL
+const OncValueSignature kCertificateListSignature = {
+ Value::TYPE_LIST, NULL, &kCertificateSignature
+};
+const OncValueSignature kNetworkConfigurationListSignature = {
+ Value::TYPE_LIST, NULL, &kNetworkConfigurationSignature
+};
+const OncValueSignature kToplevelConfigurationSignature = {
+ Value::TYPE_DICTIONARY, toplevel_configuration_fields, NULL
};
const OncFieldSignature* GetFieldSignature(const OncValueSignature& signature,
diff --git a/chromeos/network/onc/onc_signature.h b/chromeos/network/onc/onc_signature.h
index 1a9b507..7ef17c0 100644
--- a/chromeos/network/onc/onc_signature.h
+++ b/chromeos/network/onc/onc_signature.h
@@ -46,8 +46,10 @@ CHROMEOS_EXPORT extern const OncValueSignature kProxySettingsSignature;
CHROMEOS_EXPORT extern const OncValueSignature kWiFiSignature;
CHROMEOS_EXPORT extern const OncValueSignature kCertificateSignature;
CHROMEOS_EXPORT extern const OncValueSignature kNetworkConfigurationSignature;
+CHROMEOS_EXPORT extern const OncValueSignature kCertificateListSignature;
CHROMEOS_EXPORT extern const OncValueSignature
- kUnencryptedConfigurationSignature;
+ kNetworkConfigurationListSignature;
+CHROMEOS_EXPORT extern const OncValueSignature kToplevelConfigurationSignature;
} // namespace onc
} // namespace chromeos
diff --git a/chromeos/network/onc/onc_translator_unittest.cc b/chromeos/network/onc/onc_translator_unittest.cc
index a9b8fb5..da9e658 100644
--- a/chromeos/network/onc/onc_translator_unittest.cc
+++ b/chromeos/network/onc/onc_translator_unittest.cc
@@ -41,7 +41,7 @@ INSTANTIATE_TEST_CASE_P(
ONCTranslatorOncToShillTest,
ONCTranslatorOncToShillTest,
::testing::Values(
- std::make_pair("valid.onc", "shill_ethernet.json"),
+ std::make_pair("managed_ethernet.onc", "shill_ethernet.json"),
std::make_pair("valid_l2tpipsec.onc", "shill_l2tpipsec.json"),
std::make_pair("valid_openvpn.onc", "shill_openvpn.json")));
diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
index 62e0d46..85cfe64 100644
--- a/chromeos/network/onc/onc_utils.cc
+++ b/chromeos/network/onc/onc_utils.cc
@@ -27,6 +27,10 @@ const char kUnableToDecode[] = "Unable to decode encrypted ONC";
} // namespace
+const char kEmptyUnencryptedConfiguration[] =
+ "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[],"
+ "\"Certificates\":[]}";
+
scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson(
const std::string& json) {
std::string error;
@@ -64,7 +68,7 @@ scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase,
!root.GetInteger(encrypted::kIterations, &iterations) ||
!root.GetString(encrypted::kSalt, &salt) ||
!root.GetString(encrypted::kStretch, &stretch_method) ||
- !root.GetString(encrypted::kType, &onc_type) ||
+ !root.GetString(kType, &onc_type) ||
onc_type != kEncryptedConfiguration) {
ONC_LOG_ERROR("Encrypted ONC malformed.");
diff --git a/chromeos/network/onc/onc_utils.h b/chromeos/network/onc/onc_utils.h
index 96b8a1e..13263a8 100644
--- a/chromeos/network/onc/onc_utils.h
+++ b/chromeos/network/onc/onc_utils.h
@@ -18,6 +18,10 @@ class DictionaryValue;
namespace chromeos {
namespace onc {
+// A valid but empty (no networks and no certificates) and unencrypted
+// configuration.
+CHROMEOS_EXPORT extern const char kEmptyUnencryptedConfiguration[];
+
// Parses |json| according to the JSON format. If |json| is a JSON formatted
// dictionary, the function returns the dictionary as a DictionaryValue.
// Otherwise returns NULL.
diff --git a/chromeos/network/onc/onc_validator.cc b/chromeos/network/onc/onc_validator.cc
index 684eca3..a661d51 100644
--- a/chromeos/network/onc/onc_validator.cc
+++ b/chromeos/network/onc/onc_validator.cc
@@ -7,7 +7,9 @@
#include <algorithm>
#include <string>
+#include "base/json/json_writer.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chromeos/network/onc/onc_constants.h"
@@ -16,6 +18,33 @@
namespace chromeos {
namespace onc {
+namespace {
+
+std::string ValueToString(const base::Value& value) {
+ std::string json;
+ base::JSONWriter::Write(&value, &json);
+ return json;
+}
+
+// Copied from policy/configuration_policy_handler.cc.
+// TODO(pneubeck): move to a common place like base/.
+std::string ValueTypeToString(Value::Type type) {
+ static const char* strings[] = {
+ "null",
+ "boolean",
+ "integer",
+ "double",
+ "string",
+ "binary",
+ "dictionary",
+ "list"
+ };
+ CHECK(static_cast<size_t>(type) < arraysize(strings));
+ return strings[type];
+}
+
+} // namespace
+
Validator::Validator(
bool error_on_unknown_field,
bool error_on_wrong_recommended,
@@ -32,10 +61,23 @@ Validator::~Validator() {
scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
const OncValueSignature* object_signature,
- const base::DictionaryValue& onc_object) {
+ const base::DictionaryValue& onc_object,
+ Result* result) {
CHECK(object_signature != NULL);
+ *result = VALID;
+ error_or_warning_found_ = false;
+ bool error = false;
scoped_ptr<base::Value> result_value =
- MapValue(*object_signature, onc_object);
+ MapValue(*object_signature, onc_object, &error);
+ if (error) {
+ *result = INVALID;
+ result_value.reset();
+ } else if (error_or_warning_found_) {
+ *result = VALID_WITH_WARNINGS;
+ }
+ // The return value should be NULL if, and only if, |result| equals INVALID.
+ DCHECK_EQ(result_value.get() == NULL, *result == INVALID);
+
base::DictionaryValue* result_dict = NULL;
if (result_value.get() != NULL) {
result_value.release()->GetAsDictionary(&result_dict);
@@ -47,14 +89,19 @@ scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
scoped_ptr<base::Value> Validator::MapValue(
const OncValueSignature& signature,
- const base::Value& onc_value) {
+ const base::Value& onc_value,
+ bool* error) {
if (onc_value.GetType() != signature.onc_type) {
- DVLOG(1) << "Wrong type. Expected " << signature.onc_type
- << ", but found " << onc_value.GetType();
+ LOG(ERROR) << ErrorHeader() << "Found value '" << onc_value
+ << "' of type '" << ValueTypeToString(onc_value.GetType())
+ << "', but type '" << ValueTypeToString(signature.onc_type)
+ << "' is required.";
+ error_or_warning_found_ = *error = true;
return scoped_ptr<base::Value>();
}
- scoped_ptr<base::Value> repaired = Mapper::MapValue(signature, onc_value);
+ scoped_ptr<base::Value> repaired =
+ Mapper::MapValue(signature, onc_value, error);
if (repaired.get() != NULL)
CHECK_EQ(repaired->GetType(), signature.onc_type);
return repaired.Pass();
@@ -62,11 +109,14 @@ scoped_ptr<base::Value> Validator::MapValue(
scoped_ptr<base::DictionaryValue> Validator::MapObject(
const OncValueSignature& signature,
- const base::DictionaryValue& onc_object) {
+ const base::DictionaryValue& onc_object,
+ bool* error) {
scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
bool valid;
- if (&signature == &kNetworkConfigurationSignature)
+ if (&signature == &kToplevelConfigurationSignature)
+ valid = ValidateToplevelConfiguration(onc_object, repaired.get());
+ else if (&signature == &kNetworkConfigurationSignature)
valid = ValidateNetworkConfiguration(onc_object, repaired.get());
else if (&signature == &kEthernetSignature)
valid = ValidateEthernet(onc_object, repaired.get());
@@ -93,10 +143,52 @@ scoped_ptr<base::DictionaryValue> Validator::MapObject(
else
valid = ValidateObjectDefault(signature, onc_object, repaired.get());
- if (valid)
+ if (valid) {
return repaired.Pass();
- else
+ } else {
+ error_or_warning_found_ = *error = true;
return scoped_ptr<base::DictionaryValue>();
+ }
+}
+
+scoped_ptr<base::Value> Validator::MapField(
+ const std::string& field_name,
+ const OncValueSignature& object_signature,
+ const base::Value& onc_value,
+ bool* found_unknown_field,
+ bool* error) {
+ path_.push_back(field_name);
+ bool current_field_unknown = false;
+ scoped_ptr<base::Value> result = Mapper::MapField(
+ field_name, object_signature, onc_value, &current_field_unknown, error);
+
+ DCHECK_EQ(field_name, path_.back());
+ path_.pop_back();
+
+ if (current_field_unknown) {
+ error_or_warning_found_ = *found_unknown_field = true;
+ std::string message = MessageHeader(error_on_unknown_field_)
+ + "Field name '" + field_name + "' is unknown.";
+ if (error_on_unknown_field_)
+ LOG(ERROR) << message;
+ else
+ LOG(WARNING) << message;
+ }
+
+ return result.Pass();
+}
+
+scoped_ptr<base::Value> Validator::MapEntry(int index,
+ const OncValueSignature& signature,
+ const base::Value& onc_value,
+ bool* error) {
+ std::string str = base::IntToString(index);
+ path_.push_back(str);
+ scoped_ptr<base::Value> result =
+ Mapper::MapEntry(index, signature, onc_value, error);
+ DCHECK_EQ(str, path_.back());
+ path_.pop_back();
+ return result.Pass();
}
bool Validator::ValidateObjectDefault(
@@ -107,17 +199,15 @@ bool Validator::ValidateObjectDefault(
bool nested_error_occured = false;
MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
result);
- if (nested_error_occured)
- return false;
- if (found_unknown_field) {
- if (error_on_unknown_field_) {
- DVLOG(1) << "Unknown field name. Aborting.";
- return false;
- }
- DVLOG(1) << "Unknown field name. Ignoring.";
+ if (found_unknown_field && error_on_unknown_field_) {
+ DVLOG(1) << "Unknown field names are errors: Aborting.";
+ return false;
}
+ if (nested_error_occured)
+ return false;
+
return ValidateRecommendedField(signature, result);
}
@@ -140,8 +230,8 @@ bool Validator::ValidateRecommendedField(
recommended.reset(recommended_list);
if (!managed_onc_) {
- DVLOG(1) << "Found a " << onc::kRecommended
- << " field in unmanaged ONC. Removing it.";
+ LOG(WARNING) << WarningHeader() << "Found the field '" << onc::kRecommended
+ << "' in an unmanaged ONC. Removing it.";
return true;
}
@@ -169,13 +259,19 @@ bool Validator::ValidateRecommendedField(
}
if (found_error) {
- DVLOG(1) << "Found " << error_cause << " field name '" << field_name
- << "' in kRecommended array. "
- << (error_on_wrong_recommended_ ? "Aborting." : "Ignoring.");
- if (error_on_wrong_recommended_)
+ error_or_warning_found_ = true;
+ path_.push_back(onc::kRecommended);
+ std::string message = MessageHeader(error_on_wrong_recommended_) +
+ "The " + error_cause + " field '" + field_name +
+ "' cannot be recommended.";
+ path_.pop_back();
+ if (error_on_wrong_recommended_) {
+ LOG(ERROR) << message;
return false;
- else
+ } else {
+ LOG(WARNING) << message;
continue;
+ }
}
repaired_recommended->Append((*it)->DeepCopy());
@@ -195,33 +291,94 @@ std::string JoinStringRange(const char** range_begin,
return JoinString(string_vector, separator);
}
-bool RequireAnyOf(const std::string &actual, const char** valid_values) {
+} // namespace
+
+bool Validator::FieldExistsAndHasNoValidValue(
+ const base::DictionaryValue& object,
+ const std::string &field_name,
+ const char** valid_values) {
+ std::string actual_value;
+ if (!object.GetStringWithoutPathExpansion(field_name, &actual_value))
+ return false;
+
const char** it = valid_values;
for (; *it != NULL; ++it) {
- if (actual == *it)
- return true;
+ if (actual_value == *it)
+ return false;
}
- DVLOG(1) << "Found " << actual << ", but expected one of "
- << JoinStringRange(valid_values, it, ", ");
- return false;
+ error_or_warning_found_ = true;
+ std::string valid_values_str =
+ "[" + JoinStringRange(valid_values, it, ", ") + "]";
+ path_.push_back(field_name);
+ LOG(ERROR) << ErrorHeader() << "Found value '" << actual_value <<
+ "', but expected one of the values " << valid_values_str;
+ path_.pop_back();
+ return true;
}
-bool IsInRange(int actual, int lower_bound, int upper_bound) {
- if (lower_bound <= actual && actual <= upper_bound)
- return true;
- DVLOG(1) << "Found " << actual << ", which is out of range [" << lower_bound
- << ", " << upper_bound << "]";
- return false;
+bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
+ const std::string &field_name,
+ int lower_bound,
+ int upper_bound) {
+ int actual_value;
+ if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
+ (lower_bound <= actual_value && actual_value <= upper_bound)) {
+ return false;
+ }
+ error_or_warning_found_ = true;
+ path_.push_back(field_name);
+ LOG(ERROR) << ErrorHeader() << "Found value '" << actual_value
+ << "', but expected a value in the range [" << lower_bound
+ << ", " << upper_bound << "] (boundaries inclusive)";
+ path_.pop_back();
+ return true;
}
-bool RequireField(const base::DictionaryValue& dict, std::string key) {
- if (dict.HasKey(key))
+bool Validator::RequireField(const base::DictionaryValue& dict,
+ const std::string& field_name) {
+ if (dict.HasKey(field_name))
return true;
- DVLOG(1) << "Required field " << key << " missing.";
+ error_or_warning_found_ = true;
+ LOG(ERROR) << ErrorHeader() << "The required field '" << field_name
+ << "' is missing.";
return false;
}
-} // namespace
+bool Validator::ValidateToplevelConfiguration(
+ const base::DictionaryValue& onc_object,
+ base::DictionaryValue* result) {
+ if (!ValidateObjectDefault(kToplevelConfigurationSignature,
+ onc_object, result)) {
+ return false;
+ }
+
+ static const char* kValidTypes[] =
+ { kUnencryptedConfiguration, kEncryptedConfiguration, NULL };
+ if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes))
+ return false;
+
+ bool allRequiredExist = true;
+
+ // Not part of the ONC spec yet:
+ // We don't require the type field and default to UnencryptedConfiguration.
+ std::string type = kUnencryptedConfiguration;
+ result->GetStringWithoutPathExpansion(kType, &type);
+ if (type == kUnencryptedConfiguration &&
+ !result->HasKey(kNetworkConfigurations) &&
+ !result->HasKey(kCertificates)) {
+ error_or_warning_found_ = true;
+ std::string message = MessageHeader(error_on_missing_field_) +
+ "Neither the field '" + kNetworkConfigurations + "' nor '" +
+ kCertificates + "is present, but at least one is required.";
+ if (error_on_missing_field_)
+ LOG(ERROR) << message;
+ else
+ LOG(WARNING) << message;
+ allRequiredExist = false;
+ }
+
+ return !error_on_missing_field_ || allRequiredExist;
+}
bool Validator::ValidateNetworkConfiguration(
const base::DictionaryValue& onc_object,
@@ -231,12 +388,9 @@ bool Validator::ValidateNetworkConfiguration(
return false;
}
- std::string type;
static const char* kValidTypes[] = { kEthernet, kVPN, kWiFi, NULL };
- if (result->GetStringWithoutPathExpansion(kType, &type) &&
- !RequireAnyOf(type, kValidTypes)) {
+ if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes))
return false;
- }
bool allRequiredExist = RequireField(*result, kGUID);
@@ -245,6 +399,9 @@ bool Validator::ValidateNetworkConfiguration(
if (!remove) {
allRequiredExist &= RequireField(*result, kName);
allRequiredExist &= RequireField(*result, kType);
+
+ std::string type;
+ result->GetStringWithoutPathExpansion(kType, &type);
allRequiredExist &= type.empty() || RequireField(*result, type);
}
@@ -258,14 +415,15 @@ bool Validator::ValidateEthernet(
if (!ValidateObjectDefault(kEthernetSignature, onc_object, result))
return false;
- std::string auth;
static const char* kValidAuthentications[] = { kNone, k8021X, NULL };
- if (result->GetStringWithoutPathExpansion(kAuthentication, &auth) &&
- !RequireAnyOf(auth, kValidAuthentications)) {
+ if (FieldExistsAndHasNoValidValue(*result, kAuthentication,
+ kValidAuthentications)) {
return false;
}
bool allRequiredExist = true;
+ std::string auth;
+ result->GetStringWithoutPathExpansion(kAuthentication, &auth);
if (auth == k8021X)
allRequiredExist &= RequireField(*result, kEAP);
@@ -279,19 +437,17 @@ bool Validator::ValidateIPConfig(
if (!ValidateObjectDefault(kIPConfigSignature, onc_object, result))
return false;
- std::string type;
static const char* kValidTypes[] = { kIPv4, kIPv6, NULL };
- if (result->GetStringWithoutPathExpansion(ipconfig::kType, &type) &&
- !RequireAnyOf(type, kValidTypes)) {
+ if (FieldExistsAndHasNoValidValue(*result, ipconfig::kType, kValidTypes))
return false;
- }
- int routing_prefix;
+ std::string type;
+ result->GetStringWithoutPathExpansion(ipconfig::kType, &type);
int lower_bound = 1;
// In case of missing type, choose higher upper_bound.
int upper_bound = (type == kIPv4) ? 32 : 128;
- if (result->GetIntegerWithoutPathExpansion(kRoutingPrefix, &routing_prefix) &&
- !IsInRange(routing_prefix, lower_bound, upper_bound)) {
+ if (FieldExistsAndIsNotInRange(*result, kRoutingPrefix,
+ lower_bound, upper_bound)) {
return false;
}
@@ -309,16 +465,16 @@ bool Validator::ValidateWiFi(
if (!ValidateObjectDefault(kWiFiSignature, onc_object, result))
return false;
- std::string security;
static const char* kValidSecurities[] =
{ kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL };
- if (result->GetStringWithoutPathExpansion(kSecurity, &security) &&
- !RequireAnyOf(security, kValidSecurities)) {
+ if (FieldExistsAndHasNoValidValue(*result, kSecurity, kValidSecurities))
return false;
- }
bool allRequiredExist = RequireField(*result, kSecurity) &
RequireField(*result, kSSID);
+
+ std::string security;
+ result->GetStringWithoutPathExpansion(kSecurity, &security);
if (security == kWEP_8021X || security == kWPA_EAP)
allRequiredExist &= RequireField(*result, kEAP);
else if (security == kWEP_PSK || security == kWPA_PSK)
@@ -334,16 +490,14 @@ bool Validator::ValidateVPN(
if (!ValidateObjectDefault(kVPNSignature, onc_object, result))
return false;
- std::string type;
static const char* kValidTypes[] =
{ kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL };
- if (result->GetStringWithoutPathExpansion(vpn::kType, &type) &&
- !RequireAnyOf(type, kValidTypes)) {
+ if (FieldExistsAndHasNoValidValue(*result, vpn::kType, kValidTypes))
return false;
- }
bool allRequiredExist = RequireField(*result, vpn::kType);
-
+ std::string type;
+ result->GetStringWithoutPathExpansion(vpn::kType, &type);
if (type == kOpenVPN) {
allRequiredExist &= RequireField(*result, kOpenVPN);
} else if (type == kIPsec) {
@@ -364,26 +518,26 @@ bool Validator::ValidateIPsec(
if (!ValidateObjectDefault(kIPsecSignature, onc_object, result))
return false;
- std::string auth;
static const char* kValidAuthentications[] = { kPSK, kCert, NULL };
- if (result->GetStringWithoutPathExpansion(kAuthenticationType, &auth) &&
- !RequireAnyOf(auth, kValidAuthentications)) {
- return false;
- }
-
- std::string cert_type;
static const char* kValidCertTypes[] = { kRef, kPattern, NULL };
- if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
- !RequireAnyOf(cert_type, kValidCertTypes)) {
+ // Using strict bit-wise OR to check all conditions.
+ if (FieldExistsAndHasNoValidValue(*result, kAuthenticationType,
+ kValidAuthentications) |
+ FieldExistsAndHasNoValidValue(*result, kClientCertType,
+ kValidCertTypes)) {
return false;
}
bool allRequiredExist = RequireField(*result, kAuthenticationType) &
RequireField(*result, kIKEVersion);
+ std::string auth;
+ result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
if (auth == kCert) {
allRequiredExist &= RequireField(*result, kClientCertType) &
RequireField(*result, kServerCARef);
}
+ std::string cert_type;
+ result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
if (cert_type == kPattern)
allRequiredExist &= RequireField(*result, kClientCertPattern);
else if (cert_type == kRef)
@@ -401,31 +555,25 @@ bool Validator::ValidateOpenVPN(
if (!ValidateObjectDefault(kOpenVPNSignature, onc_object, result))
return false;
- std::string auth_retry;
static const char* kValidAuthRetryValues[] =
{ openvpn::kNone, kInteract, kNoInteract, NULL };
- if (result->GetStringWithoutPathExpansion(kAuthRetry, &auth_retry) &&
- !RequireAnyOf(auth_retry, kValidAuthRetryValues)) {
- return false;
- }
-
- std::string cert_type;
static const char* kValidCertTypes[] =
{ certificate::kNone, kRef, kPattern, NULL };
- if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
- !RequireAnyOf(cert_type, kValidCertTypes)) {
- return false;
- }
-
- std::string cert_tls;
static const char* kValidCertTlsValues[] =
{ openvpn::kNone, openvpn::kServer, NULL };
- if (result->GetStringWithoutPathExpansion(kRemoteCertTLS, &cert_tls) &&
- !RequireAnyOf(cert_tls, kValidCertTlsValues)) {
+
+ // Using strict bit-wise OR to check all conditions.
+ if (FieldExistsAndHasNoValidValue(*result, kAuthRetry,
+ kValidAuthRetryValues) |
+ FieldExistsAndHasNoValidValue(*result, kClientCertType, kValidCertTypes) |
+ FieldExistsAndHasNoValidValue(*result, kRemoteCertTLS,
+ kValidCertTlsValues)) {
return false;
}
bool allRequiredExist = RequireField(*result, kClientCertType);
+ std::string cert_type;
+ result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
if (cert_type == kPattern)
allRequiredExist &= RequireField(*result, kClientCertPattern);
else if (cert_type == kRef)
@@ -444,9 +592,15 @@ bool Validator::ValidateCertificatePattern(
bool allRequiredExist = true;
if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
!result->HasKey(kIssuerCARef)) {
+ error_or_warning_found_ = true;
allRequiredExist = false;
- DVLOG(1) << "None of the fields " << kSubject << ", " << kIssuer << ", and "
- << kIssuerCARef << " exists, but at least one is required.";
+ std::string message = MessageHeader(error_on_missing_field_) +
+ "None of the fields '" + kSubject + "', '" + kIssuer + "', and '" +
+ kIssuerCARef + "' is present, but at least one is required.";
+ if (error_on_missing_field_)
+ LOG(ERROR) << message;
+ else
+ LOG(WARNING) << message;
}
return !error_on_missing_field_ || allRequiredExist;
@@ -458,15 +612,13 @@ bool Validator::ValidateProxySettings(const base::DictionaryValue& onc_object,
if (!ValidateObjectDefault(kProxySettingsSignature, onc_object, result))
return false;
- std::string type;
static const char* kValidTypes[] = { kDirect, kManual, kPAC, kWPAD, NULL };
- if (result->GetStringWithoutPathExpansion(proxy::kType, &type) &&
- !RequireAnyOf(type, kValidTypes)) {
+ if (FieldExistsAndHasNoValidValue(*result, proxy::kType, kValidTypes))
return false;
- }
bool allRequiredExist = RequireField(*result, proxy::kType);
-
+ std::string type;
+ result->GetStringWithoutPathExpansion(proxy::kType, &type);
if (type == kManual)
allRequiredExist &= RequireField(*result, kManual);
else if (type == kPAC)
@@ -494,32 +646,24 @@ bool Validator::ValidateEAP(const base::DictionaryValue& onc_object,
if (!ValidateObjectDefault(kEAPSignature, onc_object, result))
return false;
- std::string inner;
static const char* kValidInnerValues[] =
{ kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL };
- if (result->GetStringWithoutPathExpansion(kInner, &inner) &&
- !RequireAnyOf(inner, kValidInnerValues)) {
- return false;
- }
-
- std::string outer;
static const char* kValidOuterValues[] =
{ kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA,
NULL };
- if (result->GetStringWithoutPathExpansion(kOuter, &outer) &&
- !RequireAnyOf(outer, kValidOuterValues)) {
- return false;
- }
-
- std::string cert_type;
static const char* kValidCertTypes[] = { kRef, kPattern, NULL };
- if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) &&
- !RequireAnyOf(cert_type, kValidCertTypes )) {
+
+ // Using strict bit-wise OR to check all conditions.
+ if (FieldExistsAndHasNoValidValue(*result, kInner, kValidInnerValues) |
+ FieldExistsAndHasNoValidValue(*result, kOuter, kValidOuterValues) |
+ FieldExistsAndHasNoValidValue(*result, kClientCertType,
+ kValidCertTypes)) {
return false;
}
bool allRequiredExist = RequireField(*result, kOuter);
-
+ std::string cert_type;
+ result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
if (cert_type == kPattern)
allRequiredExist &= RequireField(*result, kClientCertPattern);
else if (cert_type == kRef)
@@ -535,12 +679,9 @@ bool Validator::ValidateCertificate(
if (!ValidateObjectDefault(kCertificateSignature, onc_object, result))
return false;
- std::string type;
static const char* kValidTypes[] = { kClient, kServer, kAuthority, NULL };
- if (result->GetStringWithoutPathExpansion(certificate::kType, &type) &&
- !RequireAnyOf(type, kValidTypes)) {
+ if (FieldExistsAndHasNoValidValue(*result, certificate::kType, kValidTypes))
return false;
- }
bool allRequiredExist = RequireField(*result, kGUID);
@@ -549,6 +690,8 @@ bool Validator::ValidateCertificate(
if (!remove) {
allRequiredExist &= RequireField(*result, certificate::kType);
+ std::string type;
+ result->GetStringWithoutPathExpansion(certificate::kType, &type);
if (type == kClient)
allRequiredExist &= RequireField(*result, kPKCS12);
else if (type == kServer || type == kAuthority)
@@ -558,5 +701,19 @@ bool Validator::ValidateCertificate(
return !error_on_missing_field_ || allRequiredExist;
}
+std::string Validator::WarningHeader() {
+ return MessageHeader(false);
+}
+
+std::string Validator::ErrorHeader() {
+ return MessageHeader(true);
+}
+
+std::string Validator::MessageHeader(bool is_error) {
+ std::string path = path_.empty() ? "toplevel" : JoinString(path_, ".");
+ std::string message = "At " + path + ": ";
+ return message;
+}
+
} // namespace onc
} // namespace chromeos
diff --git a/chromeos/network/onc/onc_validator.h b/chromeos/network/onc/onc_validator.h
index 4a74272..cef7ef5 100644
--- a/chromeos/network/onc/onc_validator.h
+++ b/chromeos/network/onc/onc_validator.h
@@ -5,13 +5,16 @@
#ifndef CHROMEOS_NETWORK_ONC_ONC_VALIDATOR_H_
#define CHROMEOS_NETWORK_ONC_ONC_VALIDATOR_H_
+#include <string>
+#include <vector>
+
#include "base/memory/scoped_ptr.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/network/onc/onc_mapper.h"
namespace base {
-class Value;
class DictionaryValue;
+class Value;
}
namespace chromeos {
@@ -19,27 +22,44 @@ namespace onc {
struct OncValueSignature;
+// The ONC Validator searches for the following invalid cases:
+// - a value is found that has the wrong type or is not expected according to
+// the ONC spec (always an error)
+//
+// - a field name is found that is not part of the signature
+// (controlled by flag |error_on_unknown_field|)
+//
+// - a kRecommended array contains a field name that is not part of the
+// enclosing object's signature or if that field is dictionary typed
+// (controlled by flag |error_on_wrong_recommended|)
+//
+// - |managed_onc| is false and a field with name kRecommended is found
+// (always ignored)
+//
+// - a required field is missing (controlled by flag |error_on_missing_field|)
+//
+// If one of these invalid cases occurs and, in case of a controlling flag, that
+// flag is true, then it is an error. The function ValidateAndRepairObject sets
+// |result| to INVALID and returns NULL.
+//
+// Otherwise, a DeepCopy of the validated object is created, which contains
+// all but the invalid fields and values.
+//
+// If one of the invalid cases occurs and the controlling flag is false, then
+// it is a warning. The function ValidateAndRepairObject sets |result| to
+// VALID_WITH_WARNINGS and returns the repaired copy.
+//
+// If no error occurred, |result| is set to VALID and an exact DeepCopy is
+// returned.
class CHROMEOS_EXPORT Validator : public Mapper {
public:
- // Creates a Validator that searches for the following invalid cases:
- // - a field name is found that is not part of the signature
- // (controlled by |error_on_unknown_field|)
- //
- // - a kRecommended array contains a field name that is not part of the
- // enclosing object's signature or if that field is dictionary typed
- // (controlled by |error_on_wrong_recommended|)
- //
- // - |managed_onc| is false and a field with name kRecommended is found
- // (always ignored)
- //
- // - a required field is missing (controlled by |error_on_missing_field|)
- //
- // If one of these invalid cases occurs and the controlling flag is true, then
- // it is an error and the validation stops. The function
- // ValidateAndRepairObject returns NULL.
- //
- // If no error occurred, then a DeepCopy of the validated object is created,
- // which contains all but the invalid fields and values.
+ enum Result {
+ VALID,
+ VALID_WITH_WARNINGS,
+ INVALID
+ };
+
+ // See the class comment.
Validator(bool error_on_unknown_field,
bool error_on_wrong_recommended,
bool error_on_missing_field,
@@ -49,25 +69,30 @@ class CHROMEOS_EXPORT Validator : public Mapper {
// Validate the given |onc_object| according to |object_signature|. The
// |object_signature| has to be a pointer to one of the signatures in
- // |onc_signature.h|. If an error is found, the function returns NULL. If
- // possible (no error encountered) a DeepCopy is created that contains all but
- // the invalid fields and values and returns this "repaired" object.
- // That means, if not handled as an error, then the following are ignored:
+ // |onc_signature.h|. If an error is found, the function returns NULL and sets
+ // |result| to INVALID. If possible (no error encountered) a DeepCopy is
+ // created that contains all but the invalid fields and values and returns
+ // this "repaired" object. That means, if not handled as an error, then the
+ // following are dropped from the copy:
// - unknown fields
// - invalid field names in kRecommended arrays
// - kRecommended fields in an unmanaged ONC
- // For details, see the comment at the Constructor.
+ // If any of these cases occurred, sets |result| to VALID_WITH_WARNINGS and
+ // otherwise to VALID.
+ // For details, see the class comment.
scoped_ptr<base::DictionaryValue> ValidateAndRepairObject(
const OncValueSignature* object_signature,
- const base::DictionaryValue& onc_object);
+ const base::DictionaryValue& onc_object,
+ Result* result);
private:
- // Overriden from Mapper:
+ // Overridden from Mapper:
// Compare |onc_value|s type with |onc_type| and validate/repair according to
// |signature|. On error returns NULL.
virtual scoped_ptr<base::Value> MapValue(
const OncValueSignature& signature,
- const base::Value& onc_value) OVERRIDE;
+ const base::Value& onc_value,
+ bool* error) OVERRIDE;
// Dispatch to the right validation function according to
// |signature|. Iterates over all fields and recursively validates/repairs
@@ -75,7 +100,23 @@ class CHROMEOS_EXPORT Validator : public Mapper {
// repaired dictionary. On error returns NULL.
virtual scoped_ptr<base::DictionaryValue> MapObject(
const OncValueSignature& signature,
- const base::DictionaryValue& onc_object) OVERRIDE;
+ const base::DictionaryValue& onc_object,
+ bool* error) OVERRIDE;
+
+ // Pushes/pops the |field_name| to |path_|, otherwise like |Mapper::MapField|.
+ virtual scoped_ptr<base::Value> MapField(
+ const std::string& field_name,
+ const OncValueSignature& object_signature,
+ const base::Value& onc_value,
+ bool* found_unknown_field,
+ bool* error) OVERRIDE;
+
+ // Pushes/pops the index to |path_|, otherwise like |Mapper::MapEntry|.
+ virtual scoped_ptr<base::Value> MapEntry(
+ int index,
+ const OncValueSignature& signature,
+ const base::Value& onc_value,
+ bool* error) OVERRIDE;
// This is the default validation of objects/dictionaries. Validates
// |onc_object| according to |object_signature|. |result| must point to a
@@ -91,6 +132,10 @@ class CHROMEOS_EXPORT Validator : public Mapper {
const OncValueSignature& object_signature,
base::DictionaryValue* result);
+ bool ValidateToplevelConfiguration(
+ const base::DictionaryValue& onc_object,
+ base::DictionaryValue* result);
+
bool ValidateNetworkConfiguration(
const base::DictionaryValue& onc_object,
base::DictionaryValue* result);
@@ -139,11 +184,34 @@ class CHROMEOS_EXPORT Validator : public Mapper {
const base::DictionaryValue& onc_object,
base::DictionaryValue* result);
+ bool FieldExistsAndHasNoValidValue(const base::DictionaryValue& object,
+ const std::string &field_name,
+ const char** valid_values);
+
+ bool FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
+ const std::string &field_name,
+ int lower_bound,
+ int upper_bound);
+
+ bool RequireField(const base::DictionaryValue& dict, const std::string& key);
+
+ std::string WarningHeader();
+ std::string ErrorHeader();
+ std::string MessageHeader(bool is_error);
+
const bool error_on_unknown_field_;
const bool error_on_wrong_recommended_;
const bool error_on_missing_field_;
const bool managed_onc_;
+ // The path of field names and indices to the current value. Indices
+ // are stored as strings in decimal notation.
+ std::vector<std::string> path_;
+
+ // Tracks if an error or warning occurred within validation initiated by
+ // function ValidateAndRepairObject.
+ bool error_or_warning_found_;
+
DISALLOW_COPY_AND_ASSIGN(Validator);
};
diff --git a/chromeos/network/onc/onc_validator_unittest.cc b/chromeos/network/onc/onc_validator_unittest.cc
index f02e9cf..5d543fe 100644
--- a/chromeos/network/onc/onc_validator_unittest.cc
+++ b/chromeos/network/onc/onc_validator_unittest.cc
@@ -5,12 +5,14 @@
#include "chromeos/network/onc/onc_validator.h"
#include <string>
+#include <utility>
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "chromeos/network/onc/onc_constants.h"
#include "chromeos/network/onc/onc_signature.h"
#include "chromeos/network/onc/onc_test_utils.h"
+#include "chromeos/network/onc/onc_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
@@ -28,25 +30,60 @@ scoped_ptr<Validator> CreateLiberalValidator(bool managed_onc) {
}
} // namespace
+TEST(ONCValidatorValidTest, EmptyUnencryptedConfiguration) {
+ scoped_ptr<Validator> validator(CreateStrictValidator(true));
+ scoped_ptr<const base::DictionaryValue> original(
+ ReadDictionaryFromJson(kEmptyUnencryptedConfiguration));
+
+ Validator::Result result;
+ scoped_ptr<const base::DictionaryValue> repaired(
+ validator->ValidateAndRepairObject(&kToplevelConfigurationSignature,
+ *original, &result));
+ EXPECT_EQ(Validator::VALID, result);
+ EXPECT_TRUE(test_utils::Equals(original.get(), repaired.get()));
+}
+
// This test case is about validating valid ONC objects.
-TEST(ONCValidatorValidTest, ValidPolicyOnc) {
+class ONCValidatorValidTest
+ : public ::testing::TestWithParam<
+ std::pair<std::string, const OncValueSignature*> > {
+ protected:
+ std::string GetFilename() const {
+ return GetParam().first;
+ }
+
+ const OncValueSignature* GetSignature() const {
+ return GetParam().second;
+ }
+};
+
+TEST_P(ONCValidatorValidTest, ValidPolicyOnc) {
scoped_ptr<Validator> validator(CreateStrictValidator(true));
- scoped_ptr<const base::DictionaryValue> network;
- scoped_ptr<base::DictionaryValue> repaired;
-
- network = test_utils::ReadTestDictionary("policy.onc");
- repaired = validator->ValidateAndRepairObject(
- &kNetworkConfigurationSignature,
- *network);
- EXPECT_TRUE(test_utils::Equals(network.get(), repaired.get()));
-
- network = test_utils::ReadTestDictionary("valid.onc");
- repaired = validator->ValidateAndRepairObject(
- &kNetworkConfigurationSignature,
- *network);
- EXPECT_TRUE(test_utils::Equals(network.get(), repaired.get()));
+ scoped_ptr<const base::DictionaryValue> original(
+ test_utils::ReadTestDictionary(GetFilename()));
+
+ Validator::Result result;
+ scoped_ptr<const base::DictionaryValue> repaired(
+ validator->ValidateAndRepairObject(GetSignature(), *original, &result));
+ EXPECT_EQ(Validator::VALID, result);
+ EXPECT_TRUE(test_utils::Equals(original.get(), repaired.get()));
}
+INSTANTIATE_TEST_CASE_P(
+ ONCValidatorValidTest,
+ ONCValidatorValidTest,
+ ::testing::Values(std::make_pair("managed_toplevel.onc",
+ &kToplevelConfigurationSignature),
+ std::make_pair("encrypted.onc",
+ &kToplevelConfigurationSignature),
+ std::make_pair("managed_vpn.onc",
+ &kNetworkConfigurationSignature),
+ std::make_pair("managed_ethernet.onc",
+ &kNetworkConfigurationSignature),
+ // Ignore recommended arrays in unmanaged ONC:
+ std::make_pair("recommended_in_unmanaged.onc",
+ &kNetworkConfigurationSignature)));
+
// Validate invalid ONC objects and check the resulting repaired object. This
// test fixture loads a test json file into |invalid_| containing several test
// objects which can be accessed by their path. The test boolean parameter
@@ -71,11 +108,14 @@ class ONCValidatorInvalidTest : public ::testing::TestWithParam<bool> {
const base::DictionaryValue* object = NULL;
ASSERT_TRUE(invalid_->GetDictionary(path_to_object, &object));
+ Validator::Result result;
scoped_ptr<base::DictionaryValue> actual_repaired =
- validator->ValidateAndRepairObject(signature, *object);
+ validator->ValidateAndRepairObject(signature, *object, &result);
if (GetParam() || path_to_repaired == "") {
+ EXPECT_EQ(Validator::INVALID, result);
EXPECT_EQ(NULL, actual_repaired.get());
} else {
+ EXPECT_EQ(Validator::VALID_WITH_WARNINGS, result);
const base::DictionaryValue* expected_repaired = NULL;
invalid_->GetDictionary(path_to_repaired, &expected_repaired);
EXPECT_TRUE(test_utils::Equals(expected_repaired, actual_repaired.get()));