| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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 "components/policy/core/common/policy_schema.h" | |
| 6 | |
| 7 #include "base/compiler_specific.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/stl_util.h" | |
| 10 #include "components/json_schema/json_schema_constants.h" | |
| 11 #include "components/json_schema/json_schema_validator.h" | |
| 12 | |
| 13 namespace policy { | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 const char kJSONSchemaVersion[] = "http://json-schema.org/draft-03/schema#"; | |
| 18 | |
| 19 // Describes the properties of a TYPE_DICTIONARY policy schema. | |
| 20 class DictionaryPolicySchema : public PolicySchema { | |
| 21 public: | |
| 22 static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema, | |
| 23 std::string* error); | |
| 24 | |
| 25 virtual ~DictionaryPolicySchema(); | |
| 26 | |
| 27 virtual const PolicySchemaMap* GetProperties() const OVERRIDE; | |
| 28 virtual const PolicySchema* GetSchemaForAdditionalProperties() const OVERRIDE; | |
| 29 | |
| 30 private: | |
| 31 DictionaryPolicySchema(); | |
| 32 | |
| 33 PolicySchemaMap properties_; | |
| 34 scoped_ptr<PolicySchema> additional_properties_; | |
| 35 | |
| 36 DISALLOW_COPY_AND_ASSIGN(DictionaryPolicySchema); | |
| 37 }; | |
| 38 | |
| 39 // Describes the items of a TYPE_LIST policy schema. | |
| 40 class ListPolicySchema : public PolicySchema { | |
| 41 public: | |
| 42 static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema, | |
| 43 std::string* error); | |
| 44 | |
| 45 virtual ~ListPolicySchema(); | |
| 46 | |
| 47 virtual const PolicySchema* GetSchemaForItems() const OVERRIDE; | |
| 48 | |
| 49 private: | |
| 50 ListPolicySchema(); | |
| 51 | |
| 52 scoped_ptr<PolicySchema> items_schema_; | |
| 53 | |
| 54 DISALLOW_COPY_AND_ASSIGN(ListPolicySchema); | |
| 55 }; | |
| 56 | |
| 57 bool SchemaTypeToValueType(const std::string& type_string, | |
| 58 base::Value::Type* type) { | |
| 59 // Note: "any" is not an accepted type. | |
| 60 static const struct { | |
| 61 const char* schema_type; | |
| 62 base::Value::Type value_type; | |
| 63 } kSchemaToValueTypeMap[] = { | |
| 64 { json_schema_constants::kArray, base::Value::TYPE_LIST }, | |
| 65 { json_schema_constants::kBoolean, base::Value::TYPE_BOOLEAN }, | |
| 66 { json_schema_constants::kInteger, base::Value::TYPE_INTEGER }, | |
| 67 { json_schema_constants::kNull, base::Value::TYPE_NULL }, | |
| 68 { json_schema_constants::kNumber, base::Value::TYPE_DOUBLE }, | |
| 69 { json_schema_constants::kObject, base::Value::TYPE_DICTIONARY }, | |
| 70 { json_schema_constants::kString, base::Value::TYPE_STRING }, | |
| 71 }; | |
| 72 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) { | |
| 73 if (kSchemaToValueTypeMap[i].schema_type == type_string) { | |
| 74 *type = kSchemaToValueTypeMap[i].value_type; | |
| 75 return true; | |
| 76 } | |
| 77 } | |
| 78 return false; | |
| 79 } | |
| 80 | |
| 81 scoped_ptr<PolicySchema> ParseSchema(const base::DictionaryValue& schema, | |
| 82 std::string* error) { | |
| 83 std::string type_string; | |
| 84 if (!schema.GetString(json_schema_constants::kType, &type_string)) { | |
| 85 *error = "The schema type must be declared."; | |
| 86 return scoped_ptr<PolicySchema>(); | |
| 87 } | |
| 88 | |
| 89 base::Value::Type type = base::Value::TYPE_NULL; | |
| 90 if (!SchemaTypeToValueType(type_string, &type)) { | |
| 91 *error = "The \"any\" type can't be used."; | |
| 92 return scoped_ptr<PolicySchema>(); | |
| 93 } | |
| 94 | |
| 95 switch (type) { | |
| 96 case base::Value::TYPE_DICTIONARY: | |
| 97 return DictionaryPolicySchema::Parse(schema, error); | |
| 98 case base::Value::TYPE_LIST: | |
| 99 return ListPolicySchema::Parse(schema, error); | |
| 100 default: | |
| 101 return make_scoped_ptr(new PolicySchema(type)); | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 DictionaryPolicySchema::DictionaryPolicySchema() | |
| 106 : PolicySchema(base::Value::TYPE_DICTIONARY) {} | |
| 107 | |
| 108 DictionaryPolicySchema::~DictionaryPolicySchema() { | |
| 109 STLDeleteValues(&properties_); | |
| 110 } | |
| 111 | |
| 112 const PolicySchemaMap* DictionaryPolicySchema::GetProperties() const { | |
| 113 return &properties_; | |
| 114 } | |
| 115 | |
| 116 const PolicySchema* | |
| 117 DictionaryPolicySchema::GetSchemaForAdditionalProperties() const { | |
| 118 return additional_properties_.get(); | |
| 119 } | |
| 120 | |
| 121 // static | |
| 122 scoped_ptr<PolicySchema> DictionaryPolicySchema::Parse( | |
| 123 const base::DictionaryValue& schema, | |
| 124 std::string* error) { | |
| 125 scoped_ptr<DictionaryPolicySchema> dict_schema(new DictionaryPolicySchema()); | |
| 126 | |
| 127 const base::DictionaryValue* dict = NULL; | |
| 128 const base::DictionaryValue* properties = NULL; | |
| 129 if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) { | |
| 130 for (base::DictionaryValue::Iterator it(*properties); | |
| 131 !it.IsAtEnd(); it.Advance()) { | |
| 132 // This should have been verified by the JSONSchemaValidator. | |
| 133 CHECK(it.value().GetAsDictionary(&dict)); | |
| 134 scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error); | |
| 135 if (!sub_schema) | |
| 136 return scoped_ptr<PolicySchema>(); | |
| 137 dict_schema->properties_[it.key()] = sub_schema.release(); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, | |
| 142 &dict)) { | |
| 143 scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error); | |
| 144 if (!sub_schema) | |
| 145 return scoped_ptr<PolicySchema>(); | |
| 146 dict_schema->additional_properties_ = sub_schema.Pass(); | |
| 147 } | |
| 148 | |
| 149 return dict_schema.PassAs<PolicySchema>(); | |
| 150 } | |
| 151 | |
| 152 ListPolicySchema::ListPolicySchema() | |
| 153 : PolicySchema(base::Value::TYPE_LIST) {} | |
| 154 | |
| 155 ListPolicySchema::~ListPolicySchema() {} | |
| 156 | |
| 157 const PolicySchema* ListPolicySchema::GetSchemaForItems() const { | |
| 158 return items_schema_.get(); | |
| 159 } | |
| 160 | |
| 161 scoped_ptr<PolicySchema> ListPolicySchema::Parse( | |
| 162 const base::DictionaryValue& schema, | |
| 163 std::string* error) { | |
| 164 const base::DictionaryValue* dict = NULL; | |
| 165 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) { | |
| 166 *error = "Arrays must declare a single schema for their items."; | |
| 167 return scoped_ptr<PolicySchema>(); | |
| 168 } | |
| 169 scoped_ptr<PolicySchema> items_schema = ParseSchema(*dict, error); | |
| 170 if (!items_schema) | |
| 171 return scoped_ptr<PolicySchema>(); | |
| 172 | |
| 173 scoped_ptr<ListPolicySchema> list_schema(new ListPolicySchema()); | |
| 174 list_schema->items_schema_ = items_schema.Pass(); | |
| 175 return list_schema.PassAs<PolicySchema>(); | |
| 176 } | |
| 177 | |
| 178 } // namespace | |
| 179 | |
| 180 PolicySchema::PolicySchema(base::Value::Type type) | |
| 181 : type_(type) {} | |
| 182 | |
| 183 PolicySchema::~PolicySchema() {} | |
| 184 | |
| 185 const PolicySchemaMap* PolicySchema::GetProperties() const { | |
| 186 NOTREACHED(); | |
| 187 return NULL; | |
| 188 } | |
| 189 | |
| 190 const PolicySchema* PolicySchema::GetSchemaForAdditionalProperties() const { | |
| 191 NOTREACHED(); | |
| 192 return NULL; | |
| 193 } | |
| 194 | |
| 195 const PolicySchema* PolicySchema::GetSchemaForProperty( | |
| 196 const std::string& key) const { | |
| 197 const PolicySchemaMap* properties = GetProperties(); | |
| 198 PolicySchemaMap::const_iterator it = properties->find(key); | |
| 199 return it == properties->end() ? GetSchemaForAdditionalProperties() | |
| 200 : it->second; | |
| 201 } | |
| 202 | |
| 203 const PolicySchema* PolicySchema::GetSchemaForItems() const { | |
| 204 NOTREACHED(); | |
| 205 return NULL; | |
| 206 } | |
| 207 | |
| 208 // static | |
| 209 scoped_ptr<PolicySchema> PolicySchema::Parse(const std::string& content, | |
| 210 std::string* error) { | |
| 211 // Validate as a generic JSON schema. | |
| 212 scoped_ptr<base::DictionaryValue> dict = | |
| 213 JSONSchemaValidator::IsValidSchema(content, error); | |
| 214 if (!dict) | |
| 215 return scoped_ptr<PolicySchema>(); | |
| 216 | |
| 217 // Validate the schema version. | |
| 218 std::string string_value; | |
| 219 if (!dict->GetString(json_schema_constants::kSchema, &string_value) || | |
| 220 string_value != kJSONSchemaVersion) { | |
| 221 *error = "Must declare JSON Schema v3 version in \"$schema\"."; | |
| 222 return scoped_ptr<PolicySchema>(); | |
| 223 } | |
| 224 | |
| 225 // Validate the main type. | |
| 226 if (!dict->GetString(json_schema_constants::kType, &string_value) || | |
| 227 string_value != json_schema_constants::kObject) { | |
| 228 *error = | |
| 229 "The main schema must have a type attribute with \"object\" value."; | |
| 230 return scoped_ptr<PolicySchema>(); | |
| 231 } | |
| 232 | |
| 233 // Checks for invalid attributes at the top-level. | |
| 234 if (dict->HasKey(json_schema_constants::kAdditionalProperties) || | |
| 235 dict->HasKey(json_schema_constants::kPatternProperties)) { | |
| 236 *error = "\"additionalProperties\" and \"patternProperties\" are not " | |
| 237 "supported at the main schema."; | |
| 238 return scoped_ptr<PolicySchema>(); | |
| 239 } | |
| 240 | |
| 241 return ParseSchema(*dict, error); | |
| 242 } | |
| 243 | |
| 244 } // namespace policy | |
| OLD | NEW |