root/chrome/browser/content_settings/content_settings_policy_provider.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. RegisterProfilePrefs
  2. GetRuleIterator
  3. GetContentSettingsFromPreferences
  4. GetAutoSelectCertificateSettingsFromPreferences
  5. ReadManagedDefaultSettings
  6. UpdateManagedDefaultSetting
  7. ReadManagedContentSettings
  8. SetWebsiteSetting
  9. ClearAllContentSettingsRules
  10. ShutdownOnUIThread
  11. OnPreferenceChanged

// 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
#if defined(OS_ANDROID)
  NULL,  // No policy for default value of app banners
#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(),
        base::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,
    base::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

/* [<][>][^][v][top][bottom][index][help] */