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