user_cloud_policy_manager_chromeos.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
1303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König// Use of this source code is governed by a BSD-style license that can be
3303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König// found in the LICENSE file.
4303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
5303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
6303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
7303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "base/bind.h"
8303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "base/bind_helpers.h"
9303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "base/logging.h"
10303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "base/metrics/histogram.h"
11303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "base/metrics/sparse_histogram.h"
12303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "base/sequenced_task_runner.h"
13303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "base/values.h"
14303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/browser/browser_process.h"
15303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h"
16303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
17303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/browser/chromeos/policy/wildcard_login_checker.h"
18303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/browser/chromeos/profiles/profile_helper.h"
19303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/browser/lifetime/application_lifetime.h"
20303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "chrome/common/chrome_content_client.h"
21303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "components/policy/core/common/cloud/cloud_external_data_manager.h"
22303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
23303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "components/policy/core/common/cloud/device_management_service.h"
24303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "components/policy/core/common/cloud/system_policy_request_context.h"
25303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "components/policy/core/common/policy_map.h"
26303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "components/policy/core/common/policy_pref_names.h"
27303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "components/policy/core/common/policy_types.h"
28303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "net/url_request/url_request_context_getter.h"
29303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "policy/policy_constants.h"
30303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König#include "url/gurl.h"
31303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
32303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Könignamespace em = enterprise_management;
33303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
34303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Könignamespace policy {
35303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
36303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Könignamespace {
37303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
38303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König// UMA histogram names.
39303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMADelayInitialization[] =
40303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.DelayInitialization";
41303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMAInitialFetchClientError[] =
42303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.InitialFetch.ClientError";
43303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMAInitialFetchDelayClientRegister[] =
44303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.InitialFetch.DelayClientRegister";
45303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMAInitialFetchDelayOAuth2Token[] =
46303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.InitialFetch.DelayOAuth2Token";
47303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMAInitialFetchDelayPolicyFetch[] =
48303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.InitialFetch.DelayPolicyFetch";
49303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMAInitialFetchDelayTotal[] =
50303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.InitialFetch.DelayTotal";
51303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMAInitialFetchOAuth2Error[] =
52303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.InitialFetch.OAuth2Error";
53303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königconst char kUMAInitialFetchOAuth2NetworkError[] =
54303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    "Enterprise.UserPolicyChromeOS.InitialFetch.OAuth2NetworkError";
55303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
56303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid OnWildcardCheckCompleted(const std::string& username,
57303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                              WildcardLoginChecker::Result result) {
58303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (result == WildcardLoginChecker::RESULT_BLOCKED) {
59303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    LOG(ERROR) << "Online wildcard login check failed, terminating session.";
60303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
61303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // TODO(mnissler): This only removes the user pod from the login screen, but
62303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // the cryptohome remains. This is because deleting the cryptohome for a
63303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // logged-in session is not possible. Fix this either by delaying the
64303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // cryptohome deletion operation or by getting rid of the in-session
65303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // wildcard check.
66303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    chromeos::UserManager::Get()->RemoveUserFromList(username);
67303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    chrome::AttemptUserExit();
68303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
69303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
70303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
71303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}  // namespace
72303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
73303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian KönigUserCloudPolicyManagerChromeOS::UserCloudPolicyManagerChromeOS(
74303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    scoped_ptr<CloudPolicyStore> store,
75303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    scoped_ptr<CloudExternalDataManager> external_data_manager,
76303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    const base::FilePath& component_policy_cache_path,
77303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    bool wait_for_policy_fetch,
78303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    base::TimeDelta initial_policy_fetch_timeout,
79303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
80303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    const scoped_refptr<base::SequencedTaskRunner>& file_task_runner,
81303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner)
82303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    : CloudPolicyManager(
83303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          PolicyNamespaceKey(dm_protocol::kChromeUserPolicyType, std::string()),
84303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          store.get(),
85303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          task_runner,
86303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          file_task_runner,
87303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          io_task_runner),
88303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      store_(store.Pass()),
89303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      external_data_manager_(external_data_manager.Pass()),
90303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      component_policy_cache_path_(component_policy_cache_path),
91303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      wait_for_policy_fetch_(wait_for_policy_fetch),
92303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      policy_fetch_timeout_(false, false) {
93303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  time_init_started_ = base::Time::Now();
94303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (wait_for_policy_fetch_) {
95303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    policy_fetch_timeout_.Start(
96303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König        FROM_HERE,
97303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König        initial_policy_fetch_timeout,
98303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König        base::Bind(&UserCloudPolicyManagerChromeOS::OnBlockingFetchTimeout,
99303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                   base::Unretained(this)));
100303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
101303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
102303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
103303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian KönigUserCloudPolicyManagerChromeOS::~UserCloudPolicyManagerChromeOS() {}
104303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
105303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::Connect(
106303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    PrefService* local_state,
107303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    DeviceManagementService* device_management_service,
108303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    scoped_refptr<net::URLRequestContextGetter> system_request_context,
109303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    UserAffiliation user_affiliation) {
110303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  DCHECK(device_management_service);
111303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  DCHECK(local_state);
112303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  local_state_ = local_state;
113303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  scoped_refptr<net::URLRequestContextGetter> request_context;
114303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (system_request_context) {
115303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // |system_request_context| can be null for tests.
116303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // Use the system request context here instead of a context derived
117303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // from the Profile because Connect() is called before the profile is
118303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // fully initialized (required so we can perform the initial policy load).
119303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // TODO(atwilson): Change this to use a UserPolicyRequestContext once
120303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // Connect() is called after profile initialization. http://crbug.com/323591
121303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    request_context = new SystemPolicyRequestContext(
122303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König        system_request_context, GetUserAgent());
123303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
124303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  scoped_ptr<CloudPolicyClient> cloud_policy_client(
125303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      new CloudPolicyClient(std::string(), std::string(),
126303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                            kPolicyVerificationKeyHash, user_affiliation,
127303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                            NULL, device_management_service,
128303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                            request_context));
129303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  core()->Connect(cloud_policy_client.Pass());
130303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  client()->AddObserver(this);
131303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
132303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  external_data_manager_->Connect(request_context);
133303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
134303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  CreateComponentCloudPolicyService(component_policy_cache_path_,
135303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                                    request_context);
136303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
137303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // Determine the next step after the CloudPolicyService initializes.
138303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (service()->IsInitializationComplete()) {
139303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    OnInitializationCompleted(service());
140303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  } else {
141303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    service()->AddObserver(this);
142303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
143303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
144303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
145303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::OnAccessTokenAvailable(
146303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    const std::string& access_token) {
147303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  access_token_ = access_token;
148303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
149303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (!wildcard_username_.empty()) {
150303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    wildcard_login_checker_.reset(new WildcardLoginChecker());
151303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    wildcard_login_checker_->StartWithAccessToken(
152303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König        access_token,
153303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König        base::Bind(&OnWildcardCheckCompleted, wildcard_username_));
154303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
155303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
156303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (service() && service()->IsInitializationComplete() &&
157303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      client() && !client()->is_registered()) {
158303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    OnOAuth2PolicyTokenFetched(
159303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König        access_token, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
160303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
161303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
162303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
163303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königbool UserCloudPolicyManagerChromeOS::IsClientRegistered() const {
164303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  return client() && client()->is_registered();
165303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
166303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
167303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::EnableWildcardLoginCheck(
168303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    const std::string& username) {
169303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  DCHECK(access_token_.empty());
170303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  wildcard_username_ = username;
171303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
172303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
173303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::Shutdown() {
174303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (client())
175303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    client()->RemoveObserver(this);
176303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (service())
177303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    service()->RemoveObserver(this);
178303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  token_fetcher_.reset();
179303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  external_data_manager_->Disconnect();
180303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  CloudPolicyManager::Shutdown();
181303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
182303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
183303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königbool UserCloudPolicyManagerChromeOS::IsInitializationComplete(
184303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    PolicyDomain domain) const {
185303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (!CloudPolicyManager::IsInitializationComplete(domain))
186303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    return false;
187303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (domain == POLICY_DOMAIN_CHROME)
188303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    return !wait_for_policy_fetch_;
189303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  return true;
190303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
191303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
192303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::OnInitializationCompleted(
193303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    CloudPolicyService* cloud_policy_service) {
194303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  DCHECK_EQ(service(), cloud_policy_service);
195303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  cloud_policy_service->RemoveObserver(this);
196303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
197303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  time_init_completed_ = base::Time::Now();
198303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  UMA_HISTOGRAM_MEDIUM_TIMES(kUMADelayInitialization,
199303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                             time_init_completed_ - time_init_started_);
200303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
201303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // If the CloudPolicyClient isn't registered at this stage then it needs an
202303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // OAuth token for the initial registration.
203303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  //
204303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // If |wait_for_policy_fetch_| is true then Profile initialization is blocking
205303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // on the initial policy fetch, so the token must be fetched immediately.
206303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // In that case, the signin Profile is used to authenticate a Gaia request to
207303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // fetch a refresh token, and then the policy token is fetched.
208303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  //
209303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // If |wait_for_policy_fetch_| is false then the UserCloudPolicyTokenForwarder
210303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // service will eventually call OnAccessTokenAvailable() once an access token
211303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // is available. That call may have already happened while waiting for
212303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // initialization of the CloudPolicyService, so in that case check if an
213303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // access token is already available.
214303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (!client()->is_registered()) {
215303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    if (wait_for_policy_fetch_) {
216303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      FetchPolicyOAuthTokenUsingSigninProfile();
217303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    } else if (!access_token_.empty()) {
218303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      OnAccessTokenAvailable(access_token_);
219303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    }
220303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
221303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
222303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (!wait_for_policy_fetch_) {
223303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // If this isn't blocking on a policy fetch then
224303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // CloudPolicyManager::OnStoreLoaded() already published the cached policy.
225303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // Start the refresh scheduler now, which will eventually refresh the
226303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // cached policy or make the first fetch once the OAuth2 token is
227303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // available.
228303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    StartRefreshSchedulerIfReady();
229303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
230303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
231303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
232303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::OnPolicyFetched(
233303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    CloudPolicyClient* client) {
234303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // No action required. If we're blocked on a policy fetch, we'll learn about
235303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  // completion of it through OnInitialPolicyFetchComplete().
236303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
237303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
238303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::OnRegistrationStateChanged(
239303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    CloudPolicyClient* cloud_policy_client) {
240303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  DCHECK_EQ(client(), cloud_policy_client);
241303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
242303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (wait_for_policy_fetch_) {
243303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    time_client_registered_ = base::Time::Now();
244303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    if (!time_token_available_.is_null()) {
245303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      UMA_HISTOGRAM_MEDIUM_TIMES(
246303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          kUMAInitialFetchDelayClientRegister,
247303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          time_client_registered_ - time_token_available_);
248303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    }
249303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
250303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    // If we're blocked on the policy fetch, now is a good time to issue it.
251303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    if (client()->is_registered()) {
252303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      service()->RefreshPolicy(
253303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König          base::Bind(
254303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König              &UserCloudPolicyManagerChromeOS::OnInitialPolicyFetchComplete,
255303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König              base::Unretained(this)));
256303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    } else {
257303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      // If the client has switched to not registered, we bail out as this
258303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      // indicates the cloud policy setup flow has been aborted.
259303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König      CancelWaitForPolicyFetch();
260303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    }
261303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
262303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König}
263303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König
264303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian Königvoid UserCloudPolicyManagerChromeOS::OnClientError(
265303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    CloudPolicyClient* cloud_policy_client) {
266303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  DCHECK_EQ(client(), cloud_policy_client);
267303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  if (wait_for_policy_fetch_) {
268303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König    UMA_HISTOGRAM_SPARSE_SLOWLY(kUMAInitialFetchClientError,
269303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König                                cloud_policy_client->status());
270303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  }
271303f4b7dcddee384d6f1dc1027cbdee840a38d7dChristian König  CancelWaitForPolicyFetch();
272}
273
274void UserCloudPolicyManagerChromeOS::OnComponentCloudPolicyUpdated() {
275  CloudPolicyManager::OnComponentCloudPolicyUpdated();
276  StartRefreshSchedulerIfReady();
277}
278
279void UserCloudPolicyManagerChromeOS::GetChromePolicy(PolicyMap* policy_map) {
280  CloudPolicyManager::GetChromePolicy(policy_map);
281
282  // Default multi-profile behavior for managed accounts to primary-only.
283  if (store()->has_policy() &&
284      !policy_map->Get(key::kChromeOsMultiProfileUserBehavior)) {
285    policy_map->Set(key::kChromeOsMultiProfileUserBehavior,
286                    POLICY_LEVEL_MANDATORY,
287                    POLICY_SCOPE_USER,
288                    new base::StringValue("primary-only"),
289                    NULL);
290  }
291}
292
293void UserCloudPolicyManagerChromeOS::FetchPolicyOAuthTokenUsingSigninProfile() {
294  scoped_refptr<net::URLRequestContextGetter> signin_context;
295  Profile* signin_profile = chromeos::ProfileHelper::GetSigninProfile();
296  if (signin_profile)
297    signin_context = signin_profile->GetRequestContext();
298  if (!signin_context.get()) {
299    LOG(ERROR) << "No signin Profile for policy oauth token fetch!";
300    OnOAuth2PolicyTokenFetched(
301        std::string(), GoogleServiceAuthError(GoogleServiceAuthError::NONE));
302    return;
303  }
304
305  token_fetcher_.reset(new PolicyOAuth2TokenFetcher(
306      signin_context.get(),
307      g_browser_process->system_request_context(),
308      base::Bind(&UserCloudPolicyManagerChromeOS::OnOAuth2PolicyTokenFetched,
309                 base::Unretained(this))));
310  token_fetcher_->Start();
311}
312
313void UserCloudPolicyManagerChromeOS::OnOAuth2PolicyTokenFetched(
314    const std::string& policy_token,
315    const GoogleServiceAuthError& error) {
316  DCHECK(!client()->is_registered());
317  time_token_available_ = base::Time::Now();
318  if (wait_for_policy_fetch_) {
319    UMA_HISTOGRAM_MEDIUM_TIMES(kUMAInitialFetchDelayOAuth2Token,
320                               time_token_available_ - time_init_completed_);
321  }
322
323  if (error.state() == GoogleServiceAuthError::NONE) {
324    // Start client registration. Either OnRegistrationStateChanged() or
325    // OnClientError() will be called back.
326    client()->Register(em::DeviceRegisterRequest::USER, policy_token,
327                       std::string(), false, std::string(), std::string());
328  } else {
329    // Failed to get a token, stop waiting and use an empty policy.
330    CancelWaitForPolicyFetch();
331
332    UMA_HISTOGRAM_ENUMERATION(kUMAInitialFetchOAuth2Error,
333                              error.state(),
334                              GoogleServiceAuthError::NUM_STATES);
335    if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
336      UMA_HISTOGRAM_SPARSE_SLOWLY(kUMAInitialFetchOAuth2NetworkError,
337                                  error.network_error());
338    }
339  }
340
341  token_fetcher_.reset();
342}
343
344void UserCloudPolicyManagerChromeOS::OnInitialPolicyFetchComplete(
345    bool success) {
346  const base::Time now = base::Time::Now();
347  UMA_HISTOGRAM_MEDIUM_TIMES(kUMAInitialFetchDelayPolicyFetch,
348                             now - time_client_registered_);
349  UMA_HISTOGRAM_MEDIUM_TIMES(kUMAInitialFetchDelayTotal,
350                             now - time_init_started_);
351  CancelWaitForPolicyFetch();
352}
353
354void UserCloudPolicyManagerChromeOS::OnBlockingFetchTimeout() {
355  if (!wait_for_policy_fetch_)
356    return;
357  LOG(WARNING) << "Timed out while waiting for the initial policy fetch. "
358               << "The first session will start without policy.";
359  CancelWaitForPolicyFetch();
360}
361
362void UserCloudPolicyManagerChromeOS::CancelWaitForPolicyFetch() {
363  if (!wait_for_policy_fetch_)
364    return;
365
366  wait_for_policy_fetch_ = false;
367  policy_fetch_timeout_.Stop();
368  CheckAndPublishPolicy();
369  // Now that |wait_for_policy_fetch_| is guaranteed to be false, the scheduler
370  // can be started.
371  StartRefreshSchedulerIfReady();
372}
373
374void UserCloudPolicyManagerChromeOS::StartRefreshSchedulerIfReady() {
375  if (core()->refresh_scheduler())
376    return;  // Already started.
377
378  if (wait_for_policy_fetch_)
379    return;  // Still waiting for the initial, blocking fetch.
380
381  if (!service() || !local_state_)
382    return;  // Not connected.
383
384  if (component_policy_service() &&
385      !component_policy_service()->is_initialized()) {
386    // If the client doesn't have the list of components to fetch yet then don't
387    // start the scheduler. The |component_policy_service_| will call back into
388    // OnComponentCloudPolicyUpdated() once it's ready.
389    return;
390  }
391
392  core()->StartRefreshScheduler();
393  core()->TrackRefreshDelayPref(local_state_,
394                                policy_prefs::kUserPolicyRefreshRate);
395}
396
397}  // namespace policy
398