OLD | NEW |
(Empty) | |
| 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/cros_user_policy_cache.h" |
| 6 |
| 7 #include <string> |
| 8 #include <vector> |
| 9 |
| 10 #include "base/bind.h" |
| 11 #include "base/callback.h" |
| 12 #include "base/file_path.h" |
| 13 #include "base/file_util.h" |
| 14 #include "chrome/browser/policy/proto/cloud_policy.pb.h" |
| 15 #include "chrome/browser/policy/proto/device_management_backend.pb.h" |
| 16 #include "chrome/browser/policy/proto/device_management_local.pb.h" |
| 17 #include "chromeos/dbus/session_manager_client.h" |
| 18 #include "content/public/browser/browser_thread.h" |
| 19 |
| 20 using content::BrowserThread; |
| 21 |
| 22 namespace em = enterprise_management; |
| 23 |
| 24 namespace policy { |
| 25 |
| 26 // Decodes a CloudPolicySettings object into a policy map. The implementation is |
| 27 // generated code in policy/cloud_policy_generated.cc. |
| 28 void DecodePolicy(const em::CloudPolicySettings& policy, |
| 29 PolicyMap* policies); |
| 30 |
| 31 // Takes care of sending a new policy blob to session manager and reports back |
| 32 // the status through a callback. |
| 33 class CrosUserPolicyCache::StorePolicyOperation { |
| 34 public: |
| 35 typedef base::Callback<void(bool)> StatusCallback; |
| 36 |
| 37 StorePolicyOperation( |
| 38 const em::PolicyFetchResponse& policy, |
| 39 chromeos::SessionManagerClient* session_manager_client, |
| 40 const StatusCallback& callback); |
| 41 |
| 42 // Executes the operation. |
| 43 void Run(); |
| 44 |
| 45 // Cancels a pending callback. |
| 46 void Cancel(); |
| 47 |
| 48 const em::PolicyFetchResponse& policy() { return policy_; } |
| 49 |
| 50 private: |
| 51 // StorePolicyOperation manages its own lifetime. |
| 52 ~StorePolicyOperation() {} |
| 53 |
| 54 // A callback function suitable for passing to session_manager_client. |
| 55 void OnPolicyStored(bool result); |
| 56 |
| 57 em::PolicyFetchResponse policy_; |
| 58 chromeos::SessionManagerClient* session_manager_client_; |
| 59 StatusCallback callback_; |
| 60 |
| 61 DISALLOW_COPY_AND_ASSIGN(StorePolicyOperation); |
| 62 }; |
| 63 |
| 64 CrosUserPolicyCache::StorePolicyOperation::StorePolicyOperation( |
| 65 const em::PolicyFetchResponse& policy, |
| 66 chromeos::SessionManagerClient* session_manager_client, |
| 67 const StatusCallback& callback) |
| 68 : policy_(policy), |
| 69 session_manager_client_(session_manager_client), |
| 70 callback_(callback) {} |
| 71 |
| 72 void CrosUserPolicyCache::StorePolicyOperation::Run() { |
| 73 std::string serialized; |
| 74 if (!policy_.SerializeToString(&serialized)) { |
| 75 LOG(ERROR) << "Failed to serialize policy protobuf!"; |
| 76 callback_.Run(false); |
| 77 delete this; |
| 78 } |
| 79 session_manager_client_->StoreUserPolicy( |
| 80 serialized, |
| 81 base::Bind(&CrosUserPolicyCache::StorePolicyOperation::OnPolicyStored, |
| 82 base::Unretained(this))); |
| 83 } |
| 84 |
| 85 void CrosUserPolicyCache::StorePolicyOperation::Cancel() { |
| 86 callback_.Reset(); |
| 87 } |
| 88 |
| 89 void CrosUserPolicyCache::StorePolicyOperation::OnPolicyStored(bool result) { |
| 90 if (!callback_.is_null()) |
| 91 callback_.Run(result); |
| 92 delete this; |
| 93 } |
| 94 |
| 95 class CrosUserPolicyCache::RetrievePolicyOperation { |
| 96 public: |
| 97 typedef base::Callback<void(bool, const em::PolicyFetchResponse&)> |
| 98 ResultCallback; |
| 99 |
| 100 RetrievePolicyOperation( |
| 101 chromeos::SessionManagerClient* session_manager_client, |
| 102 const ResultCallback& callback); |
| 103 |
| 104 // Executes the operation. |
| 105 void Run(); |
| 106 |
| 107 // Cancels a pending callback. |
| 108 void Cancel(); |
| 109 |
| 110 private: |
| 111 // RetrievePolicyOperation manages its own lifetime. |
| 112 ~RetrievePolicyOperation() {} |
| 113 |
| 114 // Decodes the policy data and triggers a signature check. |
| 115 void OnPolicyRetrieved(const std::string& policy_blob); |
| 116 |
| 117 chromeos::SessionManagerClient* session_manager_client_; |
| 118 ResultCallback callback_; |
| 119 |
| 120 DISALLOW_COPY_AND_ASSIGN(RetrievePolicyOperation); |
| 121 }; |
| 122 |
| 123 CrosUserPolicyCache::RetrievePolicyOperation::RetrievePolicyOperation( |
| 124 chromeos::SessionManagerClient* session_manager_client, |
| 125 const ResultCallback& callback) |
| 126 : session_manager_client_(session_manager_client), |
| 127 callback_(callback) {} |
| 128 |
| 129 void CrosUserPolicyCache::RetrievePolicyOperation::Run() { |
| 130 session_manager_client_->RetrieveUserPolicy( |
| 131 base::Bind( |
| 132 &CrosUserPolicyCache::RetrievePolicyOperation::OnPolicyRetrieved, |
| 133 base::Unretained(this))); |
| 134 } |
| 135 |
| 136 void CrosUserPolicyCache::RetrievePolicyOperation::Cancel() { |
| 137 callback_.Reset(); |
| 138 } |
| 139 |
| 140 void CrosUserPolicyCache::RetrievePolicyOperation::OnPolicyRetrieved( |
| 141 const std::string& policy_blob) { |
| 142 bool status = true; |
| 143 em::PolicyFetchResponse policy; |
| 144 if (!policy.ParseFromString(policy_blob) || |
| 145 !policy.has_policy_data() || |
| 146 !policy.has_policy_data_signature()) { |
| 147 LOG(ERROR) << "Failed to decode policy"; |
| 148 status = false; |
| 149 } |
| 150 |
| 151 if (!callback_.is_null()) |
| 152 callback_.Run(status, policy); |
| 153 delete this; |
| 154 } |
| 155 |
| 156 CrosUserPolicyCache::CrosUserPolicyCache( |
| 157 chromeos::SessionManagerClient* session_manager_client, |
| 158 CloudPolicyDataStore* data_store, |
| 159 bool wait_for_policy_fetch, |
| 160 const FilePath& legacy_token_cache_file, |
| 161 const FilePath& legacy_policy_cache_file) |
| 162 : session_manager_client_(session_manager_client), |
| 163 data_store_(data_store), |
| 164 pending_policy_fetch_(wait_for_policy_fetch), |
| 165 pending_disk_cache_load_(true), |
| 166 store_operation_(NULL), |
| 167 retrieve_operation_(NULL), |
| 168 legacy_cache_dir_(legacy_token_cache_file.DirName()), |
| 169 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 170 legacy_token_cache_delegate_factory_(this)), |
| 171 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 172 legacy_policy_cache_delegate_factory_(this)) { |
| 173 DCHECK_EQ(legacy_token_cache_file.DirName().value(), |
| 174 legacy_policy_cache_file.DirName().value()); |
| 175 |
| 176 legacy_token_loader_ = |
| 177 new UserPolicyTokenLoader( |
| 178 legacy_token_cache_delegate_factory_.GetWeakPtr(), |
| 179 legacy_token_cache_file); |
| 180 legacy_policy_cache_ = |
| 181 new UserPolicyDiskCache( |
| 182 legacy_policy_cache_delegate_factory_.GetWeakPtr(), |
| 183 legacy_policy_cache_file); |
| 184 } |
| 185 |
| 186 CrosUserPolicyCache::~CrosUserPolicyCache() { |
| 187 CancelStore(); |
| 188 CancelRetrieve(); |
| 189 } |
| 190 |
| 191 void CrosUserPolicyCache::Load() { |
| 192 retrieve_operation_ = |
| 193 new RetrievePolicyOperation( |
| 194 session_manager_client_, |
| 195 base::Bind(&CrosUserPolicyCache::OnPolicyLoadDone, |
| 196 base::Unretained(this))); |
| 197 retrieve_operation_->Run(); |
| 198 } |
| 199 |
| 200 bool CrosUserPolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) { |
| 201 CancelStore(); |
| 202 set_last_policy_refresh_time(base::Time::NowFromSystemTime()); |
| 203 pending_policy_fetch_ = true; |
| 204 store_operation_ = |
| 205 new StorePolicyOperation(policy, |
| 206 session_manager_client_, |
| 207 base::Bind(&CrosUserPolicyCache::OnPolicyStored, |
| 208 base::Unretained(this))); |
| 209 store_operation_->Run(); |
| 210 return true; |
| 211 } |
| 212 |
| 213 void CrosUserPolicyCache::SetUnmanaged() { |
| 214 base::Time now(base::Time::NowFromSystemTime()); |
| 215 SetUnmanagedInternal(now); |
| 216 |
| 217 // Construct a policy blob with unmanaged state. |
| 218 em::PolicyData policy_data; |
| 219 policy_data.set_policy_type(data_store_->policy_type()); |
| 220 policy_data.set_timestamp((now - base::Time::UnixEpoch()).InMilliseconds()); |
| 221 policy_data.set_state(em::PolicyData::UNMANAGED); |
| 222 |
| 223 em::PolicyFetchResponse policy; |
| 224 if (!policy_data.SerializeToString(policy.mutable_policy_data())) { |
| 225 LOG(ERROR) << "Failed to serialize policy_data"; |
| 226 return; |
| 227 } |
| 228 |
| 229 SetPolicy(policy); |
| 230 } |
| 231 |
| 232 void CrosUserPolicyCache::SetFetchingDone() { |
| 233 // If there is a pending policy store or reload, wait for that to complete |
| 234 // before reporting fetching done. |
| 235 if (store_operation_ || retrieve_operation_) |
| 236 return; |
| 237 |
| 238 pending_policy_fetch_ = false; |
| 239 CheckIfDone(); |
| 240 } |
| 241 |
| 242 bool CrosUserPolicyCache::DecodePolicyData(const em::PolicyData& policy_data, |
| 243 PolicyMap* policies) { |
| 244 em::CloudPolicySettings policy; |
| 245 if (!policy.ParseFromString(policy_data.policy_value())) { |
| 246 LOG(WARNING) << "Failed to parse CloudPolicySettings protobuf."; |
| 247 return false; |
| 248 } |
| 249 DecodePolicy(policy, policies); |
| 250 return true; |
| 251 } |
| 252 |
| 253 void CrosUserPolicyCache::OnTokenLoaded(const std::string& token, |
| 254 const std::string& device_id) { |
| 255 if (token.empty()) |
| 256 LOG(WARNING) << "Failed to load legacy token cache"; |
| 257 |
| 258 data_store_->set_device_id(device_id); |
| 259 data_store_->SetDeviceToken(token, true); |
| 260 } |
| 261 |
| 262 void CrosUserPolicyCache::OnDiskCacheLoaded( |
| 263 UserPolicyDiskCache::LoadResult result, |
| 264 const em::CachedCloudPolicyResponse& policy) { |
| 265 if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) { |
| 266 if (policy.unmanaged()) |
| 267 SetUnmanagedInternal(base::Time::FromTimeT(policy.timestamp())); |
| 268 else if (policy.has_cloud_policy()) |
| 269 InstallLegacyPolicy(policy.cloud_policy()); |
| 270 } else { |
| 271 LOG(WARNING) << "Failed to load legacy policy cache: " << result; |
| 272 } |
| 273 |
| 274 pending_disk_cache_load_ = false; |
| 275 CheckIfDone(); |
| 276 } |
| 277 |
| 278 void CrosUserPolicyCache::OnPolicyStored(bool result) { |
| 279 DCHECK(store_operation_); |
| 280 CancelStore(); |
| 281 if (result) { |
| 282 // Policy is stored successfully, reload from session_manager and apply. |
| 283 // This helps us making sure we only use policy that session_manager has |
| 284 // checked and confirmed to be good. |
| 285 CancelRetrieve(); |
| 286 retrieve_operation_ = |
| 287 new RetrievePolicyOperation( |
| 288 session_manager_client_, |
| 289 base::Bind(&CrosUserPolicyCache::OnPolicyReloadDone, |
| 290 base::Unretained(this))); |
| 291 retrieve_operation_->Run(); |
| 292 |
| 293 // Now that the new policy blob is installed, remove the old cache dir. |
| 294 if (!legacy_cache_dir_.empty()) { |
| 295 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
| 296 base::Bind(&RemoveLegacyCacheDir, |
| 297 legacy_cache_dir_)); |
| 298 } |
| 299 } else { |
| 300 LOG(ERROR) << "Failed to store user policy."; |
| 301 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, |
| 302 CloudPolicySubsystem::POLICY_LOCAL_ERROR); |
| 303 pending_policy_fetch_ = false; |
| 304 CheckIfDone(); |
| 305 } |
| 306 } |
| 307 |
| 308 void CrosUserPolicyCache::OnPolicyLoadDone( |
| 309 bool result, |
| 310 const em::PolicyFetchResponse& policy) { |
| 311 DCHECK(retrieve_operation_); |
| 312 CancelRetrieve(); |
| 313 if (!result) { |
| 314 LOG(WARNING) << "No user policy present, trying legacy caches."; |
| 315 legacy_token_loader_->Load(); |
| 316 legacy_policy_cache_->Load(); |
| 317 return; |
| 318 } |
| 319 |
| 320 // We have new-style policy, no need to clean up. |
| 321 legacy_cache_dir_.clear(); |
| 322 |
| 323 em::PolicyData policy_data; |
| 324 if (!policy_data.ParseFromString(policy.policy_data())) { |
| 325 LOG(WARNING) << "Failed to parse PolicyData protobuf."; |
| 326 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, |
| 327 CloudPolicySubsystem::POLICY_LOCAL_ERROR); |
| 328 data_store_->SetDeviceToken(std::string(), true); |
| 329 } else if (policy_data.request_token().empty() || |
| 330 policy_data.username().empty() || |
| 331 policy_data.device_id().empty()) { |
| 332 LOG(WARNING) << "Policy protobuf is missing credentials"; |
| 333 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, |
| 334 CloudPolicySubsystem::POLICY_LOCAL_ERROR); |
| 335 data_store_->SetDeviceToken(std::string(), true); |
| 336 } else { |
| 337 data_store_->set_device_id(policy_data.device_id()); |
| 338 data_store_->SetDeviceToken(policy_data.request_token(), true); |
| 339 if (SetPolicyInternal(policy, NULL, true)) |
| 340 set_last_policy_refresh_time(base::Time::NowFromSystemTime()); |
| 341 } |
| 342 |
| 343 pending_disk_cache_load_ = false; |
| 344 CheckIfDone(); |
| 345 } |
| 346 |
| 347 void CrosUserPolicyCache::OnPolicyReloadDone( |
| 348 bool result, |
| 349 const em::PolicyFetchResponse& policy) { |
| 350 DCHECK(retrieve_operation_); |
| 351 CancelRetrieve(); |
| 352 if (result) { |
| 353 if (SetPolicyInternal(policy, NULL, false)) |
| 354 set_last_policy_refresh_time(base::Time::NowFromSystemTime()); |
| 355 } else { |
| 356 InformNotifier(CloudPolicySubsystem::LOCAL_ERROR, |
| 357 CloudPolicySubsystem::POLICY_LOCAL_ERROR); |
| 358 } |
| 359 pending_policy_fetch_ = false; |
| 360 CheckIfDone(); |
| 361 } |
| 362 |
| 363 void CrosUserPolicyCache::CancelStore() { |
| 364 if (store_operation_) { |
| 365 store_operation_->Cancel(); |
| 366 store_operation_ = NULL; |
| 367 } |
| 368 } |
| 369 |
| 370 void CrosUserPolicyCache::CancelRetrieve() { |
| 371 if (retrieve_operation_) { |
| 372 retrieve_operation_->Cancel(); |
| 373 retrieve_operation_ = NULL; |
| 374 } |
| 375 } |
| 376 |
| 377 void CrosUserPolicyCache::CheckIfDone() { |
| 378 if (!pending_policy_fetch_ && !pending_disk_cache_load_) { |
| 379 if (!IsReady()) |
| 380 SetReady(); |
| 381 CloudPolicyCacheBase::SetFetchingDone(); |
| 382 } |
| 383 } |
| 384 |
| 385 void CrosUserPolicyCache::InstallLegacyPolicy( |
| 386 const em::PolicyFetchResponse& policy) { |
| 387 em::PolicyFetchResponse mutable_policy(policy); |
| 388 mutable_policy.clear_policy_data_signature(); |
| 389 mutable_policy.clear_new_public_key(); |
| 390 mutable_policy.clear_new_public_key_signature(); |
| 391 em::PolicyData policy_data; |
| 392 if (!policy_data.ParseFromString(mutable_policy.policy_data())) { |
| 393 LOG(ERROR) << "Failed to parse policy data."; |
| 394 return; |
| 395 } |
| 396 |
| 397 policy_data.clear_public_key_version(); |
| 398 if (!policy_data.SerializeToString(mutable_policy.mutable_policy_data())) { |
| 399 LOG(ERROR) << "Failed to serialize policy data."; |
| 400 return; |
| 401 } |
| 402 |
| 403 base::Time timestamp; |
| 404 if (SetPolicyInternal(mutable_policy, ×tamp, true)) |
| 405 set_last_policy_refresh_time(timestamp); |
| 406 } |
| 407 |
| 408 // static |
| 409 void CrosUserPolicyCache::RemoveLegacyCacheDir(const FilePath& dir) { |
| 410 if (!file_util::Delete(dir, true)) |
| 411 PLOG(ERROR) << "Failed to remove " << dir.value(); |
| 412 } |
| 413 |
| 414 } // namespace policy |
OLD | NEW |