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