cryptohome: Move stateless wrapper functions out of CryptohomeLibrary
[chromium-blink-merge.git] / chrome / browser / chromeos / policy / enrollment_handler_chromeos.cc
blobc4990df2452883b318ec20a5dea0adccc71b7f2e
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"
7 #include "base/bind.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;
21 namespace policy {
23 namespace {
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.
30 } // namespace
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)
42 : store_(store),
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),
54 weak_factory_(this) {
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() {
64 Stop();
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() {
75 Stop();
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()));
88 if (!policy) {
89 ReportResult(EnrollmentStatus::ForFetchError(
90 DM_STATUS_RESPONSE_DECODING_ERROR));
91 return;
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));
126 return;
128 client_->FetchPolicy();
129 } else {
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();
144 DoLockDeviceStep();
145 } else if (enrollment_step_ < STEP_POLICY_FETCH) {
146 ReportResult(EnrollmentStatus::ForRegistrationError(client_->status()));
147 } else {
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_,
185 requisition_);
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_);
199 } else {
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(),
222 0 /* max_retries */,
223 this);
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;
235 DoLockDeviceStep();
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_);
254 DoLockDeviceStep();
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: "
260 << response_code;
261 CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
262 DoLockDeviceStep();
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(),
277 user,
278 device_mode,
279 device_id));
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_);
292 return;
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(
301 FROM_HERE,
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;
307 } else {
308 ReportResult(EnrollmentStatus::ForStatus(
309 EnrollmentStatus::STATUS_LOCK_TIMEOUT));
311 return;
312 case EnterpriseInstallAttributes::LOCK_BACKEND_ERROR:
313 ReportResult(EnrollmentStatus::ForStatus(
314 EnrollmentStatus::STATUS_LOCK_ERROR));
315 return;
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));
321 return;
324 NOTREACHED() << "Invalid lock result " << lock_result;
325 ReportResult(EnrollmentStatus::ForStatus(
326 EnrollmentStatus::STATUS_LOCK_ERROR));
329 void EnrollmentHandlerChromeOS::Stop() {
330 if (client_.get())
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_;
339 Stop();
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