Less strict CHECK for DeviceCapabilities results.
[chromium-blink-merge.git] / chromeos / network / managed_network_configuration_handler_impl.cc
blob67ab01f8ebd6eee71199543365fa5f28edafadcb
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
3 // found in the LICENSE file.
5 #include "chromeos/network/managed_network_configuration_handler_impl.h"
7 #include <set>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/guid.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/stl_util.h"
17 #include "base/values.h"
18 #include "chromeos/dbus/shill_manager_client.h"
19 #include "chromeos/dbus/shill_profile_client.h"
20 #include "chromeos/dbus/shill_service_client.h"
21 #include "chromeos/network/network_configuration_handler.h"
22 #include "chromeos/network/network_event_log.h"
23 #include "chromeos/network/network_policy_observer.h"
24 #include "chromeos/network/network_profile.h"
25 #include "chromeos/network/network_profile_handler.h"
26 #include "chromeos/network/network_state.h"
27 #include "chromeos/network/network_state_handler.h"
28 #include "chromeos/network/network_ui_data.h"
29 #include "chromeos/network/onc/onc_merger.h"
30 #include "chromeos/network/onc/onc_signature.h"
31 #include "chromeos/network/onc/onc_translator.h"
32 #include "chromeos/network/onc/onc_validator.h"
33 #include "chromeos/network/policy_util.h"
34 #include "chromeos/network/shill_property_util.h"
35 #include "components/onc/onc_constants.h"
36 #include "third_party/cros_system_api/dbus/service_constants.h"
38 namespace chromeos {
40 namespace {
42 typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
44 // These are error strings used for error callbacks. None of these error
45 // messages are user-facing: they should only appear in logs.
46 const char kInvalidUserSettings[] = "InvalidUserSettings";
47 const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
48 const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
49 const char kProfileNotInitialized[] = "ProflieNotInitialized";
50 const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
51 const char kUnknownProfilePath[] = "UnknownProfilePath";
52 const char kUnknownServicePath[] = "UnknownServicePath";
54 std::string ToDebugString(::onc::ONCSource source,
55 const std::string& userhash) {
56 return source == ::onc::ONC_SOURCE_USER_POLICY ?
57 ("user policy of " + userhash) : "device policy";
60 void InvokeErrorCallback(const std::string& service_path,
61 const network_handler::ErrorCallback& error_callback,
62 const std::string& error_name) {
63 std::string error_msg = "ManagedConfig Error: " + error_name;
64 NET_LOG_ERROR(error_msg, service_path);
65 network_handler::RunErrorCallback(
66 error_callback, service_path, error_name, error_msg);
69 void LogErrorWithDict(const tracked_objects::Location& from_where,
70 const std::string& error_name,
71 scoped_ptr<base::DictionaryValue> error_data) {
72 LOG(ERROR) << from_where.ToString() << ": " << error_name;
75 const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
76 const std::string& guid) {
77 GuidToPolicyMap::const_iterator it = policies.find(guid);
78 if (it == policies.end())
79 return NULL;
80 return it->second;
83 void TranslatePropertiesToOncAndRunCallback(
84 const network_handler::DictionaryResultCallback& callback,
85 const std::string& service_path,
86 const base::DictionaryValue& shill_properties) {
87 scoped_ptr<base::DictionaryValue> onc_network(
88 onc::TranslateShillServiceToONCPart(
89 shill_properties,
90 &onc::kNetworkWithStateSignature));
91 callback.Run(service_path, *onc_network);
94 } // namespace
96 struct ManagedNetworkConfigurationHandlerImpl::Policies {
97 ~Policies();
99 GuidToPolicyMap per_network_config;
100 base::DictionaryValue global_network_config;
103 ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
104 STLDeleteValues(&per_network_config);
107 void ManagedNetworkConfigurationHandlerImpl::AddObserver(
108 NetworkPolicyObserver* observer) {
109 observers_.AddObserver(observer);
112 void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
113 NetworkPolicyObserver* observer) {
114 observers_.RemoveObserver(observer);
117 void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
118 const std::string& userhash,
119 const std::string& service_path,
120 const network_handler::DictionaryResultCallback& callback,
121 const network_handler::ErrorCallback& error_callback) {
122 if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
123 InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
124 return;
126 network_configuration_handler_->GetProperties(
127 service_path,
128 base::Bind(
129 &ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback,
130 weak_ptr_factory_.GetWeakPtr(),
131 callback,
132 error_callback),
133 error_callback);
136 void ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback(
137 const network_handler::DictionaryResultCallback& callback,
138 const network_handler::ErrorCallback& error_callback,
139 const std::string& service_path,
140 const base::DictionaryValue& shill_properties) {
141 std::string profile_path;
142 shill_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
143 &profile_path);
144 const NetworkProfile* profile =
145 network_profile_handler_->GetProfileForPath(profile_path);
146 if (!profile) {
147 LOG(ERROR) << "No or no known profile received for service "
148 << service_path << ".";
151 scoped_ptr<NetworkUIData> ui_data =
152 shill_property_util::GetUIDataFromProperties(shill_properties);
154 const base::DictionaryValue* user_settings = NULL;
155 const base::DictionaryValue* shared_settings = NULL;
157 if (ui_data && profile) {
158 if (profile->type() == NetworkProfile::TYPE_SHARED)
159 shared_settings = ui_data->user_settings();
160 else if (profile->type() == NetworkProfile::TYPE_USER)
161 user_settings = ui_data->user_settings();
162 else
163 NOTREACHED();
164 } else if (profile) {
165 LOG(WARNING) << "Service " << service_path << " of profile "
166 << profile_path << " contains no or no valid UIData.";
167 // TODO(pneubeck): add a conversion of user configured entries of old
168 // ChromeOS versions. We will have to use a heuristic to determine which
169 // properties _might_ be user configured.
172 scoped_ptr<base::DictionaryValue> active_settings(
173 onc::TranslateShillServiceToONCPart(
174 shill_properties,
175 &onc::kNetworkWithStateSignature));
177 std::string guid;
178 active_settings->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
179 &guid);
181 const base::DictionaryValue* user_policy = NULL;
182 const base::DictionaryValue* device_policy = NULL;
183 if (!guid.empty() && profile) {
184 const Policies* policies = GetPoliciesForProfile(*profile);
185 if (!policies) {
186 InvokeErrorCallback(
187 service_path, error_callback, kPoliciesNotInitialized);
188 return;
190 const base::DictionaryValue* policy =
191 GetByGUID(policies->per_network_config, guid);
192 if (profile->type() == NetworkProfile::TYPE_SHARED)
193 device_policy = policy;
194 else if (profile->type() == NetworkProfile::TYPE_USER)
195 user_policy = policy;
196 else
197 NOTREACHED();
200 // This call also removes credentials from policies.
201 scoped_ptr<base::DictionaryValue> augmented_properties =
202 onc::MergeSettingsAndPoliciesToAugmented(
203 onc::kNetworkConfigurationSignature,
204 user_policy,
205 device_policy,
206 user_settings,
207 shared_settings,
208 active_settings.get());
209 callback.Run(service_path, *augmented_properties);
212 void ManagedNetworkConfigurationHandlerImpl::GetProperties(
213 const std::string& service_path,
214 const network_handler::DictionaryResultCallback& callback,
215 const network_handler::ErrorCallback& error_callback) const {
216 network_configuration_handler_->GetProperties(
217 service_path,
218 base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
219 error_callback);
222 void ManagedNetworkConfigurationHandlerImpl::SetProperties(
223 const std::string& service_path,
224 const base::DictionaryValue& user_settings,
225 const base::Closure& callback,
226 const network_handler::ErrorCallback& error_callback) const {
227 const NetworkState* state =
228 network_state_handler_->GetNetworkState(service_path);
230 if (!state) {
231 InvokeErrorCallback(service_path, error_callback, kUnknownServicePath);
232 return;
235 std::string guid = state->guid();
236 if (guid.empty()) {
237 // TODO(pneubeck): create an initial configuration in this case. As for
238 // CreateConfiguration, user settings from older ChromeOS versions have to
239 // determined here.
240 InvokeErrorCallback(
241 service_path, error_callback, kSetOnUnconfiguredNetwork);
242 return;
245 const std::string& profile_path = state->profile_path();
246 const NetworkProfile *profile =
247 network_profile_handler_->GetProfileForPath(profile_path);
248 if (!profile) {
249 InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
250 return;
253 VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
254 << profile->ToDebugString();
256 const Policies* policies = GetPoliciesForProfile(*profile);
257 if (!policies) {
258 InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
259 return;
262 // Validate the ONC dictionary. We are liberal and ignore unknown field
263 // names. User settings are only partial ONC, thus we ignore missing fields.
264 onc::Validator validator(false, // Ignore unknown fields.
265 false, // Ignore invalid recommended field names.
266 false, // Ignore missing fields.
267 false); // This ONC does not come from policy.
269 onc::Validator::Result validation_result;
270 scoped_ptr<base::DictionaryValue> validated_user_settings =
271 validator.ValidateAndRepairObject(
272 &onc::kNetworkConfigurationSignature,
273 user_settings,
274 &validation_result);
276 if (validation_result == onc::Validator::INVALID) {
277 InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
278 return;
280 if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
281 LOG(WARNING) << "Validation of ONC user settings produced warnings.";
283 const base::DictionaryValue* policy =
284 GetByGUID(policies->per_network_config, guid);
285 VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
287 scoped_ptr<base::DictionaryValue> shill_dictionary(
288 policy_util::CreateShillConfiguration(
289 *profile, guid, policy, validated_user_settings.get()));
291 network_configuration_handler_->SetProperties(
292 service_path, *shill_dictionary, callback, error_callback);
295 void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
296 const std::string& userhash,
297 const base::DictionaryValue& properties,
298 const network_handler::StringResultCallback& callback,
299 const network_handler::ErrorCallback& error_callback) const {
300 const Policies* policies = GetPoliciesForUser(userhash);
301 if (!policies) {
302 InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
303 return;
306 if (policy_util::FindMatchingPolicy(policies->per_network_config,
307 properties)) {
308 InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
309 return;
312 const NetworkProfile* profile =
313 network_profile_handler_->GetProfileForUserhash(userhash);
314 if (!profile) {
315 InvokeErrorCallback("", error_callback, kProfileNotInitialized);
316 return;
319 // TODO(pneubeck): In case of WiFi, check that no other configuration for the
320 // same {SSID, mode, security} exists. We don't support such multiple
321 // configurations, yet.
323 // Generate a new GUID for this configuration. Ignore the maybe provided GUID
324 // in |properties| as it is not our own and from an untrusted source.
325 std::string guid = base::GenerateGUID();
326 scoped_ptr<base::DictionaryValue> shill_dictionary(
327 policy_util::CreateShillConfiguration(
328 *profile, guid, NULL /*no policy*/, &properties));
330 network_configuration_handler_->CreateConfiguration(
331 *shill_dictionary, callback, error_callback);
334 void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
335 const std::string& service_path,
336 const base::Closure& callback,
337 const network_handler::ErrorCallback& error_callback) const {
338 network_configuration_handler_->RemoveConfiguration(
339 service_path, callback, error_callback);
342 void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
343 ::onc::ONCSource onc_source,
344 const std::string& userhash,
345 const base::ListValue& network_configs_onc,
346 const base::DictionaryValue& global_network_config) {
347 VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
348 << ".";
350 // |userhash| must be empty for device policies.
351 DCHECK(onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY ||
352 userhash.empty());
353 Policies* policies = NULL;
354 if (ContainsKey(policies_by_user_, userhash)) {
355 policies = policies_by_user_[userhash].get();
356 } else {
357 policies = new Policies;
358 policies_by_user_[userhash] = make_linked_ptr(policies);
361 policies->global_network_config.MergeDictionary(&global_network_config);
363 GuidToPolicyMap old_per_network_config;
364 policies->per_network_config.swap(old_per_network_config);
366 // This stores all GUIDs of policies that have changed or are new.
367 std::set<std::string> modified_policies;
369 for (base::ListValue::const_iterator it = network_configs_onc.begin();
370 it != network_configs_onc.end(); ++it) {
371 const base::DictionaryValue* network = NULL;
372 (*it)->GetAsDictionary(&network);
373 DCHECK(network);
375 std::string guid;
376 network->GetStringWithoutPathExpansion(::onc::network_config::kGUID, &guid);
377 DCHECK(!guid.empty());
379 if (policies->per_network_config.count(guid) > 0) {
380 LOG(ERROR) << "ONC from " << ToDebugString(onc_source, userhash)
381 << " contains several entries for the same GUID "
382 << guid << ".";
383 delete policies->per_network_config[guid];
385 const base::DictionaryValue* new_entry = network->DeepCopy();
386 policies->per_network_config[guid] = new_entry;
388 const base::DictionaryValue* old_entry = old_per_network_config[guid];
389 if (!old_entry || !old_entry->Equals(new_entry))
390 modified_policies.insert(guid);
393 STLDeleteValues(&old_per_network_config);
395 const NetworkProfile* profile =
396 network_profile_handler_->GetProfileForUserhash(userhash);
397 if (!profile) {
398 VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
399 << "policy application.";
400 return;
403 scoped_refptr<PolicyApplicator> applicator =
404 new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
405 *profile,
406 policies->per_network_config,
407 policies->global_network_config,
408 &modified_policies);
409 applicator->Run();
412 void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
413 const NetworkProfile& profile) {
414 VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
416 const Policies* policies = GetPoliciesForProfile(profile);
417 if (!policies) {
418 VLOG(1) << "The relevant policy is not initialized, "
419 << "postponing policy application.";
420 return;
423 std::set<std::string> policy_guids;
424 for (GuidToPolicyMap::const_iterator it =
425 policies->per_network_config.begin();
426 it != policies->per_network_config.end(); ++it) {
427 policy_guids.insert(it->first);
430 scoped_refptr<PolicyApplicator> applicator =
431 new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
432 profile,
433 policies->per_network_config,
434 policies->global_network_config,
435 &policy_guids);
436 applicator->Run();
439 void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
440 const NetworkProfile& profile) {
441 // Nothing to do in this case.
444 void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
445 const base::DictionaryValue& shill_properties) {
446 network_configuration_handler_->CreateConfiguration(
447 shill_properties,
448 base::Bind(
449 &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
450 weak_ptr_factory_.GetWeakPtr()),
451 base::Bind(&LogErrorWithDict, FROM_HERE));
454 void ManagedNetworkConfigurationHandlerImpl::
455 UpdateExistingConfigurationWithPropertiesFromPolicy(
456 const base::DictionaryValue& existing_properties,
457 const base::DictionaryValue& new_properties) {
458 base::DictionaryValue shill_properties;
460 std::string profile;
461 existing_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
462 &profile);
463 if (profile.empty()) {
464 LOG(ERROR) << "Missing profile property.";
465 return;
467 shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
468 profile);
470 if (!shill_property_util::CopyIdentifyingProperties(existing_properties,
471 &shill_properties)) {
472 LOG(ERROR) << "Missing identifying properties.";
475 shill_properties.MergeDictionary(&new_properties);
477 network_configuration_handler_->CreateConfiguration(
478 shill_properties,
479 base::Bind(
480 &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
481 weak_ptr_factory_.GetWeakPtr()),
482 base::Bind(&LogErrorWithDict, FROM_HERE));
485 void ManagedNetworkConfigurationHandlerImpl::OnPoliciesApplied() {
486 // After all policies were applied, trigger an update of the network lists.
487 if (network_state_handler_)
488 network_state_handler_->UpdateManagerProperties();
491 const base::DictionaryValue*
492 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
493 const std::string userhash,
494 const std::string& guid,
495 ::onc::ONCSource* onc_source) const {
496 *onc_source = ::onc::ONC_SOURCE_NONE;
498 if (!userhash.empty()) {
499 const Policies* user_policies = GetPoliciesForUser(userhash);
500 if (user_policies) {
501 const base::DictionaryValue* policy =
502 GetByGUID(user_policies->per_network_config, guid);
503 if (policy) {
504 *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
505 return policy;
510 const Policies* device_policies = GetPoliciesForUser(std::string());
511 if (device_policies) {
512 const base::DictionaryValue* policy =
513 GetByGUID(device_policies->per_network_config, guid);
514 if (policy) {
515 *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
516 return policy;
520 return NULL;
523 const base::DictionaryValue*
524 ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
525 const std::string userhash) const {
526 const Policies* policies = GetPoliciesForUser(userhash);
527 if (!policies)
528 return NULL;
530 return &policies->global_network_config;
532 const base::DictionaryValue*
533 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
534 const std::string& guid,
535 const std::string& profile_path) const {
536 const NetworkProfile* profile =
537 network_profile_handler_->GetProfileForPath(profile_path);
538 if (!profile) {
539 LOG(ERROR) << "Profile path unknown: " << profile_path;
540 return NULL;
543 const Policies* policies = GetPoliciesForProfile(*profile);
544 if (!policies)
545 return NULL;
547 return GetByGUID(policies->per_network_config, guid);
550 const ManagedNetworkConfigurationHandlerImpl::Policies*
551 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
552 const std::string& userhash) const {
553 UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
554 if (it == policies_by_user_.end())
555 return NULL;
556 return it->second.get();
559 const ManagedNetworkConfigurationHandlerImpl::Policies*
560 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
561 const NetworkProfile& profile) const {
562 DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
563 profile.userhash.empty());
564 return GetPoliciesForUser(profile.userhash);
567 ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
568 : network_state_handler_(NULL),
569 network_profile_handler_(NULL),
570 network_configuration_handler_(NULL),
571 weak_ptr_factory_(this) {}
573 ManagedNetworkConfigurationHandlerImpl::
574 ~ManagedNetworkConfigurationHandlerImpl() {
575 network_profile_handler_->RemoveObserver(this);
578 void ManagedNetworkConfigurationHandlerImpl::Init(
579 NetworkStateHandler* network_state_handler,
580 NetworkProfileHandler* network_profile_handler,
581 NetworkConfigurationHandler* network_configuration_handler) {
582 network_state_handler_ = network_state_handler;
583 network_profile_handler_ = network_profile_handler;
584 network_configuration_handler_ = network_configuration_handler;
585 network_profile_handler_->AddObserver(this);
588 void ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork(
589 const std::string& service_path) {
590 if (service_path.empty())
591 return;
592 FOR_EACH_OBSERVER(
593 NetworkPolicyObserver, observers_, PolicyApplied(service_path));
596 } // namespace chromeos