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