| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/content_settings/content_settings_policy_provider.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/json/json_reader.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/values.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/content_settings/content_settings_rule.h" |
| #include "chrome/browser/content_settings/content_settings_utils.h" |
| #include "chrome/common/content_settings_pattern.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/user_prefs/pref_registry_syncable.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_details.h" |
| #include "content/public/browser/notification_source.h" |
| |
| using content::BrowserThread; |
| |
| namespace { |
| |
| // The preferences used to manage ContentSettingsTypes. |
| const char* kPrefToManageType[] = { |
| prefs::kManagedDefaultCookiesSetting, |
| prefs::kManagedDefaultImagesSetting, |
| prefs::kManagedDefaultJavaScriptSetting, |
| prefs::kManagedDefaultPluginsSetting, |
| prefs::kManagedDefaultPopupsSetting, |
| prefs::kManagedDefaultGeolocationSetting, |
| prefs::kManagedDefaultNotificationsSetting, |
| NULL, // No policy for default value of content type auto-select-certificate |
| NULL, // No policy for default value of fullscreen requests |
| NULL, // No policy for default value of mouse lock requests |
| NULL, // No policy for default value of mixed script blocking |
| prefs::kManagedDefaultMediaStreamSetting, |
| NULL, // No policy for default value of media stream mic |
| NULL, // No policy for default value of media stream camera |
| NULL, // No policy for default value of protocol handlers |
| NULL, // No policy for default value of PPAPI broker |
| NULL, // No policy for default value of multiple automatic downloads |
| NULL, // No policy for default value of MIDI system exclusive requests |
| #if defined(OS_WIN) |
| NULL, // No policy for default value of "switch to desktop" |
| #elif defined(OS_ANDROID) || defined(OS_CHROMEOS) |
| NULL, // No policy for default value of protected media identifier |
| #endif |
| }; |
| COMPILE_ASSERT(arraysize(kPrefToManageType) == CONTENT_SETTINGS_NUM_TYPES, |
| managed_content_settings_pref_names_array_size_incorrect); |
| |
| struct PrefsForManagedContentSettingsMapEntry { |
| const char* pref_name; |
| ContentSettingsType content_type; |
| ContentSetting setting; |
| }; |
| |
| const PrefsForManagedContentSettingsMapEntry |
| kPrefsForManagedContentSettingsMap[] = { |
| { |
| prefs::kManagedCookiesAllowedForUrls, |
| CONTENT_SETTINGS_TYPE_COOKIES, |
| CONTENT_SETTING_ALLOW |
| }, { |
| prefs::kManagedCookiesSessionOnlyForUrls, |
| CONTENT_SETTINGS_TYPE_COOKIES, |
| CONTENT_SETTING_SESSION_ONLY |
| }, { |
| prefs::kManagedCookiesBlockedForUrls, |
| CONTENT_SETTINGS_TYPE_COOKIES, |
| CONTENT_SETTING_BLOCK |
| }, { |
| prefs::kManagedImagesAllowedForUrls, |
| CONTENT_SETTINGS_TYPE_IMAGES, |
| CONTENT_SETTING_ALLOW |
| }, { |
| prefs::kManagedImagesBlockedForUrls, |
| CONTENT_SETTINGS_TYPE_IMAGES, |
| CONTENT_SETTING_BLOCK |
| }, { |
| prefs::kManagedJavaScriptAllowedForUrls, |
| CONTENT_SETTINGS_TYPE_JAVASCRIPT, |
| CONTENT_SETTING_ALLOW |
| }, { |
| prefs::kManagedJavaScriptBlockedForUrls, |
| CONTENT_SETTINGS_TYPE_JAVASCRIPT, |
| CONTENT_SETTING_BLOCK |
| }, { |
| prefs::kManagedPluginsAllowedForUrls, |
| CONTENT_SETTINGS_TYPE_PLUGINS, |
| CONTENT_SETTING_ALLOW |
| }, { |
| prefs::kManagedPluginsBlockedForUrls, |
| CONTENT_SETTINGS_TYPE_PLUGINS, |
| CONTENT_SETTING_BLOCK |
| }, { |
| prefs::kManagedPopupsAllowedForUrls, |
| CONTENT_SETTINGS_TYPE_POPUPS, |
| CONTENT_SETTING_ALLOW |
| }, { |
| prefs::kManagedPopupsBlockedForUrls, |
| CONTENT_SETTINGS_TYPE_POPUPS, |
| CONTENT_SETTING_BLOCK |
| }, { |
| prefs::kManagedNotificationsAllowedForUrls, |
| CONTENT_SETTINGS_TYPE_NOTIFICATIONS, |
| CONTENT_SETTING_ALLOW |
| }, { |
| prefs::kManagedNotificationsBlockedForUrls, |
| CONTENT_SETTINGS_TYPE_NOTIFICATIONS, |
| CONTENT_SETTING_BLOCK |
| } |
| }; |
| |
| } // namespace |
| |
| namespace content_settings { |
| |
| // static |
| void PolicyProvider::RegisterProfilePrefs( |
| user_prefs::PrefRegistrySyncable* registry) { |
| registry->RegisterListPref(prefs::kManagedAutoSelectCertificateForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedCookiesAllowedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedCookiesBlockedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedCookiesSessionOnlyForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedImagesAllowedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedImagesBlockedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedJavaScriptAllowedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedJavaScriptBlockedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedPluginsAllowedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedPluginsBlockedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedPopupsAllowedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedPopupsBlockedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedNotificationsAllowedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterListPref(prefs::kManagedNotificationsBlockedForUrls, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| // Preferences for default content setting policies. If a policy is not set of |
| // the corresponding preferences below is set to CONTENT_SETTING_DEFAULT. |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultCookiesSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultImagesSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultJavaScriptSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultPluginsSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultPopupsSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultGeolocationSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultNotificationsSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kManagedDefaultMediaStreamSetting, |
| CONTENT_SETTING_DEFAULT, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| } |
| |
| PolicyProvider::PolicyProvider(PrefService* prefs) : prefs_(prefs) { |
| ReadManagedDefaultSettings(); |
| ReadManagedContentSettings(false); |
| |
| pref_change_registrar_.Init(prefs_); |
| PrefChangeRegistrar::NamedChangeCallback callback = |
| base::Bind(&PolicyProvider::OnPreferenceChanged, base::Unretained(this)); |
| pref_change_registrar_.Add( |
| prefs::kManagedAutoSelectCertificateForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedCookiesBlockedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedCookiesAllowedForUrls, callback); |
| pref_change_registrar_.Add( |
| prefs::kManagedCookiesSessionOnlyForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedImagesBlockedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedImagesAllowedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedJavaScriptBlockedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedJavaScriptAllowedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedPluginsBlockedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedPluginsAllowedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedPopupsBlockedForUrls, callback); |
| pref_change_registrar_.Add(prefs::kManagedPopupsAllowedForUrls, callback); |
| pref_change_registrar_.Add( |
| prefs::kManagedNotificationsAllowedForUrls, callback); |
| pref_change_registrar_.Add( |
| prefs::kManagedNotificationsBlockedForUrls, callback); |
| // The following preferences are only used to indicate if a |
| // default content setting is managed and to hold the managed default setting |
| // value. If the value for any of the following perferences is set then the |
| // corresponding default content setting is managed. These preferences exist |
| // in parallel to the preference default content settings. If a |
| // default content settings type is managed any user defined excpetions |
| // (patterns) for this type are ignored. |
| pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, callback); |
| pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, callback); |
| pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, callback); |
| pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, callback); |
| pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, callback); |
| pref_change_registrar_.Add( |
| prefs::kManagedDefaultGeolocationSetting, callback); |
| pref_change_registrar_.Add( |
| prefs::kManagedDefaultNotificationsSetting, callback); |
| pref_change_registrar_.Add( |
| prefs::kManagedDefaultMediaStreamSetting, callback); |
| } |
| |
| PolicyProvider::~PolicyProvider() { |
| DCHECK(!prefs_); |
| } |
| |
| RuleIterator* PolicyProvider::GetRuleIterator( |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier, |
| bool incognito) const { |
| return value_map_.GetRuleIterator(content_type, resource_identifier, &lock_); |
| } |
| |
| void PolicyProvider::GetContentSettingsFromPreferences( |
| OriginIdentifierValueMap* value_map) { |
| for (size_t i = 0; i < arraysize(kPrefsForManagedContentSettingsMap); ++i) { |
| const char* pref_name = kPrefsForManagedContentSettingsMap[i].pref_name; |
| // Skip unset policies. |
| if (!prefs_->HasPrefPath(pref_name)) { |
| VLOG(2) << "Skipping unset preference: " << pref_name; |
| continue; |
| } |
| |
| const PrefService::Preference* pref = prefs_->FindPreference(pref_name); |
| DCHECK(pref); |
| DCHECK(pref->IsManaged()); |
| |
| const base::ListValue* pattern_str_list = NULL; |
| if (!pref->GetValue()->GetAsList(&pattern_str_list)) { |
| NOTREACHED(); |
| return; |
| } |
| |
| for (size_t j = 0; j < pattern_str_list->GetSize(); ++j) { |
| std::string original_pattern_str; |
| if (!pattern_str_list->GetString(j, &original_pattern_str)) { |
| NOTREACHED(); |
| continue; |
| } |
| |
| PatternPair pattern_pair = ParsePatternString(original_pattern_str); |
| // Ignore invalid patterns. |
| if (!pattern_pair.first.IsValid()) { |
| VLOG(1) << "Ignoring invalid content settings pattern: " << |
| original_pattern_str; |
| continue; |
| } |
| |
| ContentSettingsType content_type = |
| kPrefsForManagedContentSettingsMap[i].content_type; |
| DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE); |
| // If only one pattern was defined auto expand it to a pattern pair. |
| ContentSettingsPattern secondary_pattern = |
| !pattern_pair.second.IsValid() ? ContentSettingsPattern::Wildcard() |
| : pattern_pair.second; |
| value_map->SetValue( |
| pattern_pair.first, |
| secondary_pattern, |
| content_type, |
| NO_RESOURCE_IDENTIFIER, |
| base::Value::CreateIntegerValue( |
| kPrefsForManagedContentSettingsMap[i].setting)); |
| } |
| } |
| } |
| |
| void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences( |
| OriginIdentifierValueMap* value_map) { |
| const char* pref_name = prefs::kManagedAutoSelectCertificateForUrls; |
| |
| if (!prefs_->HasPrefPath(pref_name)) { |
| VLOG(2) << "Skipping unset preference: " << pref_name; |
| return; |
| } |
| |
| const PrefService::Preference* pref = prefs_->FindPreference(pref_name); |
| DCHECK(pref); |
| DCHECK(pref->IsManaged()); |
| |
| const base::ListValue* pattern_filter_str_list = NULL; |
| if (!pref->GetValue()->GetAsList(&pattern_filter_str_list)) { |
| NOTREACHED(); |
| return; |
| } |
| |
| // Parse the list of pattern filter strings. A pattern filter string has |
| // the following JSON format: |
| // |
| // { |
| // "pattern": <content settings pattern string>, |
| // "filter" : <certificate filter in JSON format> |
| // } |
| // |
| // e.g. |
| // { |
| // "pattern": "[*.]example.com", |
| // "filter": { |
| // "ISSUER": { |
| // "CN": "some name" |
| // } |
| // } |
| // } |
| for (size_t j = 0; j < pattern_filter_str_list->GetSize(); ++j) { |
| std::string pattern_filter_json; |
| if (!pattern_filter_str_list->GetString(j, &pattern_filter_json)) { |
| NOTREACHED(); |
| continue; |
| } |
| |
| scoped_ptr<base::Value> value(base::JSONReader::Read(pattern_filter_json, |
| base::JSON_ALLOW_TRAILING_COMMAS)); |
| if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) { |
| VLOG(1) << "Ignoring invalid certificate auto select setting. Reason:" |
| " Invalid JSON object: " << pattern_filter_json; |
| continue; |
| } |
| |
| scoped_ptr<base::DictionaryValue> pattern_filter_pair( |
| static_cast<base::DictionaryValue*>(value.release())); |
| std::string pattern_str; |
| bool pattern_read = pattern_filter_pair->GetString("pattern", &pattern_str); |
| scoped_ptr<base::Value> cert_filter; |
| bool filter_read = pattern_filter_pair->Remove("filter", &cert_filter); |
| if (!pattern_read || !filter_read || |
| !cert_filter->IsType(base::Value::TYPE_DICTIONARY)) { |
| VLOG(1) << "Ignoring invalid certificate auto select setting. Reason:" |
| " Missing pattern or filter."; |
| continue; |
| } |
| |
| ContentSettingsPattern pattern = |
| ContentSettingsPattern::FromString(pattern_str); |
| // Ignore invalid patterns. |
| if (!pattern.IsValid()) { |
| VLOG(1) << "Ignoring invalid certificate auto select setting:" |
| " Invalid content settings pattern: " << pattern; |
| continue; |
| } |
| |
| value_map->SetValue(pattern, |
| ContentSettingsPattern::Wildcard(), |
| CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, |
| std::string(), |
| cert_filter.release()); |
| } |
| } |
| |
| void PolicyProvider::ReadManagedDefaultSettings() { |
| for (size_t type = 0; type < arraysize(kPrefToManageType); ++type) { |
| if (kPrefToManageType[type] == NULL) { |
| continue; |
| } |
| UpdateManagedDefaultSetting(ContentSettingsType(type)); |
| } |
| } |
| |
| void PolicyProvider::UpdateManagedDefaultSetting( |
| ContentSettingsType content_type) { |
| // If a pref to manage a default-content-setting was not set (NOTICE: |
| // "HasPrefPath" returns false if no value was set for a registered pref) then |
| // the default value of the preference is used. The default value of a |
| // preference to manage a default-content-settings is CONTENT_SETTING_DEFAULT. |
| // This indicates that no managed value is set. If a pref was set, than it |
| // MUST be managed. |
| DCHECK(!prefs_->HasPrefPath(kPrefToManageType[content_type]) || |
| prefs_->IsManagedPreference(kPrefToManageType[content_type])); |
| base::AutoLock auto_lock(lock_); |
| |
| int setting = prefs_->GetInteger(kPrefToManageType[content_type]); |
| if (setting == CONTENT_SETTING_DEFAULT) { |
| value_map_.DeleteValue( |
| ContentSettingsPattern::Wildcard(), |
| ContentSettingsPattern::Wildcard(), |
| content_type, |
| std::string()); |
| } else { |
| value_map_.SetValue( |
| ContentSettingsPattern::Wildcard(), |
| ContentSettingsPattern::Wildcard(), |
| content_type, |
| std::string(), |
| Value::CreateIntegerValue(setting)); |
| } |
| } |
| |
| |
| void PolicyProvider::ReadManagedContentSettings(bool overwrite) { |
| base::AutoLock auto_lock(lock_); |
| if (overwrite) |
| value_map_.clear(); |
| GetContentSettingsFromPreferences(&value_map_); |
| GetAutoSelectCertificateSettingsFromPreferences(&value_map_); |
| } |
| |
| // Since the PolicyProvider is a read only content settings provider, all |
| // methodes of the ProviderInterface that set or delete any settings do nothing. |
| bool PolicyProvider::SetWebsiteSetting( |
| const ContentSettingsPattern& primary_pattern, |
| const ContentSettingsPattern& secondary_pattern, |
| ContentSettingsType content_type, |
| const ResourceIdentifier& resource_identifier, |
| Value* value) { |
| return false; |
| } |
| |
| void PolicyProvider::ClearAllContentSettingsRules( |
| ContentSettingsType content_type) { |
| } |
| |
| void PolicyProvider::ShutdownOnUIThread() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| RemoveAllObservers(); |
| if (!prefs_) |
| return; |
| pref_change_registrar_.RemoveAll(); |
| prefs_ = NULL; |
| } |
| |
| void PolicyProvider::OnPreferenceChanged(const std::string& name) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| if (name == prefs::kManagedDefaultCookiesSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES); |
| } else if (name == prefs::kManagedDefaultImagesSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_IMAGES); |
| } else if (name == prefs::kManagedDefaultJavaScriptSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT); |
| } else if (name == prefs::kManagedDefaultPluginsSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_PLUGINS); |
| } else if (name == prefs::kManagedDefaultPopupsSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS); |
| } else if (name == prefs::kManagedDefaultGeolocationSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_GEOLOCATION); |
| } else if (name == prefs::kManagedDefaultNotificationsSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); |
| } else if (name == prefs::kManagedDefaultMediaStreamSetting) { |
| UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM); |
| } else if (name == prefs::kManagedAutoSelectCertificateForUrls || |
| name == prefs::kManagedCookiesAllowedForUrls || |
| name == prefs::kManagedCookiesBlockedForUrls || |
| name == prefs::kManagedCookiesSessionOnlyForUrls || |
| name == prefs::kManagedImagesAllowedForUrls || |
| name == prefs::kManagedImagesBlockedForUrls || |
| name == prefs::kManagedJavaScriptAllowedForUrls || |
| name == prefs::kManagedJavaScriptBlockedForUrls || |
| name == prefs::kManagedPluginsAllowedForUrls || |
| name == prefs::kManagedPluginsBlockedForUrls || |
| name == prefs::kManagedPopupsAllowedForUrls || |
| name == prefs::kManagedPopupsBlockedForUrls || |
| name == prefs::kManagedNotificationsAllowedForUrls || |
| name == prefs::kManagedNotificationsBlockedForUrls) { |
| ReadManagedContentSettings(true); |
| ReadManagedDefaultSettings(); |
| } |
| |
| NotifyObservers(ContentSettingsPattern(), |
| ContentSettingsPattern(), |
| CONTENT_SETTINGS_TYPE_DEFAULT, |
| std::string()); |
| } |
| |
| } // namespace content_settings |