- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / policy / cloud / cloud_policy_client.cc
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 "chrome/browser/policy/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 "chrome/browser/policy/cloud/device_management_service.h"
12 #include "google_apis/gaia/gaia_constants.h"
13 #include "google_apis/gaia/gaia_urls.h"
14
15 namespace em = enterprise_management;
16
17 namespace policy {
18
19 namespace {
20
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) {
25   switch (mode) {
26     case em::DeviceRegisterResponse::ENTERPRISE:
27       return DEVICE_MODE_ENTERPRISE;
28     case em::DeviceRegisterResponse::RETAIL:
29       return DEVICE_MODE_RETAIL_KIOSK;
30   }
31   LOG(ERROR) << "Unknown enrollment mode in registration response: " << mode;
32   return DEVICE_MODE_NOT_SET;
33 }
34
35 bool IsChromePolicy(const std::string& type) {
36   return type == dm_protocol::kChromeDevicePolicyType ||
37          type == GetChromeUserPolicyType();
38 }
39
40 }  // namespace
41
42 CloudPolicyClient::Observer::~Observer() {}
43
44 void CloudPolicyClient::Observer::OnRobotAuthCodesFetched(
45     CloudPolicyClient* client) {}
46
47 CloudPolicyClient::StatusProvider::~StatusProvider() {}
48
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) {
66 }
67
68 CloudPolicyClient::~CloudPolicyClient() {
69   STLDeleteValues(&responses_);
70 }
71
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());
77
78   dm_token_ = dm_token;
79   client_id_ = client_id;
80   request_job_.reset();
81   STLDeleteValues(&responses_);
82
83   NotifyRegistrationStateChanged();
84 }
85
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) {
91   DCHECK(service_);
92   DCHECK(!auth_token.empty());
93   DCHECK(!is_registered());
94
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();
100   } else {
101     client_id_ = client_id;
102   }
103
104   request_job_.reset(
105       service_->CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION));
106   request_job_->SetOAuthToken(auth_token);
107   request_job_->SetClientID(client_id_);
108
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);
122
123   request_job_->SetRetryCallback(
124       base::Bind(&CloudPolicyClient::OnRetryRegister, base::Unretained(this)));
125
126   request_job_->Start(base::Bind(&CloudPolicyClient::OnRegisterCompleted,
127                                  base::Unretained(this)));
128 }
129
130 void CloudPolicyClient::SetInvalidationInfo(
131     int64 version,
132     const std::string& payload) {
133   invalidation_version_ = version;
134   invalidation_payload_ = payload;
135 }
136
137 void CloudPolicyClient::FetchPolicy() {
138   CHECK(is_registered());
139   CHECK(!namespaces_to_fetch_.empty());
140
141   request_job_.reset(
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_);
146
147   em::DeviceManagementRequest* request = request_job_->GetRequest();
148
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);
157
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);
161 #else
162     // Don't request signed blobs for desktop policy.
163     fetch_request->set_signature_type(em::PolicyFetchRequest::NONE);
164 #endif
165     if (public_key_version_valid_)
166       fetch_request->set_public_key_version(public_key_version_);
167
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());
176       }
177       if (!invalidation_payload_.empty()) {
178         fetch_request->set_invalidation_version(invalidation_version_);
179         fetch_request->set_invalidation_payload(invalidation_payload_);
180       }
181     }
182   }
183
184   // Add status data.
185   if (status_provider_) {
186     if (!status_provider_->GetDeviceStatus(
187             request->mutable_device_status_report_request())) {
188       request->clear_device_status_report_request();
189     }
190     if (!status_provider_->GetSessionStatus(
191             request->mutable_session_status_report_request())) {
192       request->clear_session_status_report_request();
193     }
194   }
195
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_;
199
200   // Fire the job.
201   request_job_->Start(base::Bind(&CloudPolicyClient::OnPolicyFetchCompleted,
202                                  base::Unretained(this)));
203 }
204
205 void CloudPolicyClient::FetchRobotAuthCodes(const std::string& auth_token) {
206   CHECK(is_registered());
207   DCHECK(!auth_token.empty());
208
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_);
216
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);
222
223   request_job_->Start(
224       base::Bind(&CloudPolicyClient::OnFetchRobotAuthCodesCompleted,
225                  base::Unretained(this)));
226 }
227
228 void CloudPolicyClient::Unregister() {
229   DCHECK(service_);
230   request_job_.reset(
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)));
237 }
238
239 void CloudPolicyClient::UploadCertificate(
240     const std::string& certificate_data,
241     const CloudPolicyClient::StatusCallback& callback) {
242   CHECK(is_registered());
243   request_job_.reset(
244       service_->CreateJob(DeviceManagementRequestJob::TYPE_UPLOAD_CERTIFICATE));
245   request_job_->SetDMToken(dm_token_);
246   request_job_->SetClientID(client_id_);
247
248   em::DeviceManagementRequest* request = request_job_->GetRequest();
249   request->mutable_cert_upload_request()->set_device_certificate(
250       certificate_data);
251
252   DeviceManagementRequestJob::Callback job_callback = base::Bind(
253       &CloudPolicyClient::OnCertificateUploadCompleted,
254       base::Unretained(this),
255       callback);
256   request_job_->Start(job_callback);
257 }
258
259 void CloudPolicyClient::AddObserver(Observer* observer) {
260   observers_.AddObserver(observer);
261 }
262
263 void CloudPolicyClient::RemoveObserver(Observer* observer) {
264   observers_.RemoveObserver(observer);
265 }
266
267 void CloudPolicyClient::AddNamespaceToFetch(const PolicyNamespaceKey& key) {
268   namespaces_to_fetch_.insert(key);
269 }
270
271 void CloudPolicyClient::RemoveNamespaceToFetch(const PolicyNamespaceKey& key) {
272   namespaces_to_fetch_.erase(key);
273 }
274
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;
279 }
280
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);
289 }
290
291 void CloudPolicyClient::OnRegisterCompleted(
292     DeviceManagementStatus status,
293     int net_error,
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;
300   }
301
302   status_ = status;
303   if (status == DM_STATUS_SUCCESS) {
304     dm_token_ = response.register_response().device_management_token();
305     DVLOG(1) << "Client registration complete - DMToken = " << dm_token_;
306
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());
313     }
314
315     NotifyRegistrationStateChanged();
316   } else {
317     NotifyClientError();
318   }
319 }
320
321 void CloudPolicyClient::OnFetchRobotAuthCodesCompleted(
322     DeviceManagementStatus status,
323     int net_error,
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;
330   }
331
332   status_ = status;
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_;
337
338     NotifyRobotAuthCodesFetched();
339   } else {
340     NotifyClientError();
341   }
342 }
343
344 void CloudPolicyClient::OnPolicyFetchCompleted(
345     DeviceManagementStatus status,
346     int net_error,
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;
353     }
354   }
355
356   status_ = status;
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";
368         continue;
369       }
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";
378         continue;
379       }
380       responses_[key] = new em::PolicyFetchResponse(response);
381     }
382     if (status_provider_)
383       status_provider_->OnSubmittedSuccessfully();
384     NotifyPolicyFetched();
385   } else {
386     NotifyClientError();
387   }
388 }
389
390 void CloudPolicyClient::OnUnregisterCompleted(
391     DeviceManagementStatus status,
392     int net_error,
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.";
397   }
398
399   status_ = status;
400   if (status == DM_STATUS_SUCCESS) {
401     dm_token_.clear();
402     NotifyRegistrationStateChanged();
403   } else {
404     NotifyClientError();
405   }
406 }
407
408 void CloudPolicyClient::OnCertificateUploadCompleted(
409     const CloudPolicyClient::StatusCallback& callback,
410     DeviceManagementStatus status,
411     int net_error,
412     const enterprise_management::DeviceManagementResponse& response) {
413   if (status == DM_STATUS_SUCCESS && !response.has_cert_upload_response()) {
414     LOG(WARNING) << "Empty upload certificate response.";
415     callback.Run(false);
416     return;
417   }
418
419   status_ = status;
420   if (status != DM_STATUS_SUCCESS) {
421     NotifyClientError();
422     callback.Run(false);
423     return;
424   }
425   callback.Run(true);
426 }
427
428 void CloudPolicyClient::NotifyPolicyFetched() {
429   FOR_EACH_OBSERVER(Observer, observers_, OnPolicyFetched(this));
430 }
431
432 void CloudPolicyClient::NotifyRegistrationStateChanged() {
433   FOR_EACH_OBSERVER(Observer, observers_, OnRegistrationStateChanged(this));
434 }
435
436 void CloudPolicyClient::NotifyRobotAuthCodesFetched() {
437   FOR_EACH_OBSERVER(Observer, observers_, OnRobotAuthCodesFetched(this));
438 }
439
440 void CloudPolicyClient::NotifyClientError() {
441   FOR_EACH_OBSERVER(Observer, observers_, OnClientError(this));
442 }
443
444 }  // namespace policy