consumer_management_service.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2014 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/consumer_management_service.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/location.h"
10#include "base/logging.h"
11#include "base/message_loop/message_loop.h"
12#include "base/prefs/pref_registry_simple.h"
13#include "base/prefs/pref_service.h"
14#include "base/time/time.h"
15#include "chrome/browser/browser_process.h"
16#include "chrome/browser/browser_process_platform_part.h"
17#include "chrome/browser/chrome_notification_types.h"
18#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
19#include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
20#include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
21#include "chrome/browser/chromeos/profiles/profile_helper.h"
22#include "chrome/browser/profiles/profile.h"
23#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
24#include "chrome/browser/signin/signin_manager_factory.h"
25#include "chrome/common/pref_names.h"
26#include "chromeos/dbus/cryptohome/rpc.pb.h"
27#include "chromeos/dbus/cryptohome_client.h"
28#include "components/policy/core/common/cloud/cloud_policy_constants.h"
29#include "components/signin/core/browser/profile_oauth2_token_service.h"
30#include "components/signin/core/browser/signin_manager_base.h"
31#include "components/user_manager/user_manager.h"
32#include "content/public/browser/notification_details.h"
33#include "content/public/browser/notification_service.h"
34#include "content/public/browser/notification_source.h"
35#include "google_apis/gaia/gaia_constants.h"
36#include "google_apis/gaia/google_service_auth_error.h"
37#include "policy/proto/device_management_backend.pb.h"
38
39namespace {
40
41const char* kAttributeOwnerId = "consumer_management.owner_id";
42
43}  // namespace
44
45namespace policy {
46
47ConsumerManagementService::ConsumerManagementService(
48    chromeos::CryptohomeClient* client)
49    : Consumer("consumer_management_service"),
50      client_(client),
51      enrolling_token_service_(NULL),
52      weak_ptr_factory_(this) {
53  registrar_.Add(this,
54                 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
55                 content::NotificationService::AllSources());
56}
57
58ConsumerManagementService::~ConsumerManagementService() {
59  registrar_.Remove(this,
60                    chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
61                    content::NotificationService::AllSources());
62  if (enrolling_token_service_)
63    enrolling_token_service_->RemoveObserver(this);
64}
65
66// static
67void ConsumerManagementService::RegisterPrefs(PrefRegistrySimple* registry) {
68  registry->RegisterIntegerPref(
69      prefs::kConsumerManagementEnrollmentState, ENROLLMENT_NONE);
70}
71
72ConsumerManagementService::ConsumerEnrollmentState
73ConsumerManagementService::GetEnrollmentState() const {
74  const PrefService* prefs = g_browser_process->local_state();
75  int state = prefs->GetInteger(prefs::kConsumerManagementEnrollmentState);
76  if (state < 0 || state >= ENROLLMENT_LAST) {
77    LOG(ERROR) << "Unknown enrollment state: " << state;
78    state = 0;
79  }
80  return static_cast<ConsumerEnrollmentState>(state);
81}
82
83void ConsumerManagementService::SetEnrollmentState(
84    ConsumerEnrollmentState state) {
85  PrefService* prefs = g_browser_process->local_state();
86  prefs->SetInteger(prefs::kConsumerManagementEnrollmentState, state);
87}
88
89void ConsumerManagementService::GetOwner(const GetOwnerCallback& callback) {
90  cryptohome::GetBootAttributeRequest request;
91  request.set_name(kAttributeOwnerId);
92  client_->GetBootAttribute(
93      request,
94      base::Bind(&ConsumerManagementService::OnGetBootAttributeDone,
95                 weak_ptr_factory_.GetWeakPtr(),
96                 callback));
97}
98
99void ConsumerManagementService::OnGetBootAttributeDone(
100    const GetOwnerCallback& callback,
101    chromeos::DBusMethodCallStatus call_status,
102    bool dbus_success,
103    const cryptohome::BaseReply& reply) {
104  if (!dbus_success || reply.error() != 0) {
105    LOG(ERROR) << "Failed to get the owner info from boot lockbox.";
106    callback.Run("");
107    return;
108  }
109
110  callback.Run(
111      reply.GetExtension(cryptohome::GetBootAttributeReply::reply).value());
112}
113
114void ConsumerManagementService::SetOwner(const std::string& user_id,
115                                         const SetOwnerCallback& callback) {
116  cryptohome::SetBootAttributeRequest request;
117  request.set_name(kAttributeOwnerId);
118  request.set_value(user_id.data(), user_id.size());
119  client_->SetBootAttribute(
120      request,
121      base::Bind(&ConsumerManagementService::OnSetBootAttributeDone,
122                 weak_ptr_factory_.GetWeakPtr(),
123                 callback));
124}
125
126void ConsumerManagementService::OnSetBootAttributeDone(
127    const SetOwnerCallback& callback,
128    chromeos::DBusMethodCallStatus call_status,
129    bool dbus_success,
130    const cryptohome::BaseReply& reply) {
131  if (!dbus_success || reply.error() != 0) {
132    LOG(ERROR) << "Failed to set owner info in boot lockbox.";
133    callback.Run(false);
134    return;
135  }
136
137  cryptohome::FlushAndSignBootAttributesRequest request;
138  client_->FlushAndSignBootAttributes(
139      request,
140      base::Bind(&ConsumerManagementService::OnFlushAndSignBootAttributesDone,
141                 weak_ptr_factory_.GetWeakPtr(),
142                 callback));
143}
144
145void ConsumerManagementService::OnFlushAndSignBootAttributesDone(
146    const SetOwnerCallback& callback,
147    chromeos::DBusMethodCallStatus call_status,
148    bool dbus_success,
149    const cryptohome::BaseReply& reply) {
150  if (!dbus_success || reply.error() != 0) {
151    LOG(ERROR) << "Failed to flush and sign boot lockbox.";
152    callback.Run(false);
153    return;
154  }
155
156  callback.Run(true);
157}
158
159void ConsumerManagementService::Observe(
160    int type,
161    const content::NotificationSource& source,
162    const content::NotificationDetails& details) {
163  if (type != chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED) {
164    NOTREACHED() << "Unexpected notification " << type;
165    return;
166  }
167
168  Profile* profile = content::Details<Profile>(details).ptr();
169  if (chromeos::ProfileHelper::IsOwnerProfile(profile))
170    OnOwnerSignin(profile);
171}
172
173void ConsumerManagementService::OnRefreshTokenAvailable(
174    const std::string& account_id) {
175  if (account_id == enrolling_account_id_) {
176    enrolling_token_service_->RemoveObserver(this);
177    OnOwnerRefreshTokenAvailable();
178  }
179}
180
181void ConsumerManagementService::OnGetTokenSuccess(
182      const OAuth2TokenService::Request* request,
183      const std::string& access_token,
184      const base::Time& expiration_time) {
185  DCHECK_EQ(token_request_, request);
186  base::MessageLoop::current()->DeleteSoon(FROM_HERE, token_request_.release());
187
188  OnOwnerAccessTokenAvailable(access_token);
189}
190
191void ConsumerManagementService::OnGetTokenFailure(
192      const OAuth2TokenService::Request* request,
193      const GoogleServiceAuthError& error) {
194  DCHECK_EQ(token_request_, request);
195  base::MessageLoop::current()->DeleteSoon(FROM_HERE, token_request_.release());
196
197  LOG(ERROR) << "Failed to get the access token: " << error.ToString();
198  EndEnrollment(ENROLLMENT_GET_TOKEN_FAILED);
199}
200
201void ConsumerManagementService::OnOwnerSignin(Profile* profile) {
202  const ConsumerEnrollmentState state = GetEnrollmentState();
203  switch (state) {
204    case ENROLLMENT_NONE:
205      // Do nothing.
206      return;
207
208    case ENROLLMENT_OWNER_STORED:
209      // Continue the enrollment process after the owner signs in.
210      ContinueEnrollmentProcess(profile);
211      return;
212
213    case ENROLLMENT_SUCCESS:
214    case ENROLLMENT_CANCELED:
215    case ENROLLMENT_BOOT_LOCKBOX_FAILED:
216    case ENROLLMENT_DM_SERVER_FAILED:
217    case ENROLLMENT_GET_TOKEN_FAILED:
218      ShowDesktopNotificationAndResetState(state);
219      return;
220
221    case ENROLLMENT_REQUESTED:
222    case ENROLLMENT_LAST:
223      NOTREACHED() << "Unexpected enrollment state " << state;
224      return;
225  }
226}
227
228void ConsumerManagementService::ContinueEnrollmentProcess(Profile* profile) {
229  // First, we need to ensure that the refresh token is available.
230  SigninManagerBase* signin_manager =
231      SigninManagerFactory::GetForProfile(profile);
232  enrolling_account_id_ = signin_manager->GetAuthenticatedAccountId();
233
234  enrolling_token_service_ =
235      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
236  if (enrolling_token_service_->RefreshTokenIsAvailable(
237          enrolling_account_id_)) {
238    OnOwnerRefreshTokenAvailable();
239  } else {
240    enrolling_token_service_->AddObserver(this);
241  }
242}
243
244void ConsumerManagementService::OnOwnerRefreshTokenAvailable() {
245  CHECK(enrolling_token_service_);
246
247  // Now we can request the OAuth access token for device management to send the
248  // device registration request to the device management server.
249  OAuth2TokenService::ScopeSet oauth_scopes;
250  oauth_scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
251
252  token_request_ = enrolling_token_service_->StartRequest(
253      enrolling_account_id_, oauth_scopes, this);
254}
255
256void ConsumerManagementService::OnOwnerAccessTokenAvailable(
257    const std::string& access_token) {
258  // Now that we have the access token, we got everything we need to send the
259  // device registration request to the device management server.
260  BrowserPolicyConnectorChromeOS* connector =
261      g_browser_process->platform_part()->browser_policy_connector_chromeos();
262  DeviceCloudPolicyInitializer* initializer =
263      connector->GetDeviceCloudPolicyInitializer();
264  CHECK(initializer);
265
266  policy::DeviceCloudPolicyInitializer::AllowedDeviceModes device_modes;
267  device_modes[policy::DEVICE_MODE_ENTERPRISE] = true;
268
269  initializer->StartEnrollment(
270      enterprise_management::PolicyData::ENTERPRISE_MANAGED,
271      connector->GetDeviceManagementServiceForConsumer(),
272      access_token,
273      false,  // is_auto_enrollment
274      device_modes,
275      base::Bind(&ConsumerManagementService::OnEnrollmentCompleted,
276                 weak_ptr_factory_.GetWeakPtr()));
277}
278
279void ConsumerManagementService::OnEnrollmentCompleted(EnrollmentStatus status) {
280  if (status.status() != EnrollmentStatus::STATUS_SUCCESS) {
281    LOG(ERROR) << "Failed to enroll the device."
282               << " status=" << status.status()
283               << " client_status=" << status.client_status()
284               << " http_status=" << status.http_status()
285               << " store_status=" << status.store_status()
286               << " validation_status=" << status.validation_status();
287    EndEnrollment(ENROLLMENT_DM_SERVER_FAILED);
288    return;
289  }
290
291  EndEnrollment(ENROLLMENT_SUCCESS);
292}
293
294void ConsumerManagementService::EndEnrollment(ConsumerEnrollmentState state) {
295  SetEnrollmentState(state);
296  if (user_manager::UserManager::Get()->IsCurrentUserOwner())
297    ShowDesktopNotificationAndResetState(state);
298}
299
300void ConsumerManagementService::ShowDesktopNotificationAndResetState(
301    ConsumerEnrollmentState state) {
302  // TODO(davidyu): Show a desktop notification to the current user, who should
303  // be the owner.
304  SetEnrollmentState(ENROLLMENT_NONE);
305}
306
307}  // namespace policy
308