1 // Copyright (c) 2012 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 "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/logging.h" 10 #include "base/metrics/histogram.h" 11 #include "base/metrics/sparse_histogram.h" 12 #include "base/sequenced_task_runner.h" 13 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h" 15 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h" 16 #include "chrome/browser/chromeos/policy/wildcard_login_checker.h" 17 #include "chrome/browser/chromeos/profiles/profile_helper.h" 18 #include "chrome/browser/lifetime/application_lifetime.h" 19 #include "components/policy/core/common/cloud/cloud_external_data_manager.h" 20 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h" 21 #include "components/policy/core/common/cloud/device_management_service.h" 22 #include "components/policy/core/common/cloud/system_policy_request_context.h" 23 #include "components/policy/core/common/policy_pref_names.h" 24 #include "content/public/common/content_client.h" 25 #include "net/url_request/url_request_context_getter.h" 26 #include "url/gurl.h" 27 28 namespace em = enterprise_management; 29 30 namespace policy { 31 32 namespace { 33 34 // UMA histogram names. 35 const char kUMADelayInitialization[] = 36 "Enterprise.UserPolicyChromeOS.DelayInitialization"; 37 const char kUMAInitialFetchClientError[] = 38 "Enterprise.UserPolicyChromeOS.InitialFetch.ClientError"; 39 const char kUMAInitialFetchDelayClientRegister[] = 40 "Enterprise.UserPolicyChromeOS.InitialFetch.DelayClientRegister"; 41 const char kUMAInitialFetchDelayOAuth2Token[] = 42 "Enterprise.UserPolicyChromeOS.InitialFetch.DelayOAuth2Token"; 43 const char kUMAInitialFetchDelayPolicyFetch[] = 44 "Enterprise.UserPolicyChromeOS.InitialFetch.DelayPolicyFetch"; 45 const char kUMAInitialFetchDelayTotal[] = 46 "Enterprise.UserPolicyChromeOS.InitialFetch.DelayTotal"; 47 const char kUMAInitialFetchOAuth2Error[] = 48 "Enterprise.UserPolicyChromeOS.InitialFetch.OAuth2Error"; 49 const char kUMAInitialFetchOAuth2NetworkError[] = 50 "Enterprise.UserPolicyChromeOS.InitialFetch.OAuth2NetworkError"; 51 52 void OnWildcardCheckCompleted(const std::string& username, bool result) { 53 if (!result) { 54 LOG(ERROR) << "Online wildcard login check failed, terminating session."; 55 56 // TODO(mnissler): This only removes the user pod from the login screen, but 57 // the cryptohome remains. This is because deleting the cryptohome for a 58 // logged-in session is not possible. Fix this either by delaying the 59 // cryptohome deletion operation or by getting rid of the in-session 60 // wildcard check. 61 chromeos::UserManager::Get()->RemoveUserFromList(username); 62 chrome::AttemptUserExit(); 63 } 64 } 65 66 } // namespace 67 68 UserCloudPolicyManagerChromeOS::UserCloudPolicyManagerChromeOS( 69 scoped_ptr<CloudPolicyStore> store, 70 scoped_ptr<CloudExternalDataManager> external_data_manager, 71 const base::FilePath& component_policy_cache_path, 72 bool wait_for_policy_fetch, 73 base::TimeDelta initial_policy_fetch_timeout, 74 const scoped_refptr<base::SequencedTaskRunner>& task_runner, 75 const scoped_refptr<base::SequencedTaskRunner>& file_task_runner, 76 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) 77 : CloudPolicyManager( 78 PolicyNamespaceKey(dm_protocol::kChromeUserPolicyType, std::string()), 79 store.get(), 80 task_runner, 81 file_task_runner, 82 io_task_runner), 83 store_(store.Pass()), 84 external_data_manager_(external_data_manager.Pass()), 85 component_policy_cache_path_(component_policy_cache_path), 86 wait_for_policy_fetch_(wait_for_policy_fetch), 87 policy_fetch_timeout_(false, false) { 88 time_init_started_ = base::Time::Now(); 89 if (wait_for_policy_fetch_) { 90 policy_fetch_timeout_.Start( 91 FROM_HERE, 92 initial_policy_fetch_timeout, 93 base::Bind(&UserCloudPolicyManagerChromeOS::CancelWaitForPolicyFetch, 94 base::Unretained(this))); 95 } 96 } 97 98 UserCloudPolicyManagerChromeOS::~UserCloudPolicyManagerChromeOS() {} 99 100 void UserCloudPolicyManagerChromeOS::Connect( 101 PrefService* local_state, 102 DeviceManagementService* device_management_service, 103 scoped_refptr<net::URLRequestContextGetter> system_request_context, 104 UserAffiliation user_affiliation) { 105 DCHECK(device_management_service); 106 DCHECK(local_state); 107 local_state_ = local_state; 108 scoped_refptr<net::URLRequestContextGetter> request_context; 109 if (system_request_context) { 110 // |system_request_context| can be null for tests. 111 // Use the system request context here instead of a context derived 112 // from the Profile because Connect() is called before the profile is 113 // fully initialized (required so we can perform the initial policy load). 114 // TODO(atwilson): Change this to use a UserPolicyRequestContext once 115 // Connect() is called after profile initialization. http://crbug.com/323591 116 request_context = new SystemPolicyRequestContext( 117 system_request_context, 118 content::GetUserAgent(GURL( 119 device_management_service->GetServerUrl()))); 120 } 121 scoped_ptr<CloudPolicyClient> cloud_policy_client( 122 new CloudPolicyClient(std::string(), std::string(), user_affiliation, 123 NULL, device_management_service, 124 request_context)); 125 core()->Connect(cloud_policy_client.Pass()); 126 client()->AddObserver(this); 127 128 external_data_manager_->Connect(request_context); 129 130 CreateComponentCloudPolicyService(component_policy_cache_path_, 131 request_context); 132 133 // Determine the next step after the CloudPolicyService initializes. 134 if (service()->IsInitializationComplete()) { 135 OnInitializationCompleted(service()); 136 } else { 137 service()->AddObserver(this); 138 } 139 } 140 141 void UserCloudPolicyManagerChromeOS::OnAccessTokenAvailable( 142 const std::string& access_token) { 143 access_token_ = access_token; 144 145 if (!wildcard_username_.empty()) { 146 wildcard_login_checker_.reset(new WildcardLoginChecker()); 147 wildcard_login_checker_->StartWithAccessToken( 148 access_token, 149 base::Bind(&OnWildcardCheckCompleted, wildcard_username_)); 150 } 151 152 if (service() && service()->IsInitializationComplete() && 153 client() && !client()->is_registered()) { 154 OnOAuth2PolicyTokenFetched( 155 access_token, GoogleServiceAuthError(GoogleServiceAuthError::NONE)); 156 } 157 } 158 159 bool UserCloudPolicyManagerChromeOS::IsClientRegistered() const { 160 return client() && client()->is_registered(); 161 } 162 163 void UserCloudPolicyManagerChromeOS::EnableWildcardLoginCheck( 164 const std::string& username) { 165 DCHECK(access_token_.empty()); 166 wildcard_username_ = username; 167 } 168 169 void UserCloudPolicyManagerChromeOS::Shutdown() { 170 if (client()) 171 client()->RemoveObserver(this); 172 if (service()) 173 service()->RemoveObserver(this); 174 token_fetcher_.reset(); 175 external_data_manager_->Disconnect(); 176 CloudPolicyManager::Shutdown(); 177 } 178 179 bool UserCloudPolicyManagerChromeOS::IsInitializationComplete( 180 PolicyDomain domain) const { 181 if (!CloudPolicyManager::IsInitializationComplete(domain)) 182 return false; 183 if (domain == POLICY_DOMAIN_CHROME) 184 return !wait_for_policy_fetch_; 185 return true; 186 } 187 188 void UserCloudPolicyManagerChromeOS::OnInitializationCompleted( 189 CloudPolicyService* cloud_policy_service) { 190 DCHECK_EQ(service(), cloud_policy_service); 191 cloud_policy_service->RemoveObserver(this); 192 193 time_init_completed_ = base::Time::Now(); 194 UMA_HISTOGRAM_TIMES(kUMADelayInitialization, 195 time_init_completed_ - time_init_started_); 196 197 // If the CloudPolicyClient isn't registered at this stage then it needs an 198 // OAuth token for the initial registration. 199 // 200 // If |wait_for_policy_fetch_| is true then Profile initialization is blocking 201 // on the initial policy fetch, so the token must be fetched immediately. 202 // In that case, the signin Profile is used to authenticate a Gaia request to 203 // fetch a refresh token, and then the policy token is fetched. 204 // 205 // If |wait_for_policy_fetch_| is false then the UserCloudPolicyTokenForwarder 206 // service will eventually call OnAccessTokenAvailable() once an access token 207 // is available. That call may have already happened while waiting for 208 // initialization of the CloudPolicyService, so in that case check if an 209 // access token is already available. 210 if (!client()->is_registered()) { 211 if (wait_for_policy_fetch_) { 212 FetchPolicyOAuthTokenUsingSigninProfile(); 213 } else if (!access_token_.empty()) { 214 OnAccessTokenAvailable(access_token_); 215 } 216 } 217 218 if (!wait_for_policy_fetch_) { 219 // If this isn't blocking on a policy fetch then 220 // CloudPolicyManager::OnStoreLoaded() already published the cached policy. 221 // Start the refresh scheduler now, which will eventually refresh the 222 // cached policy or make the first fetch once the OAuth2 token is 223 // available. 224 StartRefreshSchedulerIfReady(); 225 } 226 } 227 228 void UserCloudPolicyManagerChromeOS::OnPolicyFetched( 229 CloudPolicyClient* client) { 230 // No action required. If we're blocked on a policy fetch, we'll learn about 231 // completion of it through OnInitialPolicyFetchComplete(). 232 } 233 234 void UserCloudPolicyManagerChromeOS::OnRegistrationStateChanged( 235 CloudPolicyClient* cloud_policy_client) { 236 DCHECK_EQ(client(), cloud_policy_client); 237 238 if (wait_for_policy_fetch_) { 239 time_client_registered_ = base::Time::Now(); 240 if (!time_token_available_.is_null()) { 241 UMA_HISTOGRAM_TIMES(kUMAInitialFetchDelayClientRegister, 242 time_client_registered_ - time_token_available_); 243 } 244 245 // If we're blocked on the policy fetch, now is a good time to issue it. 246 if (client()->is_registered()) { 247 service()->RefreshPolicy( 248 base::Bind( 249 &UserCloudPolicyManagerChromeOS::OnInitialPolicyFetchComplete, 250 base::Unretained(this))); 251 } else { 252 // If the client has switched to not registered, we bail out as this 253 // indicates the cloud policy setup flow has been aborted. 254 CancelWaitForPolicyFetch(); 255 } 256 } 257 } 258 259 void UserCloudPolicyManagerChromeOS::OnClientError( 260 CloudPolicyClient* cloud_policy_client) { 261 DCHECK_EQ(client(), cloud_policy_client); 262 if (wait_for_policy_fetch_) { 263 UMA_HISTOGRAM_SPARSE_SLOWLY(kUMAInitialFetchClientError, 264 cloud_policy_client->status()); 265 } 266 CancelWaitForPolicyFetch(); 267 } 268 269 void UserCloudPolicyManagerChromeOS::OnComponentCloudPolicyUpdated() { 270 CloudPolicyManager::OnComponentCloudPolicyUpdated(); 271 StartRefreshSchedulerIfReady(); 272 } 273 274 void UserCloudPolicyManagerChromeOS::FetchPolicyOAuthTokenUsingSigninProfile() { 275 scoped_refptr<net::URLRequestContextGetter> signin_context; 276 Profile* signin_profile = chromeos::ProfileHelper::GetSigninProfile(); 277 if (signin_profile) 278 signin_context = signin_profile->GetRequestContext(); 279 if (!signin_context.get()) { 280 LOG(ERROR) << "No signin Profile for policy oauth token fetch!"; 281 OnOAuth2PolicyTokenFetched( 282 std::string(), GoogleServiceAuthError(GoogleServiceAuthError::NONE)); 283 return; 284 } 285 286 token_fetcher_.reset(new PolicyOAuth2TokenFetcher( 287 signin_context.get(), 288 g_browser_process->system_request_context(), 289 base::Bind(&UserCloudPolicyManagerChromeOS::OnOAuth2PolicyTokenFetched, 290 base::Unretained(this)))); 291 token_fetcher_->Start(); 292 } 293 294 void UserCloudPolicyManagerChromeOS::OnOAuth2PolicyTokenFetched( 295 const std::string& policy_token, 296 const GoogleServiceAuthError& error) { 297 DCHECK(!client()->is_registered()); 298 time_token_available_ = base::Time::Now(); 299 if (wait_for_policy_fetch_) { 300 UMA_HISTOGRAM_TIMES(kUMAInitialFetchDelayOAuth2Token, 301 time_token_available_ - time_init_completed_); 302 } 303 304 if (error.state() == GoogleServiceAuthError::NONE) { 305 // Start client registration. Either OnRegistrationStateChanged() or 306 // OnClientError() will be called back. 307 client()->Register(em::DeviceRegisterRequest::USER, 308 policy_token, std::string(), false, std::string()); 309 } else { 310 // Failed to get a token, stop waiting and use an empty policy. 311 CancelWaitForPolicyFetch(); 312 313 UMA_HISTOGRAM_ENUMERATION(kUMAInitialFetchOAuth2Error, 314 error.state(), 315 GoogleServiceAuthError::NUM_STATES); 316 if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) { 317 UMA_HISTOGRAM_SPARSE_SLOWLY(kUMAInitialFetchOAuth2NetworkError, 318 error.network_error()); 319 } 320 } 321 322 token_fetcher_.reset(); 323 } 324 325 void UserCloudPolicyManagerChromeOS::OnInitialPolicyFetchComplete( 326 bool success) { 327 const base::Time now = base::Time::Now(); 328 UMA_HISTOGRAM_TIMES(kUMAInitialFetchDelayPolicyFetch, 329 now - time_client_registered_); 330 UMA_HISTOGRAM_TIMES(kUMAInitialFetchDelayTotal, now - time_init_started_); 331 CancelWaitForPolicyFetch(); 332 } 333 334 void UserCloudPolicyManagerChromeOS::CancelWaitForPolicyFetch() { 335 if (!wait_for_policy_fetch_) 336 return; 337 338 wait_for_policy_fetch_ = false; 339 CheckAndPublishPolicy(); 340 // Now that |wait_for_policy_fetch_| is guaranteed to be false, the scheduler 341 // can be started. 342 StartRefreshSchedulerIfReady(); 343 } 344 345 void UserCloudPolicyManagerChromeOS::StartRefreshSchedulerIfReady() { 346 if (core()->refresh_scheduler()) 347 return; // Already started. 348 349 if (wait_for_policy_fetch_) 350 return; // Still waiting for the initial, blocking fetch. 351 352 if (!service() || !local_state_) 353 return; // Not connected. 354 355 if (component_policy_service() && 356 !component_policy_service()->is_initialized()) { 357 // If the client doesn't have the list of components to fetch yet then don't 358 // start the scheduler. The |component_policy_service_| will call back into 359 // OnComponentCloudPolicyUpdated() once it's ready. 360 return; 361 } 362 363 core()->StartRefreshScheduler(); 364 core()->TrackRefreshDelayPref(local_state_, 365 policy_prefs::kUserPolicyRefreshRate); 366 } 367 368 } // namespace policy 369