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 "components/policy/core/common/cloud/cloud_policy_client.h"
6
7 #include "base/bind.h"
8 #include "base/guid.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "components/policy/core/common/cloud/device_management_service.h"
12 #include "google_apis/gaia/gaia_constants.h"
13 #include "google_apis/gaia/gaia_urls.h"
14 #include "net/url_request/url_request_context_getter.h"
15
16 namespace em = enterprise_management;
17
18 namespace policy {
19
20 namespace {
21
22 // Translates the DeviceRegisterResponse::DeviceMode |mode| to the enum used
23 // internally to represent different device modes.
TranslateProtobufDeviceMode(em::DeviceRegisterResponse::DeviceMode mode)24 DeviceMode TranslateProtobufDeviceMode(
25 em::DeviceRegisterResponse::DeviceMode mode) {
26 switch (mode) {
27 case em::DeviceRegisterResponse::ENTERPRISE:
28 return DEVICE_MODE_ENTERPRISE;
29 case em::DeviceRegisterResponse::RETAIL:
30 return DEVICE_MODE_RETAIL_KIOSK;
31 }
32 LOG(ERROR) << "Unknown enrollment mode in registration response: " << mode;
33 return DEVICE_MODE_NOT_SET;
34 }
35
IsChromePolicy(const std::string & type)36 bool IsChromePolicy(const std::string& type) {
37 return type == dm_protocol::kChromeDevicePolicyType ||
38 type == GetChromeUserPolicyType();
39 }
40
41 } // namespace
42
~Observer()43 CloudPolicyClient::Observer::~Observer() {}
44
OnRobotAuthCodesFetched(CloudPolicyClient * client)45 void CloudPolicyClient::Observer::OnRobotAuthCodesFetched(
46 CloudPolicyClient* client) {}
47
~StatusProvider()48 CloudPolicyClient::StatusProvider::~StatusProvider() {}
49
CloudPolicyClient(const std::string & machine_id,const std::string & machine_model,const std::string & verification_key_hash,UserAffiliation user_affiliation,StatusProvider * status_provider,DeviceManagementService * service,scoped_refptr<net::URLRequestContextGetter> request_context)50 CloudPolicyClient::CloudPolicyClient(
51 const std::string& machine_id,
52 const std::string& machine_model,
53 const std::string& verification_key_hash,
54 UserAffiliation user_affiliation,
55 StatusProvider* status_provider,
56 DeviceManagementService* service,
57 scoped_refptr<net::URLRequestContextGetter> request_context)
58 : machine_id_(machine_id),
59 machine_model_(machine_model),
60 verification_key_hash_(verification_key_hash),
61 user_affiliation_(user_affiliation),
62 device_mode_(DEVICE_MODE_NOT_SET),
63 submit_machine_id_(false),
64 public_key_version_(-1),
65 public_key_version_valid_(false),
66 invalidation_version_(0),
67 fetched_invalidation_version_(0),
68 service_(service), // Can be NULL for unit tests.
69 status_provider_(status_provider), // Can be NULL for unit tests.
70 status_(DM_STATUS_SUCCESS),
71 request_context_(request_context) {
72 }
73
~CloudPolicyClient()74 CloudPolicyClient::~CloudPolicyClient() {
75 STLDeleteValues(&responses_);
76 }
77
SetupRegistration(const std::string & dm_token,const std::string & client_id)78 void CloudPolicyClient::SetupRegistration(const std::string& dm_token,
79 const std::string& client_id) {
80 DCHECK(!dm_token.empty());
81 DCHECK(!client_id.empty());
82 DCHECK(!is_registered());
83
84 dm_token_ = dm_token;
85 client_id_ = client_id;
86 request_job_.reset();
87 STLDeleteValues(&responses_);
88
89 NotifyRegistrationStateChanged();
90 }
91
Register(em::DeviceRegisterRequest::Type type,const std::string & auth_token,const std::string & client_id,bool is_auto_enrollement,const std::string & requisition,const std::string & current_state_key)92 void CloudPolicyClient::Register(em::DeviceRegisterRequest::Type type,
93 const std::string& auth_token,
94 const std::string& client_id,
95 bool is_auto_enrollement,
96 const std::string& requisition,
97 const std::string& current_state_key) {
98 DCHECK(service_);
99 DCHECK(!auth_token.empty());
100 DCHECK(!is_registered());
101
102 if (client_id.empty()) {
103 // Generate a new client ID. This is intentionally done on each new
104 // registration request in order to preserve privacy. Reusing IDs would mean
105 // the server could track clients by their registration attempts.
106 client_id_ = base::GenerateGUID();
107 } else {
108 client_id_ = client_id;
109 }
110
111 request_job_.reset(
112 service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION,
113 GetRequestContext()));
114 request_job_->SetOAuthToken(auth_token);
115 request_job_->SetClientID(client_id_);
116
117 em::DeviceRegisterRequest* request =
118 request_job_->GetRequest()->mutable_register_request();
119 if (!client_id.empty())
120 request->set_reregister(true);
121 request->set_type(type);
122 if (!machine_id_.empty())
123 request->set_machine_id(machine_id_);
124 if (!machine_model_.empty())
125 request->set_machine_model(machine_model_);
126 if (is_auto_enrollement)
127 request->set_auto_enrolled(true);
128 if (!requisition.empty())
129 request->set_requisition(requisition);
130 if (!current_state_key.empty())
131 request->set_server_backed_state_key(current_state_key);
132
133 request_job_->SetRetryCallback(
134 base::Bind(&CloudPolicyClient::OnRetryRegister, base::Unretained(this)));
135
136 request_job_->Start(base::Bind(&CloudPolicyClient::OnRegisterCompleted,
137 base::Unretained(this)));
138 }
139
SetInvalidationInfo(int64 version,const std::string & payload)140 void CloudPolicyClient::SetInvalidationInfo(
141 int64 version,
142 const std::string& payload) {
143 invalidation_version_ = version;
144 invalidation_payload_ = payload;
145 }
146
FetchPolicy()147 void CloudPolicyClient::FetchPolicy() {
148 CHECK(is_registered());
149 CHECK(!namespaces_to_fetch_.empty());
150
151 request_job_.reset(
152 service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH,
153 GetRequestContext()));
154 request_job_->SetDMToken(dm_token_);
155 request_job_->SetClientID(client_id_);
156 request_job_->SetUserAffiliation(user_affiliation_);
157
158 em::DeviceManagementRequest* request = request_job_->GetRequest();
159
160 // Build policy fetch requests.
161 em::DevicePolicyRequest* policy_request = request->mutable_policy_request();
162 for (NamespaceSet::iterator it = namespaces_to_fetch_.begin();
163 it != namespaces_to_fetch_.end(); ++it) {
164 em::PolicyFetchRequest* fetch_request = policy_request->add_request();
165 fetch_request->set_policy_type(it->first);
166 if (!it->second.empty())
167 fetch_request->set_settings_entity_id(it->second);
168
169 // Request signed policy blobs to help prevent tampering on the client.
170 fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA);
171 if (public_key_version_valid_)
172 fetch_request->set_public_key_version(public_key_version_);
173
174 if (!verification_key_hash_.empty())
175 fetch_request->set_verification_key_hash(verification_key_hash_);
176
177 // These fields are included only in requests for chrome policy.
178 if (IsChromePolicy(it->first)) {
179 if (submit_machine_id_ && !machine_id_.empty())
180 fetch_request->set_machine_id(machine_id_);
181 if (!last_policy_timestamp_.is_null()) {
182 base::TimeDelta timestamp(
183 last_policy_timestamp_ - base::Time::UnixEpoch());
184 fetch_request->set_timestamp(timestamp.InMilliseconds());
185 }
186 if (!invalidation_payload_.empty()) {
187 fetch_request->set_invalidation_version(invalidation_version_);
188 fetch_request->set_invalidation_payload(invalidation_payload_);
189 }
190 }
191 }
192
193 // Add status data.
194 if (status_provider_) {
195 if (!status_provider_->GetDeviceStatus(
196 request->mutable_device_status_report_request())) {
197 request->clear_device_status_report_request();
198 }
199 if (!status_provider_->GetSessionStatus(
200 request->mutable_session_status_report_request())) {
201 request->clear_session_status_report_request();
202 }
203 }
204
205 // Add device state keys.
206 if (!state_keys_to_upload_.empty()) {
207 em::DeviceStateKeyUpdateRequest* key_update_request =
208 request->mutable_device_state_key_update_request();
209 for (std::vector<std::string>::const_iterator key(
210 state_keys_to_upload_.begin());
211 key != state_keys_to_upload_.end();
212 ++key) {
213 key_update_request->add_server_backed_state_key(*key);
214 }
215 }
216
217 // Set the fetched invalidation version to the latest invalidation version
218 // since it is now the invalidation version used for the latest fetch.
219 fetched_invalidation_version_ = invalidation_version_;
220
221 // Fire the job.
222 request_job_->Start(base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted,
223 base::Unretained(this)));
224 }
225
FetchRobotAuthCodes(const std::string & auth_token)226 void CloudPolicyClient::FetchRobotAuthCodes(const std::string& auth_token) {
227 CHECK(is_registered());
228 DCHECK(!auth_token.empty());
229
230 request_job_.reset(service_->CreateJob(
231 DeviceManagementRequestJob::TYPE_API_AUTH_CODE_FETCH,
232 GetRequestContext()));
233 // The credentials of a domain user are needed in order to mint a new OAuth2
234 // authorization token for the robot account.
235 request_job_->SetOAuthToken(auth_token);
236 request_job_->SetDMToken(dm_token_);
237 request_job_->SetClientID(client_id_);
238
239 em::DeviceServiceApiAccessRequest* request =
240 request_job_->GetRequest()->mutable_service_api_access_request();
241 request->set_oauth2_client_id(
242 GaiaUrls::GetInstance()->oauth2_chrome_client_id());
243 request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope);
244
245 request_job_->Start(
246 base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
247 base::Unretained(this)));
248 }
249
Unregister()250 void CloudPolicyClient::Unregister() {
251 DCHECK(service_);
252 request_job_.reset(
253 service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION,
254 GetRequestContext()));
255 request_job_->SetDMToken(dm_token_);
256 request_job_->SetClientID(client_id_);
257 request_job_->GetRequest()->mutable_unregister_request();
258 request_job_->Start(base::Bind(&CloudPolicyClient::OnUnregisterCompleted,
259 base::Unretained(this)));
260 }
261
UploadCertificate(const std::string & certificate_data,const CloudPolicyClient::StatusCallback & callback)262 void CloudPolicyClient::UploadCertificate(
263 const std::string& certificate_data,
264 const CloudPolicyClient::StatusCallback& callback) {
265 CHECK(is_registered());
266 request_job_.reset(
267 service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE,
268 GetRequestContext()));
269 request_job_->SetDMToken(dm_token_);
270 request_job_->SetClientID(client_id_);
271
272 em::DeviceManagementRequest* request = request_job_->GetRequest();
273 request->mutable_cert_upload_request()->set_device_certificate(
274 certificate_data);
275
276 DeviceManagementRequestJob::Callback job_callback = base::Bind(
277 &CloudPolicyClient::OnCertificateUploadCompleted,
278 base::Unretained(this),
279 callback);
280 request_job_->Start(job_callback);
281 }
282
AddObserver(Observer * observer)283 void CloudPolicyClient::AddObserver(Observer* observer) {
284 observers_.AddObserver(observer);
285 }
286
RemoveObserver(Observer * observer)287 void CloudPolicyClient::RemoveObserver(Observer* observer) {
288 observers_.RemoveObserver(observer);
289 }
290
AddNamespaceToFetch(const PolicyNamespaceKey & key)291 void CloudPolicyClient::AddNamespaceToFetch(const PolicyNamespaceKey& key) {
292 namespaces_to_fetch_.insert(key);
293 }
294
RemoveNamespaceToFetch(const PolicyNamespaceKey & key)295 void CloudPolicyClient::RemoveNamespaceToFetch(const PolicyNamespaceKey& key) {
296 namespaces_to_fetch_.erase(key);
297 }
298
SetStateKeysToUpload(const std::vector<std::string> & keys)299 void CloudPolicyClient::SetStateKeysToUpload(
300 const std::vector<std::string>& keys) {
301 state_keys_to_upload_ = keys;
302 }
303
GetPolicyFor(const PolicyNamespaceKey & key) const304 const em::PolicyFetchResponse* CloudPolicyClient::GetPolicyFor(
305 const PolicyNamespaceKey& key) const {
306 ResponseMap::const_iterator it = responses_.find(key);
307 return it == responses_.end() ? NULL : it->second;
308 }
309
310 scoped_refptr<net::URLRequestContextGetter>
GetRequestContext()311 CloudPolicyClient::GetRequestContext() {
312 return request_context_;
313 }
314
OnRetryRegister(DeviceManagementRequestJob * job)315 void CloudPolicyClient::OnRetryRegister(DeviceManagementRequestJob* job) {
316 DCHECK_EQ(request_job_.get(), job);
317 // If the initial request managed to get to the server but the response didn't
318 // arrive at the client then retrying with the same client ID will fail.
319 // Set the re-registration flag so that the server accepts it.
320 // If the server hasn't seen the client ID before then it will also accept
321 // the re-registration.
322 job->GetRequest()->mutable_register_request()->set_reregister(true);
323 }
324
OnRegisterCompleted(DeviceManagementStatus status,int net_error,const em::DeviceManagementResponse & response)325 void CloudPolicyClient::OnRegisterCompleted(
326 DeviceManagementStatus status,
327 int net_error,
328 const em::DeviceManagementResponse& response) {
329 if (status == DM_STATUS_SUCCESS &&
330 (!response.has_register_response() ||
331 !response.register_response().has_device_management_token())) {
332 LOG(WARNING) << "Invalid registration response.";
333 status = DM_STATUS_RESPONSE_DECODING_ERROR;
334 }
335
336 status_ = status;
337 if (status == DM_STATUS_SUCCESS) {
338 dm_token_ = response.register_response().device_management_token();
339 DVLOG(1) << "Client registration complete - DMToken = " << dm_token_;
340
341 // Device mode is only relevant for device policy really, it's the
342 // responsibility of the consumer of the field to check validity.
343 device_mode_ = DEVICE_MODE_NOT_SET;
344 if (response.register_response().has_enrollment_type()) {
345 device_mode_ = TranslateProtobufDeviceMode(
346 response.register_response().enrollment_type());
347 }
348
349 NotifyRegistrationStateChanged();
350 } else {
351 NotifyClientError();
352 }
353 }
354
OnFetchRobotAuthCodesCompleted(DeviceManagementStatus status,int net_error,const em::DeviceManagementResponse & response)355 void CloudPolicyClient::OnFetchRobotAuthCodesCompleted(
356 DeviceManagementStatus status,
357 int net_error,
358 const em::DeviceManagementResponse& response) {
359 if (status == DM_STATUS_SUCCESS &&
360 (!response.has_service_api_access_response() ||
361 response.service_api_access_response().auth_code().empty())) {
362 LOG(WARNING) << "Invalid service api access response.";
363 status = DM_STATUS_RESPONSE_DECODING_ERROR;
364 }
365
366 status_ = status;
367 if (status == DM_STATUS_SUCCESS) {
368 robot_api_auth_code_ = response.service_api_access_response().auth_code();
369 DVLOG(1) << "Device robot account auth code fetch complete - code = "
370 << robot_api_auth_code_;
371
372 NotifyRobotAuthCodesFetched();
373 } else {
374 NotifyClientError();
375 }
376 }
377
OnPolicyFetchCompleted(DeviceManagementStatus status,int net_error,const em::DeviceManagementResponse & response)378 void CloudPolicyClient::OnPolicyFetchCompleted(
379 DeviceManagementStatus status,
380 int net_error,
381 const em::DeviceManagementResponse& response) {
382 if (status == DM_STATUS_SUCCESS) {
383 if (!response.has_policy_response() ||
384 response.policy_response().response_size() == 0) {
385 LOG(WARNING) << "Empty policy response.";
386 status = DM_STATUS_RESPONSE_DECODING_ERROR;
387 }
388 }
389
390 status_ = status;
391 if (status == DM_STATUS_SUCCESS) {
392 const em::DevicePolicyResponse& policy_response =
393 response.policy_response();
394 STLDeleteValues(&responses_);
395 for (int i = 0; i < policy_response.response_size(); ++i) {
396 const em::PolicyFetchResponse& response = policy_response.response(i);
397 em::PolicyData policy_data;
398 if (!policy_data.ParseFromString(response.policy_data()) ||
399 !policy_data.IsInitialized() ||
400 !policy_data.has_policy_type()) {
401 LOG(WARNING) << "Invalid PolicyData received, ignoring";
402 continue;
403 }
404 const std::string& type = policy_data.policy_type();
405 std::string entity_id;
406 if (policy_data.has_settings_entity_id())
407 entity_id = policy_data.settings_entity_id();
408 PolicyNamespaceKey key(type, entity_id);
409 if (ContainsKey(responses_, key)) {
410 LOG(WARNING) << "Duplicate PolicyFetchResponse for type: "
411 << type << ", entity: " << entity_id << ", ignoring";
412 continue;
413 }
414 responses_[key] = new em::PolicyFetchResponse(response);
415 }
416 if (status_provider_)
417 status_provider_->OnSubmittedSuccessfully();
418 state_keys_to_upload_.clear();
419 NotifyPolicyFetched();
420 } else {
421 NotifyClientError();
422 }
423 }
424
OnUnregisterCompleted(DeviceManagementStatus status,int net_error,const em::DeviceManagementResponse & response)425 void CloudPolicyClient::OnUnregisterCompleted(
426 DeviceManagementStatus status,
427 int net_error,
428 const em::DeviceManagementResponse& response) {
429 if (status == DM_STATUS_SUCCESS && !response.has_unregister_response()) {
430 // Assume unregistration has succeeded either way.
431 LOG(WARNING) << "Empty unregistration response.";
432 }
433
434 status_ = status;
435 if (status == DM_STATUS_SUCCESS) {
436 dm_token_.clear();
437 NotifyRegistrationStateChanged();
438 } else {
439 NotifyClientError();
440 }
441 }
442
OnCertificateUploadCompleted(const CloudPolicyClient::StatusCallback & callback,DeviceManagementStatus status,int net_error,const enterprise_management::DeviceManagementResponse & response)443 void CloudPolicyClient::OnCertificateUploadCompleted(
444 const CloudPolicyClient::StatusCallback& callback,
445 DeviceManagementStatus status,
446 int net_error,
447 const enterprise_management::DeviceManagementResponse& response) {
448 if (status == DM_STATUS_SUCCESS && !response.has_cert_upload_response()) {
449 LOG(WARNING) << "Empty upload certificate response.";
450 callback.Run(false);
451 return;
452 }
453
454 status_ = status;
455 if (status != DM_STATUS_SUCCESS) {
456 NotifyClientError();
457 callback.Run(false);
458 return;
459 }
460 callback.Run(true);
461 }
462
NotifyPolicyFetched()463 void CloudPolicyClient::NotifyPolicyFetched() {
464 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyFetched(this));
465 }
466
NotifyRegistrationStateChanged()467 void CloudPolicyClient::NotifyRegistrationStateChanged() {
468 FOR_EACH_OBSERVER(Observer, observers_, OnRegistrationStateChanged(this));
469 }
470
NotifyRobotAuthCodesFetched()471 void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
472 FOR_EACH_OBSERVER(Observer, observers_, OnRobotAuthCodesFetched(this));
473 }
474
NotifyClientError()475 void CloudPolicyClient::NotifyClientError() {
476 FOR_EACH_OBSERVER(Observer, observers_, OnClientError(this));
477 }
478
479 } // namespace policy
480