Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 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 "components/policy/core/browser/browser_policy_connector.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/command_line.h"
     11 #include "base/logging.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/message_loop/message_loop_proxy.h"
     14 #include "base/metrics/histogram.h"
     15 #include "base/metrics/sparse_histogram.h"
     16 #include "base/prefs/pref_registry_simple.h"
     17 #include "base/strings/string16.h"
     18 #include "base/strings/utf_string_conversions.h"
     19 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
     20 #include "components/policy/core/common/cloud/device_management_service.h"
     21 #include "components/policy/core/common/configuration_policy_provider.h"
     22 #include "components/policy/core/common/policy_namespace.h"
     23 #include "components/policy/core/common/policy_pref_names.h"
     24 #include "components/policy/core/common/policy_service_impl.h"
     25 #include "components/policy/core/common/policy_statistics_collector.h"
     26 #include "components/policy/core/common/policy_switches.h"
     27 #include "google_apis/gaia/gaia_auth_util.h"
     28 #include "net/url_request/url_request_context_getter.h"
     29 #include "policy/policy_constants.h"
     30 #include "third_party/icu/source/i18n/unicode/regex.h"
     31 
     32 namespace policy {
     33 
     34 namespace {
     35 
     36 // The URL for the device management server.
     37 const char kDefaultDeviceManagementServerUrl[] =
     38     "https://m.google.com/devicemanagement/data/api";
     39 
     40 // Used in BrowserPolicyConnector::SetPolicyProviderForTesting.
     41 bool g_created_policy_service = false;
     42 ConfigurationPolicyProvider* g_testing_provider = NULL;
     43 
     44 void ReportRegexSuccessMetric(bool success) {
     45   UMA_HISTOGRAM_BOOLEAN("Enterprise.DomainWhitelistRegexSuccess", success);
     46 }
     47 
     48 // Regexes that match many of the larger public email providers as we know
     49 // these users are not from hosted enterprise domains. Keep this list in sync
     50 // with the EnterpriseDomainRegex enum in histograms.xml (i.e. only add things
     51 // at the end).
     52 const wchar_t* const kNonManagedDomainPatterns[] = {
     53   L"aol\\.com",
     54   L"googlemail\\.com",
     55   L"gmail\\.com",
     56   L"hotmail(\\.co|\\.com|)\\.[^.]+", // hotmail.com, hotmail.it, hotmail.co.uk
     57   L"live\\.com",
     58   L"mail\\.ru",
     59   L"msn\\.com",
     60   L"qq\\.com",
     61   L"yahoo(\\.co|\\.com|)\\.[^.]+", // yahoo.com, yahoo.co.uk, yahoo.com.tw
     62   L"yandex\\.ru",
     63 };
     64 
     65 // Returns true if |domain| matches the regex |pattern|.
     66 bool MatchDomain(const base::string16& domain, const base::string16& pattern,
     67                  size_t index) {
     68   UErrorCode status = U_ZERO_ERROR;
     69   const icu::UnicodeString icu_pattern(pattern.data(), pattern.length());
     70   icu::RegexMatcher matcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status);
     71   if (!U_SUCCESS(status)) {
     72     // http://crbug.com/365351 - if for some reason the matcher creation fails
     73     // just return that the pattern doesn't match the domain. This is safe
     74     // because the calling method (IsNonEnterpriseUser()) is just used to enable
     75     // an optimization for non-enterprise users - better to skip the
     76     // optimization than crash.
     77     DLOG(ERROR) << "Possible invalid domain pattern: " << pattern
     78                 << " - Error: " << status;
     79     ReportRegexSuccessMetric(false);
     80     UMA_HISTOGRAM_ENUMERATION("Enterprise.DomainWhitelistRegexFailure",
     81                               index, arraysize(kNonManagedDomainPatterns));
     82     UMA_HISTOGRAM_SPARSE_SLOWLY("Enterprise.DomainWhitelistRegexFailureStatus",
     83                                 status);
     84     return false;
     85   }
     86   ReportRegexSuccessMetric(true);
     87   icu::UnicodeString icu_input(domain.data(), domain.length());
     88   matcher.reset(icu_input);
     89   status = U_ZERO_ERROR;
     90   UBool match = matcher.matches(status);
     91   DCHECK(U_SUCCESS(status));
     92   return !!match;  // !! == convert from UBool to bool.
     93 }
     94 
     95 }  // namespace
     96 
     97 BrowserPolicyConnector::BrowserPolicyConnector(
     98     const HandlerListFactory& handler_list_factory)
     99     : is_initialized_(false),
    100       platform_policy_provider_(NULL) {
    101   // GetPolicyService() must be ready after the constructor is done.
    102   // The connector is created very early during startup, when the browser
    103   // threads aren't running yet; initialize components that need local_state,
    104   // the system request context or other threads (e.g. FILE) at Init().
    105 
    106   // Initialize the SchemaRegistry with the Chrome schema before creating any
    107   // of the policy providers in subclasses.
    108   chrome_schema_ = Schema::Wrap(GetChromeSchemaData());
    109   handler_list_ = handler_list_factory.Run(chrome_schema_);
    110   schema_registry_.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_CHROME, ""),
    111                                      chrome_schema_);
    112 }
    113 
    114 BrowserPolicyConnector::~BrowserPolicyConnector() {
    115   if (is_initialized()) {
    116     // Shutdown() wasn't invoked by our owner after having called Init().
    117     // This usually means it's an early shutdown and
    118     // BrowserProcessImpl::StartTearDown() wasn't invoked.
    119     // Cleanup properly in those cases and avoid crashing the ToastCrasher test.
    120     Shutdown();
    121   }
    122 }
    123 
    124 void BrowserPolicyConnector::Init(
    125     PrefService* local_state,
    126     scoped_refptr<net::URLRequestContextGetter> request_context,
    127     scoped_ptr<DeviceManagementService> device_management_service) {
    128   DCHECK(!is_initialized());
    129 
    130   device_management_service_ = device_management_service.Pass();
    131 
    132   if (g_testing_provider)
    133     g_testing_provider->Init(GetSchemaRegistry());
    134   for (size_t i = 0; i < policy_providers_.size(); ++i)
    135     policy_providers_[i]->Init(GetSchemaRegistry());
    136 
    137   policy_statistics_collector_.reset(
    138       new policy::PolicyStatisticsCollector(
    139           base::Bind(&GetChromePolicyDetails),
    140           GetChromeSchema(),
    141           GetPolicyService(),
    142           local_state,
    143           base::MessageLoop::current()->message_loop_proxy()));
    144   policy_statistics_collector_->Initialize();
    145 
    146   is_initialized_ = true;
    147 }
    148 
    149 void BrowserPolicyConnector::Shutdown() {
    150   is_initialized_ = false;
    151   if (g_testing_provider)
    152     g_testing_provider->Shutdown();
    153   for (size_t i = 0; i < policy_providers_.size(); ++i)
    154     policy_providers_[i]->Shutdown();
    155   // Drop g_testing_provider so that tests executed with --single_process can
    156   // call SetPolicyProviderForTesting() again. It is still owned by the test.
    157   g_testing_provider = NULL;
    158   g_created_policy_service = false;
    159   device_management_service_.reset();
    160 }
    161 
    162 PolicyService* BrowserPolicyConnector::GetPolicyService() {
    163   if (!policy_service_) {
    164     g_created_policy_service = true;
    165     std::vector<ConfigurationPolicyProvider*> providers;
    166     if (g_testing_provider) {
    167       providers.push_back(g_testing_provider);
    168     } else {
    169       providers.resize(policy_providers_.size());
    170       std::copy(policy_providers_.begin(),
    171                 policy_providers_.end(),
    172                 providers.begin());
    173     }
    174     policy_service_.reset(new PolicyServiceImpl(providers));
    175   }
    176   return policy_service_.get();
    177 }
    178 
    179 ConfigurationPolicyProvider* BrowserPolicyConnector::GetPlatformProvider() {
    180   if (g_testing_provider)
    181     return g_testing_provider;
    182   return platform_policy_provider_;
    183 }
    184 
    185 const Schema& BrowserPolicyConnector::GetChromeSchema() const {
    186   return chrome_schema_;
    187 }
    188 
    189 CombinedSchemaRegistry* BrowserPolicyConnector::GetSchemaRegistry() {
    190   return &schema_registry_;
    191 }
    192 
    193 void BrowserPolicyConnector::ScheduleServiceInitialization(
    194     int64 delay_milliseconds) {
    195   // Skip device initialization if the BrowserPolicyConnector was never
    196   // initialized (unit tests).
    197   if (device_management_service_)
    198     device_management_service_->ScheduleInitialization(delay_milliseconds);
    199 }
    200 
    201 const ConfigurationPolicyHandlerList*
    202     BrowserPolicyConnector::GetHandlerList() const {
    203   return handler_list_.get();
    204 }
    205 
    206 // static
    207 void BrowserPolicyConnector::SetPolicyProviderForTesting(
    208     ConfigurationPolicyProvider* provider) {
    209   // If this function is used by a test then it must be called before the
    210   // browser is created, and GetPolicyService() gets called.
    211   CHECK(!g_created_policy_service);
    212   DCHECK(!g_testing_provider);
    213   g_testing_provider = provider;
    214 }
    215 
    216 // static
    217 bool BrowserPolicyConnector::IsNonEnterpriseUser(const std::string& username) {
    218   if (username.empty() || username.find('@') == std::string::npos) {
    219     // An empty username means incognito user in case of ChromiumOS and
    220     // no logged-in user in case of Chromium (SigninService). Many tests use
    221     // nonsense email addresses (e.g. 'test') so treat those as non-enterprise
    222     // users.
    223     return true;
    224   }
    225   const base::string16 domain = base::UTF8ToUTF16(
    226       gaia::ExtractDomainName(gaia::CanonicalizeEmail(username)));
    227   for (size_t i = 0; i < arraysize(kNonManagedDomainPatterns); i++) {
    228     base::string16 pattern = base::WideToUTF16(kNonManagedDomainPatterns[i]);
    229     if (MatchDomain(domain, pattern, i))
    230       return true;
    231   }
    232   return false;
    233 }
    234 
    235 // static
    236 std::string BrowserPolicyConnector::GetDeviceManagementUrl() {
    237   CommandLine* command_line = CommandLine::ForCurrentProcess();
    238   if (command_line->HasSwitch(switches::kDeviceManagementUrl))
    239     return command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl);
    240   else
    241     return kDefaultDeviceManagementServerUrl;
    242 }
    243 
    244 // static
    245 void BrowserPolicyConnector::RegisterPrefs(PrefRegistrySimple* registry) {
    246   registry->RegisterIntegerPref(
    247       policy_prefs::kUserPolicyRefreshRate,
    248       CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
    249 }
    250 
    251 void BrowserPolicyConnector::AddPolicyProvider(
    252     scoped_ptr<ConfigurationPolicyProvider> provider) {
    253   policy_providers_.push_back(provider.release());
    254 }
    255 
    256 void BrowserPolicyConnector::SetPlatformPolicyProvider(
    257     scoped_ptr<ConfigurationPolicyProvider> provider) {
    258   CHECK(!platform_policy_provider_);
    259   platform_policy_provider_ = provider.get();
    260   AddPolicyProvider(provider.Pass());
    261 }
    262 
    263 }  // namespace policy
    264