browser_policy_connector.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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
32namespace policy {
33
34namespace {
35
36// The URL for the device management server.
37const char kDefaultDeviceManagementServerUrl[] =
38    "https://m.google.com/devicemanagement/data/api";
39
40// Used in BrowserPolicyConnector::SetPolicyProviderForTesting.
41bool g_created_policy_service = false;
42ConfigurationPolicyProvider* g_testing_provider = NULL;
43
44void 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).
52const 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|.
66bool 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
97BrowserPolicyConnector::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
114BrowserPolicyConnector::~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
124void 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
149void 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
162PolicyService* 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
179ConfigurationPolicyProvider* BrowserPolicyConnector::GetPlatformProvider() {
180  if (g_testing_provider)
181    return g_testing_provider;
182  return platform_policy_provider_;
183}
184
185const Schema& BrowserPolicyConnector::GetChromeSchema() const {
186  return chrome_schema_;
187}
188
189CombinedSchemaRegistry* BrowserPolicyConnector::GetSchemaRegistry() {
190  return &schema_registry_;
191}
192
193void 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
201const ConfigurationPolicyHandlerList*
202    BrowserPolicyConnector::GetHandlerList() const {
203  return handler_list_.get();
204}
205
206// static
207void 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
217bool 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
236std::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
245void BrowserPolicyConnector::RegisterPrefs(PrefRegistrySimple* registry) {
246  registry->RegisterIntegerPref(
247      policy_prefs::kUserPolicyRefreshRate,
248      CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
249}
250
251void BrowserPolicyConnector::AddPolicyProvider(
252    scoped_ptr<ConfigurationPolicyProvider> provider) {
253  policy_providers_.push_back(provider.release());
254}
255
256void 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