onc_utils.cc revision 3551c9c881056c480085172ff9840cab31610854
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/values.h"
11#include "chrome/browser/chromeos/login/user.h"
12#include "chrome/browser/chromeos/login/user_manager.h"
13#include "chrome/browser/chromeos/ui_proxy_config.h"
14#include "chrome/browser/prefs/proxy_config_dictionary.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_ui_data.h"
21#include "chromeos/network/onc/onc_normalizer.h"
22#include "chromeos/network/onc/onc_signature.h"
23#include "chromeos/network/onc/onc_translator.h"
24#include "chromeos/network/onc/onc_utils.h"
25#include "net/base/host_port_pair.h"
26#include "net/proxy/proxy_bypass_rules.h"
27#include "net/proxy/proxy_server.h"
28#include "third_party/cros_system_api/dbus/service_constants.h"
29#include "url/gurl.h"
30
31namespace chromeos {
32namespace onc {
33
34namespace {
35
36net::ProxyServer ConvertOncProxyLocationToHostPort(
37    net::ProxyServer::Scheme default_proxy_scheme,
38    const base::DictionaryValue& onc_proxy_location) {
39  std::string host;
40  onc_proxy_location.GetStringWithoutPathExpansion(onc::proxy::kHost, &host);
41  // Parse |host| according to the format [<scheme>"://"]<server>[":"<port>].
42  net::ProxyServer proxy_server =
43      net::ProxyServer::FromURI(host, default_proxy_scheme);
44  int port = 0;
45  onc_proxy_location.GetIntegerWithoutPathExpansion(onc::proxy::kPort, &port);
46
47  // Replace the port parsed from |host| by the provided |port|.
48  return net::ProxyServer(
49      proxy_server.scheme(),
50      net::HostPortPair(proxy_server.host_port_pair().host(),
51                        static_cast<uint16>(port)));
52}
53
54void AppendProxyServerForScheme(
55    const base::DictionaryValue& onc_manual,
56    const std::string& onc_scheme,
57    std::string* spec) {
58  const base::DictionaryValue* onc_proxy_location = NULL;
59  if (!onc_manual.GetDictionaryWithoutPathExpansion(onc_scheme,
60                                                    &onc_proxy_location)) {
61    return;
62  }
63
64  net::ProxyServer::Scheme default_proxy_scheme = net::ProxyServer::SCHEME_HTTP;
65  std::string url_scheme;
66  if (onc_scheme == proxy::kFtp) {
67    url_scheme = "ftp";
68  } else if (onc_scheme == proxy::kHttp) {
69    url_scheme = "http";
70  } else if (onc_scheme == proxy::kHttps) {
71    url_scheme = "https";
72  } else if (onc_scheme == proxy::kSocks) {
73    default_proxy_scheme = net::ProxyServer::SCHEME_SOCKS4;
74    url_scheme = "socks";
75  } else {
76    NOTREACHED();
77  }
78
79  net::ProxyServer proxy_server = ConvertOncProxyLocationToHostPort(
80      default_proxy_scheme, *onc_proxy_location);
81
82  UIProxyConfig::EncodeAndAppendProxyServer(url_scheme, proxy_server, spec);
83}
84
85net::ProxyBypassRules ConvertOncExcludeDomainsToBypassRules(
86    const base::ListValue& onc_exclude_domains) {
87  net::ProxyBypassRules rules;
88  for (base::ListValue::const_iterator it = onc_exclude_domains.begin();
89       it != onc_exclude_domains.end(); ++it) {
90    std::string rule;
91    (*it)->GetAsString(&rule);
92    rules.AddRuleFromString(rule);
93  }
94  return rules;
95}
96
97}  // namespace
98
99scoped_ptr<base::DictionaryValue> ConvertOncProxySettingsToProxyConfig(
100    const base::DictionaryValue& onc_proxy_settings) {
101  std::string type;
102  onc_proxy_settings.GetStringWithoutPathExpansion(proxy::kType, &type);
103  scoped_ptr<DictionaryValue> proxy_dict;
104
105  if (type == proxy::kDirect) {
106    proxy_dict.reset(ProxyConfigDictionary::CreateDirect());
107  } else if (type == proxy::kWPAD) {
108    proxy_dict.reset(ProxyConfigDictionary::CreateAutoDetect());
109  } else if (type == proxy::kPAC) {
110    std::string pac_url;
111    onc_proxy_settings.GetStringWithoutPathExpansion(proxy::kPAC, &pac_url);
112    GURL url(pac_url);
113    DCHECK(url.is_valid())
114        << "PAC field is invalid for this ProxySettings.Type";
115    proxy_dict.reset(ProxyConfigDictionary::CreatePacScript(url.spec(),
116                                                            false));
117  } else if (type == proxy::kManual) {
118    const base::DictionaryValue* manual_dict = NULL;
119    onc_proxy_settings.GetDictionaryWithoutPathExpansion(proxy::kManual,
120                                                         &manual_dict);
121    std::string manual_spec;
122    AppendProxyServerForScheme(*manual_dict, proxy::kFtp, &manual_spec);
123    AppendProxyServerForScheme(*manual_dict, proxy::kHttp, &manual_spec);
124    AppendProxyServerForScheme(*manual_dict, proxy::kSocks, &manual_spec);
125    AppendProxyServerForScheme(*manual_dict, proxy::kHttps, &manual_spec);
126
127    const base::ListValue* exclude_domains = NULL;
128    net::ProxyBypassRules bypass_rules;
129    if (onc_proxy_settings.GetListWithoutPathExpansion(proxy::kExcludeDomains,
130                                                       &exclude_domains)) {
131      bypass_rules.AssignFrom(
132          ConvertOncExcludeDomainsToBypassRules(*exclude_domains));
133    }
134    proxy_dict.reset(ProxyConfigDictionary::CreateFixedServers(
135        manual_spec, bypass_rules.ToString()));
136  } else {
137    NOTREACHED();
138  }
139  return proxy_dict.Pass();
140}
141
142namespace {
143
144// This class defines which string placeholders of ONC are replaced by which
145// user attribute.
146class UserStringSubstitution : public chromeos::onc::StringSubstitution {
147 public:
148  explicit UserStringSubstitution(const chromeos::User* user) : user_(user) {}
149  virtual ~UserStringSubstitution() {}
150
151  virtual bool GetSubstitute(const std::string& placeholder,
152                             std::string* substitute) const OVERRIDE {
153    if (placeholder == chromeos::onc::substitutes::kLoginIDField)
154      *substitute = user_->GetAccountName(false);
155    else if (placeholder == chromeos::onc::substitutes::kEmailField)
156      *substitute = user_->email();
157    else
158      return false;
159    return true;
160  }
161
162 private:
163  const chromeos::User* user_;
164
165  DISALLOW_COPY_AND_ASSIGN(UserStringSubstitution);
166};
167
168}  // namespace
169
170void ExpandStringPlaceholdersInNetworksForUser(
171    const chromeos::User* user,
172    base::ListValue* network_configs) {
173  if (!user) {
174    // In tests no user may be logged in. It's not harmful if we just don't
175    // expand the strings.
176    return;
177  }
178  UserStringSubstitution substitution(user);
179  chromeos::onc::ExpandStringsInNetworks(substitution, network_configs);
180}
181
182void ImportNetworksForUser(const chromeos::User* user,
183                           const base::ListValue& network_configs,
184                           std::string* error) {
185  error->clear();
186
187  scoped_ptr<base::ListValue> expanded_networks(network_configs.DeepCopy());
188  ExpandStringPlaceholdersInNetworksForUser(user, expanded_networks.get());
189
190  const NetworkProfile* profile =
191      NetworkHandler::Get()->network_profile_handler()->GetProfileForUserhash(
192          user->username_hash());
193  if (!profile) {
194    *error = "User profile doesn't exist.";
195    return;
196  }
197
198  for (base::ListValue::const_iterator it = expanded_networks->begin();
199       it != expanded_networks->end();
200       ++it) {
201    const base::DictionaryValue* network = NULL;
202    (*it)->GetAsDictionary(&network);
203    DCHECK(network);
204
205    // Remove irrelevant fields.
206    onc::Normalizer normalizer(true /* remove recommended fields */);
207    scoped_ptr<base::DictionaryValue> normalized_network =
208        normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
209                                   *network);
210
211    scoped_ptr<base::DictionaryValue> shill_dict =
212        onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
213                                       *normalized_network);
214
215    scoped_ptr<NetworkUIData> ui_data = NetworkUIData::CreateFromONC(
216        onc::ONC_SOURCE_USER_IMPORT, *normalized_network);
217    base::DictionaryValue ui_data_dict;
218    ui_data->FillDictionary(&ui_data_dict);
219    std::string ui_data_json;
220    base::JSONWriter::Write(&ui_data_dict, &ui_data_json);
221    shill_dict->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
222                                              ui_data_json);
223
224    shill_dict->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
225                                              profile->path);
226
227    NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration(
228        *shill_dict,
229        network_handler::StringResultCallback(),
230        network_handler::ErrorCallback());
231  }
232}
233
234const base::DictionaryValue* FindPolicyForActiveUser(
235    const std::string& guid,
236    onc::ONCSource* onc_source) {
237  const User* user = UserManager::Get()->GetActiveUser();
238  std::string username_hash = user ? user->username_hash() : std::string();
239  return NetworkHandler::Get()->managed_network_configuration_handler()->
240      FindPolicyByGUID(username_hash, guid, onc_source);
241}
242
243}  // namespace onc
244}  // namespace chromeos
245