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

Side by Side Diff: chromeos/network/managed_network_configuration_handler.cc

Issue 12676017: Adding policy support to the new network configuration stack. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove policy initialized flags and wrap PolicyMaps with scoped_ptr. Created 7 years, 8 months 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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 "chromeos/network/managed_network_configuration_handler.h" 5 #include "chromeos/network/managed_network_configuration_handler.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/guid.h" 11 #include "base/guid.h"
12 #include "base/json/json_writer.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/memory/ref_counted.h" 14 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
16 #include "base/stl_util.h"
15 #include "base/values.h" 17 #include "base/values.h"
16 #include "chromeos/dbus/dbus_method_call_status.h" 18 #include "chromeos/dbus/dbus_method_call_status.h"
17 #include "chromeos/dbus/dbus_thread_manager.h" 19 #include "chromeos/dbus/dbus_thread_manager.h"
18 #include "chromeos/dbus/shill_manager_client.h" 20 #include "chromeos/dbus/shill_manager_client.h"
21 #include "chromeos/dbus/shill_profile_client.h"
19 #include "chromeos/dbus/shill_service_client.h" 22 #include "chromeos/dbus/shill_service_client.h"
20 #include "chromeos/network/network_configuration_handler.h" 23 #include "chromeos/network/network_configuration_handler.h"
21 #include "chromeos/network/network_event_log.h" 24 #include "chromeos/network/network_event_log.h"
25 #include "chromeos/network/network_handler_callbacks.h"
22 #include "chromeos/network/network_state.h" 26 #include "chromeos/network/network_state.h"
23 #include "chromeos/network/network_state_handler.h" 27 #include "chromeos/network/network_state_handler.h"
28 #include "chromeos/network/network_ui_data.h"
24 #include "chromeos/network/onc/onc_constants.h" 29 #include "chromeos/network/onc/onc_constants.h"
30 #include "chromeos/network/onc/onc_merger.h"
25 #include "chromeos/network/onc/onc_signature.h" 31 #include "chromeos/network/onc/onc_signature.h"
26 #include "chromeos/network/onc/onc_translator.h" 32 #include "chromeos/network/onc/onc_translator.h"
27 #include "dbus/object_path.h" 33 #include "chromeos/network/onc/onc_utils.h"
34 #include "chromeos/network/onc/onc_validator.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h" 35 #include "third_party/cros_system_api/dbus/service_constants.h"
29 36
30 namespace chromeos { 37 namespace chromeos {
31 38
32 namespace { 39 namespace {
33 40
34 ManagedNetworkConfigurationHandler* g_configuration_handler_instance = NULL; 41 ManagedNetworkConfigurationHandler* g_configuration_handler_instance = NULL;
35 42
36 const char kLogModule[] = "ManagedNetworkConfigurationHandler"; 43 const char kLogModule[] = "ManagedNetworkConfigurationHandler";
37 44
38 // These are error strings used for error callbacks. None of these error 45 // These are error strings used for error callbacks. None of these error
39 // messages are user-facing: they should only appear in logs. 46 // messages are user-facing: they should only appear in logs.
47 const char kInvalidUserSettingsMessage[] = "User settings are invalid.";
48 const char kInvalidUserSettings[] = "Error.InvalidUserSettings";
49 const char kNetworkAlreadyConfiguredMessage[] =
50 "Network is already configured.";
51 const char kNetworkAlreadyConfigured[] = "Error.NetworkAlreadyConfigured";
52 const char kPoliciesNotInitializedMessage[] = "Policies not initialized.";
53 const char kPoliciesNotInitialized[] = "Error.PoliciesNotInitialized";
40 const char kServicePath[] = "servicePath"; 54 const char kServicePath[] = "servicePath";
41 const char kSetOnUnconfiguredNetworkMessage[] = 55 const char kSetOnUnconfiguredNetworkMessage[] =
42 "Unable to modify properties of an unconfigured network."; 56 "Unable to modify properties of an unconfigured network.";
43 const char kSetOnUnconfiguredNetwork[] = "Error.SetCalledOnUnconfiguredNetwork"; 57 const char kSetOnUnconfiguredNetwork[] = "Error.SetCalledOnUnconfiguredNetwork";
58 const char kUIDataErrorMessage[] = "UI data contains errors.";
59 const char kUIDataError[] = "Error.UIData";
44 const char kUnknownServicePathMessage[] = "Service path is unknown."; 60 const char kUnknownServicePathMessage[] = "Service path is unknown.";
45 const char kUnknownServicePath[] = "Error.UnknownServicePath"; 61 const char kUnknownServicePath[] = "Error.UnknownServicePath";
46 62
63 enum ProfileType {
64 PROFILE_NONE, // Not in any profile.
pastarmovj 2013/04/11 14:46:29 nit: Please align the comments for easier readabil
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
65 PROFILE_SHARED, // In the shared profile, shared by all users on device.
66 PROFILE_USER // In the user profile, not visible to other users.
67 };
68
69 const char kSharedProfilePath[] = "/profile/default";
70 const char kUserProfilePath[] = "/profile/chronos/shill";
71
72 const char kFakeCredential[] = "FAKE_CREDENTIAL";
pastarmovj 2013/04/11 14:46:29 It's highly unlikely but this can never be used as
pneubeck (no reviews) 2013/04/15 12:16:24 If find it to probable, that at some other place w
73
47 void RunErrorCallback(const std::string& service_path, 74 void RunErrorCallback(const std::string& service_path,
48 const std::string& error_name, 75 const std::string& error_name,
49 const std::string& error_message, 76 const std::string& error_message,
50 const network_handler::ErrorCallback& error_callback) { 77 const network_handler::ErrorCallback& error_callback) {
51 network_event_log::AddEntry(kLogModule, error_name, error_message); 78 network_event_log::AddEntry(kLogModule, error_name, error_message);
52 error_callback.Run( 79 error_callback.Run(
53 error_name, 80 error_name,
54 make_scoped_ptr( 81 make_scoped_ptr(
55 network_handler::CreateErrorData(service_path, 82 network_handler::CreateErrorData(service_path,
56 error_name, 83 error_name,
57 error_message))); 84 error_message)));
58 } 85 }
59 86
60 void TranslatePropertiesAndRunCallback( 87 // Returns the NetworkUIData parsed from the UIData property of
61 const network_handler::DictionaryResultCallback& callback, 88 // |shill_dictionary|. If parsing fails or the field doesn't exist, returns
62 const std::string& service_path, 89 // NULL.
63 const base::DictionaryValue& shill_properties) { 90 scoped_ptr<NetworkUIData> GetUIData(
64 scoped_ptr<base::DictionaryValue> onc_network( 91 const base::DictionaryValue& shill_dictionary) {
65 onc::TranslateShillServiceToONCPart( 92 std::string ui_data_blob;
66 shill_properties, 93 if (shill_dictionary.GetStringWithoutPathExpansion(
67 &onc::kNetworkWithStateSignature)); 94 flimflam::kUIDataProperty,
68 callback.Run(service_path, *onc_network); 95 &ui_data_blob) &&
96 !ui_data_blob.empty()) {
97 scoped_ptr<base::DictionaryValue> ui_data_dict =
98 onc::ReadDictionaryFromJson(ui_data_blob);
99 if (ui_data_dict) {
100 return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
101 } else {
102 LOG(ERROR) << "UIData is not a valid JSON dictionary.";
103 }
stevenjb 2013/04/11 18:20:08 nit: no {}
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
104 }
105 return scoped_ptr<NetworkUIData>();
106 }
107
108 // Sets the UIData property in |shill_dictionary| to the serialization of
109 // |ui_data|.
110 void SetUIData(const NetworkUIData& ui_data,
111 base::DictionaryValue* shill_dictionary) {
112 base::DictionaryValue ui_data_dict;
113 ui_data.FillDictionary(&ui_data_dict);
114 std::string ui_data_blob;
115 base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
116 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
117 ui_data_blob);
118 }
119
120 // A dummy callback.
121 void DoNothing() {
122 }
123
124 // A dummy callback.
125 void IgnoreString(const std::string& str) {
126 }
127
128 // A dummy callback.
129 void IgnoreErrorDict(const std::string& error_name,
130 const scoped_ptr<base::DictionaryValue> error_data) {
131 }
132
133 // A dummy callback.
134 void IgnoreErrorMessage(const std::string& error_name,
135 const std::string& error_message) {
stevenjb 2013/04/11 18:20:08 Do we really want to ignore these error messages i
pneubeck (no reviews) 2013/04/15 12:16:24 Normally, we shouldn't get errors. However, if the
136 }
137
138 void LogError(const std::string& error) {
pastarmovj 2013/04/11 14:46:29 Why would you do that?
stevenjb 2013/04/11 18:20:08 This appears to be unused.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
139 LOG(ERROR) << error;
140 }
141
142 // Removes all kFakeCredential values from sensitive fields (determined by
143 // onc::FieldIsCredential) of |onc_object|.
144 void RemoveFakeCredentials(
145 const onc::OncValueSignature& signature,
146 base::DictionaryValue* onc_object) {
147 base::DictionaryValue::Iterator it(*onc_object);
148 while (!it.IsAtEnd()) {
149 base::Value* value = NULL;
150 std::string field_name = it.key();
151 onc_object->GetWithoutPathExpansion(field_name, &value);
pastarmovj 2013/04/11 14:46:29 Why not use it.value() here?
stevenjb 2013/04/11 18:20:08 value() returns a const&, and RemoveFakeCredential
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
152 // Advance before delete.
153 it.Advance();
154
155 base::DictionaryValue* nested_object = NULL;
156 std::string string_value;
157 if (value->GetAsDictionary(&nested_object)) {
stevenjb 2013/04/11 18:20:08 This is kind of confusing. While more verbose, I w
pneubeck (no reviews) 2013/04/15 12:16:24 This pattern is rather common and typesafe. Do you
stevenjb 2013/04/15 17:38:54 Well, I don't feel strongly enough about it to was
pneubeck (no reviews) 2013/04/16 07:50:06 Done.
158 const onc::OncFieldSignature* field_signature =
159 onc::GetFieldSignature(signature, field_name);
160
161 RemoveFakeCredentials(*field_signature->value_signature,
162 nested_object);
163 } else if (value->GetAsString(&string_value) &&
164 onc::FieldIsCredential(signature, field_name)) {
165 if (string_value == kFakeCredential) {
166 // The value wasn't modified by the UI, thus we remove the field to keep
167 // the existing value that is stored in Shill.
168 onc_object->RemoveWithoutPathExpansion(field_name, NULL);
169 }
170 // Otherwise, the value is set and modified by the UI, thus we keep that
171 // value to overwrite whatever is stored in Shill.
172 }
173 }
174 }
175
176 // Creates a Shill property dictionary from the given arguments. The resulting
177 // dictionary will be sent to Shill by the caller.
178 scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
179 const std::string& profile_path,
180 const std::string& guid,
181 const base::DictionaryValue* policy,
182 const base::DictionaryValue* user_settings) {
183 scoped_ptr<base::DictionaryValue> effective;
184
185 onc::ONCSource onc_source;
186 if (policy) {
187 if (profile_path == kSharedProfilePath) {
188 effective = onc::MergeSettingsAndPoliciesToEffective(
189 NULL, // no user policy
190 policy, // device policy
191 NULL, // no user settings
192 user_settings); // shared settings
stevenjb 2013/04/11 18:20:08 nit: Name 'settings' since may be user or shared?
pneubeck (no reviews) 2013/04/15 12:16:24 Ugh. Yes, the current naming is confusing without
193 onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
194 } else {
195 effective = onc::MergeSettingsAndPoliciesToEffective(
196 policy, // user policy
197 NULL, // no device policy
198 user_settings, // user settings
199 NULL); // no shared settings
200 onc_source = onc::ONC_SOURCE_USER_POLICY;
201 }
202 } else if (user_settings) {
203 effective.reset(user_settings->DeepCopy());
204 // TODO(pneubeck): change to source ONC_SOURCE_USER
205 onc_source = onc::ONC_SOURCE_NONE;
206 } else {
207 NOTREACHED();
208 onc_source = onc::ONC_SOURCE_NONE;
209 }
210
211 RemoveFakeCredentials(onc::kNetworkConfigurationSignature,
212 effective.get());
213
214 effective->SetStringWithoutPathExpansion(onc::network_config::kGUID, guid);
215
216 scoped_ptr<base::DictionaryValue> shill_dictionary(
217 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
218 *effective));
219
220 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
221 profile_path);
222
223 scoped_ptr<NetworkUIData> ui_data;
224 if (policy) {
225 ui_data = CreateUIDataFromONC(onc_source, *policy);
226 } else {
227 ui_data.reset(new NetworkUIData());
228 }
stevenjb 2013/04/11 18:20:08 nit: no {}
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
229
230 if (user_settings) {
231 // Shill doesn't know that sensitive data is contained in the UIData
232 // property and might write it into logs or other insecure places. Thus, we
233 // have to remove or mask credentials.
234 //
235 // Shill's GetProperties doesn't return credentials. Masking credentials
236 // instead of just removing them, allows remembering if a credential is set
237 // or not.
238 scoped_ptr<base::DictionaryValue> sanitized_user_settings(
239 onc::MaskCredentialsInOncObject(onc::kNetworkConfigurationSignature,
240 *user_settings,
241 kFakeCredential));
242 ui_data->set_user_settings(sanitized_user_settings.Pass());
243 }
244
245 SetUIData(*ui_data, shill_dictionary.get());
246
247 VLOG(2) << "Created Shill properties: " << *shill_dictionary;
248
249 return shill_dictionary.Pass();
250 }
251
252 // Returns if |policy| matches |onc_network_part|. This is should be the only
stevenjb 2013/04/11 18:20:08 s/Returns/Returns true/
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
253 // such matching function within Chrome. Shill does such matching in several
254 // functions for network identification. For compatibility, we currently should
255 // stick to Shill's matching behavior.
256 bool IsPolicyMatching(const base::DictionaryValue& policy,
257 const base::DictionaryValue& onc_network_part) {
258 std::string policy_type;
259 policy.GetStringWithoutPathExpansion(onc::network_config::kType,
260 &policy_type);
261 std::string network_type;
262 onc_network_part.GetStringWithoutPathExpansion(onc::network_config::kType,
263 &network_type);
264 if (policy_type != network_type)
pastarmovj 2013/04/11 14:46:29 Please be consistent in the file if you use or not
stevenjb 2013/04/11 18:20:08 Also while the style guide allows either, historic
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
265 return false;
266
267 if (network_type != onc::network_type::kWiFi)
268 return false;
269
270 std::string policy_ssid;
271 policy.GetStringWithoutPathExpansion(onc::wifi::kSSID,
272 &policy_ssid);
stevenjb 2013/04/11 18:20:08 nit: one line?
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
273 std::string network_ssid;
274 onc_network_part.GetStringWithoutPathExpansion(onc::wifi::kSSID,
275 &network_ssid);
276 return (policy_ssid == network_ssid);
277 }
278
279 // Returns the policy of |policies| matching |onc_network_part|, if any
280 // exists. Returns NULL otherwise.
281 const base::DictionaryValue* FindMatchingPolicy(
282 const std::map<std::string, const base::DictionaryValue*> &policies,
stevenjb 2013/04/11 18:20:08 Use ManagedNetworkConfigurationHandler::PolicyMap
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
stevenjb 2013/04/15 17:38:54 Not done?
pneubeck (no reviews) 2013/04/16 07:50:06 Yeah, I had previously replaced all within Managed
283 const base::DictionaryValue& onc_network_part) {
284 for (std::map<std::string, const base::DictionaryValue*>::const_iterator it =
285 policies.begin();
286 it != policies.end();
pastarmovj 2013/04/11 14:46:29 combine those two lines.
stevenjb 2013/04/11 18:20:08 In fact, I would suggest placing both line 286 and
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
287 ++it) {
288 if (IsPolicyMatching(*it->second, onc_network_part))
289 return it->second;
290 }
291 return NULL;
69 } 292 }
70 293
71 } // namespace 294 } // namespace
72 295
73 // static 296 // static
74 void ManagedNetworkConfigurationHandler::Initialize() { 297 void ManagedNetworkConfigurationHandler::Initialize() {
75 CHECK(!g_configuration_handler_instance); 298 CHECK(!g_configuration_handler_instance);
76 g_configuration_handler_instance = new ManagedNetworkConfigurationHandler; 299 g_configuration_handler_instance = new ManagedNetworkConfigurationHandler;
77 } 300 }
78 301
79 // static 302 // static
80 bool ManagedNetworkConfigurationHandler::IsInitialized() { 303 bool ManagedNetworkConfigurationHandler::IsInitialized() {
81 return g_configuration_handler_instance; 304 return g_configuration_handler_instance;
82 } 305 }
83 306
84 // static 307 // static
85 void ManagedNetworkConfigurationHandler::Shutdown() { 308 void ManagedNetworkConfigurationHandler::Shutdown() {
86 CHECK(g_configuration_handler_instance); 309 CHECK(g_configuration_handler_instance);
87 delete g_configuration_handler_instance; 310 delete g_configuration_handler_instance;
88 g_configuration_handler_instance = NULL; 311 g_configuration_handler_instance = NULL;
89 } 312 }
90 313
91 // static 314 // static
92 ManagedNetworkConfigurationHandler* ManagedNetworkConfigurationHandler::Get() { 315 ManagedNetworkConfigurationHandler* ManagedNetworkConfigurationHandler::Get() {
93 CHECK(g_configuration_handler_instance); 316 CHECK(g_configuration_handler_instance);
94 return g_configuration_handler_instance; 317 return g_configuration_handler_instance;
95 } 318 }
96 319
320 void ManagedNetworkConfigurationHandler::GetManagedProperties(
321 const std::string& service_path,
322 const network_handler::DictionaryResultCallback& callback,
323 const network_handler::ErrorCallback& error_callback) {
324 if (!user_policies_by_guid_ || !device_policies_by_guid_) {
325 RunErrorCallback(service_path,
326 kPoliciesNotInitialized,
327 kPoliciesNotInitializedMessage,
328 error_callback);
329 return;
330 }
331 NetworkConfigurationHandler::Get()->GetProperties(
332 service_path,
333 base::Bind(
334 &ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback,
335 weak_ptr_factory_.GetWeakPtr(),
336 callback,
337 error_callback),
338 error_callback);
339 }
340
341 void ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback(
342 const network_handler::DictionaryResultCallback& callback,
343 const network_handler::ErrorCallback& error_callback,
344 const std::string& service_path,
345 const base::DictionaryValue& shill_properties) {
346 std::string profile_path;
347 ProfileType profile_type = PROFILE_NONE;
348 if (shill_properties.GetStringWithoutPathExpansion(
349 flimflam::kProfileProperty,
pastarmovj 2013/04/11 14:46:29 Combine those two lines better.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
350 &profile_path)) {
351 if (profile_path == kSharedProfilePath)
352 profile_type = PROFILE_SHARED;
353 else if (!profile_path.empty())
354 profile_type = PROFILE_USER;
355 } else {
356 VLOG(1) << "No profile path for service " << service_path << ".";
357 }
358
359 scoped_ptr<NetworkUIData> ui_data = GetUIData(shill_properties);
360
361 base::DictionaryValue* user_settings = NULL;
362 base::DictionaryValue* shared_settings = NULL;
363
364 if (ui_data) {
365 if (profile_type == PROFILE_SHARED)
366 shared_settings = ui_data->user_settings();
367 else if (profile_type == PROFILE_USER)
368 user_settings = ui_data->user_settings();
369 } else if (profile_type != PROFILE_NONE) {
370 LOG(WARNING) << "Service " << service_path << " of profile "
371 << profile_path << " contains no or no valid UIData.";
372 // TODO(pneubeck): add a conversion of user configured entries of old
373 // ChromeOS versions. We will have to use a heuristic to determine which
374 // properties _might_ be user configured.
375 }
376
377 scoped_ptr<base::DictionaryValue> active_settings(
378 onc::TranslateShillServiceToONCPart(
379 shill_properties,
380 &onc::kNetworkWithStateSignature));
381
382 std::string guid;
383 active_settings->GetStringWithoutPathExpansion(onc::network_config::kGUID,
384 &guid);
385
386 const base::DictionaryValue* user_policy = NULL;
387 const base::DictionaryValue* device_policy = NULL;
388 if (!guid.empty()) {
389 if (profile_type == PROFILE_SHARED)
390 device_policy = (*device_policies_by_guid_)[guid];
391 else if (profile_type == PROFILE_USER)
392 user_policy = (*user_policies_by_guid_)[guid];
393 }
394
395 // This call also removes credentials from policies.
396 scoped_ptr<base::DictionaryValue> augmented_properties =
397 onc::MergeSettingsAndPoliciesToAugmented(
398 onc::kNetworkConfigurationSignature,
399 user_policy,
400 device_policy,
401 user_settings,
402 shared_settings,
403 active_settings.get());
404 callback.Run(service_path, *augmented_properties);
405 }
406
407 namespace {
stevenjb 2013/04/11 18:20:08 nit: I'd combine this with the anon namesapce at t
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
408
409 void TranslatePropertiesAndRunCallback(
410 const network_handler::DictionaryResultCallback& callback,
411 const std::string& service_path,
412 const base::DictionaryValue& shill_properties) {
413 scoped_ptr<base::DictionaryValue> onc_network(
414 onc::TranslateShillServiceToONCPart(
415 shill_properties,
416 &onc::kNetworkWithStateSignature));
417 callback.Run(service_path, *onc_network);
418 }
419
420 } // namespace
421
97 void ManagedNetworkConfigurationHandler::GetProperties( 422 void ManagedNetworkConfigurationHandler::GetProperties(
98 const std::string& service_path, 423 const std::string& service_path,
99 const network_handler::DictionaryResultCallback& callback, 424 const network_handler::DictionaryResultCallback& callback,
100 const network_handler::ErrorCallback& error_callback) const { 425 const network_handler::ErrorCallback& error_callback) const {
101 // TODO(pneubeck): Merge with policies.
102 NetworkConfigurationHandler::Get()->GetProperties( 426 NetworkConfigurationHandler::Get()->GetProperties(
103 service_path, 427 service_path,
104 base::Bind(&TranslatePropertiesAndRunCallback, callback), 428 base::Bind(&TranslatePropertiesAndRunCallback, callback),
105 error_callback); 429 error_callback);
106 } 430 }
107 431
108 void ManagedNetworkConfigurationHandler::SetProperties( 432 void ManagedNetworkConfigurationHandler::SetProperties(
109 const std::string& service_path, 433 const std::string& service_path,
110 const base::DictionaryValue& properties, 434 const base::DictionaryValue& user_settings,
111 const base::Closure& callback, 435 const base::Closure& callback,
112 const network_handler::ErrorCallback& error_callback) const { 436 const network_handler::ErrorCallback& error_callback) const {
113 const NetworkState* state = 437 const NetworkState* state =
114 NetworkStateHandler::Get()->GetNetworkState(service_path); 438 NetworkStateHandler::Get()->GetNetworkState(service_path);
115 439
116 if (!state) { 440 if (!state) {
117 RunErrorCallback(service_path, 441 RunErrorCallback(service_path,
118 kUnknownServicePath, 442 kUnknownServicePath,
119 kUnknownServicePathMessage, 443 kUnknownServicePathMessage,
120 error_callback); 444 error_callback);
445 return;
121 } 446 }
447
122 std::string guid = state->guid(); 448 std::string guid = state->guid();
123 if (guid.empty()) { 449 if (guid.empty()) {
450 // TODO(pneubeck): create an initial configuration in this case. As for
451 // CreateConfiguration, user settings from older ChromeOS versions have to
452 // determined here.
124 RunErrorCallback(service_path, 453 RunErrorCallback(service_path,
125 kSetOnUnconfiguredNetwork, 454 kSetOnUnconfiguredNetwork,
126 kSetOnUnconfiguredNetworkMessage, 455 kSetOnUnconfiguredNetworkMessage,
127 error_callback); 456 error_callback);
457 return;
128 } 458 }
129 459
130 // TODO(pneubeck): Enforce policies. 460 // Validate the ONC dictionary. We are liberal and ignore unknown field
461 // names. User settings are only partial ONC, thus we ignore missing fields.
462 onc::Validator validator(false, // Ignore unknown fields.
463 false, // Ignore invalid recommended field names.
464 false, // Ignore missing fields.
pastarmovj 2013/04/11 14:46:29 Almost aligned here.
pneubeck (no reviews) 2013/04/15 12:16:24 ? You want the comments to be aligned?
pastarmovj 2013/04/16 11:31:17 Yes, but you can leave it as is if you wish.
465 false); // This ONC does not comes from policy.
466
467 onc::Validator::Result validation_result;
468 scoped_ptr<base::DictionaryValue> validated_user_settings =
469 validator.ValidateAndRepairObject(
470 &onc::kNetworkConfigurationSignature,
471 user_settings,
472 &validation_result);
473
474 if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
475 LOG(WARNING) << "Validation of ONC user settings produced warnings.";
476 } else if (validation_result == onc::Validator::INVALID) {
477 LOG(ERROR) << "ONC user settings are invalid and couldn't be repaired.";
478 RunErrorCallback(service_path,
479 kInvalidUserSettings,
480 kInvalidUserSettingsMessage,
481 error_callback);
482 return;
stevenjb 2013/04/11 18:20:08 nit: Put error clause with early exit above warnin
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
483 }
484
485 VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
486 << state->profile_path();
487
488 const PolicyMap* policies_by_guid =
489 GetPoliciesForProfile(state->profile_path());
490
491 if (!policies_by_guid) {
492 RunErrorCallback(service_path,
493 kPoliciesNotInitialized,
494 kPoliciesNotInitializedMessage,
495 error_callback);
496 return;
497 }
498
499 const base::DictionaryValue* policy = NULL;
500 std::map<std::string, const base::DictionaryValue*>::const_iterator it =
501 policies_by_guid->find(guid);
502 if (it != policies_by_guid->end())
503 policy = it->second;
504
505 VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
131 506
132 scoped_ptr<base::DictionaryValue> shill_dictionary( 507 scoped_ptr<base::DictionaryValue> shill_dictionary(
133 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature, 508 CreateShillConfiguration(state->profile_path(), guid, policy,
134 properties)); 509 &user_settings));
135 510
136 NetworkConfigurationHandler::Get()->SetProperties(service_path, 511 NetworkConfigurationHandler::Get()->SetProperties(service_path,
137 *shill_dictionary, 512 *shill_dictionary,
138 callback, 513 callback,
139 error_callback); 514 error_callback);
140 } 515 }
141 516
142 void ManagedNetworkConfigurationHandler::Connect( 517 void ManagedNetworkConfigurationHandler::Connect(
143 const std::string& service_path, 518 const std::string& service_path,
144 const base::Closure& callback, 519 const base::Closure& callback,
145 const network_handler::ErrorCallback& error_callback) const { 520 const network_handler::ErrorCallback& error_callback) const {
146 // TODO(pneubeck): Update the user profile with tracked/followed settings of
147 // the shared profile.
148 NetworkConfigurationHandler::Get()->Connect(service_path, 521 NetworkConfigurationHandler::Get()->Connect(service_path,
149 callback, 522 callback,
150 error_callback); 523 error_callback);
151 } 524 }
152 525
153 void ManagedNetworkConfigurationHandler::Disconnect( 526 void ManagedNetworkConfigurationHandler::Disconnect(
154 const std::string& service_path, 527 const std::string& service_path,
155 const base::Closure& callback, 528 const base::Closure& callback,
156 const network_handler::ErrorCallback& error_callback) const { 529 const network_handler::ErrorCallback& error_callback) const {
157 NetworkConfigurationHandler::Get()->Disconnect(service_path, 530 NetworkConfigurationHandler::Get()->Disconnect(service_path,
158 callback, 531 callback,
159 error_callback); 532 error_callback);
160 } 533 }
161 534
162 void ManagedNetworkConfigurationHandler::CreateConfiguration( 535 void ManagedNetworkConfigurationHandler::CreateConfiguration(
163 const base::DictionaryValue& properties, 536 const base::DictionaryValue& properties,
164 const network_handler::StringResultCallback& callback, 537 const network_handler::StringResultCallback& callback,
165 const network_handler::ErrorCallback& error_callback) const { 538 const network_handler::ErrorCallback& error_callback) const {
166 scoped_ptr<base::DictionaryValue> modified_properties( 539 std::string profile_path = kUserProfilePath;
167 properties.DeepCopy()); 540 const PolicyMap* policies_by_guid = GetPoliciesForProfile(profile_path);
168 541
169 // If there isn't already a GUID attached to these properties, then 542 if (!policies_by_guid) {
170 // generate one and add it. 543 RunErrorCallback("",
171 std::string guid; 544 kPoliciesNotInitialized,
172 if (!properties.GetString(onc::network_config::kGUID, &guid)) { 545 kPoliciesNotInitializedMessage,
173 guid = base::GenerateGUID(); 546 error_callback);
174 modified_properties->SetStringWithoutPathExpansion( 547 return;
175 onc::network_config::kGUID, guid);
176 } else {
177 NOTREACHED(); // TODO(pneubeck): Return an error using error_callback.
178 } 548 }
179 549
180 // TODO(pneubeck): Enforce policies. 550 if (FindMatchingPolicy(*policies_by_guid, properties)) {
551 RunErrorCallback("",
552 kNetworkAlreadyConfigured,
553 kNetworkAlreadyConfiguredMessage,
554 error_callback);
555 }
556
557 // TODO(pneubeck): In case of WiFi, check that no other configuration for the
558 // same {SSID, mode, security} exists. We don't support such multiple
559 // configurations, yet.
560
561 // Generate a new GUID for this configuration. Ignore the maybe provided GUID
562 // in |properties| as it is not our own and from an untrusted source.
563 std::string guid = base::GenerateGUID();
181 564
182 scoped_ptr<base::DictionaryValue> shill_dictionary( 565 scoped_ptr<base::DictionaryValue> shill_dictionary(
183 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature, 566 CreateShillConfiguration(profile_path, guid, NULL /*no policy*/,
184 properties)); 567 &properties));
185 568
186 NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary, 569 NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary,
187 callback, 570 callback,
188 error_callback); 571 error_callback);
189 } 572 }
190 573
191 void ManagedNetworkConfigurationHandler::RemoveConfiguration( 574 void ManagedNetworkConfigurationHandler::RemoveConfiguration(
192 const std::string& service_path, 575 const std::string& service_path,
193 const base::Closure& callback, 576 const base::Closure& callback,
194 const network_handler::ErrorCallback& error_callback) const { 577 const network_handler::ErrorCallback& error_callback) const {
195 NetworkConfigurationHandler::Get()->RemoveConfiguration(service_path, 578 NetworkConfigurationHandler::Get()->RemoveConfiguration(service_path,
196 callback, 579 callback,
197 error_callback); 580 error_callback);
198 } 581 }
199 582
200 ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler() { 583 // This class compares (entry point is Run()) |modified_policies| with the
584 // existing entries in the provided Shill profile |profile|. It fetches all
585 // entries in parallel (GetProfileProperties), compares each entry with the
586 // current policies (GetEntry) and adds all missing policies
587 // (~PolicyApplicator).
588 class ManagedNetworkConfigurationHandler::PolicyApplicator
589 : public base::RefCounted<PolicyApplicator> {
590 public:
591 typedef ManagedNetworkConfigurationHandler::PolicyMap PolicyMap;
592
593 PolicyApplicator(base::WeakPtr<ManagedNetworkConfigurationHandler> handler,
594 const std::string& profile,
595 scoped_ptr<std::set<std::string> > modified_policies)
596 : handler_(handler),
597 profile_path_(profile) {
598 remaining_policies_.swap(*modified_policies);
pastarmovj 2013/04/11 14:46:29 Hmm is this safe in all cases?
stevenjb 2013/04/11 18:20:08 This is confusing with a member and a scoped_ptr.
pneubeck (no reviews) 2013/04/15 12:16:24 Not if modified_policies is NULL, in which case it
pneubeck (no reviews) 2013/04/15 12:16:24 The scoped_ptr indicates that ownership is passed
stevenjb 2013/04/15 17:38:54 With swap(), I do prefer it changed with the comme
599 }
600
601 void Run() {
602 DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
603 dbus::ObjectPath(profile_path_),
604 base::Bind(
605 &PolicyApplicator::GetProfileProperties,
606 this),
stevenjb 2013/04/11 18:20:08 nit: combine the above 3 lines?
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
607 base::Bind(&IgnoreErrorMessage));
608 }
609
610 private:
611 friend class base::RefCounted<PolicyApplicator>;
612
613 void GetProfileProperties(const base::DictionaryValue& profile_properties) {
614 if (!handler_) {
615 LOG(WARNING) << "Handler destructed during policy application to profile "
616 << profile_path_;
617 return;
618 }
619
620 VLOG(2) << "Received properties for profile " << profile_path_;
621 const base::ListValue* entries = NULL;
622 if (!profile_properties.GetListWithoutPathExpansion(
623 flimflam::kEntriesProperty,
624 &entries)) {
stevenjb 2013/04/11 18:20:08 nit: combine lines
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
625 LOG(ERROR) << "Profile " << profile_path_
626 << " doesn't contain the property "
627 << flimflam::kEntriesProperty;
628 return;
629 }
630
631 for (base::ListValue::const_iterator it = entries->begin();
632 it != entries->end(); ++it) {
633 std::string entry;
634 (*it)->GetAsString(&entry);
635
636 std::ostringstream entry_failure;
637 DBusThreadManager::Get()->GetShillProfileClient()->GetEntry(
638 dbus::ObjectPath(profile_path_),
639 entry,
640 base::Bind(&PolicyApplicator::GetEntry,
641 this,
642 entry),
643 base::Bind(&IgnoreErrorMessage));
644 }
645 }
646
647 void GetEntry(const std::string& entry,
648 const base::DictionaryValue& entry_properties) {
649 if (!handler_) {
650 LOG(WARNING) << "Handler destructed during policy application to profile "
651 << profile_path_;
652 return;
653 }
654
655 VLOG(2) << "Received properties for entry " << entry << " of profile "
656 << profile_path_;
657
658 scoped_ptr<base::DictionaryValue> onc_part(
659 onc::TranslateShillServiceToONCPart(
660 entry_properties,
661 &onc::kNetworkWithStateSignature));
662
663 std::string old_guid;
664 if (!onc_part->GetStringWithoutPathExpansion(onc::network_config::kGUID,
665 &old_guid)) {
pastarmovj 2013/04/11 14:46:29 align.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
666 LOG(WARNING) << "Entry " << entry << " of profile " << profile_path_
pastarmovj 2013/04/11 14:46:29 align.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
667 << " doesn't contain a GUID.";
668 // This might be an entry of an older ChromeOS version. Assume it to be
669 // unmanaged.
670 return;
671 }
672
673 scoped_ptr<NetworkUIData> ui_data = GetUIData(entry_properties);
674 if (!ui_data) {
675 VLOG(1) << "Entry " << entry << " of profile " << profile_path_
676 << " contains no or no valid UIData.";
677 // This might be an entry of an older ChromeOS version. Assume it to be
678 // unmanaged.
679 return;
680 }
681
682 bool was_managed =
683 (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY ||
684 ui_data->onc_source() == onc::ONC_SOURCE_USER_POLICY);
685
686 // The relevant policy must have been initialized, otherwise we hadn't Run
687 // this PolicyApplicator.
688 const PolicyMap& policies_by_guid =
689 *handler_->GetPoliciesForProfile(profile_path_);
690
691 const base::DictionaryValue* new_policy = NULL;
692 if (was_managed) {
693 // If we have a GUID that might match a current policy, do a lookup using
694 // that GUID at first. In particular this is necessary, as some networks
695 // can't be matched to policies by properties (e.g. VPN).
696 PolicyMap::const_iterator it = policies_by_guid.find(old_guid);
697 if (it != policies_by_guid.end())
698 new_policy = it->second;
699 }
700
701 if (!new_policy) {
702 // If we didn't find a policy by GUID, still a new policy might match.
703 new_policy = FindMatchingPolicy(policies_by_guid, *onc_part);
704 }
705
706 std::string new_guid;
707 if (new_policy) {
708 new_policy->GetStringWithoutPathExpansion(onc::network_config::kGUID,
709 &new_guid);
710 }
711
712 if (new_policy) {
pastarmovj 2013/04/11 14:46:29 Combine those ifs they are the same.
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
713 VLOG_IF(1, was_managed && old_guid != new_guid)
714 << "Updating configuration previously managed by policy " << old_guid
715 << " with new policy " << new_guid << ".";
716 VLOG_IF(1, !was_managed)
717 << "Applying policy " << new_guid << " to previously unmanaged "
718 << "configuration.";
719
720 if (old_guid == new_guid &&
721 remaining_policies_.find(new_guid) == remaining_policies_.end()) {
722 VLOG(1) << "Not updating existing managed configuration with guid "
723 << new_guid << " because the policy didn't change.";
724 } else {
725 VLOG_IF(1, old_guid == new_guid)
726 << "Updating previously managed configuration with the updated "
727 << "policy " << new_guid << ".";
728
729 // Update the existing configuration with the maybe changed
730 // policy. Thereby the GUID might change.
731 scoped_ptr<base::DictionaryValue> shill_dictionary =
732 CreateShillConfiguration(profile_path_, new_guid, new_policy,
733 ui_data->user_settings());
734 NetworkConfigurationHandler::Get()->CreateConfiguration(
735 *shill_dictionary,
736 base::Bind(&IgnoreString),
737 base::Bind(&IgnoreErrorDict));
738 remaining_policies_.erase(new_guid);
739 }
740 } else if (was_managed) {
741 VLOG(1) << "Removing configuration previously managed by policy "
742 << old_guid << ", because the policy was removed.";
743
744 // Remove the entry, because the network was managed but isn't anymore.
745 // Note: An alternative might be to preserve the user settings, but it's
746 // unclear which values originating the policy should be removed.
747 DeleteEntry(entry);
748 } else {
749 VLOG(2) << "Ignore unmanaged entry.";
750
751 // The entry wasn't managed and doesn't match any current policy. Thus
752 // leave it as it is.
753 }
754 }
755
756 void DeleteEntry(const std::string& entry) {
757 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
758 dbus::ObjectPath(profile_path_),
759 entry,
760 base::Bind(&DoNothing),
761 base::Bind(&IgnoreErrorMessage));
762 }
763
764 virtual ~PolicyApplicator() {
765 if (remaining_policies_.empty())
766 return;
767
768 VLOG(2) << "Create new managed network configurations in profile"
769 << profile_path_ << ".";
770 // All profile entries were compared to policies. |configureGUIDs_| contains
771 // all matched policies. From the remainder of policies, new configurations
772 // have to be created.
773
774 // The relevant policy must have been initialized, otherwise we hadn't Run
775 // this PolicyApplicator.
776 const PolicyMap& policies_by_guid =
777 *handler_->GetPoliciesForProfile(profile_path_);
778
779 for (std::set<std::string>::iterator it = remaining_policies_.begin();
780 it != remaining_policies_.end(); ++it) {
781 PolicyMap::const_iterator policy_it = policies_by_guid.find(*it);
782 if (policy_it == policies_by_guid.end()) {
783 LOG(ERROR) << "Policy " << *it << " doesn't exist anymore.";
784 continue;
785 }
786
787 const base::DictionaryValue* policy = policy_it->second;
788
789 VLOG(1) << "Creating new configuration managed by policy " << *it
790 << " in profile " << profile_path_ << ".";
791
792 scoped_ptr<base::DictionaryValue> shill_dictionary =
793 CreateShillConfiguration(profile_path_, *it, policy, NULL);
794 NetworkConfigurationHandler::Get()->CreateConfiguration(
795 *shill_dictionary,
796 base::Bind(&IgnoreString),
797 base::Bind(&IgnoreErrorDict));
798 }
799 }
800
801 std::set<std::string> remaining_policies_;
802 base::WeakPtr<ManagedNetworkConfigurationHandler> handler_;
803 std::string profile_path_;
804
805 DISALLOW_COPY_AND_ASSIGN(PolicyApplicator);
806 };
807
808 void ManagedNetworkConfigurationHandler::SetPolicy(
809 onc::ONCSource onc_source,
810 const base::DictionaryValue& onc_dict) {
811 VLOG(1) << "Setting policies for ONC source "
812 << onc::GetSourceAsString(onc_source) << ".";
813
814 // Validate the ONC dictionary. We are liberal and ignore unknown field
815 // names and ignore invalid field names in kRecommended arrays.
816 onc::Validator validator(false, // Ignore unknown fields.
817 false, // Ignore invalid recommended field names.
818 true, // Fail on missing fields.
819 true); // This ONC comes from policy.
820 validator.SetOncSource(onc_source);
821
822 onc::Validator::Result validation_result;
823 scoped_ptr<base::DictionaryValue> onc_validated =
824 validator.ValidateAndRepairObject(
825 &onc::kToplevelConfigurationSignature,
826 onc_dict,
827 &validation_result);
828
829 if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
830 LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source)
831 << " produced warnings.";
832 } else if (validation_result == onc::Validator::INVALID ||
833 onc_validated == NULL) {
834 LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
pastarmovj 2013/04/11 14:46:29 It there a chance you are leaking here infromation
pneubeck (no reviews) 2013/04/15 12:16:24 Good point. In most places I only log things like
835 << " is invalid and couldn't be repaired.";
836 return;
837 }
838
839 scoped_ptr<PolicyMap>* policies;
840 std::string profile;
841 if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
842 policies = &user_policies_by_guid_;
843 profile = kUserProfilePath;
844 } else {
845 policies = &device_policies_by_guid_;
846 profile = kSharedProfilePath;
847 }
848
849 if (!*policies)
850 policies->reset(new PolicyMap);
851
852 PolicyMap old_policies;
853 scoped_ptr<std::set<std::string> > modified_policies(
854 new std::set<std::string>());
stevenjb 2013/04/11 18:20:08 As noted above, this should just be 'std::set<std:
pneubeck (no reviews) 2013/04/15 12:16:24 Cannot move it much further, as it must stay in fr
855 (*policies)->swap(old_policies);
856
857 base::ListValue* network_configurations = NULL;
858 onc_validated->GetListWithoutPathExpansion(
859 onc::toplevel_config::kNetworkConfigurations,
860 &network_configurations);
861
862 if (network_configurations) {
863 while (!network_configurations->empty()) {
864 base::Value* network_value = NULL;
865 // Passes ownership of network_value.
866 network_configurations->Remove(network_configurations->GetSize() - 1,
867 &network_value);
868 const base::DictionaryValue* network = NULL;
869 network_value->GetAsDictionary(&network);
870 std::string guid;
871 network->GetStringWithoutPathExpansion(onc::network_config::kGUID,
872 &guid);
873
874 const base::DictionaryValue* old_entry = old_policies[guid];
875 const base::DictionaryValue*& new_entry = (**policies)[guid];
876 if (new_entry) {
877 LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
878 << " contains several entries for the same GUID "
879 << guid << ".";
880 delete new_entry;
881 }
882 new_entry = network;
883
884 if (!old_entry || !old_entry->Equals(new_entry)) {
885 modified_policies->insert(guid);
886 }
887 }
888 }
889
890 STLDeleteValues(&old_policies);
891
892 (new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
pastarmovj 2013/04/11 14:46:29 That a little bit too function-programming-y for C
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
893 profile,
894 modified_policies.Pass()))->Run();
895 }
896
897 const ManagedNetworkConfigurationHandler::PolicyMap*
898 ManagedNetworkConfigurationHandler::GetPoliciesForProfile(
899 const std::string& profile) const {
900 if (profile == kSharedProfilePath) {
901 return device_policies_by_guid_.get();
902 } else {
903 return user_policies_by_guid_.get();
904 }
stevenjb 2013/04/11 18:20:08 nit: no {}
pneubeck (no reviews) 2013/04/15 12:16:24 Done.
905 }
906
907 ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler()
908 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
201 } 909 }
202 910
203 ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() { 911 ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() {
912 STLDeleteValues(user_policies_by_guid_.get());
913 STLDeleteValues(device_policies_by_guid_.get());
204 } 914 }
205 915
206 } // namespace chromeos 916 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698