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.
5 #include "components/policy/core/browser/browser_policy_connector.h"
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"
36 // The URL for the device management server.
37 const char kDefaultDeviceManagementServerUrl
[] =
38 "https://m.google.com/devicemanagement/data/api";
40 // Used in BrowserPolicyConnector::SetPolicyProviderForTesting.
41 bool g_created_policy_service
= false;
42 ConfigurationPolicyProvider
* g_testing_provider
= NULL
;
44 void ReportRegexSuccessMetric(bool success
) {
45 UMA_HISTOGRAM_BOOLEAN("Enterprise.DomainWhitelistRegexSuccess", success
);
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
52 const wchar_t* const kNonManagedDomainPatterns
[] = {
56 L
"hotmail(\\.co|\\.com|)\\.[^.]+", // hotmail.com, hotmail.it, hotmail.co.uk
61 L
"yahoo(\\.co|\\.com|)\\.[^.]+", // yahoo.com, yahoo.co.uk, yahoo.com.tw
65 // Returns true if |domain| matches the regex |pattern|.
66 bool MatchDomain(const base::string16
& domain
, const base::string16
& pattern
,
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",
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.
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().
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
, ""),
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.
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());
130 device_management_service_
= device_management_service
.Pass();
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());
137 policy_statistics_collector_
.reset(
138 new policy::PolicyStatisticsCollector(
139 base::Bind(&GetChromePolicyDetails
),
143 base::MessageLoop::current()->message_loop_proxy()));
144 policy_statistics_collector_
->Initialize();
146 is_initialized_
= true;
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();
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
);
169 providers
.resize(policy_providers_
.size());
170 std::copy(policy_providers_
.begin(),
171 policy_providers_
.end(),
174 policy_service_
.reset(new PolicyServiceImpl(providers
));
176 return policy_service_
.get();
179 ConfigurationPolicyProvider
* BrowserPolicyConnector::GetPlatformProvider() {
180 if (g_testing_provider
)
181 return g_testing_provider
;
182 return platform_policy_provider_
;
185 const Schema
& BrowserPolicyConnector::GetChromeSchema() const {
186 return chrome_schema_
;
189 CombinedSchemaRegistry
* BrowserPolicyConnector::GetSchemaRegistry() {
190 return &schema_registry_
;
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
);
201 const ConfigurationPolicyHandlerList
*
202 BrowserPolicyConnector::GetHandlerList() const {
203 return handler_list_
.get();
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
;
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
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
))
236 std::string
BrowserPolicyConnector::GetDeviceManagementUrl() {
237 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
238 if (command_line
->HasSwitch(switches::kDeviceManagementUrl
))
239 return command_line
->GetSwitchValueASCII(switches::kDeviceManagementUrl
);
241 return kDefaultDeviceManagementServerUrl
;
245 void BrowserPolicyConnector::RegisterPrefs(PrefRegistrySimple
* registry
) {
246 registry
->RegisterIntegerPref(
247 policy_prefs::kUserPolicyRefreshRate
,
248 CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs
);
251 void BrowserPolicyConnector::AddPolicyProvider(
252 scoped_ptr
<ConfigurationPolicyProvider
> provider
) {
253 policy_providers_
.push_back(provider
.release());
256 void BrowserPolicyConnector::SetPlatformPolicyProvider(
257 scoped_ptr
<ConfigurationPolicyProvider
> provider
) {
258 CHECK(!platform_policy_provider_
);
259 platform_policy_provider_
= provider
.get();
260 AddPolicyProvider(provider
.Pass());
263 } // namespace policy