From 200799c3b53491d58480edcc82cc332dd5362e1b Mon Sep 17 00:00:00 2001 From: "joaodasilva@chromium.org" Date: Sun, 8 Dec 2013 22:23:46 +0000 Subject: Ignore unknown attributes when parsing JSON schemas. JSON schemas are used by extensions that support enterprise management, to declare the policies that they support. The current parser rejects schemas with unknown attributes; this CL lifts that restriction for 2 reasons: - the JSON schema spec does not mandate this behavior for validators - it restricts future extensions to this format BUG=108992 Review URL: https://codereview.chromium.org/94043003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239407 0039d316-1c4b-4281-b951-d872f2087c98 --- components/json_schema/json_schema_validator.cc | 31 +++++++++++++++------- components/json_schema/json_schema_validator.h | 13 +++++++++ .../json_schema/json_schema_validator_unittest.cc | 15 +++++++++-- 3 files changed, 48 insertions(+), 11 deletions(-) (limited to 'components/json_schema') diff --git a/components/json_schema/json_schema_validator.cc b/components/json_schema/json_schema_validator.cc index 32cb93c..310975a 100644 --- a/components/json_schema/json_schema_validator.cc +++ b/components/json_schema/json_schema_validator.cc @@ -65,7 +65,9 @@ const base::Value* ExtractNameFromDictionary(const base::Value* value) { return value; } -bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { +bool IsValidSchema(const base::DictionaryValue* dict, + int options, + std::string* error) { // This array must be sorted, so that std::lower_bound can perform a // binary search. static const ExpectedType kExpectedTypes[] = { @@ -126,7 +128,7 @@ bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { // Validate the "items" attribute, which is a schema or a list of schemas. if (it.key() == schema::kItems) { if (it.value().GetAsDictionary(&dictionary_value)) { - if (!IsValidSchema(dictionary_value, error)) { + if (!IsValidSchema(dictionary_value, options, error)) { DCHECK(!error->empty()); return false; } @@ -138,7 +140,7 @@ bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { static_cast(i)); return false; } - if (!IsValidSchema(dictionary_value, error)) { + if (!IsValidSchema(dictionary_value, options, error)) { DCHECK(!error->empty()); return false; } @@ -155,9 +157,12 @@ bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { const ExpectedType* entry = std::lower_bound( kExpectedTypes, end, it.key(), CompareToString); if (entry == end || entry->key != it.key()) { + if (options & JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES) + continue; *error = base::StringPrintf("Invalid attribute %s", it.key().c_str()); return false; } + if (!it.value().IsType(entry->type)) { *error = base::StringPrintf("Invalid value for %s attribute", it.key().c_str()); @@ -185,7 +190,7 @@ bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { *error = "Invalid value for properties attribute"; return false; } - if (!IsValidSchema(dictionary_value, error)) { + if (!IsValidSchema(dictionary_value, options, error)) { DCHECK(!error->empty()); return false; } @@ -195,7 +200,7 @@ bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { // Validate "additionalProperties" attribute, which is a schema. if (it.key() == schema::kAdditionalProperties) { it.value().GetAsDictionary(&dictionary_value); - if (!IsValidSchema(dictionary_value, error)) { + if (!IsValidSchema(dictionary_value, options, error)) { DCHECK(!error->empty()); return false; } @@ -236,7 +241,7 @@ bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) { *error = "Invalid choices attribute"; return false; } - if (!IsValidSchema(dictionary_value, error)) { + if (!IsValidSchema(dictionary_value, options, error)) { DCHECK(!error->empty()); return false; } @@ -356,9 +361,17 @@ std::string JSONSchemaValidator::FormatErrorMessage(const std::string& format, scoped_ptr JSONSchemaValidator::IsValidSchema( const std::string& schema, std::string* error) { - base::JSONParserOptions options = base::JSON_PARSE_RFC; + return JSONSchemaValidator::IsValidSchema(schema, 0, error); +} + +// static +scoped_ptr JSONSchemaValidator::IsValidSchema( + const std::string& schema, + int validator_options, + std::string* error) { + base::JSONParserOptions json_options = base::JSON_PARSE_RFC; scoped_ptr json( - base::JSONReader::ReadAndReturnError(schema, options, NULL, error)); + base::JSONReader::ReadAndReturnError(schema, json_options, NULL, error)); if (!json) return scoped_ptr(); base::DictionaryValue* dict = NULL; @@ -366,7 +379,7 @@ scoped_ptr JSONSchemaValidator::IsValidSchema( *error = "Schema must be a JSON object"; return scoped_ptr(); } - if (!::IsValidSchema(dict, error)) + if (!::IsValidSchema(dict, validator_options, error)) return scoped_ptr(); ignore_result(json.release()); return make_scoped_ptr(dict); diff --git a/components/json_schema/json_schema_validator.h b/components/json_schema/json_schema_validator.h index 4584a9d..4e8acad 100644 --- a/components/json_schema/json_schema_validator.h +++ b/components/json_schema/json_schema_validator.h @@ -70,6 +70,12 @@ class JSONSchemaValidator { std::string message; }; + enum Options { + // Ignore unknown attributes. If this option is not set then unknown + // attributes will make the schema validation fail. + OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES = 1 << 0, + }; + // Error messages. static const char kUnknownTypeReference[]; static const char kInvalidChoice[]; @@ -108,6 +114,13 @@ class JSONSchemaValidator { const std::string& schema, std::string* error); + // Same as above but with |options|, which is a bitwise-OR combination of the + // Options above. + static scoped_ptr IsValidSchema( + const std::string& schema, + int options, + std::string* error); + // Creates a validator for the specified schema. // // NOTE: This constructor assumes that |schema| is well formed and valid. diff --git a/components/json_schema/json_schema_validator_unittest.cc b/components/json_schema/json_schema_validator_unittest.cc index 6372032..73809de 100644 --- a/components/json_schema/json_schema_validator_unittest.cc +++ b/components/json_schema/json_schema_validator_unittest.cc @@ -83,8 +83,7 @@ TEST(JSONSchemaValidator, IsValidSchema) { "{" " \"type\": \"string\"," " \"enum\": [ { \"name\": {} } ]" // "enum" name must be a simple value. - "}", - &error)); + "}", &error)); EXPECT_FALSE(JSONSchemaValidator::IsValidSchema( "{" " \"type\": \"array\"," @@ -132,4 +131,16 @@ TEST(JSONSchemaValidator, IsValidSchema) { " \"type\": \"any\"" " }" "}", &error)) << error; + EXPECT_TRUE(JSONSchemaValidator::IsValidSchema( + "{" + " \"type\": \"object\"," + " \"unknown attribute\": \"that should just be ignored\"" + "}", + JSONSchemaValidator::OPTIONS_IGNORE_UNKNOWN_ATTRIBUTES, + &error)) << error; + EXPECT_FALSE(JSONSchemaValidator::IsValidSchema( + "{" + " \"type\": \"object\"," + " \"unknown attribute\": \"that will cause a failure\"" + "}", 0, &error)) << error; } -- cgit v1.1