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

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: Next round of comments. All bots meanwhile good and manual testing seems fine as well. 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"
Mattias Nissler (ping if slow) 2011/12/02 12:13:37 not needed.
pastarmovj 2011/12/02 14:43:38 Done.
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_status_(OwnershipService::GetSharedInstance()->GetStatus(true)),
98 migration_helper_(new SignedSettingsMigrationHelper()),
99 retries_left_(kNumRetriesLimit),
100 trusted_(false) {
101 // Register for notification when ownership is taken so that we can update
102 // the |ownership_status_| and reload if needed.
103 registrar_.Add(this, chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED,
104 content::NotificationService::AllSources());
105 // Make sure we have at least the cache data immediately.
106 RetrieveCachedData();
107 // Start prefetching preferences.
108 Reload();
109 }
110
111 DeviceSettingsProvider::~DeviceSettingsProvider() {
112 }
113
114 void DeviceSettingsProvider::Reload() {
115 // While fetching we can't trust the cache anymore.
116 trusted_ = false;
117 if (ownership_status_ == OwnershipService::OWNERSHIP_NONE) {
118 RetrieveCachedData();
119 } else {
120 // Retrieve the real data.
121 SignedSettingsHelper::Get()->StartRetrievePolicyOp(
122 base::Bind(&DeviceSettingsProvider::OnRetrievePolicyCompleted,
123 base::Unretained(this)));
124 }
125 }
126
127 void DeviceSettingsProvider::DoSet(const std::string& path,
128 const base::Value& in_value) {
129 if (!UserManager::Get()->current_user_is_owner() &&
130 ownership_status_ != OwnershipService::OWNERSHIP_NONE) {
131 LOG(WARNING) << "Changing settings from non-owner, setting=" << path;
132
133 // Revert UI change.
134 CrosSettings::Get()->FireObservers(path.c_str());
135 return;
136 }
137
138 if (IsControlledSetting(path))
139 SetInPolicy(path, in_value);
140 else
141 NOTREACHED() << "Try to set unhandled cros setting " << path;
142 }
143
144 void DeviceSettingsProvider::Observe(
145 int type,
146 const content::NotificationSource& source,
147 const content::NotificationDetails& details) {
148 if (type == chrome::NOTIFICATION_OWNER_KEY_FETCH_ATTEMPT_SUCCEEDED &&
149 UserManager::Get()->current_user_is_owner()) {
150 // Reload the initial policy blob, apply settings from temp storage,
151 // and write back the blob.
152 ownership_status_ = OwnershipService::OWNERSHIP_TAKEN;
153 Reload();
154 }
155 }
156
157 const em::PolicyData DeviceSettingsProvider::get_policy() const {
158 return policy_;
159 }
160
161 void DeviceSettingsProvider::RetrieveCachedData() {
162 // If there is no owner yet, this function will pull the policy cache from the
163 // temp storage and use that instead.
164 em::PolicyData policy;
165 if (!signed_settings_cache::Retrieve(&policy,
166 g_browser_process->local_state())) {
167 VLOG(1) << "Can't retrieve temp store possibly not created yet.";
168 // Prepare empty data for the case we don't have temp cache yet.
169 policy.set_policy_type(kDevicePolicyType);
170 em::ChromeDeviceSettingsProto pol;
171 policy.set_policy_value(pol.SerializeAsString());
172 }
173
174 policy_ = policy;
175 UpdateValuesCache();
176 }
177
178 void DeviceSettingsProvider::SetInPolicy(const std::string& prop,
179 const base::Value& value) {
180 if (prop == kDeviceOwner) {
181 // Just store it in the memory cache no trusted checks no persisting.
Mattias Nissler (ping if slow) 2011/12/02 12:13:37 no comma no sentence no grammar? :)
pastarmovj 2011/12/02 14:43:38 Done,
182 std::string owner;
183 if (value.GetAsString(&owner)) {
184 policy_.set_username(owner);
185 values_cache_.SetValue(prop, value.DeepCopy());
186 CrosSettings::Get()->FireObservers(prop.c_str());
187 // We can't trust this value anymore until we reload the real username.
188 trusted_ = false;
189 } else {
190 NOTREACHED();
191 }
192 return;
193 }
194
195 if (!RequestTrustedEntity()) {
196 // Otherwise we should first reload and apply on top of that.
197 SignedSettingsHelper::Get()->StartRetrievePolicyOp(
198 base::Bind(&DeviceSettingsProvider::FinishSetInPolicy,
199 base::Unretained(this),
200 prop, base::Owned(value.DeepCopy())));
201 return;
202 }
203
204 trusted_ = false;
205 em::PolicyData data = get_policy();
206 em::ChromeDeviceSettingsProto pol;
207 pol.ParseFromString(data.policy_value());
208 if (prop == kAccountsPrefAllowNewUser) {
209 em::AllowNewUsersProto* allow = pol.mutable_allow_new_users();
210 bool allow_value;
211 if (value.GetAsBoolean(&allow_value))
212 allow->set_allow_new_users(allow_value);
213 else
214 NOTREACHED();
215 } else if (prop == kAccountsPrefAllowGuest) {
216 em::GuestModeEnabledProto* guest = pol.mutable_guest_mode_enabled();
217 bool guest_value;
218 if (value.GetAsBoolean(&guest_value))
219 guest->set_guest_mode_enabled(guest_value);
220 else
221 NOTREACHED();
222 } else if (prop == kAccountsPrefShowUserNamesOnSignIn) {
223 em::ShowUserNamesOnSigninProto* show = pol.mutable_show_user_names();
224 bool show_value;
225 if (value.GetAsBoolean(&show_value))
226 show->set_show_user_names(show_value);
227 else
228 NOTREACHED();
229 } else if (prop == kSignedDataRoamingEnabled) {
230 em::DataRoamingEnabledProto* roam = pol.mutable_data_roaming_enabled();
231 bool roaming_value = false;
232 if (value.GetAsBoolean(&roaming_value))
233 roam->set_data_roaming_enabled(roaming_value);
234 else
235 NOTREACHED();
236 ApplyRoamingSetting(roaming_value);
237 } else if (prop == kSettingProxyEverywhere) {
238 // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed.
239 std::string proxy_value;
240 if (value.GetAsString(&proxy_value)) {
241 bool success =
242 pol.mutable_device_proxy_settings()->ParseFromString(proxy_value);
243 DCHECK(success);
244 } else {
245 NOTREACHED();
246 }
247 } else if (prop == kReleaseChannel) {
248 em::ReleaseChannelProto* release_channel = pol.mutable_release_channel();
249 std::string channel_value;
250 if (value.GetAsString(&channel_value))
251 release_channel->set_release_channel(channel_value);
252 else
253 NOTREACHED();
254 } else if (prop == kStatsReportingPref) {
255 em::MetricsEnabledProto* metrics = pol.mutable_metrics_enabled();
256 bool metrics_value = false;
257 if (value.GetAsBoolean(&metrics_value))
258 metrics->set_metrics_enabled(metrics_value);
259 else
260 NOTREACHED();
261 ApplyMetricsSetting(false, metrics_value);
262 } else if (prop == kAccountsPrefUsers) {
263 em::UserWhitelistProto* whitelist_proto = pol.mutable_user_whitelist();
264 whitelist_proto->clear_user_whitelist();
265 const base::ListValue& users = static_cast<const base::ListValue&>(value);
266 for (base::ListValue::const_iterator i = users.begin();
267 i != users.end(); ++i) {
268 std::string email;
269 if ((*i)->GetAsString(&email))
270 whitelist_proto->add_user_whitelist(email.c_str());
271 }
272 } else {
273 NOTREACHED();
274 }
275 data.set_policy_value(pol.SerializeAsString());
276 // Set the cache to the updated value.
277 policy_ = data;
278 UpdateValuesCache();
279 CrosSettings::Get()->FireObservers(prop.c_str());
280
281 if (!signed_settings_cache::Store(data, g_browser_process->local_state()))
282 LOG(ERROR) << "Couldn't store to the temp storage.";
283
284 if (ownership_status_ == OwnershipService::OWNERSHIP_TAKEN) {
285 em::PolicyFetchResponse policy_envelope;
286 policy_envelope.set_policy_data(policy_.SerializeAsString());
287 SignedSettingsHelper::Get()->StartStorePolicyOp(
288 policy_envelope,
289 base::Bind(&DeviceSettingsProvider::OnStorePolicyCompleted,
290 base::Unretained(this)));
291 }
292 }
293
294 void DeviceSettingsProvider::FinishSetInPolicy(
295 const std::string& prop,
296 const base::Value* value,
297 SignedSettings::ReturnCode code,
298 const em::PolicyFetchResponse& policy) {
299 if (code != SignedSettings::SUCCESS) {
300 LOG(ERROR) << "Can't serialize to policy error code: " << code;
301 Reload();
302 return;
303 }
304 SetInPolicy(prop, *value);
305 }
306
307 void DeviceSettingsProvider::UpdateValuesCache() {
308 const em::PolicyData data = get_policy();
309 values_cache_.Clear();
310
311 if (data.has_username() && !data.has_request_token())
312 values_cache_.SetString(kDeviceOwner, data.username());
313
314 em::ChromeDeviceSettingsProto pol;
315 pol.ParseFromString(data.policy_value());
316
317 // For all our boolean settings the following is applicable:
318 // true is default permissive value and false is safe prohibitive value.
319 // Exception: kSignedDataRoamingEnabled which has default value of false.
320 if (pol.has_allow_new_users() &&
321 pol.allow_new_users().has_allow_new_users() &&
322 pol.allow_new_users().allow_new_users()) {
323 // New users allowed, user_whitelist() ignored.
324 values_cache_.SetBoolean(kAccountsPrefAllowNewUser, true);
325 } else if (!pol.has_user_whitelist()) {
326 // If we have the allow_new_users bool, and it is true, we honor that above.
327 // In all other cases (don't have it, have it and it is set to false, etc),
328 // We will honor the user_whitelist() if it is there and populated.
329 // Otherwise we default to allowing new users.
330 values_cache_.SetBoolean(kAccountsPrefAllowNewUser, true);
331 } else {
332 values_cache_.SetBoolean(kAccountsPrefAllowNewUser,
333 pol.user_whitelist().user_whitelist_size() == 0);
334 }
335
336 values_cache_.SetBoolean(
337 kAccountsPrefAllowGuest,
338 !pol.has_guest_mode_enabled() ||
339 !pol.guest_mode_enabled().has_guest_mode_enabled() ||
340 pol.guest_mode_enabled().guest_mode_enabled());
341
342 values_cache_.SetBoolean(
343 kAccountsPrefShowUserNamesOnSignIn,
344 !pol.has_show_user_names() ||
345 !pol.show_user_names().has_show_user_names() ||
346 pol.show_user_names().show_user_names());
347
348 values_cache_.SetBoolean(
349 kSignedDataRoamingEnabled,
350 pol.has_data_roaming_enabled() &&
351 pol.data_roaming_enabled().has_data_roaming_enabled() &&
352 pol.data_roaming_enabled().data_roaming_enabled());
353
354 // TODO(cmasone): NOTIMPLEMENTED() once http://crosbug.com/13052 is fixed.
355 std::string serialized;
356 if (pol.has_device_proxy_settings() &&
357 pol.device_proxy_settings().SerializeToString(&serialized)) {
358 values_cache_.SetString(kSettingProxyEverywhere, serialized);
359 }
360
361 if (!pol.has_release_channel() ||
362 !pol.release_channel().has_release_channel()) {
363 // Default to an invalid channel (will be ignored).
364 values_cache_.SetString(kReleaseChannel, "");
365 } else {
366 values_cache_.SetString(kReleaseChannel,
367 pol.release_channel().release_channel());
368 }
369
370 if (pol.has_metrics_enabled()) {
371 values_cache_.SetBoolean(kStatsReportingPref,
372 pol.metrics_enabled().metrics_enabled());
373 } else {
374 values_cache_.SetBoolean(kStatsReportingPref, HasOldMetricsFile());
375 }
376
377 base::ListValue* list = new base::ListValue();
378 const em::UserWhitelistProto& whitelist_proto = pol.user_whitelist();
379 const RepeatedPtrField<std::string>& whitelist =
380 whitelist_proto.user_whitelist();
381 for (RepeatedPtrField<std::string>::const_iterator it = whitelist.begin();
382 it != whitelist.end(); ++it) {
383 list->Append(base::Value::CreateStringValue(*it));
384 }
385 values_cache_.SetValue(kAccountsPrefUsers, list);
386 }
387
388 void DeviceSettingsProvider::ApplyMetricsSetting(bool use_file,
389 bool new_value) const {
390 // TODO(pastarmovj): Remove this once migration is not needed anymore.
391 // If the value is not set we should try to migrate legacy consent file.
392 if (use_file) {
393 new_value = HasOldMetricsFile();
394 // Make sure the values will get eventually written to the policy file.
395 migration_helper_->AddMigrationValue(
396 kStatsReportingPref, base::Value::CreateBooleanValue(new_value));
397 migration_helper_->MigrateValues();
398 LOG(INFO) << "No metrics policy set will revert to checking "
399 << "consent file which is "
400 << (new_value ? "on." : "off.");
401 }
402 VLOG(1) << "Metrics policy is being set to : " << new_value
403 << "(use file : " << use_file << ")";
404 // TODO(pastarmovj): Remove this once we don't need to regenerate the
405 // consent file for the GUID anymore.
406 OptionsUtil::ResolveMetricsReportingEnabled(new_value);
407 }
408
409 void DeviceSettingsProvider::ApplyRoamingSetting(bool new_value) const {
410 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
411 const NetworkDevice* cellular = cros->FindCellularDevice();
412 if (cellular) {
413 bool device_value = cellular->data_roaming_allowed();
414 if (!device_value && cros->IsCellularAlwaysInRoaming()) {
415 // If operator requires roaming always enabled, ignore supplied value
416 // and set data roaming allowed in true always.
417 cros->SetCellularDataRoamingAllowed(true);
418 } else if (device_value != new_value) {
419 cros->SetCellularDataRoamingAllowed(new_value);
420 }
421 }
422 }
423
424 void DeviceSettingsProvider::ApplySideEffects() const {
425 const em::PolicyData data = get_policy();
426 em::ChromeDeviceSettingsProto pol;
427 pol.ParseFromString(data.policy_value());
428 // First migrate metrics settings as needed.
429 if (pol.has_metrics_enabled())
430 ApplyMetricsSetting(false, pol.metrics_enabled().metrics_enabled());
431 else
432 ApplyMetricsSetting(true, false);
433 // Next set the roaming setting as needed.
434 ApplyRoamingSetting(pol.has_data_roaming_enabled() ?
435 pol.data_roaming_enabled().data_roaming_enabled() : false);
436 }
437
438 const base::Value* DeviceSettingsProvider::Get(const std::string& path) const {
439 if (IsControlledSetting(path)) {
440 const base::Value* value;
441 if (values_cache_.GetValue(path, &value))
442 return value;
443 } else {
444 NOTREACHED() << "Trying to get non cros setting.";
445 }
446
447 return NULL;
448 }
449
450 bool DeviceSettingsProvider::GetTrusted(const std::string& path,
451 const base::Closure& callback) {
452 if (!IsControlledSetting(path)) {
453 NOTREACHED();
454 return true;
455 }
456
457 if (RequestTrustedEntity()) {
458 return true;
459 } else {
460 if (!callback.is_null())
461 callbacks_.push_back(callback);
462 return false;
463 }
464 }
465
466 bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const {
467 return IsControlledSetting(path);
468 }
469
470 bool DeviceSettingsProvider::RequestTrustedEntity() {
471 if (ownership_status_ == OwnershipService::OWNERSHIP_NONE)
472 return true;
473 return trusted_;
474 }
475
476 void DeviceSettingsProvider::OnStorePolicyCompleted(
477 SignedSettings::ReturnCode code) {
478 // In any case reload the policy cache to now.
479 if (code != SignedSettings::SUCCESS)
480 Reload();
481 else
482 trusted_ = true;
483 }
484
485 void DeviceSettingsProvider::OnRetrievePolicyCompleted(
486 SignedSettings::ReturnCode code,
487 const em::PolicyFetchResponse& policy) {
488 switch (code) {
489 case SignedSettings::SUCCESS: {
490 DCHECK(policy.has_policy_data());
491 policy_.ParseFromString(policy.policy_data());
492 signed_settings_cache::Store(get_policy(),
493 g_browser_process->local_state());
494 UpdateValuesCache();
495 trusted_ = true;
496 for (size_t i = 0; i < callbacks_.size(); ++i)
497 callbacks_[i].Run();
498 callbacks_.clear();
499 // TODO(pastarmovj): Make those side effects responsibility of the
500 // respective subsystems.
501 ApplySideEffects();
502 break;
503 }
504 case SignedSettings::NOT_FOUND:
505 case SignedSettings::KEY_UNAVAILABLE: {
506 if (ownership_status_ != OwnershipService::OWNERSHIP_TAKEN)
507 NOTREACHED() << "No policies present yet, will use the temp storage.";
508 break;
509 }
510 case SignedSettings::BAD_SIGNATURE:
511 case SignedSettings::OPERATION_FAILED: {
512 LOG(ERROR) << "Failed to retrieve cros policies. Reason:" << code;
513 if (retries_left_ > 0) {
514 retries_left_ -= 1;
515 Reload();
516 return;
517 }
518 LOG(ERROR) << "No retries left";
519 break;
520 }
521 }
522 }
523
524 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698