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.
5 #include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
12 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
13 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
14 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
15 #include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
16 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
17 #include "google_apis/gaia/gaia_urls.h"
19 namespace em
= enterprise_management
;
25 // Retry for InstallAttrs initialization every 500ms.
26 const int kLockRetryIntervalMs
= 500;
27 // Maximum time to retry InstallAttrs initialization before we give up.
28 const int kLockRetryTimeoutMs
= 10 * 60 * 1000; // 10 minutes.
32 EnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
33 DeviceCloudPolicyStoreChromeOS
* store
,
34 EnterpriseInstallAttributes
* install_attributes
,
35 scoped_ptr
<CloudPolicyClient
> client
,
36 const std::string
& auth_token
,
37 const std::string
& client_id
,
38 bool is_auto_enrollment
,
39 const std::string
& requisition
,
40 const AllowedDeviceModes
& allowed_device_modes
,
41 const EnrollmentCallback
& completion_callback
)
43 install_attributes_(install_attributes
),
44 client_(client
.Pass()),
45 auth_token_(auth_token
),
46 client_id_(client_id
),
47 is_auto_enrollment_(is_auto_enrollment
),
48 requisition_(requisition
),
49 allowed_device_modes_(allowed_device_modes
),
50 completion_callback_(completion_callback
),
51 device_mode_(DEVICE_MODE_NOT_SET
),
52 enrollment_step_(STEP_PENDING
),
53 lockbox_init_duration_(0),
55 CHECK(!client_
->is_registered());
56 CHECK_EQ(DM_STATUS_SUCCESS
, client_
->status());
57 store_
->AddObserver(this);
58 client_
->AddObserver(this);
59 client_
->AddNamespaceToFetch(PolicyNamespaceKey(
60 dm_protocol::kChromeDevicePolicyType
, std::string()));
63 EnrollmentHandlerChromeOS::~EnrollmentHandlerChromeOS() {
65 store_
->RemoveObserver(this);
68 void EnrollmentHandlerChromeOS::StartEnrollment() {
69 CHECK_EQ(STEP_PENDING
, enrollment_step_
);
70 enrollment_step_
= STEP_LOADING_STORE
;
71 AttemptRegistration();
74 scoped_ptr
<CloudPolicyClient
> EnrollmentHandlerChromeOS::ReleaseClient() {
76 return client_
.Pass();
79 void EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient
* client
) {
80 DCHECK_EQ(client_
.get(), client
);
81 CHECK_EQ(STEP_POLICY_FETCH
, enrollment_step_
);
83 enrollment_step_
= STEP_VALIDATION
;
85 // Validate the policy.
86 const em::PolicyFetchResponse
* policy
= client_
->GetPolicyFor(
87 PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType
, std::string()));
89 ReportResult(EnrollmentStatus::ForFetchError(
90 DM_STATUS_RESPONSE_DECODING_ERROR
));
94 scoped_ptr
<DeviceCloudPolicyValidator
> validator(
95 DeviceCloudPolicyValidator::Create(
96 scoped_ptr
<em::PolicyFetchResponse
>(
97 new em::PolicyFetchResponse(*policy
))));
99 validator
->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(),
100 CloudPolicyValidatorBase::TIMESTAMP_REQUIRED
);
101 if (install_attributes_
->IsEnterpriseDevice())
102 validator
->ValidateDomain(install_attributes_
->GetDomain());
103 validator
->ValidateDMToken(client
->dm_token(),
104 CloudPolicyValidatorBase::DM_TOKEN_REQUIRED
);
105 validator
->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType
);
106 validator
->ValidatePayload();
107 validator
->ValidateInitialKey();
108 validator
.release()->StartValidation(
109 base::Bind(&EnrollmentHandlerChromeOS::PolicyValidated
,
110 weak_factory_
.GetWeakPtr()));
113 void EnrollmentHandlerChromeOS::OnRegistrationStateChanged(
114 CloudPolicyClient
* client
) {
115 DCHECK_EQ(client_
.get(), client
);
117 if (enrollment_step_
== STEP_REGISTRATION
&& client_
->is_registered()) {
118 enrollment_step_
= STEP_POLICY_FETCH
,
119 device_mode_
= client_
->device_mode();
120 if (device_mode_
== DEVICE_MODE_NOT_SET
)
121 device_mode_
= DEVICE_MODE_ENTERPRISE
;
122 if (!allowed_device_modes_
.test(device_mode_
)) {
123 LOG(ERROR
) << "Bad device mode " << device_mode_
;
124 ReportResult(EnrollmentStatus::ForStatus(
125 EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE
));
128 client_
->FetchPolicy();
130 LOG(FATAL
) << "Registration state changed to " << client_
->is_registered()
131 << " in step " << enrollment_step_
;
135 void EnrollmentHandlerChromeOS::OnClientError(CloudPolicyClient
* client
) {
136 DCHECK_EQ(client_
.get(), client
);
138 if (enrollment_step_
== STEP_ROBOT_AUTH_FETCH
) {
139 LOG(WARNING
) << "API authentication code fetch failed: "
140 << client_
->status();
141 // Robot auth tokens are currently optional. Skip fetching the refresh
142 // token and jump directly to the lock device step.
143 robot_refresh_token_
.clear();
145 } else if (enrollment_step_
< STEP_POLICY_FETCH
) {
146 ReportResult(EnrollmentStatus::ForRegistrationError(client_
->status()));
148 ReportResult(EnrollmentStatus::ForFetchError(client_
->status()));
152 void EnrollmentHandlerChromeOS::OnStoreLoaded(CloudPolicyStore
* store
) {
153 DCHECK_EQ(store_
, store
);
155 if (enrollment_step_
== STEP_LOADING_STORE
) {
156 // If the |store_| wasn't initialized when StartEnrollment() was
157 // called, then AttemptRegistration() bails silently. This gets
158 // registration rolling again after the store finishes loading.
159 AttemptRegistration();
160 } else if (enrollment_step_
== STEP_STORE_POLICY
) {
161 // Store the robot API auth refresh token.
162 // Currently optional, so always return success.
163 chromeos::DeviceOAuth2TokenService
* token_service
=
164 chromeos::DeviceOAuth2TokenServiceFactory::Get();
165 if (token_service
&& !robot_refresh_token_
.empty()) {
166 token_service
->SetAndSaveRefreshToken(robot_refresh_token_
);
169 ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS
));
173 void EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore
* store
) {
174 DCHECK_EQ(store_
, store
);
175 ReportResult(EnrollmentStatus::ForStoreError(store_
->status(),
176 store_
->validation_status()));
179 void EnrollmentHandlerChromeOS::AttemptRegistration() {
180 CHECK_EQ(STEP_LOADING_STORE
, enrollment_step_
);
181 if (store_
->is_initialized()) {
182 enrollment_step_
= STEP_REGISTRATION
;
183 client_
->Register(em::DeviceRegisterRequest::DEVICE
,
184 auth_token_
, client_id_
, is_auto_enrollment_
,
189 void EnrollmentHandlerChromeOS::PolicyValidated(
190 DeviceCloudPolicyValidator
* validator
) {
191 CHECK_EQ(STEP_VALIDATION
, enrollment_step_
);
192 if (validator
->success()) {
193 policy_
= validator
->policy().Pass();
194 username_
= validator
->policy_data()->username();
195 device_id_
= validator
->policy_data()->device_id();
197 enrollment_step_
= STEP_ROBOT_AUTH_FETCH
;
198 client_
->FetchRobotAuthCodes(auth_token_
);
200 ReportResult(EnrollmentStatus::ForValidationError(validator
->status()));
204 void EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched(
205 CloudPolicyClient
* client
) {
206 DCHECK_EQ(client_
.get(), client
);
207 CHECK_EQ(STEP_ROBOT_AUTH_FETCH
, enrollment_step_
);
209 enrollment_step_
= STEP_ROBOT_AUTH_REFRESH
;
211 gaia::OAuthClientInfo client_info
;
212 client_info
.client_id
= GaiaUrls::GetInstance()->oauth2_chrome_client_id();
213 client_info
.client_secret
=
214 GaiaUrls::GetInstance()->oauth2_chrome_client_secret();
215 client_info
.redirect_uri
= "oob";
217 // Use the system request context to avoid sending user cookies.
218 gaia_oauth_client_
.reset(new gaia::GaiaOAuthClient(
219 g_browser_process
->system_request_context()));
220 gaia_oauth_client_
->GetTokensFromAuthCode(client_info
,
221 client
->robot_api_auth_code(),
226 // GaiaOAuthClient::Delegate callback for OAuth2 refresh token fetched.
227 void EnrollmentHandlerChromeOS::OnGetTokensResponse(
228 const std::string
& refresh_token
,
229 const std::string
& access_token
,
230 int expires_in_seconds
) {
231 CHECK_EQ(STEP_ROBOT_AUTH_REFRESH
, enrollment_step_
);
233 robot_refresh_token_
= refresh_token
;
238 void EnrollmentHandlerChromeOS::DoLockDeviceStep() {
239 enrollment_step_
= STEP_LOCK_DEVICE
,
240 StartLockDevice(username_
, device_mode_
, device_id_
);
243 // GaiaOAuthClient::Delegate
244 void EnrollmentHandlerChromeOS::OnRefreshTokenResponse(
245 const std::string
& access_token
,
246 int expires_in_seconds
) {
247 // We never use the code that should trigger this callback.
248 LOG(FATAL
) << "Unexpected callback invoked";
251 // GaiaOAuthClient::Delegate OAuth2 error when fetching refresh token request.
252 void EnrollmentHandlerChromeOS::OnOAuthError() {
253 CHECK_EQ(STEP_ROBOT_AUTH_REFRESH
, enrollment_step_
);
257 // GaiaOAuthClient::Delegate network error when fetching refresh token.
258 void EnrollmentHandlerChromeOS::OnNetworkError(int response_code
) {
259 LOG(ERROR
) << "Network error while fetching API refresh token: "
261 CHECK_EQ(STEP_ROBOT_AUTH_REFRESH
, enrollment_step_
);
265 void EnrollmentHandlerChromeOS::StartLockDevice(
266 const std::string
& user
,
267 DeviceMode device_mode
,
268 const std::string
& device_id
) {
269 CHECK_EQ(STEP_LOCK_DEVICE
, enrollment_step_
);
270 // Since this method is also called directly.
271 weak_factory_
.InvalidateWeakPtrs();
273 install_attributes_
->LockDevice(
274 user
, device_mode
, device_id
,
275 base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult
,
276 weak_factory_
.GetWeakPtr(),
282 void EnrollmentHandlerChromeOS::HandleLockDeviceResult(
283 const std::string
& user
,
284 DeviceMode device_mode
,
285 const std::string
& device_id
,
286 EnterpriseInstallAttributes::LockResult lock_result
) {
287 CHECK_EQ(STEP_LOCK_DEVICE
, enrollment_step_
);
288 switch (lock_result
) {
289 case EnterpriseInstallAttributes::LOCK_SUCCESS
:
290 enrollment_step_
= STEP_STORE_POLICY
;
291 store_
->InstallInitialPolicy(*policy_
);
293 case EnterpriseInstallAttributes::LOCK_NOT_READY
:
294 // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't
295 // succeeded by then show an error to the user and stop the enrollment.
296 if (lockbox_init_duration_
< kLockRetryTimeoutMs
) {
297 // InstallAttributes not ready yet, retry later.
298 LOG(WARNING
) << "Install Attributes not ready yet will retry in "
299 << kLockRetryIntervalMs
<< "ms.";
300 base::MessageLoop::current()->PostDelayedTask(
302 base::Bind(&EnrollmentHandlerChromeOS::StartLockDevice
,
303 weak_factory_
.GetWeakPtr(),
304 user
, device_mode
, device_id
),
305 base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs
));
306 lockbox_init_duration_
+= kLockRetryIntervalMs
;
308 ReportResult(EnrollmentStatus::ForStatus(
309 EnrollmentStatus::STATUS_LOCK_TIMEOUT
));
312 case EnterpriseInstallAttributes::LOCK_BACKEND_ERROR
:
313 ReportResult(EnrollmentStatus::ForStatus(
314 EnrollmentStatus::STATUS_LOCK_ERROR
));
316 case EnterpriseInstallAttributes::LOCK_WRONG_USER
:
317 LOG(ERROR
) << "Enrollment cannot proceed because the InstallAttrs "
318 << "has been locked already!";
319 ReportResult(EnrollmentStatus::ForStatus(
320 EnrollmentStatus::STATUS_LOCK_WRONG_USER
));
324 NOTREACHED() << "Invalid lock result " << lock_result
;
325 ReportResult(EnrollmentStatus::ForStatus(
326 EnrollmentStatus::STATUS_LOCK_ERROR
));
329 void EnrollmentHandlerChromeOS::Stop() {
331 client_
->RemoveObserver(this);
332 enrollment_step_
= STEP_FINISHED
;
333 weak_factory_
.InvalidateWeakPtrs();
334 completion_callback_
.Reset();
337 void EnrollmentHandlerChromeOS::ReportResult(EnrollmentStatus status
) {
338 EnrollmentCallback callback
= completion_callback_
;
341 if (status
.status() != EnrollmentStatus::STATUS_SUCCESS
) {
342 LOG(WARNING
) << "Enrollment failed: " << status
.status()
343 << " " << status
.client_status()
344 << " " << status
.validation_status()
345 << " " << status
.store_status();
348 if (!callback
.is_null())
349 callback
.Run(status
);
352 } // namespace policy