OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/policy/core/common/cloud/user_cloud_policy_store.h" | 5 #include "components/policy/core/common/cloud/user_cloud_policy_store.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/metrics/histogram.h" |
10 #include "base/task_runner_util.h" | 11 #include "base/task_runner_util.h" |
11 #include "policy/proto/cloud_policy.pb.h" | 12 #include "policy/proto/cloud_policy.pb.h" |
12 #include "policy/proto/device_management_backend.pb.h" | 13 #include "policy/proto/device_management_backend.pb.h" |
| 14 #include "policy/proto/policy_signing_key.pb.h" |
13 | 15 |
14 namespace em = enterprise_management; | 16 namespace em = enterprise_management; |
15 | 17 |
16 namespace policy { | 18 namespace policy { |
17 | 19 |
18 enum PolicyLoadStatus { | 20 enum PolicyLoadStatus { |
19 // Policy blob was successfully loaded and parsed. | 21 // Policy blob was successfully loaded and parsed. |
20 LOAD_RESULT_SUCCESS, | 22 LOAD_RESULT_SUCCESS, |
21 | 23 |
22 // No previously stored policy was found. | 24 // No previously stored policy was found. |
23 LOAD_RESULT_NO_POLICY_FILE, | 25 LOAD_RESULT_NO_POLICY_FILE, |
24 | 26 |
25 // Could not load the previously stored policy due to either a parse or | 27 // Could not load the previously stored policy due to either a parse or |
26 // file read error. | 28 // file read error. |
27 LOAD_RESULT_LOAD_ERROR, | 29 LOAD_RESULT_LOAD_ERROR, |
28 }; | 30 }; |
29 | 31 |
30 // Struct containing the result of a policy load - if |status| == | 32 // Struct containing the result of a policy load - if |status| == |
31 // LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk. | 33 // LOAD_RESULT_SUCCESS, |policy| is initialized from the policy file on disk. |
32 struct PolicyLoadResult { | 34 struct PolicyLoadResult { |
33 PolicyLoadStatus status; | 35 PolicyLoadStatus status; |
34 em::PolicyFetchResponse policy; | 36 em::PolicyFetchResponse policy; |
| 37 em::PolicySigningKey key; |
35 }; | 38 }; |
36 | 39 |
37 namespace { | 40 namespace { |
38 | 41 |
39 // Subdirectory in the user's profile for storing user policies. | 42 // Subdirectory in the user's profile for storing user policies. |
40 const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy"); | 43 const base::FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Policy"); |
41 // File in the above directory for storing user policy data. | 44 // File in the above directory for storing user policy data. |
42 const base::FilePath::CharType kPolicyCacheFile[] = | 45 const base::FilePath::CharType kPolicyCacheFile[] = |
43 FILE_PATH_LITERAL("User Policy"); | 46 FILE_PATH_LITERAL("User Policy"); |
44 | 47 |
| 48 // File in the above directory for storing policy signing key data. |
| 49 const base::FilePath::CharType kKeyCacheFile[] = |
| 50 FILE_PATH_LITERAL("Signing Key"); |
| 51 |
| 52 const char kMetricPolicyHasVerifiedCachedKey[] = |
| 53 "Enterprise.PolicyHasVerifiedCachedKey"; |
| 54 |
45 // Loads policy from the backing file. Returns a PolicyLoadResult with the | 55 // Loads policy from the backing file. Returns a PolicyLoadResult with the |
46 // results of the fetch. | 56 // results of the fetch. |
47 policy::PolicyLoadResult LoadPolicyFromDisk(const base::FilePath& path) { | 57 policy::PolicyLoadResult LoadPolicyFromDisk( |
| 58 const base::FilePath& policy_path, |
| 59 const base::FilePath& key_path) { |
48 policy::PolicyLoadResult result; | 60 policy::PolicyLoadResult result; |
49 // If the backing file does not exist, just return. | 61 // If the backing file does not exist, just return. We don't verify the key |
50 if (!base::PathExists(path)) { | 62 // path here, because the key is optional (the validation code will fail if |
| 63 // the key does not exist but the loaded policy is unsigned). |
| 64 if (!base::PathExists(policy_path)) { |
51 result.status = policy::LOAD_RESULT_NO_POLICY_FILE; | 65 result.status = policy::LOAD_RESULT_NO_POLICY_FILE; |
52 return result; | 66 return result; |
53 } | 67 } |
54 std::string data; | 68 std::string data; |
55 if (!base::ReadFileToString(path, &data) || | 69 // TODO(atwilson): Enforce a policy/key maxsize when ReadFileToString() can |
56 !result.policy.ParseFromArray(data.c_str(), data.size())) { | 70 // accept a max_size (http://crbug.com/339417). |
57 LOG(WARNING) << "Failed to read or parse policy data from " << path.value(); | 71 if (!base::ReadFileToString(policy_path, &data) || |
| 72 !result.policy.ParseFromString(data)) { |
| 73 LOG(WARNING) << "Failed to read or parse policy data from " |
| 74 << policy_path.value(); |
58 result.status = policy::LOAD_RESULT_LOAD_ERROR; | 75 result.status = policy::LOAD_RESULT_LOAD_ERROR; |
59 return result; | 76 return result; |
60 } | 77 } |
61 | 78 |
| 79 if (!base::ReadFileToString(key_path, &data) || |
| 80 !result.key.ParseFromString(data)) { |
| 81 // Log an error on missing key data, but do not trigger a load failure |
| 82 // for now since there are still old unsigned cached policy blobs in the |
| 83 // wild with no associated key (see kMetricPolicyHasVerifiedCachedKey UMA |
| 84 // stat below). |
| 85 LOG(ERROR) << "Failed to read or parse key data from " << key_path.value(); |
| 86 result.key.clear_signing_key(); |
| 87 } |
| 88 |
| 89 // Track the occurrence of valid cached keys - when this ratio gets high |
| 90 // enough, we can update the code to reject unsigned policy or unverified |
| 91 // keys. |
| 92 UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey, |
| 93 result.key.has_signing_key()); |
| 94 |
62 result.status = policy::LOAD_RESULT_SUCCESS; | 95 result.status = policy::LOAD_RESULT_SUCCESS; |
63 return result; | 96 return result; |
64 } | 97 } |
65 | 98 |
| 99 bool WriteStringToFile(const base::FilePath path, const std::string& data) { |
| 100 if (!base::CreateDirectory(path.DirName())) { |
| 101 DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); |
| 102 return false; |
| 103 } |
| 104 |
| 105 int size = data.size(); |
| 106 if (file_util::WriteFile(path, data.c_str(), size) != size) { |
| 107 DLOG(WARNING) << "Failed to write " << path.value(); |
| 108 return false; |
| 109 } |
| 110 |
| 111 return true; |
| 112 } |
| 113 |
66 // Stores policy to the backing file (must be called via a task on | 114 // Stores policy to the backing file (must be called via a task on |
67 // the background thread). | 115 // the background thread). |
68 void StorePolicyToDiskOnBackgroundThread( | 116 void StorePolicyToDiskOnBackgroundThread( |
69 const base::FilePath& path, | 117 const base::FilePath& policy_path, |
| 118 const base::FilePath& key_path, |
70 const em::PolicyFetchResponse& policy) { | 119 const em::PolicyFetchResponse& policy) { |
71 DVLOG(1) << "Storing policy to " << path.value(); | 120 DVLOG(1) << "Storing policy to " << policy_path.value(); |
72 std::string data; | 121 std::string data; |
73 if (!policy.SerializeToString(&data)) { | 122 if (!policy.SerializeToString(&data)) { |
74 DLOG(WARNING) << "Failed to serialize policy data"; | 123 DLOG(WARNING) << "Failed to serialize policy data"; |
75 return; | 124 return; |
76 } | 125 } |
77 | 126 |
78 if (!base::CreateDirectory(path.DirName())) { | 127 if (!WriteStringToFile(policy_path, data)) |
79 DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); | |
80 return; | 128 return; |
81 } | |
82 | 129 |
83 int size = data.size(); | 130 if (policy.has_new_public_key()) { |
84 if (file_util::WriteFile(path, data.c_str(), size) != size) { | 131 // Write the new public key and its verification signature to a file. |
85 DLOG(WARNING) << "Failed to write " << path.value(); | 132 em::PolicySigningKey key_info; |
| 133 key_info.set_signing_key(policy.new_public_key()); |
| 134 key_info.set_signing_key_signature( |
| 135 policy.new_public_key_verification_signature()); |
| 136 std::string key_data; |
| 137 if (!key_info.SerializeToString(&key_data)) { |
| 138 DLOG(WARNING) << "Failed to serialize policy signing key"; |
| 139 return; |
| 140 } |
| 141 |
| 142 WriteStringToFile(key_path, key_data); |
86 } | 143 } |
87 } | 144 } |
88 | 145 |
89 } // namespace | 146 } // namespace |
90 | 147 |
91 UserCloudPolicyStore::UserCloudPolicyStore( | 148 UserCloudPolicyStore::UserCloudPolicyStore( |
92 const base::FilePath& path, | 149 const base::FilePath& policy_path, |
| 150 const base::FilePath& key_path, |
| 151 const std::string& verification_key, |
93 scoped_refptr<base::SequencedTaskRunner> background_task_runner) | 152 scoped_refptr<base::SequencedTaskRunner> background_task_runner) |
94 : UserCloudPolicyStoreBase(background_task_runner), | 153 : UserCloudPolicyStoreBase(background_task_runner), |
95 weak_factory_(this), | 154 weak_factory_(this), |
96 backing_file_path_(path) {} | 155 policy_path_(policy_path), |
| 156 key_path_(key_path), |
| 157 verification_key_(verification_key) {} |
97 | 158 |
98 UserCloudPolicyStore::~UserCloudPolicyStore() {} | 159 UserCloudPolicyStore::~UserCloudPolicyStore() {} |
99 | 160 |
100 // static | 161 // static |
101 scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create( | 162 scoped_ptr<UserCloudPolicyStore> UserCloudPolicyStore::Create( |
102 const base::FilePath& profile_path, | 163 const base::FilePath& profile_path, |
| 164 const std::string& verification_key, |
103 scoped_refptr<base::SequencedTaskRunner> background_task_runner) { | 165 scoped_refptr<base::SequencedTaskRunner> background_task_runner) { |
104 base::FilePath path = | 166 base::FilePath policy_path = |
105 profile_path.Append(kPolicyDir).Append(kPolicyCacheFile); | 167 profile_path.Append(kPolicyDir).Append(kPolicyCacheFile); |
106 return make_scoped_ptr( | 168 base::FilePath key_path = |
107 new UserCloudPolicyStore(path, background_task_runner)); | 169 profile_path.Append(kPolicyDir).Append(kKeyCacheFile); |
| 170 return make_scoped_ptr(new UserCloudPolicyStore( |
| 171 policy_path, key_path, verification_key, background_task_runner)); |
108 } | 172 } |
109 | 173 |
110 void UserCloudPolicyStore::SetSigninUsername(const std::string& username) { | 174 void UserCloudPolicyStore::SetSigninUsername(const std::string& username) { |
111 signin_username_ = username; | 175 signin_username_ = username; |
112 } | 176 } |
113 | 177 |
114 void UserCloudPolicyStore::LoadImmediately() { | 178 void UserCloudPolicyStore::LoadImmediately() { |
115 DVLOG(1) << "Initiating immediate policy load from disk"; | 179 DVLOG(1) << "Initiating immediate policy load from disk"; |
116 // Cancel any pending Load/Store/Validate operations. | 180 // Cancel any pending Load/Store/Validate operations. |
117 weak_factory_.InvalidateWeakPtrs(); | 181 weak_factory_.InvalidateWeakPtrs(); |
118 // Load the policy from disk... | 182 // Load the policy from disk... |
119 PolicyLoadResult result = LoadPolicyFromDisk(backing_file_path_); | 183 PolicyLoadResult result = LoadPolicyFromDisk(policy_path_, key_path_); |
120 // ...and install it, reporting success/failure to any observers. | 184 // ...and install it, reporting success/failure to any observers. |
121 PolicyLoaded(false, result); | 185 PolicyLoaded(false, result); |
122 } | 186 } |
123 | 187 |
124 void UserCloudPolicyStore::Clear() { | 188 void UserCloudPolicyStore::Clear() { |
125 background_task_runner()->PostTask( | 189 background_task_runner()->PostTask( |
126 FROM_HERE, | 190 FROM_HERE, |
127 base::Bind( | 191 base::Bind(base::IgnoreResult(&base::DeleteFile), policy_path_, false)); |
128 base::IgnoreResult(&base::DeleteFile), backing_file_path_, false)); | 192 background_task_runner()->PostTask( |
| 193 FROM_HERE, |
| 194 base::Bind(base::IgnoreResult(&base::DeleteFile), key_path_, false)); |
129 policy_.reset(); | 195 policy_.reset(); |
130 policy_map_.Clear(); | 196 policy_map_.Clear(); |
| 197 policy_key_.clear(); |
131 NotifyStoreLoaded(); | 198 NotifyStoreLoaded(); |
132 } | 199 } |
133 | 200 |
134 void UserCloudPolicyStore::Load() { | 201 void UserCloudPolicyStore::Load() { |
135 DVLOG(1) << "Initiating policy load from disk"; | 202 DVLOG(1) << "Initiating policy load from disk"; |
136 // Cancel any pending Load/Store/Validate operations. | 203 // Cancel any pending Load/Store/Validate operations. |
137 weak_factory_.InvalidateWeakPtrs(); | 204 weak_factory_.InvalidateWeakPtrs(); |
138 | 205 |
139 // Start a new Load operation and have us get called back when it is | 206 // Start a new Load operation and have us get called back when it is |
140 // complete. | 207 // complete. |
141 base::PostTaskAndReplyWithResult( | 208 base::PostTaskAndReplyWithResult( |
142 background_task_runner(), | 209 background_task_runner(), |
143 FROM_HERE, | 210 FROM_HERE, |
144 base::Bind(&LoadPolicyFromDisk, backing_file_path_), | 211 base::Bind(&LoadPolicyFromDisk, policy_path_, key_path_), |
145 base::Bind(&UserCloudPolicyStore::PolicyLoaded, | 212 base::Bind(&UserCloudPolicyStore::PolicyLoaded, |
146 weak_factory_.GetWeakPtr(), true)); | 213 weak_factory_.GetWeakPtr(), true)); |
147 } | 214 } |
148 | 215 |
149 void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background, | 216 void UserCloudPolicyStore::PolicyLoaded(bool validate_in_background, |
150 PolicyLoadResult result) { | 217 PolicyLoadResult result) { |
151 switch (result.status) { | 218 switch (result.status) { |
152 case LOAD_RESULT_LOAD_ERROR: | 219 case LOAD_RESULT_LOAD_ERROR: |
153 status_ = STATUS_LOAD_ERROR; | 220 status_ = STATUS_LOAD_ERROR; |
154 NotifyStoreError(); | 221 NotifyStoreError(); |
155 break; | 222 break; |
156 | 223 |
157 case LOAD_RESULT_NO_POLICY_FILE: | 224 case LOAD_RESULT_NO_POLICY_FILE: |
158 DVLOG(1) << "No policy found on disk"; | 225 DVLOG(1) << "No policy found on disk"; |
159 NotifyStoreLoaded(); | 226 NotifyStoreLoaded(); |
160 break; | 227 break; |
161 | 228 |
162 case LOAD_RESULT_SUCCESS: { | 229 case LOAD_RESULT_SUCCESS: { |
163 // Found policy on disk - need to validate it before it can be used. | 230 // Found policy on disk - need to validate it before it can be used. |
164 scoped_ptr<em::PolicyFetchResponse> cloud_policy( | 231 scoped_ptr<em::PolicyFetchResponse> cloud_policy( |
165 new em::PolicyFetchResponse(result.policy)); | 232 new em::PolicyFetchResponse(result.policy)); |
| 233 scoped_ptr<em::PolicySigningKey> key( |
| 234 new em::PolicySigningKey(result.key)); |
166 Validate(cloud_policy.Pass(), | 235 Validate(cloud_policy.Pass(), |
| 236 key.Pass(), |
167 validate_in_background, | 237 validate_in_background, |
168 base::Bind( | 238 base::Bind( |
169 &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation, | 239 &UserCloudPolicyStore::InstallLoadedPolicyAfterValidation, |
170 weak_factory_.GetWeakPtr())); | 240 weak_factory_.GetWeakPtr(), |
| 241 result.key.has_signing_key() ? |
| 242 result.key.signing_key() : std::string())); |
171 break; | 243 break; |
172 } | 244 } |
173 default: | 245 default: |
174 NOTREACHED(); | 246 NOTREACHED(); |
175 } | 247 } |
176 } | 248 } |
177 | 249 |
178 void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation( | 250 void UserCloudPolicyStore::InstallLoadedPolicyAfterValidation( |
| 251 const std::string& signing_key, |
179 UserCloudPolicyValidator* validator) { | 252 UserCloudPolicyValidator* validator) { |
180 validation_status_ = validator->status(); | 253 validation_status_ = validator->status(); |
181 if (!validator->success()) { | 254 if (!validator->success()) { |
182 DVLOG(1) << "Validation failed: status=" << validation_status_; | 255 DVLOG(1) << "Validation failed: status=" << validation_status_; |
183 status_ = STATUS_VALIDATION_ERROR; | 256 status_ = STATUS_VALIDATION_ERROR; |
184 NotifyStoreError(); | 257 NotifyStoreError(); |
185 return; | 258 return; |
186 } | 259 } |
187 | 260 |
188 DVLOG(1) << "Validation succeeded - installing policy with dm_token: " << | 261 DVLOG(1) << "Validation succeeded - installing policy with dm_token: " << |
189 validator->policy_data()->request_token(); | 262 validator->policy_data()->request_token(); |
190 DVLOG(1) << "Device ID: " << validator->policy_data()->device_id(); | 263 DVLOG(1) << "Device ID: " << validator->policy_data()->device_id(); |
191 | 264 |
192 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | 265 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); |
| 266 // Policy validation succeeded, so we know the signing key is good. |
| 267 policy_key_ = signing_key; |
193 status_ = STATUS_OK; | 268 status_ = STATUS_OK; |
194 NotifyStoreLoaded(); | 269 NotifyStoreLoaded(); |
195 } | 270 } |
196 | 271 |
197 void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) { | 272 void UserCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) { |
198 // Stop any pending requests to store policy, then validate the new policy | 273 // Stop any pending requests to store policy, then validate the new policy |
199 // before storing it. | 274 // before storing it. |
200 weak_factory_.InvalidateWeakPtrs(); | 275 weak_factory_.InvalidateWeakPtrs(); |
201 scoped_ptr<em::PolicyFetchResponse> policy_copy( | 276 scoped_ptr<em::PolicyFetchResponse> policy_copy( |
202 new em::PolicyFetchResponse(policy)); | 277 new em::PolicyFetchResponse(policy)); |
203 Validate(policy_copy.Pass(), | 278 Validate(policy_copy.Pass(), |
| 279 scoped_ptr<em::PolicySigningKey>(), |
204 true, | 280 true, |
205 base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation, | 281 base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation, |
206 weak_factory_.GetWeakPtr())); | 282 weak_factory_.GetWeakPtr())); |
207 } | 283 } |
208 | 284 |
209 void UserCloudPolicyStore::Validate( | 285 void UserCloudPolicyStore::Validate( |
210 scoped_ptr<em::PolicyFetchResponse> policy, | 286 scoped_ptr<em::PolicyFetchResponse> policy, |
| 287 scoped_ptr<em::PolicySigningKey> cached_key, |
211 bool validate_in_background, | 288 bool validate_in_background, |
212 const UserCloudPolicyValidator::CompletionCallback& callback) { | 289 const UserCloudPolicyValidator::CompletionCallback& callback) { |
| 290 |
| 291 const bool signed_policy = policy->has_policy_data_signature(); |
| 292 |
213 // Configure the validator. | 293 // Configure the validator. |
214 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator( | 294 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator( |
215 policy.Pass(), | 295 policy.Pass(), |
216 CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE); | 296 CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE); |
217 | 297 |
218 // Validate the username if the user is signed in. | 298 // Validate the username if the user is signed in. |
219 if (!signin_username_.empty()) | 299 if (!signin_username_.empty()) { |
| 300 DVLOG(1) << "Validating username: " << signin_username_; |
220 validator->ValidateUsername(signin_username_); | 301 validator->ValidateUsername(signin_username_); |
| 302 } |
| 303 |
| 304 // There are 4 cases: |
| 305 // |
| 306 // 1) Validation after loading from cache with no cached key. |
| 307 // Action: Don't validate signature (migration from previously cached |
| 308 // unsigned blob). |
| 309 // |
| 310 // 2) Validation after loading from cache with a cached key |
| 311 // Action: Validate signature on policy blob but don't allow key rotation. |
| 312 // |
| 313 // 3) Validation after loading new policy from the server with no cached key |
| 314 // Action: Validate as initial key provisioning (case where we are migrating |
| 315 // from unsigned policy) |
| 316 // |
| 317 // 4) Validation after loading new policy from the server with a cached key |
| 318 // Action: Validate as normal, and allow key rotation. |
| 319 if (cached_key) { |
| 320 // Loading from cache should not change the cached keys. |
| 321 DCHECK(policy_key_.empty() || policy_key_ == cached_key->signing_key()); |
| 322 if (!signed_policy || !cached_key->has_signing_key()) { |
| 323 // Case #1 - loading from cache with no signing key. |
| 324 // TODO(atwilson): Reject policy with no cached key once |
| 325 // kMetricPolicyHasVerifiedCachedKey rises to a high enough level. |
| 326 DLOG(WARNING) << "Allowing unsigned cached blob for migration"; |
| 327 } else { |
| 328 // Case #2 - loading from cache with a cached key - just do normal |
| 329 // signature validation using this key. We're loading from cache so don't |
| 330 // allow key rotation. |
| 331 const bool no_rotation = false; |
| 332 validator->ValidateSignature(cached_key->signing_key(), |
| 333 verification_key_, |
| 334 cached_key->signing_key_signature(), |
| 335 no_rotation); |
| 336 } |
| 337 } else { |
| 338 // No passed cached_key - this is not validating the initial policy load |
| 339 // from cache, but rather an update from the server. |
| 340 if (policy_key_.empty()) { |
| 341 // Case #3 - no valid existing policy key, so this new policy fetch should |
| 342 // include an initial key provision. |
| 343 validator->ValidateInitialKey(verification_key_); |
| 344 } else { |
| 345 // Case #4 - verify new policy with existing key. We always allow key |
| 346 // rotation - the verification key will prevent invalid policy from being |
| 347 // injected. |policy_key_| is already known to be valid, so no |
| 348 // verification signature is passed in. |
| 349 const bool allow_rotation = true; |
| 350 validator->ValidateSignature( |
| 351 policy_key_, verification_key_, std::string(), allow_rotation); |
| 352 } |
| 353 } |
221 | 354 |
222 if (validate_in_background) { | 355 if (validate_in_background) { |
223 // Start validation in the background. The Validator will free itself once | 356 // Start validation in the background. The Validator will free itself once |
224 // validation is complete. | 357 // validation is complete. |
225 validator.release()->StartValidation(callback); | 358 validator.release()->StartValidation(callback); |
226 } else { | 359 } else { |
227 // Run validation immediately and invoke the callback with the results. | 360 // Run validation immediately and invoke the callback with the results. |
228 validator->RunValidation(); | 361 validator->RunValidation(); |
229 callback.Run(validator.get()); | 362 callback.Run(validator.get()); |
230 } | 363 } |
231 } | 364 } |
232 | 365 |
233 void UserCloudPolicyStore::StorePolicyAfterValidation( | 366 void UserCloudPolicyStore::StorePolicyAfterValidation( |
234 UserCloudPolicyValidator* validator) { | 367 UserCloudPolicyValidator* validator) { |
235 validation_status_ = validator->status(); | 368 validation_status_ = validator->status(); |
236 DVLOG(1) << "Policy validation complete: status = " << validation_status_; | 369 DVLOG(1) << "Policy validation complete: status = " << validation_status_; |
237 if (!validator->success()) { | 370 if (!validator->success()) { |
238 status_ = STATUS_VALIDATION_ERROR; | 371 status_ = STATUS_VALIDATION_ERROR; |
239 NotifyStoreError(); | 372 NotifyStoreError(); |
240 return; | 373 return; |
241 } | 374 } |
242 | 375 |
243 // Persist the validated policy (just fire a task - don't bother getting a | 376 // Persist the validated policy (just fire a task - don't bother getting a |
244 // reply because we can't do anything if it fails). | 377 // reply because we can't do anything if it fails). |
245 background_task_runner()->PostTask( | 378 background_task_runner()->PostTask( |
246 FROM_HERE, | 379 FROM_HERE, |
247 base::Bind(&StorePolicyToDiskOnBackgroundThread, | 380 base::Bind(&StorePolicyToDiskOnBackgroundThread, |
248 backing_file_path_, *validator->policy())); | 381 policy_path_, key_path_, *validator->policy())); |
249 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); | 382 InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); |
| 383 |
| 384 // If the key was rotated, update our local cache of the key. |
| 385 if (validator->policy()->has_new_public_key()) |
| 386 policy_key_ = validator->policy()->new_public_key(); |
250 status_ = STATUS_OK; | 387 status_ = STATUS_OK; |
251 NotifyStoreLoaded(); | 388 NotifyStoreLoaded(); |
252 } | 389 } |
253 | 390 |
254 } // namespace policy | 391 } // namespace policy |
OLD | NEW |