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 "components/policy/core/common/cloud/cloud_policy_client.h"
8 #include "base/bind_helpers.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "components/policy/core/common/cloud/device_management_service.h"
13 #include "google_apis/gaia/gaia_constants.h"
14 #include "google_apis/gaia/gaia_urls.h"
15 #include "net/url_request/url_request_context_getter.h"
17 namespace em
= enterprise_management
;
23 // Translates the DeviceRegisterResponse::DeviceMode |mode| to the enum used
24 // internally to represent different device modes.
25 DeviceMode
TranslateProtobufDeviceMode(
26 em::DeviceRegisterResponse::DeviceMode mode
) {
28 case em::DeviceRegisterResponse::ENTERPRISE
:
29 return DEVICE_MODE_ENTERPRISE
;
30 case em::DeviceRegisterResponse::RETAIL
:
31 return DEVICE_MODE_LEGACY_RETAIL_MODE
;
33 LOG(ERROR
) << "Unknown enrollment mode in registration response: " << mode
;
34 return DEVICE_MODE_NOT_SET
;
37 bool IsChromePolicy(const std::string
& type
) {
38 return type
== dm_protocol::kChromeDevicePolicyType
||
39 type
== GetChromeUserPolicyType();
44 CloudPolicyClient::Observer::~Observer() {}
46 void CloudPolicyClient::Observer::OnRobotAuthCodesFetched(
47 CloudPolicyClient
* client
) {}
49 CloudPolicyClient::CloudPolicyClient(
50 const std::string
& machine_id
,
51 const std::string
& machine_model
,
52 const std::string
& verification_key_hash
,
53 UserAffiliation user_affiliation
,
54 DeviceManagementService
* service
,
55 scoped_refptr
<net::URLRequestContextGetter
> request_context
)
56 : machine_id_(machine_id
),
57 machine_model_(machine_model
),
58 verification_key_hash_(verification_key_hash
),
59 user_affiliation_(user_affiliation
),
60 device_mode_(DEVICE_MODE_NOT_SET
),
61 submit_machine_id_(false),
62 public_key_version_(-1),
63 public_key_version_valid_(false),
64 invalidation_version_(0),
65 fetched_invalidation_version_(0),
66 service_(service
), // Can be null for unit tests.
67 status_(DM_STATUS_SUCCESS
),
68 request_context_(request_context
) {
71 CloudPolicyClient::~CloudPolicyClient() {
72 STLDeleteValues(&responses_
);
75 void CloudPolicyClient::SetupRegistration(const std::string
& dm_token
,
76 const std::string
& client_id
) {
77 DCHECK(!dm_token
.empty());
78 DCHECK(!client_id
.empty());
79 DCHECK(!is_registered());
82 client_id_
= client_id
;
83 request_jobs_
.clear();
84 policy_fetch_request_job_
.reset();
85 STLDeleteValues(&responses_
);
87 NotifyRegistrationStateChanged();
90 void CloudPolicyClient::Register(em::DeviceRegisterRequest::Type type
,
91 em::DeviceRegisterRequest::Flavor flavor
,
92 const std::string
& auth_token
,
93 const std::string
& client_id
,
94 const std::string
& requisition
,
95 const std::string
& current_state_key
) {
97 DCHECK(!auth_token
.empty());
98 DCHECK(!is_registered());
100 if (client_id
.empty()) {
101 // Generate a new client ID. This is intentionally done on each new
102 // registration request in order to preserve privacy. Reusing IDs would mean
103 // the server could track clients by their registration attempts.
104 client_id_
= base::GenerateGUID();
106 client_id_
= client_id
;
109 policy_fetch_request_job_
.reset(
110 service_
->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION
,
111 GetRequestContext()));
112 policy_fetch_request_job_
->SetOAuthToken(auth_token
);
113 policy_fetch_request_job_
->SetClientID(client_id_
);
115 em::DeviceRegisterRequest
* request
=
116 policy_fetch_request_job_
->GetRequest()->mutable_register_request();
117 if (!client_id
.empty())
118 request
->set_reregister(true);
119 request
->set_type(type
);
120 if (!machine_id_
.empty())
121 request
->set_machine_id(machine_id_
);
122 if (!machine_model_
.empty())
123 request
->set_machine_model(machine_model_
);
124 if (!requisition
.empty())
125 request
->set_requisition(requisition
);
126 if (!current_state_key
.empty())
127 request
->set_server_backed_state_key(current_state_key
);
128 request
->set_flavor(flavor
);
130 policy_fetch_request_job_
->SetRetryCallback(
131 base::Bind(&CloudPolicyClient::OnRetryRegister
, base::Unretained(this)));
133 policy_fetch_request_job_
->Start(
134 base::Bind(&CloudPolicyClient::OnRegisterCompleted
,
135 base::Unretained(this)));
138 void CloudPolicyClient::SetInvalidationInfo(
140 const std::string
& payload
) {
141 invalidation_version_
= version
;
142 invalidation_payload_
= payload
;
145 void CloudPolicyClient::FetchPolicy() {
146 CHECK(is_registered());
147 CHECK(!types_to_fetch_
.empty());
149 policy_fetch_request_job_
.reset(
150 service_
->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH
,
151 GetRequestContext()));
152 policy_fetch_request_job_
->SetDMToken(dm_token_
);
153 policy_fetch_request_job_
->SetClientID(client_id_
);
154 policy_fetch_request_job_
->SetUserAffiliation(user_affiliation_
);
156 em::DeviceManagementRequest
* request
=
157 policy_fetch_request_job_
->GetRequest();
159 // Build policy fetch requests.
160 em::DevicePolicyRequest
* policy_request
= request
->mutable_policy_request();
161 for (const auto& type_to_fetch
: types_to_fetch_
) {
162 em::PolicyFetchRequest
* fetch_request
= policy_request
->add_request();
163 fetch_request
->set_policy_type(type_to_fetch
.first
);
164 if (!type_to_fetch
.second
.empty())
165 fetch_request
->set_settings_entity_id(type_to_fetch
.second
);
167 // Request signed policy blobs to help prevent tampering on the client.
168 fetch_request
->set_signature_type(em::PolicyFetchRequest::SHA1_RSA
);
169 if (public_key_version_valid_
)
170 fetch_request
->set_public_key_version(public_key_version_
);
172 if (!verification_key_hash_
.empty())
173 fetch_request
->set_verification_key_hash(verification_key_hash_
);
175 // These fields are included only in requests for chrome policy.
176 if (IsChromePolicy(type_to_fetch
.first
)) {
177 if (submit_machine_id_
&& !machine_id_
.empty())
178 fetch_request
->set_machine_id(machine_id_
);
179 if (!last_policy_timestamp_
.is_null()) {
180 base::TimeDelta
timestamp(
181 last_policy_timestamp_
- base::Time::UnixEpoch());
182 fetch_request
->set_timestamp(timestamp
.InMilliseconds());
184 if (!invalidation_payload_
.empty()) {
185 fetch_request
->set_invalidation_version(invalidation_version_
);
186 fetch_request
->set_invalidation_payload(invalidation_payload_
);
191 // Add device state keys.
192 if (!state_keys_to_upload_
.empty()) {
193 em::DeviceStateKeyUpdateRequest
* key_update_request
=
194 request
->mutable_device_state_key_update_request();
195 for (std::vector
<std::string
>::const_iterator
key(
196 state_keys_to_upload_
.begin());
197 key
!= state_keys_to_upload_
.end();
199 key_update_request
->add_server_backed_state_key(*key
);
203 // Set the fetched invalidation version to the latest invalidation version
204 // since it is now the invalidation version used for the latest fetch.
205 fetched_invalidation_version_
= invalidation_version_
;
208 policy_fetch_request_job_
->Start(
209 base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted
,
210 base::Unretained(this)));
213 void CloudPolicyClient::FetchRobotAuthCodes(const std::string
& auth_token
) {
214 CHECK(is_registered());
215 DCHECK(!auth_token
.empty());
217 policy_fetch_request_job_
.reset(service_
->CreateJob(
218 DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH
,
219 GetRequestContext()));
220 // The credentials of a domain user are needed in order to mint a new OAuth2
221 // authorization token for the robot account.
222 policy_fetch_request_job_
->SetOAuthToken(auth_token
);
223 policy_fetch_request_job_
->SetDMToken(dm_token_
);
224 policy_fetch_request_job_
->SetClientID(client_id_
);
226 em::DeviceServiceApiAccessRequest
* request
=
227 policy_fetch_request_job_
->GetRequest()->
228 mutable_service_api_access_request();
229 request
->set_oauth2_client_id(
230 GaiaUrls::GetInstance()->oauth2_chrome_client_id());
231 request
->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope
);
233 policy_fetch_request_job_
->Start(
234 base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted
,
235 base::Unretained(this)));
238 void CloudPolicyClient::Unregister() {
240 policy_fetch_request_job_
.reset(
241 service_
->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION
,
242 GetRequestContext()));
243 policy_fetch_request_job_
->SetDMToken(dm_token_
);
244 policy_fetch_request_job_
->SetClientID(client_id_
);
245 policy_fetch_request_job_
->GetRequest()->mutable_unregister_request();
246 policy_fetch_request_job_
->Start(
247 base::Bind(&CloudPolicyClient::OnUnregisterCompleted
,
248 base::Unretained(this)));
251 void CloudPolicyClient::UploadCertificate(
252 const std::string
& certificate_data
,
253 const CloudPolicyClient::StatusCallback
& callback
) {
254 CHECK(is_registered());
255 scoped_ptr
<DeviceManagementRequestJob
> request_job(
256 service_
->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE
,
257 GetRequestContext()));
258 request_job
->SetDMToken(dm_token_
);
259 request_job
->SetClientID(client_id_
);
261 em::DeviceManagementRequest
* request
= request_job
->GetRequest();
262 request
->mutable_cert_upload_request()->set_device_certificate(
265 const DeviceManagementRequestJob::Callback job_callback
=
266 base::Bind(&CloudPolicyClient::OnCertificateUploadCompleted
,
267 base::Unretained(this), request_job
.get(), callback
);
269 request_jobs_
.push_back(request_job
.Pass());
270 request_jobs_
.back()->Start(job_callback
);
273 void CloudPolicyClient::UploadDeviceStatus(
274 const em::DeviceStatusReportRequest
* device_status
,
275 const em::SessionStatusReportRequest
* session_status
,
276 const CloudPolicyClient::StatusCallback
& callback
) {
277 CHECK(is_registered());
278 // Should pass in at least one type of status.
279 DCHECK(device_status
|| session_status
);
280 scoped_ptr
<DeviceManagementRequestJob
> request_job(
281 service_
->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_STATUS
,
282 GetRequestContext()));
283 request_job
->SetDMToken(dm_token_
);
284 request_job
->SetClientID(client_id_
);
286 em::DeviceManagementRequest
* request
= request_job
->GetRequest();
288 *request
->mutable_device_status_report_request() = *device_status
;
290 *request
->mutable_session_status_report_request() = *session_status
;
292 const DeviceManagementRequestJob::Callback job_callback
=
293 base::Bind(&CloudPolicyClient::OnStatusUploadCompleted
,
294 base::Unretained(this), request_job
.get(), callback
);
296 request_jobs_
.push_back(request_job
.Pass());
297 request_jobs_
.back()->Start(job_callback
);
300 void CloudPolicyClient::FetchRemoteCommands(
301 scoped_ptr
<RemoteCommandJob::UniqueIDType
> last_command_id
,
302 const std::vector
<em::RemoteCommandResult
>& command_results
,
303 const RemoteCommandCallback
& callback
) {
304 CHECK(is_registered());
305 scoped_ptr
<DeviceManagementRequestJob
> request_job(service_
->CreateJob(
306 DeviceManagementRequestJob::TYPE_REMOTE_COMMANDS
, GetRequestContext()));
308 request_job
->SetDMToken(dm_token_
);
309 request_job
->SetClientID(client_id_
);
311 em::DeviceRemoteCommandRequest
* const request
=
312 request_job
->GetRequest()->mutable_remote_command_request();
315 request
->set_last_command_unique_id(*last_command_id
);
317 for (const auto& command_result
: command_results
)
318 *request
->add_command_results() = command_result
;
320 const DeviceManagementRequestJob::Callback job_callback
=
321 base::Bind(&CloudPolicyClient::OnRemoteCommandsFetched
,
322 base::Unretained(this), request_job
.get(), callback
);
324 request_jobs_
.push_back(request_job
.Pass());
325 request_jobs_
.back()->Start(job_callback
);
328 void CloudPolicyClient::GetDeviceAttributeUpdatePermission(
329 const std::string
&auth_token
,
330 const CloudPolicyClient::StatusCallback
& callback
) {
331 CHECK(is_registered());
332 DCHECK(!auth_token
.empty());
334 scoped_ptr
<DeviceManagementRequestJob
> request_job(
336 DeviceManagementRequestJob::TYPE_ATTRIBUTE_UPDATE_PERMISSION
,
337 GetRequestContext()));
339 request_job
->SetOAuthToken(auth_token
);
340 request_job
->SetClientID(client_id_
);
342 request_job
->GetRequest()->
343 mutable_device_attribute_update_permission_request();
345 const DeviceManagementRequestJob::Callback job_callback
=
346 base::Bind(&CloudPolicyClient::OnDeviceAttributeUpdatePermissionCompleted
,
347 base::Unretained(this), request_job
.get(), callback
);
349 request_jobs_
.push_back(request_job
.Pass());
350 request_jobs_
.back()->Start(job_callback
);
353 void CloudPolicyClient::UpdateDeviceAttributes(
354 const std::string
& auth_token
,
355 const std::string
& asset_id
,
356 const std::string
& location
,
357 const CloudPolicyClient::StatusCallback
& callback
) {
358 CHECK(is_registered());
359 DCHECK(!auth_token
.empty());
361 scoped_ptr
<DeviceManagementRequestJob
> request_job(
363 DeviceManagementRequestJob::TYPE_ATTRIBUTE_UPDATE
,
364 GetRequestContext()));
366 request_job
->SetOAuthToken(auth_token
);
367 request_job
->SetClientID(client_id_
);
369 em::DeviceAttributeUpdateRequest
* request
=
370 request_job
->GetRequest()->mutable_device_attribute_update_request();
372 request
->set_asset_id(asset_id
);
373 request
->set_location(location
);
375 const DeviceManagementRequestJob::Callback job_callback
=
376 base::Bind(&CloudPolicyClient::OnDeviceAttributeUpdated
,
377 base::Unretained(this), request_job
.get(), callback
);
379 request_jobs_
.push_back(request_job
.Pass());
380 request_jobs_
.back()->Start(job_callback
);
383 void CloudPolicyClient::AddObserver(Observer
* observer
) {
384 observers_
.AddObserver(observer
);
387 void CloudPolicyClient::RemoveObserver(Observer
* observer
) {
388 observers_
.RemoveObserver(observer
);
391 void CloudPolicyClient::AddPolicyTypeToFetch(
392 const std::string
& policy_type
,
393 const std::string
& settings_entity_id
) {
394 types_to_fetch_
.insert(std::make_pair(policy_type
, settings_entity_id
));
397 void CloudPolicyClient::RemovePolicyTypeToFetch(
398 const std::string
& policy_type
,
399 const std::string
& settings_entity_id
) {
400 types_to_fetch_
.erase(std::make_pair(policy_type
, settings_entity_id
));
403 void CloudPolicyClient::SetStateKeysToUpload(
404 const std::vector
<std::string
>& keys
) {
405 state_keys_to_upload_
= keys
;
408 const em::PolicyFetchResponse
* CloudPolicyClient::GetPolicyFor(
409 const std::string
& policy_type
,
410 const std::string
& settings_entity_id
) const {
411 ResponseMap::const_iterator it
=
412 responses_
.find(std::make_pair(policy_type
, settings_entity_id
));
413 return it
== responses_
.end() ? nullptr : it
->second
;
416 scoped_refptr
<net::URLRequestContextGetter
>
417 CloudPolicyClient::GetRequestContext() {
418 return request_context_
;
421 int CloudPolicyClient::GetActiveRequestCountForTest() const {
422 return request_jobs_
.size();
425 void CloudPolicyClient::OnRetryRegister(DeviceManagementRequestJob
* job
) {
426 DCHECK_EQ(policy_fetch_request_job_
.get(), job
);
427 // If the initial request managed to get to the server but the response didn't
428 // arrive at the client then retrying with the same client ID will fail.
429 // Set the re-registration flag so that the server accepts it.
430 // If the server hasn't seen the client ID before then it will also accept
431 // the re-registration.
432 job
->GetRequest()->mutable_register_request()->set_reregister(true);
435 void CloudPolicyClient::OnRegisterCompleted(
436 DeviceManagementStatus status
,
438 const em::DeviceManagementResponse
& response
) {
439 if (status
== DM_STATUS_SUCCESS
&&
440 (!response
.has_register_response() ||
441 !response
.register_response().has_device_management_token())) {
442 LOG(WARNING
) << "Invalid registration response.";
443 status
= DM_STATUS_RESPONSE_DECODING_ERROR
;
447 if (status
== DM_STATUS_SUCCESS
) {
448 dm_token_
= response
.register_response().device_management_token();
449 DVLOG(1) << "Client registration complete - DMToken = " << dm_token_
;
451 // Device mode is only relevant for device policy really, it's the
452 // responsibility of the consumer of the field to check validity.
453 device_mode_
= DEVICE_MODE_NOT_SET
;
454 if (response
.register_response().has_enrollment_type()) {
455 device_mode_
= TranslateProtobufDeviceMode(
456 response
.register_response().enrollment_type());
459 NotifyRegistrationStateChanged();
465 void CloudPolicyClient::OnFetchRobotAuthCodesCompleted(
466 DeviceManagementStatus status
,
468 const em::DeviceManagementResponse
& response
) {
469 if (status
== DM_STATUS_SUCCESS
&&
470 (!response
.has_service_api_access_response() ||
471 response
.service_api_access_response().auth_code().empty())) {
472 LOG(WARNING
) << "Invalid service api access response.";
473 status
= DM_STATUS_RESPONSE_DECODING_ERROR
;
477 if (status
== DM_STATUS_SUCCESS
) {
478 robot_api_auth_code_
= response
.service_api_access_response().auth_code();
479 DVLOG(1) << "Device robot account auth code fetch complete - code = "
480 << robot_api_auth_code_
;
482 NotifyRobotAuthCodesFetched();
488 void CloudPolicyClient::OnPolicyFetchCompleted(
489 DeviceManagementStatus status
,
491 const em::DeviceManagementResponse
& response
) {
492 if (status
== DM_STATUS_SUCCESS
) {
493 if (!response
.has_policy_response() ||
494 response
.policy_response().response_size() == 0) {
495 LOG(WARNING
) << "Empty policy response.";
496 status
= DM_STATUS_RESPONSE_DECODING_ERROR
;
501 if (status
== DM_STATUS_SUCCESS
) {
502 const em::DevicePolicyResponse
& policy_response
=
503 response
.policy_response();
504 STLDeleteValues(&responses_
);
505 for (int i
= 0; i
< policy_response
.response_size(); ++i
) {
506 const em::PolicyFetchResponse
& response
= policy_response
.response(i
);
507 em::PolicyData policy_data
;
508 if (!policy_data
.ParseFromString(response
.policy_data()) ||
509 !policy_data
.IsInitialized() ||
510 !policy_data
.has_policy_type()) {
511 LOG(WARNING
) << "Invalid PolicyData received, ignoring";
514 const std::string
& type
= policy_data
.policy_type();
515 std::string entity_id
;
516 if (policy_data
.has_settings_entity_id())
517 entity_id
= policy_data
.settings_entity_id();
518 std::pair
<std::string
, std::string
> key(type
, entity_id
);
519 if (ContainsKey(responses_
, key
)) {
520 LOG(WARNING
) << "Duplicate PolicyFetchResponse for type: "
521 << type
<< ", entity: " << entity_id
<< ", ignoring";
524 responses_
[key
] = new em::PolicyFetchResponse(response
);
526 state_keys_to_upload_
.clear();
527 NotifyPolicyFetched();
533 void CloudPolicyClient::OnUnregisterCompleted(
534 DeviceManagementStatus status
,
536 const em::DeviceManagementResponse
& response
) {
537 if (status
== DM_STATUS_SUCCESS
&& !response
.has_unregister_response()) {
538 // Assume unregistration has succeeded either way.
539 LOG(WARNING
) << "Empty unregistration response.";
543 if (status
== DM_STATUS_SUCCESS
) {
545 // Cancel all outstanding jobs.
546 request_jobs_
.clear();
547 NotifyRegistrationStateChanged();
553 void CloudPolicyClient::OnCertificateUploadCompleted(
554 const DeviceManagementRequestJob
* job
,
555 const CloudPolicyClient::StatusCallback
& callback
,
556 DeviceManagementStatus status
,
558 const enterprise_management::DeviceManagementResponse
& response
) {
561 if (status
!= DM_STATUS_SUCCESS
) {
564 } else if (!response
.has_cert_upload_response()) {
565 LOG(WARNING
) << "Empty upload certificate response.";
568 callback
.Run(success
);
569 // Must call RemoveJob() last, because it frees |callback|.
573 void CloudPolicyClient::OnDeviceAttributeUpdatePermissionCompleted(
574 const DeviceManagementRequestJob
* job
,
575 const CloudPolicyClient::StatusCallback
& callback
,
576 DeviceManagementStatus status
,
578 const em::DeviceManagementResponse
& response
) {
579 bool success
= false;
581 if (status
== DM_STATUS_SUCCESS
&&
582 !response
.has_device_attribute_update_permission_response()) {
583 LOG(WARNING
) << "Invalid device attribute update permission response.";
584 status
= DM_STATUS_RESPONSE_DECODING_ERROR
;
588 if (status
== DM_STATUS_SUCCESS
&&
589 response
.device_attribute_update_permission_response().has_result() &&
590 response
.device_attribute_update_permission_response().result() ==
591 em::DeviceAttributeUpdatePermissionResponse::ATTRIBUTE_UPDATE_ALLOWED
) {
595 callback
.Run(success
);
599 void CloudPolicyClient::OnDeviceAttributeUpdated(
600 const DeviceManagementRequestJob
* job
,
601 const CloudPolicyClient::StatusCallback
& callback
,
602 DeviceManagementStatus status
,
604 const em::DeviceManagementResponse
& response
) {
605 bool success
= false;
607 if (status
== DM_STATUS_SUCCESS
&&
608 !response
.has_device_attribute_update_response()) {
609 LOG(WARNING
) << "Invalid device attribute update response.";
610 status
= DM_STATUS_RESPONSE_DECODING_ERROR
;
614 if (status
== DM_STATUS_SUCCESS
&&
615 response
.device_attribute_update_response().has_result() &&
616 response
.device_attribute_update_response().result() ==
617 em::DeviceAttributeUpdateResponse::ATTRIBUTE_UPDATE_SUCCESS
) {
621 callback
.Run(success
);
625 void CloudPolicyClient::RemoveJob(const DeviceManagementRequestJob
* job
) {
626 for (auto it
= request_jobs_
.begin(); it
!= request_jobs_
.end(); ++it
) {
628 request_jobs_
.erase(it
);
632 // This job was already deleted from our list, somehow. This shouldn't
633 // happen since deleting the job should cancel the callback.
637 void CloudPolicyClient::OnStatusUploadCompleted(
638 const DeviceManagementRequestJob
* job
,
639 const CloudPolicyClient::StatusCallback
& callback
,
640 DeviceManagementStatus status
,
642 const enterprise_management::DeviceManagementResponse
& response
) {
644 if (status
!= DM_STATUS_SUCCESS
)
647 callback
.Run(status
== DM_STATUS_SUCCESS
);
648 // Must call RemoveJob() last, because it frees |callback|.
652 void CloudPolicyClient::OnRemoteCommandsFetched(
653 const DeviceManagementRequestJob
* job
,
654 const RemoteCommandCallback
& callback
,
655 DeviceManagementStatus status
,
657 const enterprise_management::DeviceManagementResponse
& response
) {
658 std::vector
<enterprise_management::RemoteCommand
> commands
;
659 if (status
== DM_STATUS_SUCCESS
) {
660 if (response
.has_remote_command_response()) {
661 for (const auto& command
: response
.remote_command_response().commands())
662 commands
.push_back(command
);
664 status
= DM_STATUS_RESPONSE_DECODING_ERROR
;
667 callback
.Run(status
, commands
);
668 // Must call RemoveJob() last, because it frees |callback|.
672 void CloudPolicyClient::NotifyPolicyFetched() {
673 FOR_EACH_OBSERVER(Observer
, observers_
, OnPolicyFetched(this));
676 void CloudPolicyClient::NotifyRegistrationStateChanged() {
677 FOR_EACH_OBSERVER(Observer
, observers_
, OnRegistrationStateChanged(this));
680 void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
681 FOR_EACH_OBSERVER(Observer
, observers_
, OnRobotAuthCodesFetched(this));
684 void CloudPolicyClient::NotifyClientError() {
685 FOR_EACH_OBSERVER(Observer
, observers_
, OnClientError(this));
688 } // namespace policy