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

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

Powered by Google App Engine
This is Rietveld 408576698