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.
4
5#include "chrome/browser/content_settings/content_settings_policy_provider.h"
6
7#include <string>
8#include <vector>
9
10#include "base/json/json_reader.h"
11#include "base/prefs/pref_service.h"
12#include "base/values.h"
13#include "chrome/browser/content_settings/content_settings_utils.h"
14#include "chrome/common/pref_names.h"
15#include "components/content_settings/core/browser/content_settings_rule.h"
16#include "components/content_settings/core/common/content_settings_pattern.h"
17#include "components/pref_registry/pref_registry_syncable.h"
18#include "content/public/browser/browser_thread.h"
19
20using content::BrowserThread;
21
22namespace {
23
24// The preferences used to manage ContentSettingsTypes.
25const char* kPrefToManageType[] = {
26  prefs::kManagedDefaultCookiesSetting,
27  prefs::kManagedDefaultImagesSetting,
28  prefs::kManagedDefaultJavaScriptSetting,
29  prefs::kManagedDefaultPluginsSetting,
30  prefs::kManagedDefaultPopupsSetting,
31  prefs::kManagedDefaultGeolocationSetting,
32  prefs::kManagedDefaultNotificationsSetting,
33  NULL,  // No policy for default value of content type auto-select-certificate
34  NULL,  // No policy for default value of fullscreen requests
35  NULL,  // No policy for default value of mouse lock requests
36  NULL,  // No policy for default value of mixed script blocking
37  prefs::kManagedDefaultMediaStreamSetting,
38  NULL,  // No policy for default value of media stream mic
39  NULL,  // No policy for default value of media stream camera
40  NULL,  // No policy for default value of protocol handlers
41  NULL,  // No policy for default value of PPAPI broker
42  NULL,  // No policy for default value of multiple automatic downloads
43  NULL,  // No policy for default value of MIDI system exclusive requests
44  NULL,  // No policy for default value of push messaging requests
45  NULL,  // No policy for default value of SSL certificate decisions
46#if defined(OS_WIN)
47  NULL,  // No policy for default value of "switch to desktop"
48#elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
49  NULL,  // No policy for default value of protected media identifier
50#endif
51#if defined(OS_ANDROID)
52  NULL,  // No policy for default value of app banners
53#endif
54};
55COMPILE_ASSERT(arraysize(kPrefToManageType) == CONTENT_SETTINGS_NUM_TYPES,
56               managed_content_settings_pref_names_array_size_incorrect);
57
58struct PrefsForManagedContentSettingsMapEntry {
59  const char* pref_name;
60  ContentSettingsType content_type;
61  ContentSetting setting;
62};
63
64const PrefsForManagedContentSettingsMapEntry
65    kPrefsForManagedContentSettingsMap[] = {
66  {
67    prefs::kManagedCookiesAllowedForUrls,
68    CONTENT_SETTINGS_TYPE_COOKIES,
69    CONTENT_SETTING_ALLOW
70  }, {
71    prefs::kManagedCookiesSessionOnlyForUrls,
72    CONTENT_SETTINGS_TYPE_COOKIES,
73    CONTENT_SETTING_SESSION_ONLY
74  }, {
75    prefs::kManagedCookiesBlockedForUrls,
76    CONTENT_SETTINGS_TYPE_COOKIES,
77    CONTENT_SETTING_BLOCK
78  }, {
79    prefs::kManagedImagesAllowedForUrls,
80    CONTENT_SETTINGS_TYPE_IMAGES,
81    CONTENT_SETTING_ALLOW
82  }, {
83    prefs::kManagedImagesBlockedForUrls,
84    CONTENT_SETTINGS_TYPE_IMAGES,
85    CONTENT_SETTING_BLOCK
86  }, {
87    prefs::kManagedJavaScriptAllowedForUrls,
88    CONTENT_SETTINGS_TYPE_JAVASCRIPT,
89    CONTENT_SETTING_ALLOW
90  }, {
91    prefs::kManagedJavaScriptBlockedForUrls,
92    CONTENT_SETTINGS_TYPE_JAVASCRIPT,
93    CONTENT_SETTING_BLOCK
94  }, {
95    prefs::kManagedPluginsAllowedForUrls,
96    CONTENT_SETTINGS_TYPE_PLUGINS,
97    CONTENT_SETTING_ALLOW
98  }, {
99    prefs::kManagedPluginsBlockedForUrls,
100    CONTENT_SETTINGS_TYPE_PLUGINS,
101    CONTENT_SETTING_BLOCK
102  }, {
103    prefs::kManagedPopupsAllowedForUrls,
104    CONTENT_SETTINGS_TYPE_POPUPS,
105    CONTENT_SETTING_ALLOW
106  }, {
107    prefs::kManagedPopupsBlockedForUrls,
108    CONTENT_SETTINGS_TYPE_POPUPS,
109    CONTENT_SETTING_BLOCK
110  }, {
111    prefs::kManagedNotificationsAllowedForUrls,
112    CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
113    CONTENT_SETTING_ALLOW
114  }, {
115    prefs::kManagedNotificationsBlockedForUrls,
116    CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
117    CONTENT_SETTING_BLOCK
118  }
119};
120
121}  // namespace
122
123namespace content_settings {
124
125// static
126void PolicyProvider::RegisterProfilePrefs(
127    user_prefs::PrefRegistrySyncable* registry) {
128  registry->RegisterListPref(prefs::kManagedAutoSelectCertificateForUrls,
129                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
130  registry->RegisterListPref(prefs::kManagedCookiesAllowedForUrls,
131                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
132  registry->RegisterListPref(prefs::kManagedCookiesBlockedForUrls,
133                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
134  registry->RegisterListPref(prefs::kManagedCookiesSessionOnlyForUrls,
135                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
136  registry->RegisterListPref(prefs::kManagedImagesAllowedForUrls,
137                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
138  registry->RegisterListPref(prefs::kManagedImagesBlockedForUrls,
139                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
140  registry->RegisterListPref(prefs::kManagedJavaScriptAllowedForUrls,
141                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
142  registry->RegisterListPref(prefs::kManagedJavaScriptBlockedForUrls,
143                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
144  registry->RegisterListPref(prefs::kManagedPluginsAllowedForUrls,
145                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
146  registry->RegisterListPref(prefs::kManagedPluginsBlockedForUrls,
147                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
148  registry->RegisterListPref(prefs::kManagedPopupsAllowedForUrls,
149                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
150  registry->RegisterListPref(prefs::kManagedPopupsBlockedForUrls,
151                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
152  registry->RegisterListPref(prefs::kManagedNotificationsAllowedForUrls,
153                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
154  registry->RegisterListPref(prefs::kManagedNotificationsBlockedForUrls,
155                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
156  // Preferences for default content setting policies. If a policy is not set of
157  // the corresponding preferences below is set to CONTENT_SETTING_DEFAULT.
158  registry->RegisterIntegerPref(
159      prefs::kManagedDefaultCookiesSetting,
160      CONTENT_SETTING_DEFAULT,
161      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
162  registry->RegisterIntegerPref(
163      prefs::kManagedDefaultImagesSetting,
164      CONTENT_SETTING_DEFAULT,
165      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
166  registry->RegisterIntegerPref(
167      prefs::kManagedDefaultJavaScriptSetting,
168      CONTENT_SETTING_DEFAULT,
169      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
170  registry->RegisterIntegerPref(
171      prefs::kManagedDefaultPluginsSetting,
172      CONTENT_SETTING_DEFAULT,
173      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
174  registry->RegisterIntegerPref(
175      prefs::kManagedDefaultPopupsSetting,
176      CONTENT_SETTING_DEFAULT,
177      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
178  registry->RegisterIntegerPref(
179      prefs::kManagedDefaultGeolocationSetting,
180      CONTENT_SETTING_DEFAULT,
181      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
182  registry->RegisterIntegerPref(
183      prefs::kManagedDefaultNotificationsSetting,
184      CONTENT_SETTING_DEFAULT,
185      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
186  registry->RegisterIntegerPref(
187      prefs::kManagedDefaultMediaStreamSetting,
188      CONTENT_SETTING_DEFAULT,
189      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
190}
191
192PolicyProvider::PolicyProvider(PrefService* prefs) : prefs_(prefs) {
193  ReadManagedDefaultSettings();
194  ReadManagedContentSettings(false);
195
196  pref_change_registrar_.Init(prefs_);
197  PrefChangeRegistrar::NamedChangeCallback callback =
198      base::Bind(&PolicyProvider::OnPreferenceChanged, base::Unretained(this));
199  pref_change_registrar_.Add(
200      prefs::kManagedAutoSelectCertificateForUrls, callback);
201  pref_change_registrar_.Add(prefs::kManagedCookiesBlockedForUrls, callback);
202  pref_change_registrar_.Add(prefs::kManagedCookiesAllowedForUrls, callback);
203  pref_change_registrar_.Add(
204      prefs::kManagedCookiesSessionOnlyForUrls, callback);
205  pref_change_registrar_.Add(prefs::kManagedImagesBlockedForUrls, callback);
206  pref_change_registrar_.Add(prefs::kManagedImagesAllowedForUrls, callback);
207  pref_change_registrar_.Add(prefs::kManagedJavaScriptBlockedForUrls, callback);
208  pref_change_registrar_.Add(prefs::kManagedJavaScriptAllowedForUrls, callback);
209  pref_change_registrar_.Add(prefs::kManagedPluginsBlockedForUrls, callback);
210  pref_change_registrar_.Add(prefs::kManagedPluginsAllowedForUrls, callback);
211  pref_change_registrar_.Add(prefs::kManagedPopupsBlockedForUrls, callback);
212  pref_change_registrar_.Add(prefs::kManagedPopupsAllowedForUrls, callback);
213  pref_change_registrar_.Add(
214      prefs::kManagedNotificationsAllowedForUrls, callback);
215  pref_change_registrar_.Add(
216      prefs::kManagedNotificationsBlockedForUrls, callback);
217  // The following preferences are only used to indicate if a default content
218  // setting is managed and to hold the managed default setting value. If the
219  // value for any of the following preferences is set then the corresponding
220  // default content setting is managed. These preferences exist in parallel to
221  // the preference default content settings. If a default content settings type
222  // is managed any user defined exceptions (patterns) for this type are
223  // ignored.
224  pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, callback);
225  pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, callback);
226  pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, callback);
227  pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, callback);
228  pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, callback);
229  pref_change_registrar_.Add(
230      prefs::kManagedDefaultGeolocationSetting, callback);
231  pref_change_registrar_.Add(
232      prefs::kManagedDefaultNotificationsSetting, callback);
233  pref_change_registrar_.Add(
234      prefs::kManagedDefaultMediaStreamSetting, callback);
235}
236
237PolicyProvider::~PolicyProvider() {
238  DCHECK(!prefs_);
239}
240
241RuleIterator* PolicyProvider::GetRuleIterator(
242    ContentSettingsType content_type,
243    const ResourceIdentifier& resource_identifier,
244    bool incognito) const {
245  return value_map_.GetRuleIterator(content_type, resource_identifier, &lock_);
246}
247
248void PolicyProvider::GetContentSettingsFromPreferences(
249    OriginIdentifierValueMap* value_map) {
250  for (size_t i = 0; i < arraysize(kPrefsForManagedContentSettingsMap); ++i) {
251    const char* pref_name = kPrefsForManagedContentSettingsMap[i].pref_name;
252    // Skip unset policies.
253    if (!prefs_->HasPrefPath(pref_name)) {
254      VLOG(2) << "Skipping unset preference: " << pref_name;
255      continue;
256    }
257
258    const PrefService::Preference* pref = prefs_->FindPreference(pref_name);
259    DCHECK(pref);
260    DCHECK(pref->IsManaged());
261
262    const base::ListValue* pattern_str_list = NULL;
263    if (!pref->GetValue()->GetAsList(&pattern_str_list)) {
264      NOTREACHED();
265      return;
266    }
267
268    for (size_t j = 0; j < pattern_str_list->GetSize(); ++j) {
269      std::string original_pattern_str;
270      if (!pattern_str_list->GetString(j, &original_pattern_str)) {
271        NOTREACHED();
272        continue;
273      }
274
275      PatternPair pattern_pair = ParsePatternString(original_pattern_str);
276      // Ignore invalid patterns.
277      if (!pattern_pair.first.IsValid()) {
278        VLOG(1) << "Ignoring invalid content settings pattern: " <<
279                   original_pattern_str;
280        continue;
281      }
282
283      ContentSettingsType content_type =
284          kPrefsForManagedContentSettingsMap[i].content_type;
285      DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE);
286      // If only one pattern was defined auto expand it to a pattern pair.
287      ContentSettingsPattern secondary_pattern =
288          !pattern_pair.second.IsValid() ? ContentSettingsPattern::Wildcard()
289                                         : pattern_pair.second;
290      value_map->SetValue(pattern_pair.first,
291                          secondary_pattern,
292                          content_type,
293                          NO_RESOURCE_IDENTIFIER,
294                          new base::FundamentalValue(
295                              kPrefsForManagedContentSettingsMap[i].setting));
296    }
297  }
298}
299
300void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences(
301    OriginIdentifierValueMap* value_map) {
302  const char* pref_name = prefs::kManagedAutoSelectCertificateForUrls;
303
304  if (!prefs_->HasPrefPath(pref_name)) {
305    VLOG(2) << "Skipping unset preference: " << pref_name;
306    return;
307  }
308
309  const PrefService::Preference* pref = prefs_->FindPreference(pref_name);
310  DCHECK(pref);
311  DCHECK(pref->IsManaged());
312
313  const base::ListValue* pattern_filter_str_list = NULL;
314  if (!pref->GetValue()->GetAsList(&pattern_filter_str_list)) {
315    NOTREACHED();
316    return;
317  }
318
319  // Parse the list of pattern filter strings. A pattern filter string has
320  // the following JSON format:
321  //
322  // {
323  //   "pattern": <content settings pattern string>,
324  //   "filter" : <certificate filter in JSON format>
325  // }
326  //
327  // e.g.
328  // {
329  //   "pattern": "[*.]example.com",
330  //   "filter": {
331  //      "ISSUER": {
332  //        "CN": "some name"
333  //      }
334  //   }
335  // }
336  for (size_t j = 0; j < pattern_filter_str_list->GetSize(); ++j) {
337    std::string pattern_filter_json;
338    if (!pattern_filter_str_list->GetString(j, &pattern_filter_json)) {
339      NOTREACHED();
340      continue;
341    }
342
343    scoped_ptr<base::Value> value(base::JSONReader::Read(pattern_filter_json,
344        base::JSON_ALLOW_TRAILING_COMMAS));
345    if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
346      VLOG(1) << "Ignoring invalid certificate auto select setting. Reason:"
347                 " Invalid JSON object: " << pattern_filter_json;
348      continue;
349    }
350
351    scoped_ptr<base::DictionaryValue> pattern_filter_pair(
352        static_cast<base::DictionaryValue*>(value.release()));
353    std::string pattern_str;
354    bool pattern_read = pattern_filter_pair->GetStringWithoutPathExpansion(
355        "pattern", &pattern_str);
356    base::DictionaryValue* cert_filter = NULL;
357    pattern_filter_pair->GetDictionaryWithoutPathExpansion("filter",
358                                                           &cert_filter);
359    if (!pattern_read || !cert_filter) {
360      VLOG(1) << "Ignoring invalid certificate auto select setting. Reason:"
361                 " Missing pattern or filter.";
362      continue;
363    }
364
365    ContentSettingsPattern pattern =
366        ContentSettingsPattern::FromString(pattern_str);
367    // Ignore invalid patterns.
368    if (!pattern.IsValid()) {
369      VLOG(1) << "Ignoring invalid certificate auto select setting:"
370                 " Invalid content settings pattern: " << pattern.ToString();
371      continue;
372    }
373
374    // Don't pass removed values from |value|, because base::Values read with
375    // JSONReader use a shared string buffer. Instead, DeepCopy here.
376    value_map->SetValue(pattern,
377                        ContentSettingsPattern::Wildcard(),
378                        CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE,
379                        std::string(),
380                        cert_filter->DeepCopy());
381  }
382}
383
384void PolicyProvider::ReadManagedDefaultSettings() {
385  for (size_t type = 0; type < arraysize(kPrefToManageType); ++type) {
386    if (kPrefToManageType[type] == NULL) {
387      continue;
388    }
389    UpdateManagedDefaultSetting(ContentSettingsType(type));
390  }
391}
392
393void PolicyProvider::UpdateManagedDefaultSetting(
394    ContentSettingsType content_type) {
395  // If a pref to manage a default-content-setting was not set (NOTICE:
396  // "HasPrefPath" returns false if no value was set for a registered pref) then
397  // the default value of the preference is used. The default value of a
398  // preference to manage a default-content-settings is CONTENT_SETTING_DEFAULT.
399  // This indicates that no managed value is set. If a pref was set, than it
400  // MUST be managed.
401  DCHECK(!prefs_->HasPrefPath(kPrefToManageType[content_type]) ||
402          prefs_->IsManagedPreference(kPrefToManageType[content_type]));
403  base::AutoLock auto_lock(lock_);
404
405  int setting = prefs_->GetInteger(kPrefToManageType[content_type]);
406  if (setting == CONTENT_SETTING_DEFAULT) {
407    value_map_.DeleteValue(
408        ContentSettingsPattern::Wildcard(),
409        ContentSettingsPattern::Wildcard(),
410        content_type,
411        std::string());
412  } else {
413    value_map_.SetValue(ContentSettingsPattern::Wildcard(),
414                        ContentSettingsPattern::Wildcard(),
415                        content_type,
416                        std::string(),
417                        new base::FundamentalValue(setting));
418  }
419}
420
421
422void PolicyProvider::ReadManagedContentSettings(bool overwrite) {
423  base::AutoLock auto_lock(lock_);
424  if (overwrite)
425    value_map_.clear();
426  GetContentSettingsFromPreferences(&value_map_);
427  GetAutoSelectCertificateSettingsFromPreferences(&value_map_);
428}
429
430// Since the PolicyProvider is a read only content settings provider, all
431// methodes of the ProviderInterface that set or delete any settings do nothing.
432bool PolicyProvider::SetWebsiteSetting(
433    const ContentSettingsPattern& primary_pattern,
434    const ContentSettingsPattern& secondary_pattern,
435    ContentSettingsType content_type,
436    const ResourceIdentifier& resource_identifier,
437    base::Value* value) {
438  return false;
439}
440
441void PolicyProvider::ClearAllContentSettingsRules(
442    ContentSettingsType content_type) {
443}
444
445void PolicyProvider::ShutdownOnUIThread() {
446  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
447  RemoveAllObservers();
448  if (!prefs_)
449    return;
450  pref_change_registrar_.RemoveAll();
451  prefs_ = NULL;
452}
453
454void PolicyProvider::OnPreferenceChanged(const std::string& name) {
455  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
456
457  if (name == prefs::kManagedDefaultCookiesSetting) {
458    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES);
459  } else if (name == prefs::kManagedDefaultImagesSetting) {
460    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_IMAGES);
461  } else if (name == prefs::kManagedDefaultJavaScriptSetting) {
462    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
463  } else if (name == prefs::kManagedDefaultPluginsSetting) {
464    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
465  } else if (name == prefs::kManagedDefaultPopupsSetting) {
466    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS);
467  } else if (name == prefs::kManagedDefaultGeolocationSetting) {
468    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_GEOLOCATION);
469  } else if (name == prefs::kManagedDefaultNotificationsSetting) {
470    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
471  } else if (name == prefs::kManagedDefaultMediaStreamSetting) {
472    UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
473  } else if (name == prefs::kManagedAutoSelectCertificateForUrls ||
474             name == prefs::kManagedCookiesAllowedForUrls ||
475             name == prefs::kManagedCookiesBlockedForUrls ||
476             name == prefs::kManagedCookiesSessionOnlyForUrls ||
477             name == prefs::kManagedImagesAllowedForUrls ||
478             name == prefs::kManagedImagesBlockedForUrls ||
479             name == prefs::kManagedJavaScriptAllowedForUrls ||
480             name == prefs::kManagedJavaScriptBlockedForUrls ||
481             name == prefs::kManagedPluginsAllowedForUrls ||
482             name == prefs::kManagedPluginsBlockedForUrls ||
483             name == prefs::kManagedPopupsAllowedForUrls ||
484             name == prefs::kManagedPopupsBlockedForUrls ||
485             name == prefs::kManagedNotificationsAllowedForUrls ||
486             name == prefs::kManagedNotificationsBlockedForUrls) {
487    ReadManagedContentSettings(true);
488    ReadManagedDefaultSettings();
489  }
490
491  NotifyObservers(ContentSettingsPattern(),
492                  ContentSettingsPattern(),
493                  CONTENT_SETTINGS_TYPE_DEFAULT,
494                  std::string());
495}
496
497}  // namespace content_settings
498