blob: bf33b5d7da38453b7979bd2126c5ceb70df45f16 [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"
Nick Petersond952cb772018-03-07 15:46:0311#include "build/build_config.h"
binjin1e1cc33a2014-10-09 18:08:1612#include "chrome/browser/extensions/extension_management_constants.h"
[email protected]01253d272013-10-21 17:07:5013#include "chrome/browser/extensions/external_policy_loader.h"
[email protected]fdd28372014-08-21 02:27:2614#include "components/crx_file/id_util.h"
[email protected]f6c403b2013-12-05 19:01:2515#include "components/policy/core/browser/policy_error_map.h"
[email protected]c4a138a2013-11-21 19:54:5716#include "components/policy/core/common/policy_map.h"
binjin1e1cc33a2014-10-09 18:08:1617#include "components/policy/core/common/schema.h"
brettw39d6ba42016-08-24 16:56:3818#include "components/policy/policy_constants.h"
brettwb1fc1b82016-02-02 00:19:0819#include "components/prefs/pref_value_map.h"
thestig4a2e88e2016-08-27 23:23:5120#include "components/strings/grit/components_strings.h"
[email protected]234fc5ff2014-01-16 23:32:2821#include "extensions/browser/pref_names.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
Nick Petersond952cb772018-03-07 15:46:0323#include "extensions/common/extension_urls.h"
binjin1e1cc33a2014-10-09 18:08:1624#include "url/gurl.h"
[email protected]01253d272013-10-21 17:07:5025
Nick Petersond952cb772018-03-07 15:46:0326#if defined(OS_WIN)
27#include "base/win/win_util.h"
28#endif
29
[email protected]01253d272013-10-21 17:07:5030namespace extensions {
31
32// ExtensionListPolicyHandler implementation -----------------------------------
33
34ExtensionListPolicyHandler::ExtensionListPolicyHandler(const char* policy_name,
35 const char* pref_path,
36 bool allow_wildcards)
Lutz Justene45e3fe2017-08-18 07:11:3937 : policy::ListPolicyHandler(policy_name, base::Value::Type::STRING),
[email protected]01253d272013-10-21 17:07:5038 pref_path_(pref_path),
39 allow_wildcards_(allow_wildcards) {}
40
41ExtensionListPolicyHandler::~ExtensionListPolicyHandler() {}
42
Lutz Justene45e3fe2017-08-18 07:11:3943bool ExtensionListPolicyHandler::CheckListEntry(const base::Value& value) {
44 const std::string& str = value.GetString();
45 if (allow_wildcards_ && str == "*")
[email protected]01253d272013-10-21 17:07:5046 return true;
47
Lutz Justene45e3fe2017-08-18 07:11:3948 // Make sure str is an extension id.
49 return crx_file::id_util::IdIsValid(str);
50}
[email protected]01253d272013-10-21 17:07:5051
Lutz Justene45e3fe2017-08-18 07:11:3952void ExtensionListPolicyHandler::ApplyList(
53 std::unique_ptr<base::ListValue> filtered_list,
54 PrefValueMap* prefs) {
55 prefs->SetValue(pref_path_, std::move(filtered_list));
[email protected]01253d272013-10-21 17:07:5056}
57
achuith4607f072017-03-08 11:49:1358// ExtensionInstallListPolicyHandler implementation ----------------------------
[email protected]01253d272013-10-21 17:07:5059
achuith4607f072017-03-08 11:49:1360ExtensionInstallListPolicyHandler::ExtensionInstallListPolicyHandler(
61 const char* policy_name,
62 const char* pref_name)
63 : policy::TypeCheckingPolicyHandler(policy_name, base::Value::Type::LIST),
64 pref_name_(pref_name) {}
[email protected]01253d272013-10-21 17:07:5065
achuith4607f072017-03-08 11:49:1366bool ExtensionInstallListPolicyHandler::CheckPolicySettings(
[email protected]01253d272013-10-21 17:07:5067 const policy::PolicyMap& policies,
68 policy::PolicyErrorMap* errors) {
69 const base::Value* value;
70 return CheckAndGetValue(policies, errors, &value) &&
achuith4607f072017-03-08 11:49:1371 ParseList(value, nullptr, errors);
[email protected]01253d272013-10-21 17:07:5072}
73
achuith4607f072017-03-08 11:49:1374void ExtensionInstallListPolicyHandler::ApplyPolicySettings(
[email protected]01253d272013-10-21 17:07:5075 const policy::PolicyMap& policies,
76 PrefValueMap* prefs) {
achuith4607f072017-03-08 11:49:1377 const base::Value* value = nullptr;
dchengc963c7142016-04-08 03:55:2278 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
achuith4607f072017-03-08 11:49:1379 if (CheckAndGetValue(policies, nullptr, &value) && value &&
80 ParseList(value, dict.get(), nullptr)) {
81 prefs->SetValue(pref_name_, std::move(dict));
[email protected]01253d272013-10-21 17:07:5082 }
83}
84
achuith4607f072017-03-08 11:49:1385bool ExtensionInstallListPolicyHandler::ParseList(
[email protected]01253d272013-10-21 17:07:5086 const base::Value* policy_value,
87 base::DictionaryValue* extension_dict,
88 policy::PolicyErrorMap* errors) {
89 if (!policy_value)
90 return true;
91
achuith4607f072017-03-08 11:49:1392 const base::ListValue* policy_list_value = nullptr;
[email protected]01253d272013-10-21 17:07:5093 if (!policy_value->GetAsList(&policy_list_value)) {
94 // This should have been caught in CheckPolicySettings.
95 NOTREACHED();
96 return false;
97 }
98
99 for (base::ListValue::const_iterator entry(policy_list_value->begin());
100 entry != policy_list_value->end(); ++entry) {
101 std::string entry_string;
jdoerriea5676c62017-04-11 18:09:14102 if (!entry->GetAsString(&entry_string)) {
[email protected]01253d272013-10-21 17:07:50103 if (errors) {
thestige7615d6c2016-07-19 19:43:46104 errors->AddError(policy_name(), entry - policy_list_value->begin(),
[email protected]01253d272013-10-21 17:07:50105 IDS_POLICY_TYPE_ERROR,
jdoerriedc72ee942016-12-07 15:43:28106 base::Value::GetTypeName(base::Value::Type::STRING));
[email protected]01253d272013-10-21 17:07:50107 }
108 continue;
109 }
110
Maksim Ivanoveaac2ff2018-04-16 16:23:24111 // Each string item of the list should be of one of the following forms:
112 // * <extension_id>
113 // * <extension_id>;<update_url>
[email protected]01253d272013-10-21 17:07:50114 // Note: The update URL might also contain semicolons.
Maksim Ivanoveaac2ff2018-04-16 16:23:24115 std::string extension_id;
116 std::string update_url;
[email protected]01253d272013-10-21 17:07:50117 size_t pos = entry_string.find(';');
118 if (pos == std::string::npos) {
Maksim Ivanoveaac2ff2018-04-16 16:23:24119 extension_id = entry_string;
120 update_url = extension_urls::kChromeWebstoreUpdateURL;
121 } else {
122 extension_id = entry_string.substr(0, pos);
123 update_url = entry_string.substr(pos + 1);
[email protected]01253d272013-10-21 17:07:50124 }
125
[email protected]fdd28372014-08-21 02:27:26126 if (!crx_file::id_util::IdIsValid(extension_id) ||
[email protected]01253d272013-10-21 17:07:50127 !GURL(update_url).is_valid()) {
128 if (errors) {
129 errors->AddError(policy_name(),
130 entry - policy_list_value->begin(),
131 IDS_POLICY_VALUE_FORMAT_ERROR);
132 }
133 continue;
134 }
135
136 if (extension_dict) {
achuith4607f072017-03-08 11:49:13137 ExternalPolicyLoader::AddExtension(extension_dict, extension_id,
138 update_url);
[email protected]01253d272013-10-21 17:07:50139 }
140 }
141
142 return true;
143}
144
achuith4607f072017-03-08 11:49:13145// ExtensionInstallForcelistPolicyHandler implementation -----------------------
146
147ExtensionInstallForcelistPolicyHandler::ExtensionInstallForcelistPolicyHandler()
148 : ExtensionInstallListPolicyHandler(policy::key::kExtensionInstallForcelist,
149 pref_names::kInstallForceList) {}
150
151// ExtensionInstallLoginScreenAppListPolicyHandler implementation --------------
152
153ExtensionInstallLoginScreenAppListPolicyHandler::
154 ExtensionInstallLoginScreenAppListPolicyHandler()
155 : ExtensionInstallListPolicyHandler(
156 policy::key::kDeviceLoginScreenAppInstallList,
157 pref_names::kInstallLoginScreenAppList) {}
158
[email protected]01253d272013-10-21 17:07:50159// ExtensionURLPatternListPolicyHandler implementation -------------------------
160
161ExtensionURLPatternListPolicyHandler::ExtensionURLPatternListPolicyHandler(
162 const char* policy_name,
163 const char* pref_path)
jdoerriedc72ee942016-12-07 15:43:28164 : policy::TypeCheckingPolicyHandler(policy_name, base::Value::Type::LIST),
[email protected]01253d272013-10-21 17:07:50165 pref_path_(pref_path) {}
166
167ExtensionURLPatternListPolicyHandler::~ExtensionURLPatternListPolicyHandler() {}
168
169bool ExtensionURLPatternListPolicyHandler::CheckPolicySettings(
170 const policy::PolicyMap& policies,
171 policy::PolicyErrorMap* errors) {
172 const base::Value* value = NULL;
173 if (!CheckAndGetValue(policies, errors, &value))
174 return false;
175
176 if (!value)
177 return true;
178
179 const base::ListValue* list_value = NULL;
180 if (!value->GetAsList(&list_value)) {
181 NOTREACHED();
182 return false;
183 }
184
185 // Check that the list contains valid URLPattern strings only.
186 for (base::ListValue::const_iterator entry(list_value->begin());
187 entry != list_value->end(); ++entry) {
188 std::string url_pattern_string;
jdoerriea5676c62017-04-11 18:09:14189 if (!entry->GetAsString(&url_pattern_string)) {
thestige7615d6c2016-07-19 19:43:46190 errors->AddError(policy_name(), entry - list_value->begin(),
[email protected]01253d272013-10-21 17:07:50191 IDS_POLICY_TYPE_ERROR,
jdoerriedc72ee942016-12-07 15:43:28192 base::Value::GetTypeName(base::Value::Type::STRING));
[email protected]01253d272013-10-21 17:07:50193 return false;
194 }
195
196 URLPattern pattern(URLPattern::SCHEME_ALL);
Devlin Croninbd7f2b5fa2018-09-05 17:41:18197 if (pattern.Parse(url_pattern_string) !=
198 URLPattern::ParseResult::kSuccess) {
[email protected]01253d272013-10-21 17:07:50199 errors->AddError(policy_name(),
200 entry - list_value->begin(),
201 IDS_POLICY_VALUE_FORMAT_ERROR);
202 return false;
203 }
204 }
205
206 return true;
207}
208
209void ExtensionURLPatternListPolicyHandler::ApplyPolicySettings(
210 const policy::PolicyMap& policies,
211 PrefValueMap* prefs) {
212 if (!pref_path_)
213 return;
[email protected]cb1078de2013-12-23 20:04:22214 const base::Value* value = policies.GetValue(policy_name());
[email protected]01253d272013-10-21 17:07:50215 if (value)
estade0bd407f2015-06-26 18:16:18216 prefs->SetValue(pref_path_, value->CreateDeepCopy());
[email protected]01253d272013-10-21 17:07:50217}
218
binjin1e1cc33a2014-10-09 18:08:16219// ExtensionSettingsPolicyHandler implementation ------------------------------
220
221ExtensionSettingsPolicyHandler::ExtensionSettingsPolicyHandler(
222 const policy::Schema& chrome_schema)
223 : policy::SchemaValidatingPolicyHandler(
224 policy::key::kExtensionSettings,
225 chrome_schema.GetKnownProperty(policy::key::kExtensionSettings),
226 policy::SCHEMA_ALLOW_UNKNOWN) {
227}
228
229ExtensionSettingsPolicyHandler::~ExtensionSettingsPolicyHandler() {
230}
231
232bool ExtensionSettingsPolicyHandler::CheckPolicySettings(
233 const policy::PolicyMap& policies,
234 policy::PolicyErrorMap* errors) {
dchengc963c7142016-04-08 03:55:22235 std::unique_ptr<base::Value> policy_value;
binjin1e1cc33a2014-10-09 18:08:16236 if (!CheckAndGetValue(policies, errors, &policy_value))
237 return false;
238 if (!policy_value)
239 return true;
240
241 // |policy_value| is expected to conform to the defined schema. But it's
242 // not strictly valid since there are additional restrictions.
243 const base::DictionaryValue* dict_value = NULL;
jdoerrie1f536b22017-10-23 17:15:11244 DCHECK(policy_value->is_dict());
binjin1e1cc33a2014-10-09 18:08:16245 policy_value->GetAsDictionary(&dict_value);
246
247 for (base::DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
248 it.Advance()) {
249 DCHECK(it.key() == schema_constants::kWildcard ||
250 crx_file::id_util::IdIsValid(it.key()));
jdoerrie1f536b22017-10-23 17:15:11251 DCHECK(it.value().is_dict());
binjin1e1cc33a2014-10-09 18:08:16252
253 // Extracts sub dictionary.
254 const base::DictionaryValue* sub_dict = NULL;
255 it.value().GetAsDictionary(&sub_dict);
256
257 std::string installation_mode;
258 if (sub_dict->GetString(schema_constants::kInstallationMode,
259 &installation_mode)) {
260 if (installation_mode == schema_constants::kForceInstalled ||
261 installation_mode == schema_constants::kNormalInstalled) {
262 DCHECK(it.key() != schema_constants::kWildcard);
263 // Verifies that 'update_url' is specified for 'force_installed' and
264 // 'normal_installed' mode.
265 std::string update_url;
266 if (!sub_dict->GetString(schema_constants::kUpdateUrl, &update_url) ||
267 update_url.empty()) {
268 errors->AddError(policy_name(),
269 it.key() + "." + schema_constants::kUpdateUrl,
270 IDS_POLICY_NOT_SPECIFIED_ERROR);
271 return false;
272 }
Nick Petersond952cb772018-03-07 15:46:03273 if (GURL(update_url).is_valid()) {
274// Unless enterprise managed only extensions from the Chrome Webstore
275// can be force installed.
276#if defined(OS_WIN)
277 // We can't use IsWebstoreUpdateUrl() here since the ExtensionClient
278 // isn't set this early during startup.
279 if (!base::win::IsEnterpriseManaged() &&
280 !base::LowerCaseEqualsASCII(
281 update_url, extension_urls::kChromeWebstoreUpdateURL)) {
282 errors->AddError(policy_name(), it.key(),
283 IDS_POLICY_OFF_CWS_URL_ERROR,
284 extension_urls::kChromeWebstoreUpdateURL);
285 return false;
286 }
287#endif
288 } else {
289 // Warns about an invalid update URL.
binjin1e1cc33a2014-10-09 18:08:16290 errors->AddError(
291 policy_name(), IDS_POLICY_INVALID_UPDATE_URL_ERROR, it.key());
292 return false;
293 }
294 }
295 }
Nick Peterson6bdf5822017-06-01 20:42:45296 // Host keys that don't support user defined paths.
Devlin Cronin7e0f41ff2018-05-16 17:19:36297 const char* host_keys[] = {schema_constants::kPolicyBlockedHosts,
298 schema_constants::kPolicyAllowedHosts};
Nick Peterson6bdf5822017-06-01 20:42:45299 const int extension_scheme_mask =
300 URLPattern::GetValidSchemeMaskForExtensions();
301 for (const char* key : host_keys) {
302 const base::ListValue* unparsed_urls;
303 if (sub_dict->GetList(key, &unparsed_urls)) {
304 for (size_t i = 0; i < unparsed_urls->GetSize(); ++i) {
305 std::string unparsed_url;
306 unparsed_urls->GetString(i, &unparsed_url);
307 URLPattern pattern(extension_scheme_mask);
308 URLPattern::ParseResult parse_result = pattern.Parse(
309 unparsed_url, URLPattern::ALLOW_WILDCARD_FOR_EFFECTIVE_TLD);
310 // These keys don't support paths due to how we track the initiator
311 // of a webRequest and cookie security policy. We expect a valid
312 // pattern to return a PARSE_ERROR_EMPTY_PATH.
Devlin Croninbd7f2b5fa2018-09-05 17:41:18313 if (parse_result == URLPattern::ParseResult::kEmptyPath) {
Nick Peterson6bdf5822017-06-01 20:42:45314 // Add a wildcard path to the URL as it should match any path.
315 parse_result =
316 pattern.Parse(unparsed_url + "/*",
317 URLPattern::ALLOW_WILDCARD_FOR_EFFECTIVE_TLD);
Devlin Croninbd7f2b5fa2018-09-05 17:41:18318 } else if (parse_result == URLPattern::ParseResult::kSuccess) {
Nick Peterson6bdf5822017-06-01 20:42:45319 // The user supplied a path, notify them that this is not supported.
320 if (!pattern.match_all_urls()) {
321 errors->AddError(
322 policy_name(), it.key(),
323 "The URL pattern '" + unparsed_url + "' for attribute " +
324 key + " has a path specified. Paths are not " +
325 "supported, please remove the path and try again. " +
326 "e.g. *://example.com/ => *://example.com");
327 return false;
328 }
329 }
Devlin Croninbd7f2b5fa2018-09-05 17:41:18330 if (parse_result != URLPattern::ParseResult::kSuccess) {
Nick Peterson6bdf5822017-06-01 20:42:45331 errors->AddError(policy_name(), it.key(),
332 "Invalid URL pattern '" + unparsed_url +
333 "' for attribute " + key);
334 return false;
335 }
336 }
337 }
338 }
binjin1e1cc33a2014-10-09 18:08:16339 }
340
341 return true;
342}
343
344void ExtensionSettingsPolicyHandler::ApplyPolicySettings(
345 const policy::PolicyMap& policies,
346 PrefValueMap* prefs) {
dchengc963c7142016-04-08 03:55:22347 std::unique_ptr<base::Value> policy_value;
binjin1e1cc33a2014-10-09 18:08:16348 if (!CheckAndGetValue(policies, NULL, &policy_value) || !policy_value)
349 return;
dcheng1fc00f12015-12-26 22:18:03350 prefs->SetValue(pref_names::kExtensionManagement, std::move(policy_value));
binjin1e1cc33a2014-10-09 18:08:16351}
352
[email protected]01253d272013-10-21 17:07:50353} // namespace extensions