enrollment_handler_chromeos.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
151a8d8528135ba4e3e4cf7cd711a9e47b19078a3Chris Lattner// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman// Use of this source code is governed by a BSD-style license that can be 36fbcc26f1460eaee4e0eb8b426fc1ff0c7af11beJohn Criswell// found in the LICENSE file. 46fbcc26f1460eaee4e0eb8b426fc1ff0c7af11beJohn Criswell 57ed47a13356daed2a34cd2209a31f92552e3bdd8Chris Lattner#include "chrome/browser/chromeos/policy/enrollment_handler_chromeos.h" 67ed47a13356daed2a34cd2209a31f92552e3bdd8Chris Lattner 7ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman#include "base/bind.h" 86fbcc26f1460eaee4e0eb8b426fc1ff0c7af11beJohn Criswell#include "base/command_line.h" 9ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman#include "base/logging.h" 10e8b5413e5d0c7c0fc5b384e975c4ca87f4c00699Chris Lattner#include "base/message_loop/message_loop.h" 11e8b5413e5d0c7c0fc5b384e975c4ca87f4c00699Chris Lattner#include "chrome/browser/browser_process.h" 1251a8d8528135ba4e3e4cf7cd711a9e47b19078a3Chris Lattner#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h" 13deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" 14fce1143bcfa73f61845002fa50473d1a01384202Misha Brukman#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" 15fce1143bcfa73f61845002fa50473d1a01384202Misha Brukman#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h" 16deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve#include "chromeos/chromeos_switches.h" 17c0b9dc5be79f009d260edb5cd5e1d8346587aaa2Alkis Evlogimenos#include "components/policy/core/common/cloud/cloud_policy_constants.h" 18551ccae044b0ff658fe629dd67edd5ffe75d10e8Reid Spencer#include "google_apis/gaia/gaia_urls.h" 19d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke#include "net/http/http_status_code.h" 20d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke#include "policy/proto/device_management_backend.pb.h" 21fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 22853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohmannamespace em = enterprise_management; 23fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 24fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohmannamespace policy { 25a655f088b88cf015fc48721fd9869787d1b8ce13Chris Lattner 26a655f088b88cf015fc48721fd9869787d1b8ce13Chris Lattnernamespace { 271cd1d98232c3c3a0bd3810c3bf6c2572ea02f208Daniel Dunbar 28d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke// Retry for InstallAttrs initialization every 500ms. 2994dc07728f091c652f0a8059aba6dce5018485eeAlkis Evlogimenosconst int kLockRetryIntervalMs = 500; 308e4018e2de52c534405d7155c7009d0b35afb861Cedric Venet// Maximum time to retry InstallAttrs initialization before we give up. 318e4018e2de52c534405d7155c7009d0b35afb861Cedric Venetconst int kLockRetryTimeoutMs = 10 * 60 * 1000; // 10 minutes. 327309be6735666143bd9835b275dc8501617a2591Gabor Greif 33fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman// Testing token used when the enrollment-skip-robot-auth is set to skip talking 348e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman// to GAIA for an actual token. This is needed to be able to run against the 3594dc07728f091c652f0a8059aba6dce5018485eeAlkis Evlogimenos// testing DMServer implementations. 368e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohmanconst char kTestingRobotToken[] = "test-token"; 3794dc07728f091c652f0a8059aba6dce5018485eeAlkis Evlogimenos 388e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman} // namespace 39c7f6b8c5d40e17bf43fd3a1549d7d89c9da735e1Gabor Greif 40c7f6b8c5d40e17bf43fd3a1549d7d89c9da735e1Gabor GreifEnrollmentHandlerChromeOS::EnrollmentHandlerChromeOS( 41c7f6b8c5d40e17bf43fd3a1549d7d89c9da735e1Gabor Greif DeviceCloudPolicyStoreChromeOS* store, 42fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman EnterpriseInstallAttributes* install_attributes, 4394dc07728f091c652f0a8059aba6dce5018485eeAlkis Evlogimenos scoped_ptr<CloudPolicyClient> client, 44c23b8719ef9d6b1220e854b37d40e9e1c48a82bcGabor Greif scoped_refptr<base::SequencedTaskRunner> background_task_runner, 45c23b8719ef9d6b1220e854b37d40e9e1c48a82bcGabor Greif const std::string& auth_token, 46f3841fcbd587c31aa9842b3f33bd57de40c9f443Gabor Greif const std::string& client_id, 47c23b8719ef9d6b1220e854b37d40e9e1c48a82bcGabor Greif bool is_auto_enrollment, 48aad5c0505183a5b7913f1a443a1f0650122551ccAlkis Evlogimenos const std::string& requisition, 49aad5c0505183a5b7913f1a443a1f0650122551ccAlkis Evlogimenos const AllowedDeviceModes& allowed_device_modes, 50fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman const EnrollmentCallback& completion_callback) 51fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman : store_(store), 52fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman install_attributes_(install_attributes), 538e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman client_(client.Pass()), 54fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman background_task_runner_(background_task_runner), 55fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman auth_token_(auth_token), 5694dc07728f091c652f0a8059aba6dce5018485eeAlkis Evlogimenos client_id_(client_id), 5794dc07728f091c652f0a8059aba6dce5018485eeAlkis Evlogimenos is_auto_enrollment_(is_auto_enrollment), 58fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman requisition_(requisition), 59fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman allowed_device_modes_(allowed_device_modes), 60c0b9dc5be79f009d260edb5cd5e1d8346587aaa2Alkis Evlogimenos completion_callback_(completion_callback), 611194e9501984daf0d3237ed1bf18a156173e7fd4Chris Lattner device_mode_(DEVICE_MODE_NOT_SET), 62c07d8d8a26f63dfc54dbd0e1ff776763ec6443adBrian Gaeke enrollment_step_(STEP_PENDING), 63f20c1a497fe3922ac718429d65a5fe396890575eChris Lattner lockbox_init_duration_(0), 64f20c1a497fe3922ac718429d65a5fe396890575eChris Lattner weak_ptr_factory_(this) { 6513d828567812041c1ca1817f4b66fce840903a1fEvan Cheng CHECK(!client_->is_registered()); 6613d828567812041c1ca1817f4b66fce840903a1fEvan Cheng CHECK_EQ(DM_STATUS_SUCCESS, client_->status()); 6713d828567812041c1ca1817f4b66fce840903a1fEvan Cheng store_->AddObserver(this); 6813d828567812041c1ca1817f4b66fce840903a1fEvan Cheng client_->AddObserver(this); 6913d828567812041c1ca1817f4b66fce840903a1fEvan Cheng client_->AddNamespaceToFetch(PolicyNamespaceKey( 7013d828567812041c1ca1817f4b66fce840903a1fEvan Cheng dm_protocol::kChromeDevicePolicyType, std::string())); 7113d828567812041c1ca1817f4b66fce840903a1fEvan Cheng} 7213d828567812041c1ca1817f4b66fce840903a1fEvan Cheng 73fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan ChengEnrollmentHandlerChromeOS::~EnrollmentHandlerChromeOS() { 74fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng Stop(); 75fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng store_->RemoveObserver(this); 76fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng} 7730b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey 7830b8e51addc23fb317c03d093a25828d3d5be45aJim Laskeyvoid EnrollmentHandlerChromeOS::StartEnrollment() { 7930b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey CHECK_EQ(STEP_PENDING, enrollment_step_); 8030b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey enrollment_step_ = STEP_LOADING_STORE; 8113d828567812041c1ca1817f4b66fce840903a1fEvan Cheng AttemptRegistration(); 828c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman} 838c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman 848c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohmanscoped_ptr<CloudPolicyClient> EnrollmentHandlerChromeOS::ReleaseClient() { 858c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman Stop(); 86fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman return client_.Pass(); 87fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman} 88fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 898e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohmanvoid EnrollmentHandlerChromeOS::OnPolicyFetched(CloudPolicyClient* client) { 908e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman DCHECK_EQ(client_.get(), client); 912c3f7ae3843bdc9dcfe85393e178211976c1f9bdDan Gohman CHECK_EQ(STEP_POLICY_FETCH, enrollment_step_); 9217fb34bf8cd10a798c9206eeef3bff151b4d3688Tanya Lattner 938e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman enrollment_step_ = STEP_VALIDATION; 948e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman 95ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman // Validate the policy. 968e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman const em::PolicyFetchResponse* policy = client_->GetPolicyFor( 97d0aa0cdbc6fee00f2b2019633a9b9d00d301ac68Chris Lattner PolicyNamespaceKey(dm_protocol::kChromeDevicePolicyType, std::string())); 98324da7647cfc3025e0c987176f0a300f9f780e6fJakob Stoklund Olesen if (!policy) { 99324da7647cfc3025e0c987176f0a300f9f780e6fJakob Stoklund Olesen ReportResult(EnrollmentStatus::ForFetchError( 100d0aa0cdbc6fee00f2b2019633a9b9d00d301ac68Chris Lattner DM_STATUS_RESPONSE_DECODING_ERROR)); 1011194e9501984daf0d3237ed1bf18a156173e7fd4Chris Lattner return; 1025e61fa95196b85281eec655787e9c73267532bd1Chris Lattner } 103324da7647cfc3025e0c987176f0a300f9f780e6fJakob Stoklund Olesen 104324da7647cfc3025e0c987176f0a300f9f780e6fJakob Stoklund Olesen scoped_ptr<DeviceCloudPolicyValidator> validator( 105324da7647cfc3025e0c987176f0a300f9f780e6fJakob Stoklund Olesen DeviceCloudPolicyValidator::Create( 106324da7647cfc3025e0c987176f0a300f9f780e6fJakob Stoklund Olesen scoped_ptr<em::PolicyFetchResponse>( 1078c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman new em::PolicyFetchResponse(*policy)), 1088c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman background_task_runner_)); 1098c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman 1108c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman validator->ValidateTimestamp(base::Time(), base::Time::NowFromSystemTime(), 1118c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman CloudPolicyValidatorBase::TIMESTAMP_REQUIRED); 1128c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman 1138c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman // If this is re-enrollment, make sure that the new policy matches the 1148c2b52552c90f39e4b2fed43e309e599e742b6acDan Gohman // previously-enrolled domain. 1155e61fa95196b85281eec655787e9c73267532bd1Chris Lattner std::string domain; 1165e61fa95196b85281eec655787e9c73267532bd1Chris Lattner if (install_attributes_->IsEnterpriseDevice()) { 117f20c1a497fe3922ac718429d65a5fe396890575eChris Lattner domain = install_attributes_->GetDomain(); 118f20c1a497fe3922ac718429d65a5fe396890575eChris Lattner validator->ValidateDomain(domain); 1195e61fa95196b85281eec655787e9c73267532bd1Chris Lattner } 1208e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman validator->ValidateDMToken(client->dm_token(), 1218e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman CloudPolicyValidatorBase::DM_TOKEN_REQUIRED); 122deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve validator->ValidatePolicyType(dm_protocol::kChromeDevicePolicyType); 123deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve validator->ValidatePayload(); 124deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve // If |domain| is empty here, the policy validation code will just use the 12534cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Cheng // domain from the username field in the policy itself to do key validation. 126deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve // TODO(mnissler): Plumb the enrolling user's username into this object so 127deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve // we can validate the username on the resulting policy, and use the domain 128c0b9dc5be79f009d260edb5cd5e1d8346587aaa2Alkis Evlogimenos // from that username to validate the key below (http://crbug.com/343074). 129c0b9dc5be79f009d260edb5cd5e1d8346587aaa2Alkis Evlogimenos validator->ValidateInitialKey(GetPolicyVerificationKey(), domain); 1308e8b8a223c2b0e69f44c0639f846260c8011668fDan Gohman validator.release()->StartValidation( 1318e8b8a223c2b0e69f44c0639f846260c8011668fDan Gohman base::Bind(&EnrollmentHandlerChromeOS::PolicyValidated, 132deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve weak_ptr_factory_.GetWeakPtr())); 133deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve} 134deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve 135deb9654056939a12981446f6ed1139dca3412746Vikram S. Advevoid EnrollmentHandlerChromeOS::OnRegistrationStateChanged( 136deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve CloudPolicyClient* client) { 137deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve DCHECK_EQ(client_.get(), client); 138deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve 139deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve if (enrollment_step_ == STEP_REGISTRATION && client_->is_registered()) { 140deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve enrollment_step_ = STEP_POLICY_FETCH, 141deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve device_mode_ = client_->device_mode(); 14276456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke if (device_mode_ == DEVICE_MODE_NOT_SET) 14376456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke device_mode_ = DEVICE_MODE_ENTERPRISE; 14476456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke if (!allowed_device_modes_.test(device_mode_)) { 14576456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke LOG(ERROR) << "Bad device mode " << device_mode_; 14676456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke ReportResult(EnrollmentStatus::ForStatus( 1476603d7ec67e64b987451975771759ade4e9f19baEvan Cheng EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE)); 1486603d7ec67e64b987451975771759ade4e9f19baEvan Cheng return; 1496603d7ec67e64b987451975771759ade4e9f19baEvan Cheng } 1506603d7ec67e64b987451975771759ade4e9f19baEvan Cheng client_->FetchPolicy(); 1516603d7ec67e64b987451975771759ade4e9f19baEvan Cheng } else { 1526603d7ec67e64b987451975771759ade4e9f19baEvan Cheng LOG(FATAL) << "Registration state changed to " << client_->is_registered() 1536603d7ec67e64b987451975771759ade4e9f19baEvan Cheng << " in step " << enrollment_step_; 1546603d7ec67e64b987451975771759ade4e9f19baEvan Cheng } 155ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman} 156cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner 157cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattnervoid EnrollmentHandlerChromeOS::OnClientError(CloudPolicyClient* client) { 158cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner DCHECK_EQ(client_.get(), client); 159cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner 1606603d7ec67e64b987451975771759ade4e9f19baEvan Cheng if (enrollment_step_ == STEP_ROBOT_AUTH_FETCH) { 1616603d7ec67e64b987451975771759ade4e9f19baEvan Cheng LOG(ERROR) << "API authentication code fetch failed: " 1626603d7ec67e64b987451975771759ade4e9f19baEvan Cheng << client_->status(); 1636603d7ec67e64b987451975771759ade4e9f19baEvan Cheng ReportResult(EnrollmentStatus::ForRobotAuthFetchError(client_->status())); 1646603d7ec67e64b987451975771759ade4e9f19baEvan Cheng } else if (enrollment_step_ < STEP_POLICY_FETCH) { 1656603d7ec67e64b987451975771759ade4e9f19baEvan Cheng ReportResult(EnrollmentStatus::ForRegistrationError(client_->status())); 1666603d7ec67e64b987451975771759ade4e9f19baEvan Cheng } else { 1676603d7ec67e64b987451975771759ade4e9f19baEvan Cheng ReportResult(EnrollmentStatus::ForFetchError(client_->status())); 16834cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Cheng } 16934cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Cheng} 17034cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Cheng 171cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattnervoid EnrollmentHandlerChromeOS::OnStoreLoaded(CloudPolicyStore* store) { 172cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner DCHECK_EQ(store_, store); 173cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner 174cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner if (enrollment_step_ == STEP_LOADING_STORE) { 175cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner // If the |store_| wasn't initialized when StartEnrollment() was 1766603d7ec67e64b987451975771759ade4e9f19baEvan Cheng // called, then AttemptRegistration() bails silently. This gets 1776603d7ec67e64b987451975771759ade4e9f19baEvan Cheng // registration rolling again after the store finishes loading. 1786603d7ec67e64b987451975771759ade4e9f19baEvan Cheng AttemptRegistration(); 1796603d7ec67e64b987451975771759ade4e9f19baEvan Cheng } else if (enrollment_step_ == STEP_STORE_POLICY) { 1806603d7ec67e64b987451975771759ade4e9f19baEvan Cheng ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS)); 1816603d7ec67e64b987451975771759ade4e9f19baEvan Cheng } 1826603d7ec67e64b987451975771759ade4e9f19baEvan Cheng} 1836603d7ec67e64b987451975771759ade4e9f19baEvan Cheng 18434cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Chengvoid EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) { 18534cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Cheng DCHECK_EQ(store_, store); 18634cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Cheng ReportResult(EnrollmentStatus::ForStoreError(store_->status(), 187cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner store_->validation_status())); 18876456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke} 18913d828567812041c1ca1817f4b66fce840903a1fEvan Cheng 19013d828567812041c1ca1817f4b66fce840903a1fEvan Chengvoid EnrollmentHandlerChromeOS::AttemptRegistration() { 19113d828567812041c1ca1817f4b66fce840903a1fEvan Cheng CHECK_EQ(STEP_LOADING_STORE, enrollment_step_); 19213d828567812041c1ca1817f4b66fce840903a1fEvan Cheng if (store_->is_initialized()) { 19313d828567812041c1ca1817f4b66fce840903a1fEvan Cheng enrollment_step_ = STEP_REGISTRATION; 19413d828567812041c1ca1817f4b66fce840903a1fEvan Cheng client_->Register(em::DeviceRegisterRequest::DEVICE, 195b371f457b0ea4a652a9f526ba4375c80ae542252Evan Cheng auth_token_, client_id_, is_auto_enrollment_, 196b371f457b0ea4a652a9f526ba4375c80ae542252Evan Cheng requisition_); 197b371f457b0ea4a652a9f526ba4375c80ae542252Evan Cheng } 198b371f457b0ea4a652a9f526ba4375c80ae542252Evan Cheng} 199a971dbdde27fd4ff53dbebdd4aaf87826d081aa2Evan Cheng 200a971dbdde27fd4ff53dbebdd4aaf87826d081aa2Evan Chengvoid EnrollmentHandlerChromeOS::PolicyValidated( 201a971dbdde27fd4ff53dbebdd4aaf87826d081aa2Evan Cheng DeviceCloudPolicyValidator* validator) { 202a971dbdde27fd4ff53dbebdd4aaf87826d081aa2Evan Cheng CHECK_EQ(STEP_VALIDATION, enrollment_step_); 20313d828567812041c1ca1817f4b66fce840903a1fEvan Cheng if (validator->success()) { 20413d828567812041c1ca1817f4b66fce840903a1fEvan Cheng policy_ = validator->policy().Pass(); 20581bf03eb5cd68243eabb52505105aa5f4a831bf3Dan Gohman username_ = validator->policy_data()->username(); 20681bf03eb5cd68243eabb52505105aa5f4a831bf3Dan Gohman device_id_ = validator->policy_data()->device_id(); 20781bf03eb5cd68243eabb52505105aa5f4a831bf3Dan Gohman 20813d828567812041c1ca1817f4b66fce840903a1fEvan Cheng if (CommandLine::ForCurrentProcess()->HasSwitch( 20913d828567812041c1ca1817f4b66fce840903a1fEvan Cheng chromeos::switches::kEnterpriseEnrollmentSkipRobotAuth)) { 210fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng // For test purposes we allow enrollment to succeed without proper robot 211fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng // account and use the provided value as a token. 212fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng refresh_token_ = kTestingRobotToken; 213fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng enrollment_step_ = STEP_LOCK_DEVICE, 214fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng StartLockDevice(username_, device_mode_, device_id_); 215fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng return; 216fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng } 217fb8075d03f5c87bd57dcc9c5f2304f6b13c55aadEvan Cheng 21830b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey enrollment_step_ = STEP_ROBOT_AUTH_FETCH; 21930b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey client_->FetchRobotAuthCodes(auth_token_); 22030b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey } else { 22130b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey ReportResult(EnrollmentStatus::ForValidationError(validator->status())); 22230b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey } 22330b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey} 22430b8e51addc23fb317c03d093a25828d3d5be45aJim Laskey 22530b8e51addc23fb317c03d093a25828d3d5be45aJim Laskeyvoid EnrollmentHandlerChromeOS::OnRobotAuthCodesFetched( 22634ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner CloudPolicyClient* client) { 22734ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner DCHECK_EQ(client_.get(), client); 22834ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner CHECK_EQ(STEP_ROBOT_AUTH_FETCH, enrollment_step_); 22934ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner 23034ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner enrollment_step_ = STEP_ROBOT_AUTH_REFRESH; 23134ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner 23234ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner gaia::OAuthClientInfo client_info; 2337707a0df5b00c8326a581205639d6b2871f182e9Jim Grosbach client_info.client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id(); 2347707a0df5b00c8326a581205639d6b2871f182e9Jim Grosbach client_info.client_secret = 2357707a0df5b00c8326a581205639d6b2871f182e9Jim Grosbach GaiaUrls::GetInstance()->oauth2_chrome_client_secret(); 2367707a0df5b00c8326a581205639d6b2871f182e9Jim Grosbach client_info.redirect_uri = "oob"; 2377707a0df5b00c8326a581205639d6b2871f182e9Jim Grosbach 2387707a0df5b00c8326a581205639d6b2871f182e9Jim Grosbach // Use the system request context to avoid sending user cookies. 2397707a0df5b00c8326a581205639d6b2871f182e9Jim Grosbach gaia_oauth_client_.reset(new gaia::GaiaOAuthClient( 24076456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke g_browser_process->system_request_context())); 24134ea07692f4cd7c007f1c5062bcebb6d03131077Chris Lattner gaia_oauth_client_->GetTokensFromAuthCode(client_info, 24276456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke client->robot_api_auth_code(), 24376456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke 0 /* max_retries */, 24476456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke this); 2453dfbb558b5e74554104710ed16807fe74ec220a3Chris Lattner} 24676456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke 247dc4a4922d32b470acd68498d41e3b8130cf1e74eChris Lattner// GaiaOAuthClient::Delegate callback for OAuth2 refresh token fetched. 24876456bc40c79fcae4da52d34f96c079d9759257cBrian Gaekevoid EnrollmentHandlerChromeOS::OnGetTokensResponse( 24976456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke const std::string& refresh_token, 2503dfbb558b5e74554104710ed16807fe74ec220a3Chris Lattner const std::string& access_token, 251dc4a4922d32b470acd68498d41e3b8130cf1e74eChris Lattner int expires_in_seconds) { 252dc4a4922d32b470acd68498d41e3b8130cf1e74eChris Lattner CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_); 253dc4a4922d32b470acd68498d41e3b8130cf1e74eChris Lattner 2548a46d342d8cbca7c9c7be6c66007d41329babad0David Greene refresh_token_ = refresh_token; 255dc4a4922d32b470acd68498d41e3b8130cf1e74eChris Lattner 2568a46d342d8cbca7c9c7be6c66007d41329babad0David Greene enrollment_step_ = STEP_LOCK_DEVICE, 257cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner StartLockDevice(username_, device_mode_, device_id_); 25863307c335aa08b0d6a75f81d64d79af7e90eb78bMon P Wang} 25963307c335aa08b0d6a75f81d64d79af7e90eb78bMon P Wang 2601edb8e0910db4cda46a81a4abad80a2a755442aaDan Gohman// GaiaOAuthClient::Delegate 26163307c335aa08b0d6a75f81d64d79af7e90eb78bMon P Wangvoid EnrollmentHandlerChromeOS::OnRefreshTokenResponse( 26214152b480d09c7ca912af7c06d00b0ff3912e4f5Dan Gohman const std::string& access_token, 26314152b480d09c7ca912af7c06d00b0ff3912e4f5Dan Gohman int expires_in_seconds) { 26414152b480d09c7ca912af7c06d00b0ff3912e4f5Dan Gohman // We never use the code that should trigger this callback. 26514152b480d09c7ca912af7c06d00b0ff3912e4f5Dan Gohman LOG(FATAL) << "Unexpected callback invoked"; 26614152b480d09c7ca912af7c06d00b0ff3912e4f5Dan Gohman} 26763307c335aa08b0d6a75f81d64d79af7e90eb78bMon P Wang 268cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattner// GaiaOAuthClient::Delegate OAuth2 error when fetching refresh token request. 269cd5bad37112ba22f4c546e5443714570b4104bb6Chris Lattnervoid EnrollmentHandlerChromeOS::OnOAuthError() { 2706d1b89e74f98470d05666ca9f59a8ec5d04b5eb4Dan Gohman CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_); 27176456bc40c79fcae4da52d34f96c079d9759257cBrian Gaeke // OnOAuthError is only called if the request is bad (malformed) or the 2726ade6f55a836129af634074e96f660ff23f59a30Dan Gohman // response is bad (empty access token returned). 2736ade6f55a836129af634074e96f660ff23f59a30Dan Gohman LOG(ERROR) << "OAuth protocol error while fetching API refresh token."; 2746ade6f55a836129af634074e96f660ff23f59a30Dan Gohman ReportResult( 2756ade6f55a836129af634074e96f660ff23f59a30Dan Gohman EnrollmentStatus::ForRobotRefreshFetchError(net::HTTP_BAD_REQUEST)); 2766ade6f55a836129af634074e96f660ff23f59a30Dan Gohman} 2776d1b89e74f98470d05666ca9f59a8ec5d04b5eb4Dan Gohman 2786ade6f55a836129af634074e96f660ff23f59a30Dan Gohman// GaiaOAuthClient::Delegate network error when fetching refresh token. 27915acadde5f87703da5f36721a19c09a7e3f97f53Bob Wilsonvoid EnrollmentHandlerChromeOS::OnNetworkError(int response_code) { 28015acadde5f87703da5f36721a19c09a7e3f97f53Bob Wilson CHECK_EQ(STEP_ROBOT_AUTH_REFRESH, enrollment_step_); 28115acadde5f87703da5f36721a19c09a7e3f97f53Bob Wilson LOG(ERROR) << "Network error while fetching API refresh token: " 28215acadde5f87703da5f36721a19c09a7e3f97f53Bob Wilson << response_code; 28315acadde5f87703da5f36721a19c09a7e3f97f53Bob Wilson ReportResult( 28415acadde5f87703da5f36721a19c09a7e3f97f53Bob Wilson EnrollmentStatus::ForRobotRefreshFetchError(response_code)); 285d463a7446402f0771465fe66fe0a7d9f72534902Dan Gohman} 286d463a7446402f0771465fe66fe0a7d9f72534902Dan Gohman 287d463a7446402f0771465fe66fe0a7d9f72534902Dan Gohmanvoid EnrollmentHandlerChromeOS::StartLockDevice( 288d463a7446402f0771465fe66fe0a7d9f72534902Dan Gohman const std::string& user, 289d463a7446402f0771465fe66fe0a7d9f72534902Dan Gohman DeviceMode device_mode, 290d463a7446402f0771465fe66fe0a7d9f72534902Dan Gohman const std::string& device_id) { 291d463a7446402f0771465fe66fe0a7d9f72534902Dan Gohman CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_); 292743d0a1f831f1d5a3141a6ca730558f40c35690aAlkis Evlogimenos // Since this method is also called directly. 293743d0a1f831f1d5a3141a6ca730558f40c35690aAlkis Evlogimenos weak_ptr_factory_.InvalidateWeakPtrs(); 294743d0a1f831f1d5a3141a6ca730558f40c35690aAlkis Evlogimenos 295743d0a1f831f1d5a3141a6ca730558f40c35690aAlkis Evlogimenos install_attributes_->LockDevice( 296743d0a1f831f1d5a3141a6ca730558f40c35690aAlkis Evlogimenos user, device_mode, device_id, 297853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohman base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult, 298853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohman weak_ptr_factory_.GetWeakPtr(), 299853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohman user, 300853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohman device_mode, 301853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohman device_id)); 302853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohman} 303853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohman 304853d3fb8d24fab2258e9cd5dce3ec8ff4189eedaDan Gohmanvoid EnrollmentHandlerChromeOS::HandleLockDeviceResult( 3050bbcd6bfd1a90c2aa7386a88ba9fc9aba47d03a7Brian Gaeke const std::string& user, 306f24d879520a615a03f19ced3c7491f7b51934d1cChris Lattner DeviceMode device_mode, 307deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve const std::string& device_id, 308deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve EnterpriseInstallAttributes::LockResult lock_result) { 309deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve CHECK_EQ(STEP_LOCK_DEVICE, enrollment_step_); 310deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve switch (lock_result) { 311deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve case EnterpriseInstallAttributes::LOCK_SUCCESS: 31246d6a1aeb549a2e4ccd982a1a2cefda541d79c52Vikram S. Adve // Get the token service so we can store our robot refresh token. 313c0b9dc5be79f009d260edb5cd5e1d8346587aaa2Alkis Evlogimenos enrollment_step_ = STEP_STORE_ROBOT_AUTH; 314deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve chromeos::DeviceOAuth2TokenServiceFactory::Get()->SetAndSaveRefreshToken( 31546d6a1aeb549a2e4ccd982a1a2cefda541d79c52Vikram S. Adve refresh_token_, 316deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve base::Bind(&EnrollmentHandlerChromeOS::HandleRobotAuthTokenStored, 31783706a5a3a6f19451765b743c5a72b62f74eb71aChris Lattner weak_ptr_factory_.GetWeakPtr())); 318da44b151259525abc9c299f89b9532f3a9883b4eBrian Gaeke return; 319ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman case EnterpriseInstallAttributes::LOCK_NOT_READY: 320c475c3608a5f0fc0c6bd43da04ae786649690070Dan Gohman // We wait up to |kLockRetryTimeoutMs| milliseconds and if it hasn't 321c475c3608a5f0fc0c6bd43da04ae786649690070Dan Gohman // succeeded by then show an error to the user and stop the enrollment. 322c475c3608a5f0fc0c6bd43da04ae786649690070Dan Gohman if (lockbox_init_duration_ < kLockRetryTimeoutMs) { 323c475c3608a5f0fc0c6bd43da04ae786649690070Dan Gohman // InstallAttributes not ready yet, retry later. 324c475c3608a5f0fc0c6bd43da04ae786649690070Dan Gohman LOG(WARNING) << "Install Attributes not ready yet will retry in " 325c475c3608a5f0fc0c6bd43da04ae786649690070Dan Gohman << kLockRetryIntervalMs << "ms."; 326f24d879520a615a03f19ced3c7491f7b51934d1cChris Lattner base::MessageLoop::current()->PostDelayedTask( 327f24d879520a615a03f19ced3c7491f7b51934d1cChris Lattner FROM_HERE, 328f24d879520a615a03f19ced3c7491f7b51934d1cChris Lattner base::Bind(&EnrollmentHandlerChromeOS::StartLockDevice, 329f24d879520a615a03f19ced3c7491f7b51934d1cChris Lattner weak_ptr_factory_.GetWeakPtr(), 330f24d879520a615a03f19ced3c7491f7b51934d1cChris Lattner user, device_mode, device_id), 331f24d879520a615a03f19ced3c7491f7b51934d1cChris Lattner base::TimeDelta::FromMilliseconds(kLockRetryIntervalMs)); 3328e7ae9860bd1f29c95e4e10fe151a22aaafafef9Chris Lattner lockbox_init_duration_ += kLockRetryIntervalMs; 3338e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman } else { 3348e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman ReportResult(EnrollmentStatus::ForStatus( 3358e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman EnrollmentStatus::STATUS_LOCK_TIMEOUT)); 3368e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman } 3378e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman return; 3388e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman case EnterpriseInstallAttributes::LOCK_BACKEND_ERROR: 3398e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman ReportResult(EnrollmentStatus::ForStatus( 3408e5f2c6f65841542e2a7092553fe42a00048e4c7Dan Gohman EnrollmentStatus::STATUS_LOCK_ERROR)); 3410370fad74b48388412c52d1325512f2c218487faEvan Cheng return; 3420370fad74b48388412c52d1325512f2c218487faEvan Cheng case EnterpriseInstallAttributes::LOCK_WRONG_USER: 3430370fad74b48388412c52d1325512f2c218487faEvan Cheng LOG(ERROR) << "Enrollment cannot proceed because the InstallAttrs " 3440370fad74b48388412c52d1325512f2c218487faEvan Cheng << "has been locked already!"; 3452bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng ReportResult(EnrollmentStatus::ForStatus( 3462bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng EnrollmentStatus::STATUS_LOCK_WRONG_USER)); 3472bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng return; 3482bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng } 3492bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng 3502bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng NOTREACHED() << "Invalid lock result " << lock_result; 3512bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng ReportResult(EnrollmentStatus::ForStatus( 3522bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng EnrollmentStatus::STATUS_LOCK_ERROR)); 3532bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng} 3542bdb7d0cc88881857073b36f4a09ebe2f2008c24Evan Cheng 35573e884bb3e971b1e794ba2501df15138f73b8b1aDale Johannesenvoid EnrollmentHandlerChromeOS::HandleRobotAuthTokenStored(bool result) { 3563b1906f48d0b541e5be0bc1918c94a454e908bc0Dale Johannesen CHECK_EQ(STEP_STORE_ROBOT_AUTH, enrollment_step_); 35773e884bb3e971b1e794ba2501df15138f73b8b1aDale Johannesen 35873e884bb3e971b1e794ba2501df15138f73b8b1aDale Johannesen if (!result) { 359f13a3f4dd1eaa89ca9a64a1e820b089facca3366Brian Gaeke LOG(ERROR) << "Failed to store API refresh token."; 360f13a3f4dd1eaa89ca9a64a1e820b089facca3366Brian Gaeke ReportResult(EnrollmentStatus::ForStatus( 3612d8e3d20be377112999670f210200b3658762571Chris Lattner EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED)); 362f13a3f4dd1eaa89ca9a64a1e820b089facca3366Brian Gaeke return; 363da86bdc75c8d36cb7b1f4e785a3749d7c8f8e638Brian Gaeke } 364da86bdc75c8d36cb7b1f4e785a3749d7c8f8e638Brian Gaeke 365da86bdc75c8d36cb7b1f4e785a3749d7c8f8e638Brian Gaeke enrollment_step_ = STEP_STORE_POLICY; 366da86bdc75c8d36cb7b1f4e785a3749d7c8f8e638Brian Gaeke store_->InstallInitialPolicy(*policy_); 367c07d8d8a26f63dfc54dbd0e1ff776763ec6443adBrian Gaeke} 36820a6d8e63056cc2025e7143a5f7226e079e0bc80Chris Lattner 369c07d8d8a26f63dfc54dbd0e1ff776763ec6443adBrian Gaekevoid EnrollmentHandlerChromeOS::Stop() { 370f71cb015c1386ff8adc9ef0aa03fc0f0fc4a6e3eChris Lattner if (client_.get()) 371f71cb015c1386ff8adc9ef0aa03fc0f0fc4a6e3eChris Lattner client_->RemoveObserver(this); 3721b2eb0e8a6aaf034675b17be6d853cb1c666200fChris Lattner enrollment_step_ = STEP_FINISHED; 373f71cb015c1386ff8adc9ef0aa03fc0f0fc4a6e3eChris Lattner weak_ptr_factory_.InvalidateWeakPtrs(); 3748e7ae9860bd1f29c95e4e10fe151a22aaafafef9Chris Lattner completion_callback_.Reset(); 375fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman} 3768560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke 3778560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaekevoid EnrollmentHandlerChromeOS::ReportResult(EnrollmentStatus status) { 3788560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke EnrollmentCallback callback = completion_callback_; 3798560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke Stop(); 3808560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke 3818560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke if (status.status() != EnrollmentStatus::STATUS_SUCCESS) { 3828560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke LOG(WARNING) << "Enrollment failed: " << status.status() 3833dfbb558b5e74554104710ed16807fe74ec220a3Chris Lattner << " " << status.client_status() 3848560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke << " " << status.validation_status() 3858560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke << " " << status.store_status(); 3868560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke } 3878560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke 3888560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke if (!callback.is_null()) 3898560af4f5fe589cf792bd44617c2308c4f087ba8Brian Gaeke callback.Run(status); 3903dfbb558b5e74554104710ed16807fe74ec220a3Chris Lattner} 391deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve 392deb9654056939a12981446f6ed1139dca3412746Vikram S. Adve} // namespace policy 3931cd1d98232c3c3a0bd3810c3bf6c2572ea02f208Daniel Dunbar