- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / net / onc_utils.cc
1 // Copyright (c) 2012 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/net/onc_utils.h"
6
7 #include "base/bind_helpers.h"
8 #include "base/json/json_writer.h"
9 #include "base/logging.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/values.h"
12 #include "chrome/browser/chromeos/login/user.h"
13 #include "chrome/browser/chromeos/login/user_manager.h"
14 #include "chrome/browser/chromeos/ui_proxy_config.h"
15 #include "chrome/browser/prefs/proxy_config_dictionary.h"
16 #include "chrome/common/pref_names.h"
17 #include "chromeos/network/favorite_state.h"
18 #include "chromeos/network/managed_network_configuration_handler.h"
19 #include "chromeos/network/network_configuration_handler.h"
20 #include "chromeos/network/network_handler.h"
21 #include "chromeos/network/network_profile.h"
22 #include "chromeos/network/network_profile_handler.h"
23 #include "chromeos/network/network_state.h"
24 #include "chromeos/network/network_state_handler.h"
25 #include "chromeos/network/network_ui_data.h"
26 #include "chromeos/network/onc/onc_normalizer.h"
27 #include "chromeos/network/onc/onc_signature.h"
28 #include "chromeos/network/onc/onc_translator.h"
29 #include "chromeos/network/onc/onc_utils.h"
30 #include "chromeos/network/shill_property_util.h"
31 #include "net/base/host_port_pair.h"
32 #include "net/proxy/proxy_bypass_rules.h"
33 #include "net/proxy/proxy_server.h"
34 #include "third_party/cros_system_api/dbus/service_constants.h"
35 #include "url/gurl.h"
36
37 namespace chromeos {
38 namespace onc {
39
40 namespace {
41
42 net::ProxyServer ConvertOncProxyLocationToHostPort(
43     net::ProxyServer::Scheme default_proxy_scheme,
44     const base::DictionaryValue& onc_proxy_location) {
45   std::string host;
46   onc_proxy_location.GetStringWithoutPathExpansion(::onc::proxy::kHost, &host);
47   // Parse |host| according to the format [<scheme>"://"]<server>[":"<port>].
48   net::ProxyServer proxy_server =
49       net::ProxyServer::FromURI(host, default_proxy_scheme);
50   int port = 0;
51   onc_proxy_location.GetIntegerWithoutPathExpansion(::onc::proxy::kPort, &port);
52
53   // Replace the port parsed from |host| by the provided |port|.
54   return net::ProxyServer(
55       proxy_server.scheme(),
56       net::HostPortPair(proxy_server.host_port_pair().host(),
57                         static_cast<uint16>(port)));
58 }
59
60 void AppendProxyServerForScheme(
61     const base::DictionaryValue& onc_manual,
62     const std::string& onc_scheme,
63     std::string* spec) {
64   const base::DictionaryValue* onc_proxy_location = NULL;
65   if (!onc_manual.GetDictionaryWithoutPathExpansion(onc_scheme,
66                                                     &onc_proxy_location)) {
67     return;
68   }
69
70   net::ProxyServer::Scheme default_proxy_scheme = net::ProxyServer::SCHEME_HTTP;
71   std::string url_scheme;
72   if (onc_scheme == ::onc::proxy::kFtp) {
73     url_scheme = "ftp";
74   } else if (onc_scheme == ::onc::proxy::kHttp) {
75     url_scheme = "http";
76   } else if (onc_scheme == ::onc::proxy::kHttps) {
77     url_scheme = "https";
78   } else if (onc_scheme == ::onc::proxy::kSocks) {
79     default_proxy_scheme = net::ProxyServer::SCHEME_SOCKS4;
80     url_scheme = "socks";
81   } else {
82     NOTREACHED();
83   }
84
85   net::ProxyServer proxy_server = ConvertOncProxyLocationToHostPort(
86       default_proxy_scheme, *onc_proxy_location);
87
88   UIProxyConfig::EncodeAndAppendProxyServer(url_scheme, proxy_server, spec);
89 }
90
91 net::ProxyBypassRules ConvertOncExcludeDomainsToBypassRules(
92     const base::ListValue& onc_exclude_domains) {
93   net::ProxyBypassRules rules;
94   for (base::ListValue::const_iterator it = onc_exclude_domains.begin();
95        it != onc_exclude_domains.end(); ++it) {
96     std::string rule;
97     (*it)->GetAsString(&rule);
98     rules.AddRuleFromString(rule);
99   }
100   return rules;
101 }
102
103 }  // namespace
104
105 scoped_ptr<base::DictionaryValue> ConvertOncProxySettingsToProxyConfig(
106     const base::DictionaryValue& onc_proxy_settings) {
107   std::string type;
108   onc_proxy_settings.GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
109   scoped_ptr<DictionaryValue> proxy_dict;
110
111   if (type == ::onc::proxy::kDirect) {
112     proxy_dict.reset(ProxyConfigDictionary::CreateDirect());
113   } else if (type == ::onc::proxy::kWPAD) {
114     proxy_dict.reset(ProxyConfigDictionary::CreateAutoDetect());
115   } else if (type == ::onc::proxy::kPAC) {
116     std::string pac_url;
117     onc_proxy_settings.GetStringWithoutPathExpansion(::onc::proxy::kPAC,
118                                                      &pac_url);
119     GURL url(pac_url);
120     DCHECK(url.is_valid())
121         << "PAC field is invalid for this ProxySettings.Type";
122     proxy_dict.reset(ProxyConfigDictionary::CreatePacScript(url.spec(),
123                                                             false));
124   } else if (type == ::onc::proxy::kManual) {
125     const base::DictionaryValue* manual_dict = NULL;
126     onc_proxy_settings.GetDictionaryWithoutPathExpansion(::onc::proxy::kManual,
127                                                          &manual_dict);
128     std::string manual_spec;
129     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kFtp, &manual_spec);
130     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kHttp, &manual_spec);
131     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kSocks,
132                                &manual_spec);
133     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kHttps,
134                                &manual_spec);
135
136     const base::ListValue* exclude_domains = NULL;
137     net::ProxyBypassRules bypass_rules;
138     if (onc_proxy_settings.GetListWithoutPathExpansion(
139             ::onc::proxy::kExcludeDomains, &exclude_domains)) {
140       bypass_rules.AssignFrom(
141           ConvertOncExcludeDomainsToBypassRules(*exclude_domains));
142     }
143     proxy_dict.reset(ProxyConfigDictionary::CreateFixedServers(
144         manual_spec, bypass_rules.ToString()));
145   } else {
146     NOTREACHED();
147   }
148   return proxy_dict.Pass();
149 }
150
151 namespace {
152
153 // This class defines which string placeholders of ONC are replaced by which
154 // user attribute.
155 class UserStringSubstitution : public chromeos::onc::StringSubstitution {
156  public:
157   explicit UserStringSubstitution(const chromeos::User* user) : user_(user) {}
158   virtual ~UserStringSubstitution() {}
159
160   virtual bool GetSubstitute(const std::string& placeholder,
161                              std::string* substitute) const OVERRIDE {
162     if (placeholder == ::onc::substitutes::kLoginIDField)
163       *substitute = user_->GetAccountName(false);
164     else if (placeholder == ::onc::substitutes::kEmailField)
165       *substitute = user_->email();
166     else
167       return false;
168     return true;
169   }
170
171  private:
172   const chromeos::User* user_;
173
174   DISALLOW_COPY_AND_ASSIGN(UserStringSubstitution);
175 };
176
177 }  // namespace
178
179 void ExpandStringPlaceholdersInNetworksForUser(
180     const chromeos::User* user,
181     base::ListValue* network_configs) {
182   if (!user) {
183     // In tests no user may be logged in. It's not harmful if we just don't
184     // expand the strings.
185     return;
186   }
187   UserStringSubstitution substitution(user);
188   chromeos::onc::ExpandStringsInNetworks(substitution, network_configs);
189 }
190
191 void ImportNetworksForUser(const chromeos::User* user,
192                            const base::ListValue& network_configs,
193                            std::string* error) {
194   error->clear();
195
196   scoped_ptr<base::ListValue> expanded_networks(network_configs.DeepCopy());
197   ExpandStringPlaceholdersInNetworksForUser(user, expanded_networks.get());
198
199   const NetworkProfile* profile =
200       NetworkHandler::Get()->network_profile_handler()->GetProfileForUserhash(
201           user->username_hash());
202   if (!profile) {
203     *error = "User profile doesn't exist.";
204     return;
205   }
206
207   bool ethernet_not_found = false;
208   for (base::ListValue::const_iterator it = expanded_networks->begin();
209        it != expanded_networks->end();
210        ++it) {
211     const base::DictionaryValue* network = NULL;
212     (*it)->GetAsDictionary(&network);
213     DCHECK(network);
214
215     // Remove irrelevant fields.
216     onc::Normalizer normalizer(true /* remove recommended fields */);
217     scoped_ptr<base::DictionaryValue> normalized_network =
218         normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
219                                    *network);
220
221     scoped_ptr<base::DictionaryValue> shill_dict =
222         onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
223                                        *normalized_network);
224
225     scoped_ptr<NetworkUIData> ui_data = NetworkUIData::CreateFromONC(
226         ::onc::ONC_SOURCE_USER_IMPORT, *normalized_network);
227     base::DictionaryValue ui_data_dict;
228     ui_data->FillDictionary(&ui_data_dict);
229     std::string ui_data_json;
230     base::JSONWriter::Write(&ui_data_dict, &ui_data_json);
231     shill_dict->SetStringWithoutPathExpansion(shill::kUIDataProperty,
232                                               ui_data_json);
233
234     shill_dict->SetStringWithoutPathExpansion(shill::kProfileProperty,
235                                               profile->path);
236
237     std::string type;
238     shill_dict->GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
239     NetworkConfigurationHandler* config_handler =
240         NetworkHandler::Get()->network_configuration_handler();
241     if (NetworkTypePattern::Ethernet().MatchesType(type)) {
242       // Ethernet has to be configured using an existing Ethernet service.
243       const NetworkState* ethernet =
244           NetworkHandler::Get()->network_state_handler()->FirstNetworkByType(
245               NetworkTypePattern::Ethernet());
246       if (ethernet) {
247         config_handler->SetProperties(ethernet->path(),
248                                       *shill_dict,
249                                       base::Closure(),
250                                       network_handler::ErrorCallback());
251       } else {
252         ethernet_not_found = true;
253       }
254
255     } else {
256       config_handler->CreateConfiguration(
257           *shill_dict,
258           network_handler::StringResultCallback(),
259           network_handler::ErrorCallback());
260     }
261   }
262
263   if (ethernet_not_found)
264     *error = "No Ethernet available to configure.";
265 }
266
267 const base::DictionaryValue* FindPolicyForActiveUser(
268     const std::string& guid,
269     ::onc::ONCSource* onc_source) {
270   const User* user = UserManager::Get()->GetActiveUser();
271   std::string username_hash = user ? user->username_hash() : std::string();
272   return NetworkHandler::Get()->managed_network_configuration_handler()->
273       FindPolicyByGUID(username_hash, guid, onc_source);
274 }
275
276 const base::DictionaryValue* GetGlobalConfigFromPolicy(bool for_active_user) {
277   std::string username_hash;
278   if (for_active_user) {
279     const User* user = UserManager::Get()->GetActiveUser();
280     if (!user) {
281       LOG(ERROR) << "No user logged in yet.";
282       return NULL;
283     }
284     username_hash = user->username_hash();
285   }
286   return NetworkHandler::Get()->managed_network_configuration_handler()->
287       GetGlobalConfigFromPolicy(username_hash);
288 }
289
290 bool PolicyAllowsOnlyPolicyNetworksToAutoconnect(bool for_active_user) {
291   const base::DictionaryValue* global_config =
292       GetGlobalConfigFromPolicy(for_active_user);
293   if (!global_config)
294     return false;  // By default, all networks are allowed to autoconnect.
295
296   bool only_policy_autoconnect = false;
297   global_config->GetBooleanWithoutPathExpansion(
298       ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
299       &only_policy_autoconnect);
300   return only_policy_autoconnect;
301 }
302
303 namespace {
304
305 const base::DictionaryValue* GetNetworkConfigByGUID(
306     const base::ListValue& network_configs,
307     const std::string& guid) {
308   for (base::ListValue::const_iterator it = network_configs.begin();
309        it != network_configs.end(); ++it) {
310     const base::DictionaryValue* network = NULL;
311     (*it)->GetAsDictionary(&network);
312     DCHECK(network);
313
314     std::string current_guid;
315     network->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
316                                            &current_guid);
317     if (current_guid == guid)
318       return network;
319   }
320   return NULL;
321 }
322
323 const base::DictionaryValue* GetNetworkConfigForEthernetWithoutEAP(
324     const base::ListValue& network_configs) {
325   VLOG(2) << "Search for ethernet policy without EAP.";
326   for (base::ListValue::const_iterator it = network_configs.begin();
327        it != network_configs.end(); ++it) {
328     const base::DictionaryValue* network = NULL;
329     (*it)->GetAsDictionary(&network);
330     DCHECK(network);
331
332     std::string type;
333     network->GetStringWithoutPathExpansion(::onc::network_config::kType, &type);
334     if (type != ::onc::network_type::kEthernet)
335       continue;
336
337     const base::DictionaryValue* ethernet = NULL;
338     network->GetDictionaryWithoutPathExpansion(::onc::network_config::kEthernet,
339                                                &ethernet);
340
341     std::string auth;
342     ethernet->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
343                                             &auth);
344     if (auth == ::onc::ethernet::kNone)
345       return network;
346   }
347   return NULL;
348 }
349
350 const base::DictionaryValue* GetNetworkConfigForNetworkFromOnc(
351     const base::ListValue& network_configs,
352     const FavoriteState& favorite) {
353   // In all cases except Ethernet, we use the GUID of |network|.
354   if (!favorite.Matches(NetworkTypePattern::Ethernet()))
355     return GetNetworkConfigByGUID(network_configs, favorite.guid());
356
357   // Ethernet is always shared and thus cannot store a GUID per user. Thus we
358   // search for any Ethernet policy intead of a matching GUID.
359   // EthernetEAP service contains only the EAP parameters and stores the GUID of
360   // the respective ONC policy. The EthernetEAP service itself is however never
361   // in state "connected". An EthernetEAP policy must be applied, if an Ethernet
362   // service is connected using the EAP parameters.
363   const FavoriteState* ethernet_eap = NULL;
364   if (NetworkHandler::IsInitialized()) {
365     ethernet_eap =
366         NetworkHandler::Get()->network_state_handler()->GetEAPForEthernet(
367             favorite.path());
368   }
369
370   // The GUID associated with the EthernetEAP service refers to the ONC policy
371   // with "Authentication: 8021X".
372   if (ethernet_eap)
373     return GetNetworkConfigByGUID(network_configs, ethernet_eap->guid());
374
375   // Otherwise, EAP is not used and instead the Ethernet policy with
376   // "Authentication: None" applies.
377   return GetNetworkConfigForEthernetWithoutEAP(network_configs);
378 }
379
380 const base::DictionaryValue* GetPolicyForNetworkFromPref(
381     const PrefService* pref_service,
382     const char* pref_name,
383     const FavoriteState& favorite) {
384   if (!pref_service) {
385     VLOG(2) << "No pref service";
386     return NULL;
387   }
388
389   const PrefService::Preference* preference =
390       pref_service->FindPreference(pref_name);
391   if (!preference) {
392     VLOG(2) << "No preference " << pref_name;
393     // The preference may not exist in tests.
394     return NULL;
395   }
396
397   // User prefs are not stored in this Preference yet but only the policy.
398   //
399   // The policy server incorrectly configures the OpenNetworkConfiguration user
400   // policy as Recommended. To work around that, we handle the Recommended and
401   // the Mandatory value in the same way.
402   // TODO(pneubeck): Remove this workaround, once the server is fixed. See
403   // http://crbug.com/280553 .
404   if (preference->IsDefaultValue()) {
405     VLOG(2) << "Preference has no recommended or mandatory value.";
406     // No policy set.
407     return NULL;
408   }
409   VLOG(2) << "Preference with policy found.";
410   const base::Value* onc_policy_value = preference->GetValue();
411   DCHECK(onc_policy_value);
412
413   const base::ListValue* onc_policy = NULL;
414   onc_policy_value->GetAsList(&onc_policy);
415   DCHECK(onc_policy);
416
417   return GetNetworkConfigForNetworkFromOnc(*onc_policy, favorite);
418 }
419
420 }  // namespace
421
422 const base::DictionaryValue* GetPolicyForFavoriteNetwork(
423     const PrefService* profile_prefs,
424     const PrefService* local_state_prefs,
425     const FavoriteState& favorite,
426     ::onc::ONCSource* onc_source) {
427   VLOG(2) << "GetPolicyForFavoriteNetwork: " << favorite.path();
428   *onc_source = ::onc::ONC_SOURCE_NONE;
429
430   const base::DictionaryValue* network_policy = GetPolicyForNetworkFromPref(
431       profile_prefs, prefs::kOpenNetworkConfiguration, favorite);
432   if (network_policy) {
433     VLOG(1) << "Network " << favorite.path() << " is managed by user policy.";
434     *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
435     return network_policy;
436   }
437   network_policy = GetPolicyForNetworkFromPref(
438       local_state_prefs, prefs::kDeviceOpenNetworkConfiguration, favorite);
439   if (network_policy) {
440     VLOG(1) << "Network " << favorite.path() << " is managed by device policy.";
441     *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
442     return network_policy;
443   }
444   VLOG(2) << "Network " << favorite.path() << " is unmanaged.";
445   return NULL;
446 }
447
448 bool HasPolicyForFavoriteNetwork(const PrefService* profile_prefs,
449                                  const PrefService* local_state_prefs,
450                                  const FavoriteState& network) {
451   ::onc::ONCSource ignored_onc_source;
452   const base::DictionaryValue* policy = onc::GetPolicyForFavoriteNetwork(
453       profile_prefs, local_state_prefs, network, &ignored_onc_source);
454   return policy != NULL;
455 }
456
457 }  // namespace onc
458 }  // namespace chromeos