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/policy/cloud/cloud_policy_client.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "chrome/browser/policy/cloud/device_management_service.h"
12 #include "google_apis/gaia/gaia_constants.h"
13 #include "google_apis/gaia/gaia_urls.h"
15 namespace em = enterprise_management;
21 // Translates the DeviceRegisterResponse::DeviceMode |mode| to the enum used
22 // internally to represent different device modes.
23 DeviceMode TranslateProtobufDeviceMode(
24 em::DeviceRegisterResponse::DeviceMode mode) {
26 case em::DeviceRegisterResponse::ENTERPRISE:
27 return DEVICE_MODE_ENTERPRISE;
28 case em::DeviceRegisterResponse::RETAIL:
29 return DEVICE_MODE_RETAIL_KIOSK;
31 LOG(ERROR) << "Unknown enrollment mode in registration response: " << mode;
32 return DEVICE_MODE_NOT_SET;
35 bool IsChromePolicy(const std::string& type) {
36 return type == dm_protocol::kChromeDevicePolicyType ||
37 type == GetChromeUserPolicyType();
42 CloudPolicyClient::Observer::~Observer() {}
44 void CloudPolicyClient::Observer::OnRobotAuthCodesFetched(
45 CloudPolicyClient* client) {}
47 CloudPolicyClient::StatusProvider::~StatusProvider() {}
49 CloudPolicyClient::CloudPolicyClient(const std::string& machine_id,
50 const std::string& machine_model,
51 UserAffiliation user_affiliation,
52 StatusProvider* status_provider,
53 DeviceManagementService* service)
54 : machine_id_(machine_id),
55 machine_model_(machine_model),
56 user_affiliation_(user_affiliation),
57 device_mode_(DEVICE_MODE_NOT_SET),
58 submit_machine_id_(false),
59 public_key_version_(-1),
60 public_key_version_valid_(false),
61 invalidation_version_(0),
62 fetched_invalidation_version_(0),
63 service_(service), // Can be NULL for unit tests.
64 status_provider_(status_provider), // Can be NULL for unit tests.
65 status_(DM_STATUS_SUCCESS) {
68 CloudPolicyClient::~CloudPolicyClient() {
69 STLDeleteValues(&responses_);
72 void CloudPolicyClient::SetupRegistration(const std::string& dm_token,
73 const std::string& client_id) {
74 DCHECK(!dm_token.empty());
75 DCHECK(!client_id.empty());
76 DCHECK(!is_registered());
79 client_id_ = client_id;
81 STLDeleteValues(&responses_);
83 NotifyRegistrationStateChanged();
86 void CloudPolicyClient::Register(em::DeviceRegisterRequest::Type type,
87 const std::string& auth_token,
88 const std::string& client_id,
89 bool is_auto_enrollement,
90 const std::string& requisition) {
92 DCHECK(!auth_token.empty());
93 DCHECK(!is_registered());
95 if (client_id.empty()) {
96 // Generate a new client ID. This is intentionally done on each new
97 // registration request in order to preserve privacy. Reusing IDs would mean
98 // the server could track clients by their registration attempts.
99 client_id_ = base::GenerateGUID();
101 client_id_ = client_id;
105 service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION));
106 request_job_->SetOAuthToken(auth_token);
107 request_job_->SetClientID(client_id_);
109 em::DeviceRegisterRequest* request =
110 request_job_->GetRequest()->mutable_register_request();
111 if (!client_id.empty())
112 request->set_reregister(true);
113 request->set_type(type);
114 if (!machine_id_.empty())
115 request->set_machine_id(machine_id_);
116 if (!machine_model_.empty())
117 request->set_machine_model(machine_model_);
118 if (is_auto_enrollement)
119 request->set_auto_enrolled(true);
120 if (!requisition.empty())
121 request->set_requisition(requisition);
123 request_job_->SetRetryCallback(
124 base::Bind(&CloudPolicyClient::OnRetryRegister, base::Unretained(this)));
126 request_job_->Start(base::Bind(&CloudPolicyClient::OnRegisterCompleted,
127 base::Unretained(this)));
130 void CloudPolicyClient::SetInvalidationInfo(
132 const std::string& payload) {
133 invalidation_version_ = version;
134 invalidation_payload_ = payload;
137 void CloudPolicyClient::FetchPolicy() {
138 CHECK(is_registered());
139 CHECK(!namespaces_to_fetch_.empty());
142 service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH));
143 request_job_->SetDMToken(dm_token_);
144 request_job_->SetClientID(client_id_);
145 request_job_->SetUserAffiliation(user_affiliation_);
147 em::DeviceManagementRequest* request = request_job_->GetRequest();
149 // Build policy fetch requests.
150 em::DevicePolicyRequest* policy_request = request->mutable_policy_request();
151 for (NamespaceSet::iterator it = namespaces_to_fetch_.begin();
152 it != namespaces_to_fetch_.end(); ++it) {
153 em::PolicyFetchRequest* fetch_request = policy_request->add_request();
154 fetch_request->set_policy_type(it->first);
155 if (!it->second.empty())
156 fetch_request->set_settings_entity_id(it->second);
158 #if defined(OS_CHROMEOS)
159 // All policy types on ChromeOS ask for a signed policy blob.
160 fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA);
162 // Don't request signed blobs for desktop policy.
163 fetch_request->set_signature_type(em::PolicyFetchRequest::NONE);
165 if (public_key_version_valid_)
166 fetch_request->set_public_key_version(public_key_version_);
168 // These fields are included only in requests for chrome policy.
169 if (IsChromePolicy(it->first)) {
170 if (submit_machine_id_ && !machine_id_.empty())
171 fetch_request->set_machine_id(machine_id_);
172 if (!last_policy_timestamp_.is_null()) {
173 base::TimeDelta timestamp(
174 last_policy_timestamp_ - base::Time::UnixEpoch());
175 fetch_request->set_timestamp(timestamp.InMilliseconds());
177 if (!invalidation_payload_.empty()) {
178 fetch_request->set_invalidation_version(invalidation_version_);
179 fetch_request->set_invalidation_payload(invalidation_payload_);
185 if (status_provider_) {
186 if (!status_provider_->GetDeviceStatus(
187 request->mutable_device_status_report_request())) {
188 request->clear_device_status_report_request();
190 if (!status_provider_->GetSessionStatus(
191 request->mutable_session_status_report_request())) {
192 request->clear_session_status_report_request();
196 // Set the fetched invalidation version to the latest invalidation version
197 // since it is now the invalidation version used for the latest fetch.
198 fetched_invalidation_version_ = invalidation_version_;
201 request_job_->Start(base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted,
202 base::Unretained(this)));
205 void CloudPolicyClient::FetchRobotAuthCodes(const std::string& auth_token) {
206 CHECK(is_registered());
207 DCHECK(!auth_token.empty());
209 request_job_.reset(service_->CreateJob(
210 DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH));
211 // The credentials of a domain user are needed in order to mint a new OAuth2
212 // authorization token for the robot account.
213 request_job_->SetOAuthToken(auth_token);
214 request_job_->SetDMToken(dm_token_);
215 request_job_->SetClientID(client_id_);
217 em::DeviceServiceApiAccessRequest* request =
218 request_job_->GetRequest()->mutable_service_api_access_request();
219 request->set_oauth2_client_id(
220 GaiaUrls::GetInstance()->oauth2_chrome_client_id());
221 request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope);
224 base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
225 base::Unretained(this)));
228 void CloudPolicyClient::Unregister() {
231 service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION));
232 request_job_->SetDMToken(dm_token_);
233 request_job_->SetClientID(client_id_);
234 request_job_->GetRequest()->mutable_unregister_request();
235 request_job_->Start(base::Bind(&CloudPolicyClient::OnUnregisterCompleted,
236 base::Unretained(this)));
239 void CloudPolicyClient::UploadCertificate(
240 const std::string& certificate_data,
241 const CloudPolicyClient::StatusCallback& callback) {
242 CHECK(is_registered());
244 service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE));
245 request_job_->SetDMToken(dm_token_);
246 request_job_->SetClientID(client_id_);
248 em::DeviceManagementRequest* request = request_job_->GetRequest();
249 request->mutable_cert_upload_request()->set_device_certificate(
252 DeviceManagementRequestJob::Callback job_callback = base::Bind(
253 &CloudPolicyClient::OnCertificateUploadCompleted,
254 base::Unretained(this),
256 request_job_->Start(job_callback);
259 void CloudPolicyClient::AddObserver(Observer* observer) {
260 observers_.AddObserver(observer);
263 void CloudPolicyClient::RemoveObserver(Observer* observer) {
264 observers_.RemoveObserver(observer);
267 void CloudPolicyClient::AddNamespaceToFetch(const PolicyNamespaceKey& key) {
268 namespaces_to_fetch_.insert(key);
271 void CloudPolicyClient::RemoveNamespaceToFetch(const PolicyNamespaceKey& key) {
272 namespaces_to_fetch_.erase(key);
275 const em::PolicyFetchResponse* CloudPolicyClient::GetPolicyFor(
276 const PolicyNamespaceKey& key) const {
277 ResponseMap::const_iterator it = responses_.find(key);
278 return it == responses_.end() ? NULL : it->second;
281 void CloudPolicyClient::OnRetryRegister(DeviceManagementRequestJob* job) {
282 DCHECK_EQ(request_job_.get(), job);
283 // If the initial request managed to get to the server but the response didn't
284 // arrive at the client then retrying with the same client ID will fail.
285 // Set the re-registration flag so that the server accepts it.
286 // If the server hasn't seen the client ID before then it will also accept
287 // the re-registration.
288 job->GetRequest()->mutable_register_request()->set_reregister(true);
291 void CloudPolicyClient::OnRegisterCompleted(
292 DeviceManagementStatus status,
294 const em::DeviceManagementResponse& response) {
295 if (status == DM_STATUS_SUCCESS &&
296 (!response.has_register_response() ||
297 !response.register_response().has_device_management_token())) {
298 LOG(WARNING) << "Invalid registration response.";
299 status = DM_STATUS_RESPONSE_DECODING_ERROR;
303 if (status == DM_STATUS_SUCCESS) {
304 dm_token_ = response.register_response().device_management_token();
305 DVLOG(1) << "Client registration complete - DMToken = " << dm_token_;
307 // Device mode is only relevant for device policy really, it's the
308 // responsibility of the consumer of the field to check validity.
309 device_mode_ = DEVICE_MODE_NOT_SET;
310 if (response.register_response().has_enrollment_type()) {
311 device_mode_ = TranslateProtobufDeviceMode(
312 response.register_response().enrollment_type());
315 NotifyRegistrationStateChanged();
321 void CloudPolicyClient::OnFetchRobotAuthCodesCompleted(
322 DeviceManagementStatus status,
324 const em::DeviceManagementResponse& response) {
325 if (status == DM_STATUS_SUCCESS &&
326 (!response.has_service_api_access_response() ||
327 response.service_api_access_response().auth_code().empty())) {
328 LOG(WARNING) << "Invalid service api access response.";
329 status = DM_STATUS_RESPONSE_DECODING_ERROR;
333 if (status == DM_STATUS_SUCCESS) {
334 robot_api_auth_code_ = response.service_api_access_response().auth_code();
335 DVLOG(1) << "Device robot account auth code fetch complete - code = "
336 << robot_api_auth_code_;
338 NotifyRobotAuthCodesFetched();
344 void CloudPolicyClient::OnPolicyFetchCompleted(
345 DeviceManagementStatus status,
347 const em::DeviceManagementResponse& response) {
348 if (status == DM_STATUS_SUCCESS) {
349 if (!response.has_policy_response() ||
350 response.policy_response().response_size() == 0) {
351 LOG(WARNING) << "Empty policy response.";
352 status = DM_STATUS_RESPONSE_DECODING_ERROR;
357 if (status == DM_STATUS_SUCCESS) {
358 const em::DevicePolicyResponse& policy_response =
359 response.policy_response();
360 STLDeleteValues(&responses_);
361 for (int i = 0; i < policy_response.response_size(); ++i) {
362 const em::PolicyFetchResponse& response = policy_response.response(i);
363 em::PolicyData policy_data;
364 if (!policy_data.ParseFromString(response.policy_data()) ||
365 !policy_data.IsInitialized() ||
366 !policy_data.has_policy_type()) {
367 LOG(WARNING) << "Invalid PolicyData received, ignoring";
370 const std::string& type = policy_data.policy_type();
371 std::string entity_id;
372 if (policy_data.has_settings_entity_id())
373 entity_id = policy_data.settings_entity_id();
374 PolicyNamespaceKey key(type, entity_id);
375 if (ContainsKey(responses_, key)) {
376 LOG(WARNING) << "Duplicate PolicyFetchResponse for type: "
377 << type << ", entity: " << entity_id << ", ignoring";
380 responses_[key] = new em::PolicyFetchResponse(response);
382 if (status_provider_)
383 status_provider_->OnSubmittedSuccessfully();
384 NotifyPolicyFetched();
390 void CloudPolicyClient::OnUnregisterCompleted(
391 DeviceManagementStatus status,
393 const em::DeviceManagementResponse& response) {
394 if (status == DM_STATUS_SUCCESS && !response.has_unregister_response()) {
395 // Assume unregistration has succeeded either way.
396 LOG(WARNING) << "Empty unregistration response.";
400 if (status == DM_STATUS_SUCCESS) {
402 NotifyRegistrationStateChanged();
408 void CloudPolicyClient::OnCertificateUploadCompleted(
409 const CloudPolicyClient::StatusCallback& callback,
410 DeviceManagementStatus status,
412 const enterprise_management::DeviceManagementResponse& response) {
413 if (status == DM_STATUS_SUCCESS && !response.has_cert_upload_response()) {
414 LOG(WARNING) << "Empty upload certificate response.";
420 if (status != DM_STATUS_SUCCESS) {
428 void CloudPolicyClient::NotifyPolicyFetched() {
429 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyFetched(this));
432 void CloudPolicyClient::NotifyRegistrationStateChanged() {
433 FOR_EACH_OBSERVER(Observer, observers_, OnRegistrationStateChanged(this));
436 void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
437 FOR_EACH_OBSERVER(Observer, observers_, OnRobotAuthCodesFetched(this));
440 void CloudPolicyClient::NotifyClientError() {
441 FOR_EACH_OBSERVER(Observer, observers_, OnClientError(this));
444 } // namespace policy