blob: c80e7f81530068bf72f1eb08697848f596d742bb [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
avia2f4804a2015-12-24 23:11:137#include <stddef.h>
dcheng1fc00f12015-12-26 22:18:038#include <utility>
avia2f4804a2015-12-24 23:11:139
[email protected]01253d272013-10-21 17:07:5010#include "base/logging.h"
binjin1e1cc33a2014-10-09 18:08:1611#include "chrome/browser/extensions/extension_management_constants.h"
[email protected]01253d272013-10-21 17:07:5012#include "chrome/browser/extensions/external_policy_loader.h"
[email protected]fdd28372014-08-21 02:27:2613#include "components/crx_file/id_util.h"
[email protected]f6c403b2013-12-05 19:01:2514#include "components/policy/core/browser/policy_error_map.h"
[email protected]c4a138a2013-11-21 19:54:5715#include "components/policy/core/common/policy_map.h"
binjin1e1cc33a2014-10-09 18:08:1616#include "components/policy/core/common/schema.h"
brettw39d6ba42016-08-24 16:56:3817#include "components/policy/policy_constants.h"
brettwb1fc1b82016-02-02 00:19:0818#include "components/prefs/pref_value_map.h"
[email protected]234fc5ff2014-01-16 23:32:2819#include "extensions/browser/pref_names.h"
[email protected]e4452d32013-11-15 23:07:4120#include "extensions/common/extension.h"
[email protected]426d676a2014-05-28 14:41:0321#include "grit/components_strings.h"
binjin1e1cc33a2014-10-09 18:08:1622#include "url/gurl.h"
[email protected]01253d272013-10-21 17:07:5023
24namespace extensions {
25
26// ExtensionListPolicyHandler implementation -----------------------------------
27
28ExtensionListPolicyHandler::ExtensionListPolicyHandler(const char* policy_name,
29 const char* pref_path,
30 bool allow_wildcards)
31 : policy::TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
32 pref_path_(pref_path),
33 allow_wildcards_(allow_wildcards) {}
34
35ExtensionListPolicyHandler::~ExtensionListPolicyHandler() {}
36
37bool ExtensionListPolicyHandler::CheckPolicySettings(
38 const policy::PolicyMap& policies,
39 policy::PolicyErrorMap* errors) {
40 return CheckAndGetList(policies, errors, NULL);
41}
42
43void ExtensionListPolicyHandler::ApplyPolicySettings(
44 const policy::PolicyMap& policies,
45 PrefValueMap* prefs) {
dchengc963c7142016-04-08 03:55:2246 std::unique_ptr<base::ListValue> list;
[email protected]01253d272013-10-21 17:07:5047 policy::PolicyErrorMap errors;
48 if (CheckAndGetList(policies, &errors, &list) && list)
dcheng1fc00f12015-12-26 22:18:0349 prefs->SetValue(pref_path(), std::move(list));
[email protected]01253d272013-10-21 17:07:5050}
51
52const char* ExtensionListPolicyHandler::pref_path() const {
53 return pref_path_;
54}
55
56bool ExtensionListPolicyHandler::CheckAndGetList(
57 const policy::PolicyMap& policies,
58 policy::PolicyErrorMap* errors,
dchengc963c7142016-04-08 03:55:2259 std::unique_ptr<base::ListValue>* extension_ids) {
[email protected]01253d272013-10-21 17:07:5060 if (extension_ids)
61 extension_ids->reset();
62
63 const base::Value* value = NULL;
64 if (!CheckAndGetValue(policies, errors, &value))
65 return false;
66
67 if (!value)
68 return true;
69
70 const base::ListValue* list_value = NULL;
71 if (!value->GetAsList(&list_value)) {
72 NOTREACHED();
73 return false;
74 }
75
76 // Filter the list, rejecting any invalid extension IDs.
dchengc963c7142016-04-08 03:55:2277 std::unique_ptr<base::ListValue> filtered_list(new base::ListValue());
[email protected]01253d272013-10-21 17:07:5078 for (base::ListValue::const_iterator entry(list_value->begin());
79 entry != list_value->end(); ++entry) {
80 std::string id;
81 if (!(*entry)->GetAsString(&id)) {
thestige7615d6c2016-07-19 19:43:4682 errors->AddError(policy_name(), entry - list_value->begin(),
[email protected]01253d272013-10-21 17:07:5083 IDS_POLICY_TYPE_ERROR,
thestige7615d6c2016-07-19 19:43:4684 base::Value::GetTypeName(base::Value::TYPE_STRING));
[email protected]01253d272013-10-21 17:07:5085 continue;
86 }
[email protected]fdd28372014-08-21 02:27:2687 if (!(allow_wildcards_ && id == "*") && !crx_file::id_util::IdIsValid(id)) {
[email protected]01253d272013-10-21 17:07:5088 errors->AddError(policy_name(),
89 entry - list_value->begin(),
90 IDS_POLICY_VALUE_FORMAT_ERROR);
91 continue;
92 }
dchengd9ea63862016-06-03 02:27:1893 filtered_list->AppendString(id);
[email protected]01253d272013-10-21 17:07:5094 }
95
96 if (extension_ids)
dcheng1fc00f12015-12-26 22:18:0397 *extension_ids = std::move(filtered_list);
[email protected]01253d272013-10-21 17:07:5098
99 return true;
100}
101
102// ExtensionInstallForcelistPolicyHandler implementation -----------------------
103
104ExtensionInstallForcelistPolicyHandler::ExtensionInstallForcelistPolicyHandler()
105 : policy::TypeCheckingPolicyHandler(policy::key::kExtensionInstallForcelist,
106 base::Value::TYPE_LIST) {}
107
108ExtensionInstallForcelistPolicyHandler::
109 ~ExtensionInstallForcelistPolicyHandler() {}
110
111bool ExtensionInstallForcelistPolicyHandler::CheckPolicySettings(
112 const policy::PolicyMap& policies,
113 policy::PolicyErrorMap* errors) {
114 const base::Value* value;
115 return CheckAndGetValue(policies, errors, &value) &&
116 ParseList(value, NULL, errors);
117}
118
119void ExtensionInstallForcelistPolicyHandler::ApplyPolicySettings(
120 const policy::PolicyMap& policies,
121 PrefValueMap* prefs) {
122 const base::Value* value = NULL;
dchengc963c7142016-04-08 03:55:22123 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
[email protected]01253d272013-10-21 17:07:50124 if (CheckAndGetValue(policies, NULL, &value) &&
125 value &&
126 ParseList(value, dict.get(), NULL)) {
dcheng1fc00f12015-12-26 22:18:03127 prefs->SetValue(pref_names::kInstallForceList, std::move(dict));
[email protected]01253d272013-10-21 17:07:50128 }
129}
130
131bool ExtensionInstallForcelistPolicyHandler::ParseList(
132 const base::Value* policy_value,
133 base::DictionaryValue* extension_dict,
134 policy::PolicyErrorMap* errors) {
135 if (!policy_value)
136 return true;
137
138 const base::ListValue* policy_list_value = NULL;
139 if (!policy_value->GetAsList(&policy_list_value)) {
140 // This should have been caught in CheckPolicySettings.
141 NOTREACHED();
142 return false;
143 }
144
145 for (base::ListValue::const_iterator entry(policy_list_value->begin());
146 entry != policy_list_value->end(); ++entry) {
147 std::string entry_string;
148 if (!(*entry)->GetAsString(&entry_string)) {
149 if (errors) {
thestige7615d6c2016-07-19 19:43:46150 errors->AddError(policy_name(), entry - policy_list_value->begin(),
[email protected]01253d272013-10-21 17:07:50151 IDS_POLICY_TYPE_ERROR,
thestige7615d6c2016-07-19 19:43:46152 base::Value::GetTypeName(base::Value::TYPE_STRING));
[email protected]01253d272013-10-21 17:07:50153 }
154 continue;
155 }
156
157 // Each string item of the list has the following form:
158 // <extension_id>;<update_url>
159 // Note: The update URL might also contain semicolons.
160 size_t pos = entry_string.find(';');
161 if (pos == std::string::npos) {
162 if (errors) {
163 errors->AddError(policy_name(),
164 entry - policy_list_value->begin(),
165 IDS_POLICY_VALUE_FORMAT_ERROR);
166 }
167 continue;
168 }
169
170 std::string extension_id = entry_string.substr(0, pos);
171 std::string update_url = entry_string.substr(pos+1);
[email protected]fdd28372014-08-21 02:27:26172 if (!crx_file::id_util::IdIsValid(extension_id) ||
[email protected]01253d272013-10-21 17:07:50173 !GURL(update_url).is_valid()) {
174 if (errors) {
175 errors->AddError(policy_name(),
176 entry - policy_list_value->begin(),
177 IDS_POLICY_VALUE_FORMAT_ERROR);
178 }
179 continue;
180 }
181
182 if (extension_dict) {
183 extensions::ExternalPolicyLoader::AddExtension(
184 extension_dict, extension_id, update_url);
185 }
186 }
187
188 return true;
189}
190
191// ExtensionURLPatternListPolicyHandler implementation -------------------------
192
193ExtensionURLPatternListPolicyHandler::ExtensionURLPatternListPolicyHandler(
194 const char* policy_name,
195 const char* pref_path)
196 : policy::TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_LIST),
197 pref_path_(pref_path) {}
198
199ExtensionURLPatternListPolicyHandler::~ExtensionURLPatternListPolicyHandler() {}
200
201bool ExtensionURLPatternListPolicyHandler::CheckPolicySettings(
202 const policy::PolicyMap& policies,
203 policy::PolicyErrorMap* errors) {
204 const base::Value* value = NULL;
205 if (!CheckAndGetValue(policies, errors, &value))
206 return false;
207
208 if (!value)
209 return true;
210
211 const base::ListValue* list_value = NULL;
212 if (!value->GetAsList(&list_value)) {
213 NOTREACHED();
214 return false;
215 }
216
217 // Check that the list contains valid URLPattern strings only.
218 for (base::ListValue::const_iterator entry(list_value->begin());
219 entry != list_value->end(); ++entry) {
220 std::string url_pattern_string;
221 if (!(*entry)->GetAsString(&url_pattern_string)) {
thestige7615d6c2016-07-19 19:43:46222 errors->AddError(policy_name(), entry - list_value->begin(),
[email protected]01253d272013-10-21 17:07:50223 IDS_POLICY_TYPE_ERROR,
thestige7615d6c2016-07-19 19:43:46224 base::Value::GetTypeName(base::Value::TYPE_STRING));
[email protected]01253d272013-10-21 17:07:50225 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) {
dchengc963c7142016-04-08 03:55:22266 std::unique_ptr<base::Value> policy_value;
binjin1e1cc33a2014-10-09 18:08:16267 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) {
dchengc963c7142016-04-08 03:55:22320 std::unique_ptr<base::Value> policy_value;
binjin1e1cc33a2014-10-09 18:08:16321 if (!CheckAndGetValue(policies, NULL, &policy_value) || !policy_value)
322 return;
dcheng1fc00f12015-12-26 22:18:03323 prefs->SetValue(pref_names::kExtensionManagement, std::move(policy_value));
binjin1e1cc33a2014-10-09 18:08:16324}
325
[email protected]01253d272013-10-21 17:07:50326} // namespace extensions