Fix crash on app list start page contents not existing.
[chromium-blink-merge.git] / components / policy / core / browser / configuration_policy_handler.cc
blob5927ab4026188034c27ae0ef15bc71555a2bb77b
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.
5 #include "components/policy/core/browser/configuration_policy_handler.h"
7 #include <algorithm>
9 #include "base/callback.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/prefs/pref_value_map.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "components/policy/core/browser/policy_error_map.h"
17 #include "components/policy/core/common/policy_map.h"
18 #include "grit/components_strings.h"
19 #include "url/gurl.h"
21 namespace policy {
23 // ConfigurationPolicyHandler implementation -----------------------------------
25 // static
26 std::string ConfigurationPolicyHandler::ValueTypeToString(
27 base::Value::Type type) {
28 static const char* strings[] = {
29 "null",
30 "boolean",
31 "integer",
32 "double",
33 "string",
34 "binary",
35 "dictionary",
36 "list"
38 CHECK(static_cast<size_t>(type) < arraysize(strings));
39 return std::string(strings[type]);
42 ConfigurationPolicyHandler::ConfigurationPolicyHandler() {
45 ConfigurationPolicyHandler::~ConfigurationPolicyHandler() {
48 void ConfigurationPolicyHandler::PrepareForDisplaying(
49 PolicyMap* policies) const {}
51 void ConfigurationPolicyHandler::ApplyPolicySettings(
52 const policy::PolicyMap& policies,
53 PrefValueMap* prefs) {
54 NOTREACHED();
57 void ConfigurationPolicyHandler::ApplyPolicySettingsWithParameters(
58 const PolicyMap& policies,
59 const PolicyHandlerParameters& parameters,
60 PrefValueMap* prefs) {
61 ApplyPolicySettings(policies, prefs);
64 // TypeCheckingPolicyHandler implementation ------------------------------------
66 TypeCheckingPolicyHandler::TypeCheckingPolicyHandler(
67 const char* policy_name,
68 base::Value::Type value_type)
69 : policy_name_(policy_name),
70 value_type_(value_type) {
73 TypeCheckingPolicyHandler::~TypeCheckingPolicyHandler() {
76 const char* TypeCheckingPolicyHandler::policy_name() const {
77 return policy_name_;
80 bool TypeCheckingPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
81 PolicyErrorMap* errors) {
82 const base::Value* value = NULL;
83 return CheckAndGetValue(policies, errors, &value);
86 bool TypeCheckingPolicyHandler::CheckAndGetValue(const PolicyMap& policies,
87 PolicyErrorMap* errors,
88 const base::Value** value) {
89 *value = policies.GetValue(policy_name_);
90 if (*value && !(*value)->IsType(value_type_)) {
91 errors->AddError(policy_name_,
92 IDS_POLICY_TYPE_ERROR,
93 ValueTypeToString(value_type_));
94 return false;
96 return true;
100 // IntRangePolicyHandlerBase implementation ------------------------------------
102 IntRangePolicyHandlerBase::IntRangePolicyHandlerBase(
103 const char* policy_name,
104 int min,
105 int max,
106 bool clamp)
107 : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_INTEGER),
108 min_(min),
109 max_(max),
110 clamp_(clamp) {
113 bool IntRangePolicyHandlerBase::CheckPolicySettings(const PolicyMap& policies,
114 PolicyErrorMap* errors) {
115 const base::Value* value;
116 return CheckAndGetValue(policies, errors, &value) &&
117 EnsureInRange(value, NULL, errors);
120 IntRangePolicyHandlerBase::~IntRangePolicyHandlerBase() {
123 bool IntRangePolicyHandlerBase::EnsureInRange(const base::Value* input,
124 int* output,
125 PolicyErrorMap* errors) {
126 if (!input)
127 return true;
129 int value;
130 if (!input->GetAsInteger(&value)) {
131 NOTREACHED();
132 return false;
135 if (value < min_ || value > max_) {
136 if (errors) {
137 errors->AddError(policy_name(),
138 IDS_POLICY_OUT_OF_RANGE_ERROR,
139 base::IntToString(value));
142 if (!clamp_)
143 return false;
145 value = std::min(std::max(value, min_), max_);
148 if (output)
149 *output = value;
150 return true;
154 // StringMappingListPolicyHandler implementation -----------------------------
156 StringMappingListPolicyHandler::MappingEntry::MappingEntry(
157 const char* policy_value, scoped_ptr<base::Value> map)
158 : enum_value(policy_value), mapped_value(map.Pass()) {}
160 StringMappingListPolicyHandler::MappingEntry::~MappingEntry() {}
162 StringMappingListPolicyHandler::StringMappingListPolicyHandler(
163 const char* policy_name,
164 const char* pref_path,
165 const GenerateMapCallback& callback)
166 : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
167 pref_path_(pref_path),
168 map_getter_(callback) {}
170 StringMappingListPolicyHandler::~StringMappingListPolicyHandler() {}
172 bool StringMappingListPolicyHandler::CheckPolicySettings(
173 const PolicyMap& policies,
174 PolicyErrorMap* errors) {
175 const base::Value* value;
176 return CheckAndGetValue(policies, errors, &value) &&
177 Convert(value, NULL, errors);
180 void StringMappingListPolicyHandler::ApplyPolicySettings(
181 const PolicyMap& policies,
182 PrefValueMap* prefs) {
183 if (!pref_path_)
184 return;
185 const base::Value* value = policies.GetValue(policy_name());
186 scoped_ptr<base::ListValue> list(new base::ListValue());
187 if (value && Convert(value, list.get(), NULL))
188 prefs->SetValue(pref_path_, list.release());
191 bool StringMappingListPolicyHandler::Convert(const base::Value* input,
192 base::ListValue* output,
193 PolicyErrorMap* errors) {
194 if (!input)
195 return true;
197 const base::ListValue* list_value = NULL;
198 if (!input->GetAsList(&list_value)) {
199 NOTREACHED();
200 return false;
203 for (base::ListValue::const_iterator entry(list_value->begin());
204 entry != list_value->end(); ++entry) {
205 std::string entry_value;
206 if (!(*entry)->GetAsString(&entry_value)) {
207 if (errors) {
208 errors->AddError(policy_name(),
209 entry - list_value->begin(),
210 IDS_POLICY_TYPE_ERROR,
211 ValueTypeToString(base::Value::TYPE_STRING));
213 continue;
216 scoped_ptr<base::Value> mapped_value = Map(entry_value);
217 if (mapped_value) {
218 if (output)
219 output->Append(mapped_value.release());
220 } else {
221 if (errors) {
222 errors->AddError(policy_name(),
223 entry - list_value->begin(),
224 IDS_POLICY_OUT_OF_RANGE_ERROR);
229 return true;
232 scoped_ptr<base::Value> StringMappingListPolicyHandler::Map(
233 const std::string& entry_value) {
234 // Lazily generate the map of policy strings to mapped values.
235 if (map_.empty())
236 map_getter_.Run(&map_);
238 scoped_ptr<base::Value> return_value;
239 for (ScopedVector<MappingEntry>::const_iterator it = map_.begin();
240 it != map_.end(); ++it) {
241 const MappingEntry* mapping_entry = *it;
242 if (mapping_entry->enum_value == entry_value) {
243 return_value = make_scoped_ptr(mapping_entry->mapped_value->DeepCopy());
244 break;
247 return return_value.Pass();
250 // IntRangePolicyHandler implementation ----------------------------------------
252 IntRangePolicyHandler::IntRangePolicyHandler(const char* policy_name,
253 const char* pref_path,
254 int min,
255 int max,
256 bool clamp)
257 : IntRangePolicyHandlerBase(policy_name, min, max, clamp),
258 pref_path_(pref_path) {
261 IntRangePolicyHandler::~IntRangePolicyHandler() {
264 void IntRangePolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
265 PrefValueMap* prefs) {
266 if (!pref_path_)
267 return;
268 const base::Value* value = policies.GetValue(policy_name());
269 int value_in_range;
270 if (value && EnsureInRange(value, &value_in_range, NULL))
271 prefs->SetInteger(pref_path_, value_in_range);
275 // IntPercentageToDoublePolicyHandler implementation ---------------------------
277 IntPercentageToDoublePolicyHandler::IntPercentageToDoublePolicyHandler(
278 const char* policy_name,
279 const char* pref_path,
280 int min,
281 int max,
282 bool clamp)
283 : IntRangePolicyHandlerBase(policy_name, min, max, clamp),
284 pref_path_(pref_path) {
287 IntPercentageToDoublePolicyHandler::~IntPercentageToDoublePolicyHandler() {
290 void IntPercentageToDoublePolicyHandler::ApplyPolicySettings(
291 const PolicyMap& policies,
292 PrefValueMap* prefs) {
293 if (!pref_path_)
294 return;
295 const base::Value* value = policies.GetValue(policy_name());
296 int percentage;
297 if (value && EnsureInRange(value, &percentage, NULL))
298 prefs->SetDouble(pref_path_, static_cast<double>(percentage) / 100.);
302 // SimplePolicyHandler implementation ------------------------------------------
304 SimplePolicyHandler::SimplePolicyHandler(
305 const char* policy_name,
306 const char* pref_path,
307 base::Value::Type value_type)
308 : TypeCheckingPolicyHandler(policy_name, value_type),
309 pref_path_(pref_path) {
312 SimplePolicyHandler::~SimplePolicyHandler() {
315 void SimplePolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
316 PrefValueMap* prefs) {
317 if (!pref_path_)
318 return;
319 const base::Value* value = policies.GetValue(policy_name());
320 if (value)
321 prefs->SetValue(pref_path_, value->DeepCopy());
325 // SchemaValidatingPolicyHandler implementation --------------------------------
327 SchemaValidatingPolicyHandler::SchemaValidatingPolicyHandler(
328 const char* policy_name,
329 Schema schema,
330 SchemaOnErrorStrategy strategy)
331 : policy_name_(policy_name), schema_(schema), strategy_(strategy) {
332 DCHECK(schema_.valid());
335 SchemaValidatingPolicyHandler::~SchemaValidatingPolicyHandler() {
338 const char* SchemaValidatingPolicyHandler::policy_name() const {
339 return policy_name_;
342 bool SchemaValidatingPolicyHandler::CheckPolicySettings(
343 const PolicyMap& policies,
344 PolicyErrorMap* errors) {
345 const base::Value* value = policies.GetValue(policy_name());
346 if (!value)
347 return true;
349 std::string error_path;
350 std::string error;
351 bool result = schema_.Validate(*value, strategy_, &error_path, &error);
353 if (errors && !error.empty()) {
354 if (error_path.empty())
355 error_path = "(ROOT)";
356 errors->AddError(policy_name_, error_path, error);
359 return result;
362 bool SchemaValidatingPolicyHandler::CheckAndGetValue(
363 const PolicyMap& policies,
364 PolicyErrorMap* errors,
365 scoped_ptr<base::Value>* output) {
366 const base::Value* value = policies.GetValue(policy_name());
367 if (!value)
368 return true;
370 output->reset(value->DeepCopy());
371 std::string error_path;
372 std::string error;
373 bool result =
374 schema_.Normalize(output->get(), strategy_, &error_path, &error, NULL);
376 if (errors && !error.empty()) {
377 if (error_path.empty())
378 error_path = "(ROOT)";
379 errors->AddError(policy_name_, error_path, error);
382 return result;
385 // SimpleSchemaValidatingPolicyHandler implementation --------------------------
387 SimpleSchemaValidatingPolicyHandler::SimpleSchemaValidatingPolicyHandler(
388 const char* policy_name,
389 const char* pref_path,
390 Schema schema,
391 SchemaOnErrorStrategy strategy,
392 RecommendedPermission recommended_permission,
393 MandatoryPermission mandatory_permission)
394 : SchemaValidatingPolicyHandler(policy_name,
395 schema.GetKnownProperty(policy_name),
396 strategy),
397 pref_path_(pref_path),
398 allow_recommended_(recommended_permission == RECOMMENDED_ALLOWED),
399 allow_mandatory_(mandatory_permission == MANDATORY_ALLOWED) {
402 SimpleSchemaValidatingPolicyHandler::~SimpleSchemaValidatingPolicyHandler() {
405 bool SimpleSchemaValidatingPolicyHandler::CheckPolicySettings(
406 const PolicyMap& policies,
407 PolicyErrorMap* errors) {
408 const PolicyMap::Entry* policy_entry = policies.Get(policy_name());
409 if (!policy_entry)
410 return true;
411 if ((policy_entry->level == policy::POLICY_LEVEL_MANDATORY &&
412 !allow_mandatory_) ||
413 (policy_entry->level == policy::POLICY_LEVEL_RECOMMENDED &&
414 !allow_recommended_)) {
415 if (errors)
416 errors->AddError(policy_name(), IDS_POLICY_LEVEL_ERROR);
417 return false;
420 return SchemaValidatingPolicyHandler::CheckPolicySettings(policies, errors);
423 void SimpleSchemaValidatingPolicyHandler::ApplyPolicySettings(
424 const PolicyMap& policies,
425 PrefValueMap* prefs) {
426 if (!pref_path_)
427 return;
428 const base::Value* value = policies.GetValue(policy_name());
429 if (value)
430 prefs->SetValue(pref_path_, value->DeepCopy());
433 // LegacyPoliciesDeprecatingPolicyHandler implementation -----------------------
435 // TODO(binjin): Add a new common base class for SchemaValidatingPolicyHandler
436 // and TypeCheckingPolicyHandler representing policy handlers for a single
437 // policy, and use it as the type of |new_policy_handler|.
438 // http://crbug.com/345299
439 LegacyPoliciesDeprecatingPolicyHandler::LegacyPoliciesDeprecatingPolicyHandler(
440 ScopedVector<ConfigurationPolicyHandler> legacy_policy_handlers,
441 scoped_ptr<SchemaValidatingPolicyHandler> new_policy_handler)
442 : legacy_policy_handlers_(legacy_policy_handlers.Pass()),
443 new_policy_handler_(new_policy_handler.Pass()) {
446 LegacyPoliciesDeprecatingPolicyHandler::
447 ~LegacyPoliciesDeprecatingPolicyHandler() {
450 bool LegacyPoliciesDeprecatingPolicyHandler::CheckPolicySettings(
451 const PolicyMap& policies,
452 PolicyErrorMap* errors) {
453 if (policies.Get(new_policy_handler_->policy_name())) {
454 return new_policy_handler_->CheckPolicySettings(policies, errors);
455 } else {
456 // The new policy is not set, fall back to legacy ones.
457 ScopedVector<ConfigurationPolicyHandler>::iterator handler;
458 bool valid_policy_found = false;
459 for (handler = legacy_policy_handlers_.begin();
460 handler != legacy_policy_handlers_.end();
461 ++handler) {
462 if ((*handler)->CheckPolicySettings(policies, errors))
463 valid_policy_found = true;
465 return valid_policy_found;
469 void LegacyPoliciesDeprecatingPolicyHandler::ApplyPolicySettings(
470 const PolicyMap& policies,
471 PrefValueMap* prefs) {
472 if (policies.Get(new_policy_handler_->policy_name())) {
473 new_policy_handler_->ApplyPolicySettings(policies, prefs);
474 } else {
475 // The new policy is not set, fall back to legacy ones.
476 PolicyErrorMap scoped_errors;
477 ScopedVector<ConfigurationPolicyHandler>::iterator handler;
478 for (handler = legacy_policy_handlers_.begin();
479 handler != legacy_policy_handlers_.end();
480 ++handler) {
481 if ((*handler)->CheckPolicySettings(policies, &scoped_errors))
482 (*handler)->ApplyPolicySettings(policies, prefs);
487 } // namespace policy