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. 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 36 bool IsChromePolicy(const std::string& type) { 37 return type == dm_protocol::kChromeDevicePolicyType || 38 type == GetChromeUserPolicyType(); 39 } 40 41 } // namespace 42 43 CloudPolicyClient::Observer::~Observer() {} 44 45 void CloudPolicyClient::Observer::OnRobotAuthCodesFetched( 46 CloudPolicyClient* client) {} 47 48 CloudPolicyClient::StatusProvider::~StatusProvider() {} 49 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 74 CloudPolicyClient::~CloudPolicyClient() { 75 STLDeleteValues(&responses_); 76 } 77 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 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 140 void CloudPolicyClient::SetInvalidationInfo( 141 int64 version, 142 const std::string& payload) { 143 invalidation_version_ = version; 144 invalidation_payload_ = payload; 145 } 146 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 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 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 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 283 void CloudPolicyClient::AddObserver(Observer* observer) { 284 observers_.AddObserver(observer); 285 } 286 287 void CloudPolicyClient::RemoveObserver(Observer* observer) { 288 observers_.RemoveObserver(observer); 289 } 290 291 void CloudPolicyClient::AddNamespaceToFetch(const PolicyNamespaceKey& key) { 292 namespaces_to_fetch_.insert(key); 293 } 294 295 void CloudPolicyClient::RemoveNamespaceToFetch(const PolicyNamespaceKey& key) { 296 namespaces_to_fetch_.erase(key); 297 } 298 299 void CloudPolicyClient::SetStateKeysToUpload( 300 const std::vector<std::string>& keys) { 301 state_keys_to_upload_ = keys; 302 } 303 304 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> 311 CloudPolicyClient::GetRequestContext() { 312 return request_context_; 313 } 314 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 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 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 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 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 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 463 void CloudPolicyClient::NotifyPolicyFetched() { 464 FOR_EACH_OBSERVER(Observer, observers_, OnPolicyFetched(this)); 465 } 466 467 void CloudPolicyClient::NotifyRegistrationStateChanged() { 468 FOR_EACH_OBSERVER(Observer, observers_, OnRegistrationStateChanged(this)); 469 } 470 471 void CloudPolicyClient::NotifyRobotAuthCodesFetched() { 472 FOR_EACH_OBSERVER(Observer, observers_, OnRobotAuthCodesFetched(this)); 473 } 474 475 void CloudPolicyClient::NotifyClientError() { 476 FOR_EACH_OBSERVER(Observer, observers_, OnClientError(this)); 477 } 478 479 } // namespace policy 480