| 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/user_cloud_policy_store.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/file_util.h" | |
| 9 #include "chrome/browser/policy/proto/cloud_policy.pb.h" | |
| 10 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
| 11 #include "chrome/browser/policy/proto/device_management_local.pb.h" | |
| 12 #include "chrome/browser/profiles/profile.h" | |
| 13 #include "chrome/browser/signin/signin_manager.h" | |
| 14 #include "chrome/browser/signin/signin_manager_factory.h" | |
| 15 #include "content/public/browser/browser_thread.h" | |
| 16 #include "policy/policy_constants.h" | |
| 17 | |
| 18 namespace em = enterprise_management; | |
| 19 | |
| 20 namespace policy { | |
| 21 | |
| 22 enum PolicyLoadStatus { | |
| 23 // Policy blob was successfully loaded and parsed. | |
| 24 LOAD_RESULT_SUCCESS, | |
| 25 | |
| 26 // No previously stored policy was found. | |
| 27 LOAD_RESULT_NO_POLICY_FILE, | |
| 28 | |
| 29 // Could not load the previously stored policy due to either a parse or | |
| 30 // file read error. | |
| 31 LOAD_RESULT_LOAD_ERROR, | |
| 32 }; | |
| 33 | |
| 34 // Struct containing the result of a policy load - if |status| == | |
| 35 // LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk. | |
| 36 struct PolicyLoadResult { | |
| 37 PolicyLoadStatus status; | |
| 38 em::PolicyFetchResponse policy; | |
| 39 }; | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 // Subdirectory in the user's profile for storing user policies. | |
| 44 const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy"); | |
| 45 // File in the above directory for storing user policy data. | |
| 46 const base::FilePath::CharType kPolicyCacheFile[] = | |
| 47 FILE_PATH_LITERAL("User Policy"); | |
| 48 | |
| 49 // Loads policy from the backing file. Returns a PolicyLoadResult with the | |
| 50 // results of the fetch. | |
| 51 policy::PolicyLoadResult LoadPolicyFromDisk(const base::FilePath& path) { | |
| 52 policy::PolicyLoadResult result; | |
| 53 // If the backing file does not exist, just return. | |
| 54 if (!file_util::PathExists(path)) { | |
| 55 result.status = policy::LOAD_RESULT_NO_POLICY_FILE; | |
| 56 return result; | |
| 57 } | |
| 58 std::string data; | |
| 59 if (!file_util::ReadFileToString(path, &data) || | |
| 60 !result.policy.ParseFromArray(data.c_str(), data.size())) { | |
| 61 LOG(WARNING) << "Failed to read or parse policy data from " << path.value(); | |
| 62 result.status = policy::LOAD_RESULT_LOAD_ERROR; | |
| 63 return result; | |
| 64 } | |
| 65 | |
| 66 result.status = policy::LOAD_RESULT_SUCCESS; | |
| 67 return result; | |
| 68 } | |
| 69 | |
| 70 // Stores policy to the backing file (must be called via a task on | |
| 71 // the FILE thread). | |
| 72 void StorePolicyToDiskOnFileThread(const base::FilePath& path, | |
| 73 const em::PolicyFetchResponse& policy) { | |
| 74 DVLOG(1) << "Storing policy to " << path.value(); | |
| 75 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 76 std::string data; | |
| 77 if (!policy.SerializeToString(&data)) { | |
| 78 DLOG(WARNING) << "Failed to serialize policy data"; | |
| 79 return; | |
| 80 } | |
| 81 | |
| 82 if (!file_util::CreateDirectory(path.DirName())) { | |
| 83 DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); | |
| 84 return; | |
| 85 } | |
| 86 | |
| 87 int size = data.size(); | |
| 88 if (file_util::WriteFile(path, data.c_str(), size) != size) { | |
| 89 DLOG(WARNING) << "Failed to write " << path.value(); | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 } // namespace | |
| 94 | |
| 95 UserCloudPolicyStore::UserCloudPolicyStore(Profile* profile, | |
| 96 const base::FilePath& path) | |
| 97 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | |
| 98 profile_(profile), | |
| 99 backing_file_path_(path) { | |
| 100 } | |
| 101 | |
| 102 UserCloudPolicyStore::~UserCloudPolicyStore() {} | |
| 103 | |
| 104 // static | |
| 105 scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create( | |
| 106 Profile* profile) { | |
| 107 base::FilePath path = | |
| 108 profile->GetPath().Append(kPolicyDir).Append(kPolicyCacheFile); | |
| 109 return make_scoped_ptr(new UserCloudPolicyStore(profile, path)); | |
| 110 } | |
| 111 | |
| 112 void UserCloudPolicyStore::LoadImmediately() { | |
| 113 DVLOG(1) << "Initiating immediate policy load from disk"; | |
| 114 // Cancel any pending Load/Store/Validate operations. | |
| 115 weak_factory_.InvalidateWeakPtrs(); | |
| 116 // Load the policy from disk... | |
| 117 PolicyLoadResult result = LoadPolicyFromDisk(backing_file_path_); | |
| 118 // ...and install it, reporting success/failure to any observers. | |
| 119 PolicyLoaded(false, result); | |
| 120 } | |
| 121 | |
| 122 void UserCloudPolicyStore::Clear() { | |
| 123 content::BrowserThread::PostTask( | |
| 124 content::BrowserThread::FILE, FROM_HERE, | |
| 125 base::Bind(base::IgnoreResult(&file_util::Delete), | |
| 126 backing_file_path_, | |
| 127 false)); | |
| 128 policy_.reset(); | |
| 129 policy_map_.Clear(); | |
| 130 NotifyStoreLoaded(); | |
| 131 } | |
| 132 | |
| 133 void UserCloudPolicyStore::Load() { | |
| 134 DVLOG(1) << "Initiating policy load from disk"; | |
| 135 // Cancel any pending Load/Store/Validate operations. | |
| 136 weak_factory_.InvalidateWeakPtrs(); | |
| 137 | |
| 138 // Start a new Load operation and have us get called back when it is | |
| 139 // complete. | |
| 140 content::BrowserThread::PostTaskAndReplyWithResult( | |
| 141 content::BrowserThread::FILE, FROM_HERE, | |
| 142 base::Bind(&LoadPolicyFromDisk, backing_file_path_), | |
| 143 base::Bind(&UserCloudPolicyStore::PolicyLoaded, | |
| 144 weak_factory_.GetWeakPtr(), true)); | |
| 145 } | |
| 146 | |
| 147 void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background, | |
| 148 PolicyLoadResult result) { | |
| 149 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 150 switch (result.status) { | |
| 151 case LOAD_RESULT_LOAD_ERROR: | |
| 152 status_ = STATUS_LOAD_ERROR; | |
| 153 NotifyStoreError(); | |
| 154 break; | |
| 155 | |
| 156 case LOAD_RESULT_NO_POLICY_FILE: | |
| 157 DVLOG(1) << "No policy found on disk"; | |
| 158 NotifyStoreLoaded(); | |
| 159 break; | |
| 160 | |
| 161 case LOAD_RESULT_SUCCESS: { | |
| 162 // Found policy on disk - need to validate it before it can be used. | |
| 163 scoped_ptr<em::PolicyFetchResponse> cloud_policy( | |
| 164 new em::PolicyFetchResponse(result.policy)); | |
| 165 Validate(cloud_policy.Pass(), | |
| 166 validate_in_background, | |
| 167 base::Bind( | |
| 168 &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation, | |
| 169 weak_factory_.GetWeakPtr())); | |
| 170 break; | |
| 171 } | |
| 172 default: | |
| 173 NOTREACHED(); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation( | |
| 178 UserCloudPolicyValidator* validator) { | |
| 179 validation_status_ = validator->status(); | |
| 180 if (!validator->success()) { | |
| 181 DVLOG(1) << "Validation failed: status=" << validation_status_; | |
| 182 status_ = STATUS_VALIDATION_ERROR; | |
| 183 NotifyStoreError(); | |
| 184 return; | |
| 185 } | |
| 186 | |
| 187 DVLOG(1) << "Validation succeeded - installing policy with dm_token: " << | |
| 188 validator->policy_data()->request_token(); | |
| 189 DVLOG(1) << "Device ID: " << validator->policy_data()->device_id(); | |
| 190 | |
| 191 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | |
| 192 status_ = STATUS_OK; | |
| 193 NotifyStoreLoaded(); | |
| 194 } | |
| 195 | |
| 196 void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) { | |
| 197 // Stop any pending requests to store policy, then validate the new policy | |
| 198 // before storing it. | |
| 199 weak_factory_.InvalidateWeakPtrs(); | |
| 200 scoped_ptr<em::PolicyFetchResponse> policy_copy( | |
| 201 new em::PolicyFetchResponse(policy)); | |
| 202 Validate(policy_copy.Pass(), | |
| 203 true, | |
| 204 base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation, | |
| 205 weak_factory_.GetWeakPtr())); | |
| 206 } | |
| 207 | |
| 208 void UserCloudPolicyStore::Validate( | |
| 209 scoped_ptr<em::PolicyFetchResponse> policy, | |
| 210 bool validate_in_background, | |
| 211 const UserCloudPolicyValidator::CompletionCallback& callback) { | |
| 212 // Configure the validator. | |
| 213 scoped_ptr<UserCloudPolicyValidator> validator = | |
| 214 CreateValidator(policy.Pass()); | |
| 215 SigninManager* signin = SigninManagerFactory::GetForProfileIfExists(profile_); | |
| 216 if (signin) { | |
| 217 std::string username = signin->GetAuthenticatedUsername(); | |
| 218 // Validate the username if the user is signed in. | |
| 219 if (!username.empty()) | |
| 220 validator->ValidateUsername(username); | |
| 221 } | |
| 222 | |
| 223 if (validate_in_background) { | |
| 224 // Start validation in the background. The Validator will free itself once | |
| 225 // validation is complete. | |
| 226 validator.release()->StartValidation(callback); | |
| 227 } else { | |
| 228 // Run validation immediately and invoke the callback with the results. | |
| 229 validator->RunValidation(); | |
| 230 callback.Run(validator.get()); | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 void UserCloudPolicyStore::StorePolicyAfterValidation( | |
| 235 UserCloudPolicyValidator* validator) { | |
| 236 validation_status_ = validator->status(); | |
| 237 DVLOG(1) << "Policy validation complete: status = " << validation_status_; | |
| 238 if (!validator->success()) { | |
| 239 status_ = STATUS_VALIDATION_ERROR; | |
| 240 NotifyStoreError(); | |
| 241 return; | |
| 242 } | |
| 243 | |
| 244 // Persist the validated policy (just fire a task - don't bother getting a | |
| 245 // reply because we can't do anything if it fails). | |
| 246 content::BrowserThread::PostTask( | |
| 247 content::BrowserThread::FILE, FROM_HERE, | |
| 248 base::Bind(&StorePolicyToDiskOnFileThread, | |
| 249 backing_file_path_, *validator->policy())); | |
| 250 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | |
| 251 status_ = STATUS_OK; | |
| 252 NotifyStoreLoaded(); | |
| 253 } | |
| 254 | |
| 255 } // namespace policy | |
| OLD | NEW |