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