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