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 445