Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: chrome/browser/chromeos/device_settings_provider.cc

Issue 8727037: Signed settings refactoring: Proper caching and more tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments. Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/chromeos/device_settings_provider.h"
6
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/callback.h"
11 #include "base/hash_tables.h"
12 #include "base/logging.h"
13 #include "base/memory/singleton.h"
14 #include "base/string_util.h"
15 #include "base/values.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chromeos/cros/cros_library.h"
18 #include "chrome/browser/chromeos/cros/network_library.h"
19 #include "chrome/browser/chromeos/cros_settings.h"
20 #include "chrome/browser/chromeos/cros_settings_names.h"
21 #include "chrome/browser/chromeos/login/ownership_service.h"
22 #include "chrome/browser/chromeos/login/ownership_status_checker.h"
23 #include "chrome/browser/chromeos/login/signed_settings_cache.h"
24 #include "chrome/browser/chromeos/login/user_manager.h"
25 #include "chrome/browser/policy/proto/chrome_device_policy.pb.h"
26 #include "chrome/browser/policy/proto/device_management_backend.pb.h"
27 #include "chrome/browser/prefs/pref_service.h"
28 #include "chrome/browser/prefs/pref_value_map.h"
29 #include "chrome/browser/prefs/scoped_user_pref_update.h"
30 #include "chrome/browser/ui/options/options_util.h"
31 #include "chrome/common/chrome_notification_types.h"
32 #include "chrome/installer/util/google_update_settings.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_service.h"
35
36 using content::BrowserThread;
37 using google::protobuf::RepeatedPtrField;
38
39 namespace chromeos {
40
41 namespace {
42
43 const char* kBooleanSettings[] = {
44 kAccountsPrefAllowNewUser,
45 kAccountsPrefAllowGuest,
46 kAccountsPrefShowUserNamesOnSignIn,
47 kSignedDataRoamingEnabled,
48 kStatsReportingPref
49 };
50
51 const char* kStringSettings[] = {
52 kDeviceOwner,
53 kReleaseChannel,
54 kSettingProxyEverywhere
55 };
56
57 const char* kListSettings[] = {
58 kAccountsPrefUsers
59 };
60
61 // Upper bound for number of retries to fetch a signed setting.
62 static const int kNumRetriesLimit = 9;
63
64 bool IsControlledBooleanSetting(const std::string& pref_path) {
65 const char** end = kBooleanSettings + arraysize(kBooleanSettings);
66 return std::find(kBooleanSettings, end, pref_path) != end;
67 }
68
69 bool IsControlledStringSetting(const std::string& pref_path) {
70 const char** end = kStringSettings + arraysize(kStringSettings);
71 return std::find(kStringSettings, end, pref_path) != end;
72 }
73
74 bool IsControlledListSetting(const std::string& pref_path) {
75 const char** end = kListSettings + arraysize(kListSettings);
76 return std::find(kListSettings, end, pref_path) != end;
77 }
78
79 bool IsControlledSetting(const std::string& pref_path) {
80 return (IsControlledBooleanSetting(pref_path) ||
81 IsControlledStringSetting(pref_path) ||
82 IsControlledListSetting(pref_path));
83 }
84
85 bool HasOldMetricsFile() {
86 // TODO(pastarmovj): Remove this once migration is not needed anymore.
87 // If the value is not set we should try to migrate legacy consent file.
88 // Loading consent file state causes us to do blocking IO on UI thread.
89 // Temporarily allow it until we fix http://crbug.com/62626
90 base::ThreadRestrictions::ScopedAllowIO allow_io;
91 return GoogleUpdateSettings::GetCollectStatsConsent();
92 }
93
94 } // namespace
95
96 DeviceSettingsProvider::DeviceSettingsProvider()
97 : ownership_service_(OwnershipService::GetSharedInstance()),
98 migration_helper_(new SignedSettingsMigrationHelper()),
99 retries_left_(kNumRetriesLimit),
100 trusted_(false) {
101 values_cache_.SetBoolean("aa_dummy", true);
102 // Register for notification when ownership is taken so that we can finalize
103 // the SignedSettingsCache.
104 registrar_.Add(this, chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED,
105 content::NotificationService::AllSources());
106 // Make sure we have at least the cache data immediately.
107 RetrieveCachedData();
108 // Start prefetching preferences.
109 Reload();
110 }
111
112 DeviceSettingsProvider::~DeviceSettingsProvider() {
113 }
114
115 void DeviceSettingsProvider::Reload() {
116 // While fetching we can't trust the cache anymore.
117 trusted_ = false;
118 OwnershipService::Status ownership_status =
119 ownership_service_->GetStatus(true);
120 if (ownership_status == OwnershipService::OWNERSHIP_NONE) {
121 RetrieveCachedData();
122 } else {
123 // Retrieve the real data.
124 SignedSettingsHelper::Get()->StartRetrievePolicyOp(
125 base::Bind(&DeviceSettingsProvider::OnRetrievePolicyCompleted,
126 base::Unretained(this)));
127 }
128 }
129
130 void DeviceSettingsProvider::DoSet(const std::string& path,
131 const base::Value& in_value) {
132 OwnershipService::Status ownership_status =
133 ownership_service_->GetStatus(true);
134 if (!UserManager::Get()->current_user_is_owner() &&
135 ownership_status != OwnershipService::OWNERSHIP_NONE) {
136 LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
137
138 // Revert UI change.
139 CrosSettings::Get()->FireObservers(path.c_str());
140 return;
141 }
142
143 if (IsControlledSetting(path))
144 SetInPolicy(path, in_value);
145 else
146 NOTREACHED() << "Try to set unhandled cros setting " << path;
147 }
148
149 void DeviceSettingsProvider::Observe(
150 int type,
151 const content::NotificationSource& source,
152 const content::NotificationDetails& details) {
153 if (type == chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED &&
154 UserManager::Get()->current_user_is_owner()) {
155 // Reload the initial policy blob, apply settings from temp storage,
156 // and write back the blob.
157 SignedSettingsHelper::Get()->StartRetrievePolicyOp(
158 base::Bind(&DeviceSettingsProvider::FinalizeTempStorage,
159 base::Unretained(this)));
160 }
161 }
162
163 void DeviceSettingsProvider::FinalizeTempStorage(
164 SignedSettings::ReturnCode code,
165 const em::PolicyFetchResponse& policy) {
166 if (code != SignedSettings::SUCCESS) {
167 LOG(ERROR) << "Can't finalize temp store error code:" << code;
168 return;
169 }
170
171 policy_.ParseFromString(policy.policy_data());
172 UpdateValuesCache();
173 trusted_ = true;
174 signed_settings_cache::Finalize(g_browser_process->local_state(), policy);
175 Reload();
176 }
177
178 const em::PolicyData DeviceSettingsProvider::get_policy() const {
179 return policy_;
180 }
181
182 void DeviceSettingsProvider::RetrieveCachedData() {
183 // If there is no owner yet, this function will pull the policy cache from the
184 // temp storage and use that instead.
185 em::PolicyData policy;
186 if (!signed_settings_cache::Retrieve(&policy,
187 g_browser_process->local_state())) {
188 VLOG(1) << "Can't retrieve temp store possibly not created yet.";
189 // Prepare empty data for the case we don't have temp cache yet.
190 policy.set_policy_type(kDevicePolicyType);
191 em::ChromeDeviceSettingsProto pol;
192 policy.set_policy_value(pol.SerializeAsString());
193 }
194
195 policy_ = policy;
196 UpdateValuesCache();
197 }
198
199 void DeviceSettingsProvider::SetInPolicy(const std::string& prop,
200 const base::Value& value) {
201 if (prop == kDeviceOwner) {
202 // Just store it in the memory cache no trusted checks no persisting.
203 std::string owner;
204 if (value.GetAsString(&owner)) {
205 policy_.set_username(owner);
206 values_cache_.SetValue(prop, value.DeepCopy());
207 CrosSettings::Get()->FireObservers(prop.c_str());
208 // We can't trust this value anymore until we reload the real username.
209 trusted_ = false;
210 } else {
211 NOTREACHED();
212 }
213 return;
214 }
215
216 if (!RequestTrustedEntity()) {
217 // Otherwise we should first reload and apply on top of that.
218 SignedSettingsHelper::Get()->StartRetrievePolicyOp(
219 base::Bind(&DeviceSettingsProvider::FinishSetInPolicy,
220 base::Unretained(this),
221 prop, base::Owned(value.DeepCopy())));
222 return;
223 }
224
225 trusted_ = false;
226 em::PolicyData data = get_policy();
227 em::ChromeDeviceSettingsProto pol;
228 pol.ParseFromString(data.policy_value());
229 if (prop == kAccountsPrefAllowNewUser) {
230 em::AllowNewUsersProto* allow = pol.mutable_allow_new_users();
231 bool allow_value;
232 if (value.GetAsBoolean(&allow_value))
233 allow->set_allow_new_users(allow_value);
234 else
235 NOTREACHED();
236 } else if (prop == kAccountsPrefAllowGuest) {
237 em::GuestModeEnabledProto* guest = pol.mutable_guest_mode_enabled();
238 bool guest_value;
239 if (value.GetAsBoolean(&guest_value))
240 guest->set_guest_mode_enabled(guest_value);
241 else
242 NOTREACHED();
243 } else if (prop == kAccountsPrefShowUserNamesOnSignIn) {
244 em::ShowUserNamesOnSigninProto* show = pol.mutable_show_user_names();
245 bool show_value;
246 if (value.GetAsBoolean(&show_value))
247 show->set_show_user_names(show_value);
248 else
249 NOTREACHED();
250 } else if (prop == kSignedDataRoamingEnabled) {
251 em::DataRoamingEnabledProto* roam = pol.mutable_data_roaming_enabled();
252 bool roaming_value = false;
253 if (value.GetAsBoolean(&roaming_value))
254 roam->set_data_roaming_enabled(roaming_value);
255 else
256 NOTREACHED();
257 ApplyRoamingSetting(roaming_value);
258 } else if (prop == kSettingProxyEverywhere) {
259 // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed.
260 std::string proxy_value;
261 if (value.GetAsString(&proxy_value)) {
262 bool success =
263 pol.mutable_device_proxy_settings()->ParseFromString(proxy_value);
264 DCHECK(success);
265 } else {
266 NOTREACHED();
267 }
268 } else if (prop == kReleaseChannel) {
269 em::ReleaseChannelProto* release_channel = pol.mutable_release_channel();
270 std::string channel_value;
271 if (value.GetAsString(&channel_value))
272 release_channel->set_release_channel(channel_value);
273 else
274 NOTREACHED();
275 } else if (prop == kStatsReportingPref) {
276 em::MetricsEnabledProto* metrics = pol.mutable_metrics_enabled();
277 bool metrics_value = false;
278 if (value.GetAsBoolean(&metrics_value))
279 metrics->set_metrics_enabled(metrics_value);
280 else
281 NOTREACHED();
282 ApplyMetricsSetting(false, metrics_value);
283 } else if (prop == kAccountsPrefUsers) {
284 em::UserWhitelistProto* whitelist_proto = pol.mutable_user_whitelist();
285 whitelist_proto->clear_user_whitelist();
286 const base::ListValue& users = static_cast<const base::ListValue&>(value);
287 for (base::ListValue::const_iterator i = users.begin();
288 i != users.end(); ++i) {
289 std::string email;
290 if ((*i)->GetAsString(&email))
291 whitelist_proto->add_user_whitelist(email.c_str());
292 }
293 } else {
294 NOTREACHED();
295 }
296 data.set_policy_value(pol.SerializeAsString());
297 // Set the cache to the updated value.
298 policy_ = data;
299 UpdateValuesCache();
300 CrosSettings::Get()->FireObservers(prop.c_str());
301
302 if (!signed_settings_cache::Store(data, g_browser_process->local_state()))
303 LOG(ERROR) << "Couldn't store to the temp storage.";
304
305 OwnershipService::Status ownership_status =
306 ownership_service_->GetStatus(true);
307 if (ownership_status == OwnershipService::OWNERSHIP_TAKEN) {
308 em::PolicyFetchResponse policy_envelope;
309 policy_envelope.set_policy_data(policy_.SerializeAsString());
310 SignedSettingsHelper::Get()->StartStorePolicyOp(
311 policy_envelope,
312 base::Bind(&DeviceSettingsProvider::OnStorePolicyCompleted,
313 base::Unretained(this)));
314 }
315 }
316
317 void DeviceSettingsProvider::FinishSetInPolicy(
318 const std::string& prop,
319 const base::Value* value,
320 SignedSettings::ReturnCode code,
321 const em::PolicyFetchResponse& policy) {
322 if (code != SignedSettings::SUCCESS) {
323 LOG(ERROR) << "Can't serialize to policy error code: " << code;
324 Reload();
325 return;
326 }
327 SetInPolicy(prop, *value);
328 }
329
330 void DeviceSettingsProvider::UpdateValuesCache() {
331 const em::PolicyData data = get_policy();
332 values_cache_.Clear();
333
334 if (data.has_username() && !data.has_request_token())
335 values_cache_.SetString(kDeviceOwner, data.username());
336
337 em::ChromeDeviceSettingsProto pol;
338 pol.ParseFromString(data.policy_value());
339
340 // For all our boolean settings the following is applicable:
341 // true is default permissive value and false is safe prohibitive value.
342 // Exception: kSignedDataRoamingEnabled which has default value of false.
343 if (pol.has_allow_new_users() &&
344 pol.allow_new_users().has_allow_new_users() &&
345 pol.allow_new_users().allow_new_users()) {
346 // New users allowed, user_whitelist() ignored.
347 values_cache_.SetBoolean(kAccountsPrefAllowNewUser, true);
348 } else if (!pol.has_user_whitelist()) {
349 // If we have the allow_new_users bool, and it is true, we honor that above.
350 // In all other cases (don't have it, have it and it is set to false, etc),
351 // We will honor the user_whitelist() if it is there and populated.
352 // Otherwise we default to allowing new users.
353 values_cache_.SetBoolean(kAccountsPrefAllowNewUser, true);
354 } else {
355 values_cache_.SetBoolean(kAccountsPrefAllowNewUser,
356 pol.user_whitelist().user_whitelist_size() == 0);
357 }
358
359 if (!pol.has_guest_mode_enabled() ||
360 !pol.guest_mode_enabled().has_guest_mode_enabled()) {
361 // Default to allowing guests;
362 values_cache_.SetBoolean(kAccountsPrefAllowGuest, true);
363 } else {
364 values_cache_.SetBoolean(kAccountsPrefAllowGuest,
365 pol.guest_mode_enabled().guest_mode_enabled());
366 }
367
368 if (!pol.has_show_user_names() ||
369 !pol.show_user_names().has_show_user_names()) {
370 // Default to showing pods on the login screen;
371 values_cache_.SetBoolean(kAccountsPrefShowUserNamesOnSignIn, true);
372 } else {
373 values_cache_.SetBoolean(kAccountsPrefShowUserNamesOnSignIn,
374 pol.show_user_names().show_user_names());
375 }
376
377 if (!pol.has_data_roaming_enabled() ||
378 !pol.data_roaming_enabled().has_data_roaming_enabled()) {
379 // Default to disabling cellular data roaming;
380 values_cache_.SetBoolean(kSignedDataRoamingEnabled, false);
381 } else {
382 values_cache_.SetBoolean(kSignedDataRoamingEnabled,
383 pol.data_roaming_enabled().data_roaming_enabled());
384 }
385
386 // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed.
387 std::string serialized;
388 if (pol.has_device_proxy_settings() &&
389 pol.device_proxy_settings().SerializeToString(&serialized)) {
390 values_cache_.SetString(kSettingProxyEverywhere, serialized);
391 }
392
393 if (!pol.has_release_channel() ||
394 !pol.release_channel().has_release_channel()) {
395 // Default to an invalid channel (will be ignored).
396 values_cache_.SetString(kReleaseChannel, "");
397 } else {
398 values_cache_.SetString(kReleaseChannel,
399 pol.release_channel().release_channel());
400 }
401
402 if (pol.has_metrics_enabled()) {
403 values_cache_.SetBoolean(kStatsReportingPref,
404 pol.metrics_enabled().metrics_enabled());
405 } else {
406 values_cache_.SetBoolean(kStatsReportingPref, HasOldMetricsFile());
407 }
408
409 base::ListValue* list = new base::ListValue();
410 const em::UserWhitelistProto& whitelist_proto = pol.user_whitelist();
411 const RepeatedPtrField<std::string>& whitelist =
412 whitelist_proto.user_whitelist();
413 for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin();
414 it != whitelist.end(); ++it) {
415 list->Append(base::Value::CreateStringValue(*it));
416 }
417 values_cache_.SetValue(kAccountsPrefUsers, list);
418 }
419
420 void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file,
421 bool new_value) const {
422 // TODO(pastarmovj): Remove this once migration is not needed anymore.
423 // If the value is not set we should try to migrate legacy consent file.
424 if (use_file) {
425 new_value = HasOldMetricsFile();
426 // Make sure the values will get eventually written to the policy file.
427 migration_helper_->AddMigrationValue(
428 kStatsReportingPref, base::Value::CreateBooleanValue(new_value));
429 migration_helper_->MigrateValues();
430 LOG(INFO) << "No metrics policy set will revert to checking "
431 << "consent file which is "
432 << (new_value ? "on." : "off.");
433 }
434 VLOG(1) << "Metrics policy is being set to : " << new_value
435 << "(use file : " << use_file << ")";
436 // TODO(pastarmovj): Remove this once we don't need to regenerate the
437 // consent file for the GUID anymore.
438 OptionsUtil::ResolveMetricsReportingEnabled(new_value);
439 }
440
441 void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) const {
442 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
443 const NetworkDevice* cellular = cros->FindCellularDevice();
444 if (cellular) {
445 bool device_value = cellular->data_roaming_allowed();
446 if (!device_value && cros->IsCellularAlwaysInRoaming()) {
447 // If operator requires roaming always enabled, ignore supplied value
448 // and set data roaming allowed in true always.
449 cros->SetCellularDataRoamingAllowed(true);
450 } else if (device_value != new_value) {
451 cros->SetCellularDataRoamingAllowed(new_value);
452 }
453 }
454 }
455
456 void DeviceSettingsProvider::ApplySideEffects() const {
457 const em::PolicyData data = get_policy();
458 em::ChromeDeviceSettingsProto pol;
459 pol.ParseFromString(data.policy_value());
460 // First migrate metrics settings as needed.
461 if (pol.has_metrics_enabled())
462 ApplyMetricsSetting(false, pol.metrics_enabled().metrics_enabled());
463 else
464 ApplyMetricsSetting(true, false);
465 // Next set the roaming setting as needed.
466 ApplyRoamingSetting(pol.has_data_roaming_enabled() ?
467 pol.data_roaming_enabled().data_roaming_enabled() : false);
468 }
469
470 const base::Value* DeviceSettingsProvider::Get(const std::string& path) const {
471 if (IsControlledSetting(path)) {
472 const base::Value* value;
473 if (values_cache_.GetValue(path, &value))
474 return value;
475 } else {
476 NOTREACHED() << "Trying to get non cros setting.";
477 }
478
479 return NULL;
480 }
481
482 bool DeviceSettingsProvider::GetTrusted(const std::string& path,
483 const base::Closure& callback) {
484 if (!IsControlledSetting(path)) {
485 NOTREACHED();
486 return true;
487 }
488
489 if (RequestTrustedEntity()) {
490 return true;
491 } else {
492 if (!callback.is_null())
493 callbacks_.push_back(callback);
494 return false;
495 }
496 }
497
498 bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const {
499 return IsControlledSetting(path);
500 }
501
502 bool DeviceSettingsProvider::RequestTrustedEntity() {
503 OwnershipService::Status ownership_status =
504 ownership_service_->GetStatus(true);
505 if (ownership_status == OwnershipService::OWNERSHIP_NONE)
506 return true;
507 return trusted_;
508 }
509
510 void DeviceSettingsProvider::OnStorePolicyCompleted(
511 SignedSettings::ReturnCode code) {
512 // In any case reload the policy cache to now.
513 if (code != SignedSettings::SUCCESS)
514 Reload();
515 else
516 trusted_ = true;
517 }
518
519 void DeviceSettingsProvider::OnRetrievePolicyCompleted(
520 SignedSettings::ReturnCode code,
521 const em::PolicyFetchResponse& policy) {
522 switch (code) {
523 case SignedSettings::SUCCESS: {
524 DCHECK(policy.has_policy_data());
525 policy_.ParseFromString(policy.policy_data());
526 signed_settings_cache::Store(get_policy(),
527 g_browser_process->local_state());
528 UpdateValuesCache();
529 trusted_ = true;
530 for (size_t i = 0; i < callbacks_.size(); ++i)
531 callbacks_[i].Run();
532 callbacks_.clear();
533 // TODO(pastarmovj): Make those side effects responsibility of the
534 // respective subsystems.
535 ApplySideEffects();
536 break;
537 }
538 case SignedSettings::NOT_FOUND:
539 case SignedSettings::KEY_UNAVAILABLE: {
540 if (ownership_service_->GetStatus(true) !=
541 OwnershipService::OWNERSHIP_TAKEN) {
542 NOTREACHED() << "No policies present yet, will use the temp storage.";
543 }
544 break;
545 }
546 case SignedSettings::BAD_SIGNATURE:
547 case SignedSettings::OPERATION_FAILED: {
548 LOG(ERROR) << "Failed to retrieve cros policies. Reason:" << code;
549 if (retries_left_ > 0) {
550 retries_left_ -= 1;
551 Reload();
552 return;
553 }
554 LOG(ERROR) << "No retries left";
555 break;
556 }
Denis Lagno 2011/12/01 00:38:12 nit: shouldn't be there default: NOTREACHED(); ?
pastarmovj 2011/12/01 10:07:17 I think not putting the default here will ensure t
557 }
558 }
559
560 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698