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