Update To 11.40.268.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/ui_proxy_config.h"
13 #include "chrome/browser/prefs/proxy_config_dictionary.h"
14 #include "chrome/common/pref_names.h"
15 #include "chromeos/network/managed_network_configuration_handler.h"
16 #include "chromeos/network/network_configuration_handler.h"
17 #include "chromeos/network/network_handler.h"
18 #include "chromeos/network/network_profile.h"
19 #include "chromeos/network/network_profile_handler.h"
20 #include "chromeos/network/network_state.h"
21 #include "chromeos/network/network_state_handler.h"
22 #include "chromeos/network/network_ui_data.h"
23 #include "chromeos/network/onc/onc_normalizer.h"
24 #include "chromeos/network/onc/onc_signature.h"
25 #include "chromeos/network/onc/onc_translator.h"
26 #include "chromeos/network/onc/onc_utils.h"
27 #include "components/user_manager/user.h"
28 #include "components/user_manager/user_manager.h"
29 #include "net/base/host_port_pair.h"
30 #include "net/proxy/proxy_bypass_rules.h"
31 #include "net/proxy/proxy_server.h"
32 #include "third_party/cros_system_api/dbus/service_constants.h"
33 #include "url/gurl.h"
34
35 namespace chromeos {
36 namespace onc {
37
38 namespace {
39
40 net::ProxyServer ConvertOncProxyLocationToHostPort(
41     net::ProxyServer::Scheme default_proxy_scheme,
42     const base::DictionaryValue& onc_proxy_location) {
43   std::string host;
44   onc_proxy_location.GetStringWithoutPathExpansion(::onc::proxy::kHost, &host);
45   // Parse |host| according to the format [<scheme>"://"]<server>[":"<port>].
46   net::ProxyServer proxy_server =
47       net::ProxyServer::FromURI(host, default_proxy_scheme);
48   int port = 0;
49   onc_proxy_location.GetIntegerWithoutPathExpansion(::onc::proxy::kPort, &port);
50
51   // Replace the port parsed from |host| by the provided |port|.
52   return net::ProxyServer(
53       proxy_server.scheme(),
54       net::HostPortPair(proxy_server.host_port_pair().host(),
55                         static_cast<uint16>(port)));
56 }
57
58 void AppendProxyServerForScheme(
59     const base::DictionaryValue& onc_manual,
60     const std::string& onc_scheme,
61     std::string* spec) {
62   const base::DictionaryValue* onc_proxy_location = NULL;
63   if (!onc_manual.GetDictionaryWithoutPathExpansion(onc_scheme,
64                                                     &onc_proxy_location)) {
65     return;
66   }
67
68   net::ProxyServer::Scheme default_proxy_scheme = net::ProxyServer::SCHEME_HTTP;
69   std::string url_scheme;
70   if (onc_scheme == ::onc::proxy::kFtp) {
71     url_scheme = "ftp";
72   } else if (onc_scheme == ::onc::proxy::kHttp) {
73     url_scheme = "http";
74   } else if (onc_scheme == ::onc::proxy::kHttps) {
75     url_scheme = "https";
76   } else if (onc_scheme == ::onc::proxy::kSocks) {
77     default_proxy_scheme = net::ProxyServer::SCHEME_SOCKS4;
78     url_scheme = "socks";
79   } else {
80     NOTREACHED();
81   }
82
83   net::ProxyServer proxy_server = ConvertOncProxyLocationToHostPort(
84       default_proxy_scheme, *onc_proxy_location);
85
86   UIProxyConfig::EncodeAndAppendProxyServer(url_scheme, proxy_server, spec);
87 }
88
89 net::ProxyBypassRules ConvertOncExcludeDomainsToBypassRules(
90     const base::ListValue& onc_exclude_domains) {
91   net::ProxyBypassRules rules;
92   for (base::ListValue::const_iterator it = onc_exclude_domains.begin();
93        it != onc_exclude_domains.end(); ++it) {
94     std::string rule;
95     (*it)->GetAsString(&rule);
96     rules.AddRuleFromString(rule);
97   }
98   return rules;
99 }
100
101 }  // namespace
102
103 scoped_ptr<base::DictionaryValue> ConvertOncProxySettingsToProxyConfig(
104     const base::DictionaryValue& onc_proxy_settings) {
105   std::string type;
106   onc_proxy_settings.GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
107   scoped_ptr<base::DictionaryValue> proxy_dict;
108
109   if (type == ::onc::proxy::kDirect) {
110     proxy_dict.reset(ProxyConfigDictionary::CreateDirect());
111   } else if (type == ::onc::proxy::kWPAD) {
112     proxy_dict.reset(ProxyConfigDictionary::CreateAutoDetect());
113   } else if (type == ::onc::proxy::kPAC) {
114     std::string pac_url;
115     onc_proxy_settings.GetStringWithoutPathExpansion(::onc::proxy::kPAC,
116                                                      &pac_url);
117     GURL url(pac_url);
118     DCHECK(url.is_valid())
119         << "PAC field is invalid for this ProxySettings.Type";
120     proxy_dict.reset(ProxyConfigDictionary::CreatePacScript(url.spec(),
121                                                             false));
122   } else if (type == ::onc::proxy::kManual) {
123     const base::DictionaryValue* manual_dict = NULL;
124     onc_proxy_settings.GetDictionaryWithoutPathExpansion(::onc::proxy::kManual,
125                                                          &manual_dict);
126     std::string manual_spec;
127     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kFtp, &manual_spec);
128     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kHttp, &manual_spec);
129     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kSocks,
130                                &manual_spec);
131     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kHttps,
132                                &manual_spec);
133
134     const base::ListValue* exclude_domains = NULL;
135     net::ProxyBypassRules bypass_rules;
136     if (onc_proxy_settings.GetListWithoutPathExpansion(
137             ::onc::proxy::kExcludeDomains, &exclude_domains)) {
138       bypass_rules.AssignFrom(
139           ConvertOncExcludeDomainsToBypassRules(*exclude_domains));
140     }
141     proxy_dict.reset(ProxyConfigDictionary::CreateFixedServers(
142         manual_spec, bypass_rules.ToString()));
143   } else {
144     NOTREACHED();
145   }
146   return proxy_dict.Pass();
147 }
148
149 namespace {
150
151 // This class defines which string placeholders of ONC are replaced by which
152 // user attribute.
153 class UserStringSubstitution : public chromeos::onc::StringSubstitution {
154  public:
155   explicit UserStringSubstitution(const user_manager::User* user)
156       : 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 user_manager::User* user_;
172
173   DISALLOW_COPY_AND_ASSIGN(UserStringSubstitution);
174 };
175
176 }  // namespace
177
178 void ExpandStringPlaceholdersInNetworksForUser(
179     const user_manager::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 user_manager::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(
225         NetworkUIData::CreateFromONC(::onc::ONC_SOURCE_USER_IMPORT));
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_manager::User* user =
270       user_manager::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_manager::User* user =
280         user_manager::UserManager::Get()->GetActiveUser();
281     if (!user) {
282       LOG(ERROR) << "No user logged in yet.";
283       return NULL;
284     }
285     username_hash = user->username_hash();
286   }
287   return NetworkHandler::Get()->managed_network_configuration_handler()->
288       GetGlobalConfigFromPolicy(username_hash);
289 }
290
291 bool PolicyAllowsOnlyPolicyNetworksToAutoconnect(bool for_active_user) {
292   const base::DictionaryValue* global_config =
293       GetGlobalConfigFromPolicy(for_active_user);
294   if (!global_config)
295     return false;  // By default, all networks are allowed to autoconnect.
296
297   bool only_policy_autoconnect = false;
298   global_config->GetBooleanWithoutPathExpansion(
299       ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
300       &only_policy_autoconnect);
301   return only_policy_autoconnect;
302 }
303
304 namespace {
305
306 const base::DictionaryValue* GetNetworkConfigByGUID(
307     const base::ListValue& network_configs,
308     const std::string& guid) {
309   for (base::ListValue::const_iterator it = network_configs.begin();
310        it != network_configs.end(); ++it) {
311     const base::DictionaryValue* network = NULL;
312     (*it)->GetAsDictionary(&network);
313     DCHECK(network);
314
315     std::string current_guid;
316     network->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
317                                            &current_guid);
318     if (current_guid == guid)
319       return network;
320   }
321   return NULL;
322 }
323
324 const base::DictionaryValue* GetNetworkConfigForEthernetWithoutEAP(
325     const base::ListValue& network_configs) {
326   VLOG(2) << "Search for ethernet policy without EAP.";
327   for (base::ListValue::const_iterator it = network_configs.begin();
328        it != network_configs.end(); ++it) {
329     const base::DictionaryValue* network = NULL;
330     (*it)->GetAsDictionary(&network);
331     DCHECK(network);
332
333     std::string type;
334     network->GetStringWithoutPathExpansion(::onc::network_config::kType, &type);
335     if (type != ::onc::network_type::kEthernet)
336       continue;
337
338     const base::DictionaryValue* ethernet = NULL;
339     network->GetDictionaryWithoutPathExpansion(::onc::network_config::kEthernet,
340                                                &ethernet);
341
342     std::string auth;
343     ethernet->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
344                                             &auth);
345     if (auth == ::onc::ethernet::kAuthenticationNone)
346       return network;
347   }
348   return NULL;
349 }
350
351 const base::DictionaryValue* GetNetworkConfigForNetworkFromOnc(
352     const base::ListValue& network_configs,
353     const NetworkState& network) {
354   // In all cases except Ethernet, we use the GUID of |network|.
355   if (!network.Matches(NetworkTypePattern::Ethernet()))
356     return GetNetworkConfigByGUID(network_configs, network.guid());
357
358   // Ethernet is always shared and thus cannot store a GUID per user. Thus we
359   // search for any Ethernet policy intead of a matching GUID.
360   // EthernetEAP service contains only the EAP parameters and stores the GUID of
361   // the respective ONC policy. The EthernetEAP service itself is however never
362   // in state "connected". An EthernetEAP policy must be applied, if an Ethernet
363   // service is connected using the EAP parameters.
364   const NetworkState* ethernet_eap = NULL;
365   if (NetworkHandler::IsInitialized()) {
366     ethernet_eap =
367         NetworkHandler::Get()->network_state_handler()->GetEAPForEthernet(
368             network.path());
369   }
370
371   // The GUID associated with the EthernetEAP service refers to the ONC policy
372   // with "Authentication: 8021X".
373   if (ethernet_eap)
374     return GetNetworkConfigByGUID(network_configs, ethernet_eap->guid());
375
376   // Otherwise, EAP is not used and instead the Ethernet policy with
377   // "Authentication: None" applies.
378   return GetNetworkConfigForEthernetWithoutEAP(network_configs);
379 }
380
381 const base::DictionaryValue* GetPolicyForNetworkFromPref(
382     const PrefService* pref_service,
383     const char* pref_name,
384     const NetworkState& network) {
385   if (!pref_service) {
386     VLOG(2) << "No pref service";
387     return NULL;
388   }
389
390   const PrefService::Preference* preference =
391       pref_service->FindPreference(pref_name);
392   if (!preference) {
393     VLOG(2) << "No preference " << pref_name;
394     // The preference may not exist in tests.
395     return NULL;
396   }
397
398   // User prefs are not stored in this Preference yet but only the policy.
399   //
400   // The policy server incorrectly configures the OpenNetworkConfiguration user
401   // policy as Recommended. To work around that, we handle the Recommended and
402   // the Mandatory value in the same way.
403   // TODO(pneubeck): Remove this workaround, once the server is fixed. See
404   // http://crbug.com/280553 .
405   if (preference->IsDefaultValue()) {
406     VLOG(2) << "Preference has no recommended or mandatory value.";
407     // No policy set.
408     return NULL;
409   }
410   VLOG(2) << "Preference with policy found.";
411   const base::Value* onc_policy_value = preference->GetValue();
412   DCHECK(onc_policy_value);
413
414   const base::ListValue* onc_policy = NULL;
415   onc_policy_value->GetAsList(&onc_policy);
416   DCHECK(onc_policy);
417
418   return GetNetworkConfigForNetworkFromOnc(*onc_policy, network);
419 }
420
421 }  // namespace
422
423 const base::DictionaryValue* GetPolicyForNetwork(
424     const PrefService* profile_prefs,
425     const PrefService* local_state_prefs,
426     const NetworkState& network,
427     ::onc::ONCSource* onc_source) {
428   VLOG(2) << "GetPolicyForNetwork: " << network.path();
429   *onc_source = ::onc::ONC_SOURCE_NONE;
430
431   const base::DictionaryValue* network_policy = GetPolicyForNetworkFromPref(
432       profile_prefs, prefs::kOpenNetworkConfiguration, network);
433   if (network_policy) {
434     VLOG(1) << "Network " << network.path() << " is managed by user policy.";
435     *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
436     return network_policy;
437   }
438   network_policy = GetPolicyForNetworkFromPref(
439       local_state_prefs, prefs::kDeviceOpenNetworkConfiguration, network);
440   if (network_policy) {
441     VLOG(1) << "Network " << network.path() << " is managed by device policy.";
442     *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
443     return network_policy;
444   }
445   VLOG(2) << "Network " << network.path() << " is unmanaged.";
446   return NULL;
447 }
448
449 bool HasPolicyForNetwork(const PrefService* profile_prefs,
450                          const PrefService* local_state_prefs,
451                          const NetworkState& network) {
452   ::onc::ONCSource ignored_onc_source;
453   const base::DictionaryValue* policy = onc::GetPolicyForNetwork(
454       profile_prefs, local_state_prefs, network, &ignored_onc_source);
455   return policy != NULL;
456 }
457
458 }  // namespace onc
459 }  // namespace chromeos