blob: 8e9be50b0213615c2b861fca58a0a7629d880eed [file] [log] [blame]
[email protected]01253d272013-10-21 17:07:501// 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 "chrome/browser/extensions/policy_handlers.h"
6
7#include "base/logging.h"
8#include "base/prefs/pref_value_map.h"
binjin1e1cc33a2014-10-09 18:08:169#include "chrome/browser/extensions/extension_management_constants.h"
[email protected]01253d272013-10-21 17:07:5010#include "chrome/browser/extensions/external_policy_loader.h"
[email protected]fdd28372014-08-21 02:27:2611#include "components/crx_file/id_util.h"
[email protected]f6c403b2013-12-05 19:01:2512#include "components/policy/core/browser/policy_error_map.h"
[email protected]c4a138a2013-11-21 19:54:5713#include "components/policy/core/common/policy_map.h"
binjin1e1cc33a2014-10-09 18:08:1614#include "components/policy/core/common/schema.h"
[email protected]234fc5ff2014-01-16 23:32:2815#include "extensions/browser/pref_names.h"
[email protected]e4452d32013-11-15 23:07:4116#include "extensions/common/extension.h"
[email protected]426d676a2014-05-28 14:41:0317#include "grit/components_strings.h"
[email protected]01253d272013-10-21 17:07:5018#include "policy/policy_constants.h"
binjin1e1cc33a2014-10-09 18:08:1619#include "url/gurl.h"
[email protected]01253d272013-10-21 17:07:5020
21namespace extensions {
22
23// ExtensionListPolicyHandler implementation -----------------------------------
24
25ExtensionListPolicyHandler::ExtensionListPolicyHandler(const char* policy_name,
26 const char* pref_path,
27 bool allow_wildcards)
28 : policy::TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
29 pref_path_(pref_path),
30 allow_wildcards_(allow_wildcards) {}
31
32ExtensionListPolicyHandler::~ExtensionListPolicyHandler() {}
33
34bool ExtensionListPolicyHandler::CheckPolicySettings(
35 const policy::PolicyMap& policies,
36 policy::PolicyErrorMap* errors) {
37 return CheckAndGetList(policies, errors, NULL);
38}
39
40void ExtensionListPolicyHandler::ApplyPolicySettings(
41 const policy::PolicyMap& policies,
42 PrefValueMap* prefs) {
43 scoped_ptr<base::ListValue> list;
44 policy::PolicyErrorMap errors;
45 if (CheckAndGetList(policies, &errors, &list) && list)
estade0bd407f2015-06-26 18:16:1846 prefs->SetValue(pref_path(), list.Pass());
[email protected]01253d272013-10-21 17:07:5047}
48
49const char* ExtensionListPolicyHandler::pref_path() const {
50 return pref_path_;
51}
52
53bool ExtensionListPolicyHandler::CheckAndGetList(
54 const policy::PolicyMap& policies,
55 policy::PolicyErrorMap* errors,
56 scoped_ptr<base::ListValue>* extension_ids) {
57 if (extension_ids)
58 extension_ids->reset();
59
60 const base::Value* value = NULL;
61 if (!CheckAndGetValue(policies, errors, &value))
62 return false;
63
64 if (!value)
65 return true;
66
67 const base::ListValue* list_value = NULL;
68 if (!value->GetAsList(&list_value)) {
69 NOTREACHED();
70 return false;
71 }
72
73 // Filter the list, rejecting any invalid extension IDs.
74 scoped_ptr<base::ListValue> filtered_list(new base::ListValue());
75 for (base::ListValue::const_iterator entry(list_value->begin());
76 entry != list_value->end(); ++entry) {
77 std::string id;
78 if (!(*entry)->GetAsString(&id)) {
79 errors->AddError(policy_name(),
80 entry - list_value->begin(),
81 IDS_POLICY_TYPE_ERROR,
82 ValueTypeToString(base::Value::TYPE_STRING));
83 continue;
84 }
[email protected]fdd28372014-08-21 02:27:2685 if (!(allow_wildcards_ && id == "*") && !crx_file::id_util::IdIsValid(id)) {
[email protected]01253d272013-10-21 17:07:5086 errors->AddError(policy_name(),
87 entry - list_value->begin(),
88 IDS_POLICY_VALUE_FORMAT_ERROR);
89 continue;
90 }
[email protected]1aea5262014-07-09 04:55:3391 filtered_list->Append(new base::StringValue(id));
[email protected]01253d272013-10-21 17:07:5092 }
93
94 if (extension_ids)
95 *extension_ids = filtered_list.Pass();
96
97 return true;
98}
99
100// ExtensionInstallForcelistPolicyHandler implementation -----------------------
101
102ExtensionInstallForcelistPolicyHandler::ExtensionInstallForcelistPolicyHandler()
103 : policy::TypeCheckingPolicyHandler(policy::key::kExtensionInstallForcelist,
104 base::Value::TYPE_LIST) {}
105
106ExtensionInstallForcelistPolicyHandler::
107 ~ExtensionInstallForcelistPolicyHandler() {}
108
109bool ExtensionInstallForcelistPolicyHandler::CheckPolicySettings(
110 const policy::PolicyMap& policies,
111 policy::PolicyErrorMap* errors) {
112 const base::Value* value;
113 return CheckAndGetValue(policies, errors, &value) &&
114 ParseList(value, NULL, errors);
115}
116
117void ExtensionInstallForcelistPolicyHandler::ApplyPolicySettings(
118 const policy::PolicyMap& policies,
119 PrefValueMap* prefs) {
120 const base::Value* value = NULL;
121 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
122 if (CheckAndGetValue(policies, NULL, &value) &&
123 value &&
124 ParseList(value, dict.get(), NULL)) {
estade0bd407f2015-06-26 18:16:18125 prefs->SetValue(pref_names::kInstallForceList, dict.Pass());
[email protected]01253d272013-10-21 17:07:50126 }
127}
128
129bool ExtensionInstallForcelistPolicyHandler::ParseList(
130 const base::Value* policy_value,
131 base::DictionaryValue* extension_dict,
132 policy::PolicyErrorMap* errors) {
133 if (!policy_value)
134 return true;
135
136 const base::ListValue* policy_list_value = NULL;
137 if (!policy_value->GetAsList(&policy_list_value)) {
138 // This should have been caught in CheckPolicySettings.
139 NOTREACHED();
140 return false;
141 }
142
143 for (base::ListValue::const_iterator entry(policy_list_value->begin());
144 entry != policy_list_value->end(); ++entry) {
145 std::string entry_string;
146 if (!(*entry)->GetAsString(&entry_string)) {
147 if (errors) {
148 errors->AddError(policy_name(),
149 entry - policy_list_value->begin(),
150 IDS_POLICY_TYPE_ERROR,
151 ValueTypeToString(base::Value::TYPE_STRING));
152 }
153 continue;
154 }
155
156 // Each string item of the list has the following form:
157 // <extension_id>;<update_url>
158 // Note: The update URL might also contain semicolons.
159 size_t pos = entry_string.find(';');
160 if (pos == std::string::npos) {
161 if (errors) {
162 errors->AddError(policy_name(),
163 entry - policy_list_value->begin(),
164 IDS_POLICY_VALUE_FORMAT_ERROR);
165 }
166 continue;
167 }
168
169 std::string extension_id = entry_string.substr(0, pos);
170 std::string update_url = entry_string.substr(pos+1);
[email protected]fdd28372014-08-21 02:27:26171 if (!crx_file::id_util::IdIsValid(extension_id) ||
[email protected]01253d272013-10-21 17:07:50172 !GURL(update_url).is_valid()) {
173 if (errors) {
174 errors->AddError(policy_name(),
175 entry - policy_list_value->begin(),
176 IDS_POLICY_VALUE_FORMAT_ERROR);
177 }
178 continue;
179 }
180
181 if (extension_dict) {
182 extensions::ExternalPolicyLoader::AddExtension(
183 extension_dict, extension_id, update_url);
184 }
185 }
186
187 return true;
188}
189
190// ExtensionURLPatternListPolicyHandler implementation -------------------------
191
192ExtensionURLPatternListPolicyHandler::ExtensionURLPatternListPolicyHandler(
193 const char* policy_name,
194 const char* pref_path)
195 : policy::TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
196 pref_path_(pref_path) {}
197
198ExtensionURLPatternListPolicyHandler::~ExtensionURLPatternListPolicyHandler() {}
199
200bool ExtensionURLPatternListPolicyHandler::CheckPolicySettings(
201 const policy::PolicyMap& policies,
202 policy::PolicyErrorMap* errors) {
203 const base::Value* value = NULL;
204 if (!CheckAndGetValue(policies, errors, &value))
205 return false;
206
207 if (!value)
208 return true;
209
210 const base::ListValue* list_value = NULL;
211 if (!value->GetAsList(&list_value)) {
212 NOTREACHED();
213 return false;
214 }
215
216 // Check that the list contains valid URLPattern strings only.
217 for (base::ListValue::const_iterator entry(list_value->begin());
218 entry != list_value->end(); ++entry) {
219 std::string url_pattern_string;
220 if (!(*entry)->GetAsString(&url_pattern_string)) {
221 errors->AddError(policy_name(),
222 entry - list_value->begin(),
223 IDS_POLICY_TYPE_ERROR,
224 ValueTypeToString(base::Value::TYPE_STRING));
225 return false;
226 }
227
228 URLPattern pattern(URLPattern::SCHEME_ALL);
229 if (pattern.Parse(url_pattern_string) != URLPattern::PARSE_SUCCESS) {
230 errors->AddError(policy_name(),
231 entry - list_value->begin(),
232 IDS_POLICY_VALUE_FORMAT_ERROR);
233 return false;
234 }
235 }
236
237 return true;
238}
239
240void ExtensionURLPatternListPolicyHandler::ApplyPolicySettings(
241 const policy::PolicyMap& policies,
242 PrefValueMap* prefs) {
243 if (!pref_path_)
244 return;
[email protected]cb1078de2013-12-23 20:04:22245 const base::Value* value = policies.GetValue(policy_name());
[email protected]01253d272013-10-21 17:07:50246 if (value)
estade0bd407f2015-06-26 18:16:18247 prefs->SetValue(pref_path_, value->CreateDeepCopy());
[email protected]01253d272013-10-21 17:07:50248}
249
binjin1e1cc33a2014-10-09 18:08:16250// ExtensionSettingsPolicyHandler implementation ------------------------------
251
252ExtensionSettingsPolicyHandler::ExtensionSettingsPolicyHandler(
253 const policy::Schema& chrome_schema)
254 : policy::SchemaValidatingPolicyHandler(
255 policy::key::kExtensionSettings,
256 chrome_schema.GetKnownProperty(policy::key::kExtensionSettings),
257 policy::SCHEMA_ALLOW_UNKNOWN) {
258}
259
260ExtensionSettingsPolicyHandler::~ExtensionSettingsPolicyHandler() {
261}
262
263bool ExtensionSettingsPolicyHandler::CheckPolicySettings(
264 const policy::PolicyMap& policies,
265 policy::PolicyErrorMap* errors) {
266 scoped_ptr<base::Value> policy_value;
267 if (!CheckAndGetValue(policies, errors, &policy_value))
268 return false;
269 if (!policy_value)
270 return true;
271
272 // |policy_value| is expected to conform to the defined schema. But it's
273 // not strictly valid since there are additional restrictions.
274 const base::DictionaryValue* dict_value = NULL;
275 DCHECK(policy_value->IsType(base::Value::TYPE_DICTIONARY));
276 policy_value->GetAsDictionary(&dict_value);
277
278 for (base::DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
279 it.Advance()) {
280 DCHECK(it.key() == schema_constants::kWildcard ||
281 crx_file::id_util::IdIsValid(it.key()));
282 DCHECK(it.value().IsType(base::Value::TYPE_DICTIONARY));
283
284 // Extracts sub dictionary.
285 const base::DictionaryValue* sub_dict = NULL;
286 it.value().GetAsDictionary(&sub_dict);
287
288 std::string installation_mode;
289 if (sub_dict->GetString(schema_constants::kInstallationMode,
290 &installation_mode)) {
291 if (installation_mode == schema_constants::kForceInstalled ||
292 installation_mode == schema_constants::kNormalInstalled) {
293 DCHECK(it.key() != schema_constants::kWildcard);
294 // Verifies that 'update_url' is specified for 'force_installed' and
295 // 'normal_installed' mode.
296 std::string update_url;
297 if (!sub_dict->GetString(schema_constants::kUpdateUrl, &update_url) ||
298 update_url.empty()) {
299 errors->AddError(policy_name(),
300 it.key() + "." + schema_constants::kUpdateUrl,
301 IDS_POLICY_NOT_SPECIFIED_ERROR);
302 return false;
303 }
304 // Verifies that update URL is valid.
305 if (!GURL(update_url).is_valid()) {
306 errors->AddError(
307 policy_name(), IDS_POLICY_INVALID_UPDATE_URL_ERROR, it.key());
308 return false;
309 }
310 }
311 }
312 }
313
314 return true;
315}
316
317void ExtensionSettingsPolicyHandler::ApplyPolicySettings(
318 const policy::PolicyMap& policies,
319 PrefValueMap* prefs) {
320 scoped_ptr<base::Value> policy_value;
321 if (!CheckAndGetValue(policies, NULL, &policy_value) || !policy_value)
322 return;
estade0bd407f2015-06-26 18:16:18323 prefs->SetValue(pref_names::kExtensionManagement, policy_value.Pass());
binjin1e1cc33a2014-10-09 18:08:16324}
325
[email protected]01253d272013-10-21 17:07:50326} // namespace extensions