Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / policy / enrollment_handler_chromeos.cc
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.
4
5 #include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h"
13 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
14 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
15 #include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h"
16 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
17 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
18 #include "chrome/browser/chromeos/settings/device_settings_service.h"
19 #include "chromeos/chromeos_switches.h"
20 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
21 #include "google_apis/gaia/gaia_urls.h"
22 #include "net/http/http_status_code.h"
23
24 namespace em = enterprise_management;
25
26 namespace policy {
27
28 namespace {
29
30 // Retry for InstallAttrs initialization every 500ms.
31 const int kLockRetryIntervalMs = 500;
32 // Maximum time to retry InstallAttrs initialization before we give up.
33 const int kLockRetryTimeoutMs = 10 * 60 * 1000;  // 10 minutes.
34
35 // Testing token used when the enrollment-skip-robot-auth is set to skip talking
36 // to GAIA for an actual token. This is needed to be able to run against the
37 // testing DMServer implementations.
38 const char kTestingRobotToken[] = "test-token";
39
40 }  // namespace
41
42 EnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS(
43     DeviceCloudPolicyStoreChromeOS* store,
44     EnterpriseInstallAttributes* install_attributes,
45     ServerBackedStateKeysBroker* state_keys_broker,
46     chromeos::DeviceSettingsService* device_settings_service,
47     scoped_ptr<CloudPolicyClient> client,
48     scoped_refptr<base::SequencedTaskRunner> background_task_runner,
49     const std::string& auth_token,
50     const std::string& client_id,
51     bool is_auto_enrollment,
52     const std::string& requisition,
53     const AllowedDeviceModes& allowed_device_modes,
54     em::PolicyData::ManagementMode management_mode,
55     const EnrollmentCallback& completion_callback)
56     : store_(store),
57       install_attributes_(install_attributes),
58       state_keys_broker_(state_keys_broker),
59       device_settings_service_(device_settings_service),
60       client_(client.Pass()),
61       background_task_runner_(background_task_runner),
62       auth_token_(auth_token),
63       client_id_(client_id),
64       is_auto_enrollment_(is_auto_enrollment),
65       requisition_(requisition),
66       allowed_device_modes_(allowed_device_modes),
67       management_mode_(management_mode),
68       completion_callback_(completion_callback),
69       device_mode_(DEVICE_MODE_NOT_SET),
70       enrollment_step_(STEP_PENDING),
71       lockbox_init_duration_(0),
72       weak_ptr_factory_(this) {
73   CHECK(!client_->is_registered());
74   CHECK_EQ(DM_STATUS_SUCCESS, client_->status());
75   CHECK(management_mode_ == em::PolicyData::ENTERPRISE_MANAGED ||
76         management_mode_ == em::PolicyData::CONSUMER_MANAGED);
77   store_->AddObserver(this);
78   client_->AddObserver(this);
79   client_->AddNamespaceToFetch(PolicyNamespaceKey(
80       dm_protocol::kChromeDevicePolicyType, std::string()));
81 }
82
83 EnrollmentHandlerChromeOS::~EnrollmentHandlerChromeOS() {
84   Stop();
85   store_->RemoveObserver(this);
86 }
87
88 void EnrollmentHandlerChromeOS::StartEnrollment() {
89   CHECK_EQ(STEP_PENDING, enrollment_step_);
90   enrollment_step_ = STEP_STATE_KEYS;
91   state_keys_broker_->RequestStateKeys(
92       base::Bind(&EnrollmentHandlerChromeOS::HandleStateKeysResult,
93                  weak_ptr_factory_.GetWeakPtr()));
94 }
95
96 scoped_ptr<CloudPolicyClient> EnrollmentHandlerChromeOS::ReleaseClient() {
97   Stop();
98   return client_.Pass();
99 }
100
101 void EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient* client) {
102   DCHECK_EQ(client_.get(), client);
103   CHECK_EQ(STEP_POLICY_FETCH, enrollment_step_);
104
105   enrollment_step_ = STEP_VALIDATION;
106
107   // Validate the policy.
108   const em::PolicyFetchResponse* policy = client_->GetPolicyFor(
109       PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType, std::string()));
110   if (!policy) {
111     ReportResult(EnrollmentStatus::ForFetchError(
112         DM_STATUS_RESPONSE_DECODING_ERROR));
113     return;
114   }
115
116   scoped_ptr<DeviceCloudPolicyValidator> validator(
117       DeviceCloudPolicyValidator::Create(
118           scoped_ptr<em::PolicyFetchResponse>(
119               new em::PolicyFetchResponse(*policy)),
120           background_task_runner_));
121
122   validator->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(),
123                                CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
124
125   // If this is re-enrollment, make sure that the new policy matches the
126   // previously-enrolled domain.
127   std::string domain;
128   if (install_attributes_->IsEnterpriseDevice()) {
129     domain = install_attributes_->GetDomain();
130     validator->ValidateDomain(domain);
131   }
132   validator->ValidateDMToken(client->dm_token(),
133                              CloudPolicyValidatorBase::DM_TOKEN_REQUIRED);
134   validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType);
135   validator->ValidatePayload();
136   if (management_mode_ == em::PolicyData::CONSUMER_MANAGED) {
137     // For consumer-managed devices, although we don't store the policy, we
138     // still need to verify its integrity since we use the request token in it.
139     // The consumer device management server does not have the verification
140     // key, and we need to skip checking on that by passing an empty key to
141     // ValidateInitialKey(). ValidateInitialKey() still checks that the policy
142     // data is correctly signed by the new public key when the verification key
143     // is empty.
144     validator->ValidateInitialKey("", "");
145   } else {
146     // If |domain| is empty here, the policy validation code will just use the
147     // domain from the username field in the policy itself to do key validation.
148     // TODO(mnissler): Plumb the enrolling user's username into this object so
149     // we can validate the username on the resulting policy, and use the domain
150     // from that username to validate the key below (http://crbug.com/343074).
151     validator->ValidateInitialKey(GetPolicyVerificationKey(), domain);
152   }
153   validator.release()->StartValidation(
154       base::Bind(&EnrollmentHandlerChromeOS::HandlePolicyValidationResult,
155                  weak_ptr_factory_.GetWeakPtr()));
156 }
157
158 void EnrollmentHandlerChromeOS::OnRegistrationStateChanged(
159     CloudPolicyClient* client) {
160   DCHECK_EQ(client_.get(), client);
161
162   if (enrollment_step_ == STEP_REGISTRATION && client_->is_registered()) {
163     enrollment_step_ = STEP_POLICY_FETCH,
164     device_mode_ = client_->device_mode();
165     if (device_mode_ == DEVICE_MODE_NOT_SET)
166       device_mode_ = DEVICE_MODE_ENTERPRISE;
167     if (!allowed_device_modes_.test(device_mode_)) {
168       LOG(ERROR) << "Bad device mode " << device_mode_;
169       ReportResult(EnrollmentStatus::ForStatus(
170           EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE));
171       return;
172     }
173     client_->FetchPolicy();
174   } else {
175     LOG(FATAL) << "Registration state changed to " << client_->is_registered()
176                << " in step " << enrollment_step_ << ".";
177   }
178 }
179
180 void EnrollmentHandlerChromeOS::OnClientError(CloudPolicyClient* client) {
181   DCHECK_EQ(client_.get(), client);
182
183   if (enrollment_step_ == STEP_ROBOT_AUTH_FETCH) {
184     LOG(ERROR) << "API authentication code fetch failed: "
185                << client_->status();
186     ReportResult(EnrollmentStatus::ForRobotAuthFetchError(client_->status()));
187   } else if (enrollment_step_ < STEP_POLICY_FETCH) {
188     ReportResult(EnrollmentStatus::ForRegistrationError(client_->status()));
189   } else {
190     ReportResult(EnrollmentStatus::ForFetchError(client_->status()));
191   }
192 }
193
194 void EnrollmentHandlerChromeOS::OnStoreLoaded(CloudPolicyStore* store) {
195   DCHECK_EQ(store_, store);
196
197   if (enrollment_step_ == STEP_LOADING_STORE) {
198     // If the |store_| wasn't initialized when StartEnrollment() was called,
199     // then StartRegistration() bails silently. This gets registration rolling
200     // again after the store finishes loading.
201     StartRegistration();
202   } else if (enrollment_step_ == STEP_STORE_POLICY) {
203     ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
204   }
205 }
206
207 void EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) {
208   DCHECK_EQ(store_, store);
209   if (enrollment_step_ == STEP_STORE_TOKEN_AND_ID) {
210     // Calling DeviceSettingsService::SetManagementSettings() on a non-
211     // enterprise-managed device will trigger OnStoreError(), as
212     // DeviceCloudPolicyStore listens to all changes on DeviceSettingsService,
213     // and it calls OnStoreError() when the device is not enterprise-managed.
214     return;
215   }
216   ReportResult(EnrollmentStatus::ForStoreError(store_->status(),
217                                                store_->validation_status()));
218 }
219
220 void EnrollmentHandlerChromeOS::HandleStateKeysResult(
221     const std::vector<std::string>& state_keys) {
222   CHECK_EQ(STEP_STATE_KEYS, enrollment_step_);
223
224   // Make sure state keys are available if forced re-enrollment is on.
225   if (chromeos::AutoEnrollmentController::GetMode() ==
226       chromeos::AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT) {
227     client_->SetStateKeysToUpload(state_keys);
228     current_state_key_ = state_keys_broker_->current_state_key();
229     if (state_keys.empty() || current_state_key_.empty()) {
230       ReportResult(
231           EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_NO_STATE_KEYS));
232       return;
233     }
234   }
235
236   enrollment_step_ = STEP_LOADING_STORE;
237   StartRegistration();
238 }
239
240 void EnrollmentHandlerChromeOS::StartRegistration() {
241   CHECK_EQ(STEP_LOADING_STORE, enrollment_step_);
242   if (store_->is_initialized()) {
243     enrollment_step_ = STEP_REGISTRATION;
244     client_->Register(em::DeviceRegisterRequest::DEVICE,
245                       auth_token_, client_id_, is_auto_enrollment_,
246                       requisition_, current_state_key_);
247   } else {
248     // Do nothing. StartRegistration() will be called again from OnStoreLoaded()
249     // after the CloudPolicyStore has initialized.
250   }
251 }
252
253 void EnrollmentHandlerChromeOS::HandlePolicyValidationResult(
254     DeviceCloudPolicyValidator* validator) {
255   CHECK_EQ(STEP_VALIDATION, enrollment_step_);
256   if (validator->success()) {
257     policy_ = validator->policy().Pass();
258     username_ = validator->policy_data()->username();
259     device_id_ = validator->policy_data()->device_id();
260     request_token_ = validator->policy_data()->request_token();
261
262     if (CommandLine::ForCurrentProcess()->HasSwitch(
263             chromeos::switches::kEnterpriseEnrollmentSkipRobotAuth)) {
264       // For test purposes we allow enrollment to succeed without proper robot
265       // account and use the provided value as a token.
266       refresh_token_ = kTestingRobotToken;
267       enrollment_step_ = STEP_LOCK_DEVICE;
268       StartLockDevice();
269       return;
270     }
271
272     enrollment_step_ = STEP_ROBOT_AUTH_FETCH;
273     client_->FetchRobotAuthCodes(auth_token_);
274   } else {
275     ReportResult(EnrollmentStatus::ForValidationError(validator->status()));
276   }
277 }
278
279 void EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched(
280     CloudPolicyClient* client) {
281   DCHECK_EQ(client_.get(), client);
282   CHECK_EQ(STEP_ROBOT_AUTH_FETCH, enrollment_step_);
283
284   enrollment_step_ = STEP_ROBOT_AUTH_REFRESH;
285
286   gaia::OAuthClientInfo client_info;
287   client_info.client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
288   client_info.client_secret =
289       GaiaUrls::GetInstance()->oauth2_chrome_client_secret();
290   client_info.redirect_uri = "oob";
291
292   // Use the system request context to avoid sending user cookies.
293   gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
294       g_browser_process->system_request_context()));
295   gaia_oauth_client_->GetTokensFromAuthCode(client_info,
296                                             client->robot_api_auth_code(),
297                                             0 /* max_retries */,
298                                             this);
299 }
300
301 // GaiaOAuthClient::Delegate callback for OAuth2 refresh token fetched.
302 void EnrollmentHandlerChromeOS::OnGetTokensResponse(
303     const std::string& refresh_token,
304     const std::string& access_token,
305     int expires_in_seconds) {
306   CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
307
308   refresh_token_ = refresh_token;
309
310   enrollment_step_ = STEP_LOCK_DEVICE;
311   StartLockDevice();
312 }
313
314 // GaiaOAuthClient::Delegate
315 void EnrollmentHandlerChromeOS::OnRefreshTokenResponse(
316     const std::string& access_token,
317     int expires_in_seconds) {
318   // We never use the code that should trigger this callback.
319   LOG(FATAL) << "Unexpected callback invoked.";
320 }
321
322 // GaiaOAuthClient::Delegate OAuth2 error when fetching refresh token request.
323 void EnrollmentHandlerChromeOS::OnOAuthError() {
324   CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
325   // OnOAuthError is only called if the request is bad (malformed) or the
326   // response is bad (empty access token returned).
327   LOG(ERROR) << "OAuth protocol error while fetching API refresh token.";
328   ReportResult(
329       EnrollmentStatus::ForRobotRefreshFetchError(net::HTTP_BAD_REQUEST));
330 }
331
332 // GaiaOAuthClient::Delegate network error when fetching refresh token.
333 void EnrollmentHandlerChromeOS::OnNetworkError(int response_code) {
334   CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_);
335   LOG(ERROR) << "Network error while fetching API refresh token: "
336              << response_code;
337   ReportResult(
338       EnrollmentStatus::ForRobotRefreshFetchError(response_code));
339 }
340
341 void EnrollmentHandlerChromeOS::StartLockDevice() {
342   CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
343   // Since this method is also called directly.
344   weak_ptr_factory_.InvalidateWeakPtrs();
345
346   if (management_mode_ == em::PolicyData::CONSUMER_MANAGED) {
347     // Consumer device enrollment doesn't use install attributes. Instead,
348     // we put the information in the owners settings.
349     enrollment_step_ = STEP_STORE_TOKEN_AND_ID;
350     device_settings_service_->SetManagementSettings(
351         management_mode_, request_token_, device_id_,
352         base::Bind(&EnrollmentHandlerChromeOS::HandleSetManagementSettingsDone,
353                    weak_ptr_factory_.GetWeakPtr()));
354   } else {
355     install_attributes_->LockDevice(
356         username_, device_mode_, device_id_,
357         base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult,
358                    weak_ptr_factory_.GetWeakPtr()));
359   }
360 }
361
362 void EnrollmentHandlerChromeOS::HandleSetManagementSettingsDone() {
363   CHECK_EQ(STEP_STORE_TOKEN_AND_ID, enrollment_step_);
364   if (device_settings_service_->status() !=
365       chromeos::DeviceSettingsService::STORE_SUCCESS) {
366     ReportResult(EnrollmentStatus::ForStatus(
367         EnrollmentStatus::STATUS_STORE_TOKEN_AND_ID_FAILED));
368     return;
369   }
370
371   StartStoreRobotAuth();
372 }
373
374 void EnrollmentHandlerChromeOS::HandleLockDeviceResult(
375     EnterpriseInstallAttributes::LockResult lock_result) {
376   CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_);
377   switch (lock_result) {
378     case EnterpriseInstallAttributes::LOCK_SUCCESS:
379       StartStoreRobotAuth();
380       break;
381     case EnterpriseInstallAttributes::LOCK_NOT_READY:
382       // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't
383       // succeeded by then show an error to the user and stop the enrollment.
384       if (lockbox_init_duration_ < kLockRetryTimeoutMs) {
385         // InstallAttributes not ready yet, retry later.
386         LOG(WARNING) << "Install Attributes not ready yet will retry in "
387                      << kLockRetryIntervalMs << "ms.";
388         base::MessageLoop::current()->PostDelayedTask(
389             FROM_HERE,
390             base::Bind(&EnrollmentHandlerChromeOS::StartLockDevice,
391                        weak_ptr_factory_.GetWeakPtr()),
392             base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs));
393         lockbox_init_duration_ += kLockRetryIntervalMs;
394       } else {
395         HandleLockDeviceResult(EnterpriseInstallAttributes::LOCK_TIMEOUT);
396       }
397       break;
398     case EnterpriseInstallAttributes::LOCK_TIMEOUT:
399     case EnterpriseInstallAttributes::LOCK_BACKEND_INVALID:
400     case EnterpriseInstallAttributes::LOCK_ALREADY_LOCKED:
401     case EnterpriseInstallAttributes::LOCK_SET_ERROR:
402     case EnterpriseInstallAttributes::LOCK_FINALIZE_ERROR:
403     case EnterpriseInstallAttributes::LOCK_READBACK_ERROR:
404     case EnterpriseInstallAttributes::LOCK_WRONG_DOMAIN:
405       ReportResult(EnrollmentStatus::ForLockError(lock_result));
406       break;
407   }
408 }
409
410 void EnrollmentHandlerChromeOS::StartStoreRobotAuth() {
411   // Get the token service so we can store our robot refresh token.
412   enrollment_step_ = STEP_STORE_ROBOT_AUTH;
413   chromeos::DeviceOAuth2TokenServiceFactory::Get()->SetAndSaveRefreshToken(
414       refresh_token_,
415       base::Bind(&EnrollmentHandlerChromeOS::HandleStoreRobotAuthTokenResult,
416                  weak_ptr_factory_.GetWeakPtr()));
417 }
418
419 void EnrollmentHandlerChromeOS::HandleStoreRobotAuthTokenResult(bool result) {
420   CHECK_EQ(STEP_STORE_ROBOT_AUTH, enrollment_step_);
421
422   if (!result) {
423     LOG(ERROR) << "Failed to store API refresh token.";
424     ReportResult(EnrollmentStatus::ForStatus(
425         EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED));
426     return;
427   }
428
429   if (management_mode_ == em::PolicyData::CONSUMER_MANAGED) {
430     // For consumer management enrollment, we don't store the policy.
431     ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS));
432     return;
433   }
434
435   enrollment_step_ = STEP_STORE_POLICY;
436   store_->InstallInitialPolicy(*policy_);
437 }
438
439 void EnrollmentHandlerChromeOS::Stop() {
440   if (client_.get())
441     client_->RemoveObserver(this);
442   enrollment_step_ = STEP_FINISHED;
443   weak_ptr_factory_.InvalidateWeakPtrs();
444   completion_callback_.Reset();
445 }
446
447 void EnrollmentHandlerChromeOS::ReportResult(EnrollmentStatus status) {
448   EnrollmentCallback callback = completion_callback_;
449   Stop();
450
451   if (status.status() != EnrollmentStatus::STATUS_SUCCESS) {
452     LOG(WARNING) << "Enrollment failed: " << status.status()
453                  << ", client: " << status.client_status()
454                  << ", validation: " << status.validation_status()
455                  << ", store: " << status.store_status()
456                  << ", lock: " << status.lock_status();
457   }
458
459   if (!callback.is_null())
460     callback.Run(status);
461 }
462
463 }  // namespace policy