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