• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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