proxy_config_handler.cc revision 3551c9c881056c480085172ff9840cab31610854
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
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/net/proxy_config_handler.h"
6
7#include "base/bind.h"
8#include "base/json/json_writer.h"
9#include "base/logging.h"
10#include "base/prefs/pref_registry_simple.h"
11#include "base/prefs/pref_service.h"
12#include "base/values.h"
13#include "chrome/browser/chromeos/net/onc_utils.h"
14#include "chrome/browser/prefs/proxy_config_dictionary.h"
15#include "chrome/common/pref_names.h"
16#include "chromeos/dbus/dbus_thread_manager.h"
17#include "chromeos/dbus/shill_service_client.h"
18#include "chromeos/network/network_handler_callbacks.h"
19#include "chromeos/network/network_profile.h"
20#include "chromeos/network/network_profile_handler.h"
21#include "chromeos/network/network_state.h"
22#include "chromeos/network/network_state_handler.h"
23#include "components/user_prefs/pref_registry_syncable.h"
24#include "dbus/object_path.h"
25#include "third_party/cros_system_api/dbus/service_constants.h"
26
27namespace chromeos {
28
29namespace {
30
31const base::DictionaryValue* GetNetworkConfigByGUID(
32    const base::ListValue& network_configs,
33    const std::string& guid) {
34  for (base::ListValue::const_iterator it = network_configs.begin();
35       it != network_configs.end();
36       ++it) {
37    const base::DictionaryValue* network = NULL;
38    (*it)->GetAsDictionary(&network);
39    std::string current_guid;
40    network->GetStringWithoutPathExpansion(onc::network_config::kGUID,
41                                           &current_guid);
42    if (current_guid == guid)
43      return network;
44  }
45  return NULL;
46}
47
48scoped_ptr<ProxyConfigDictionary> GetProxyPolicy(
49    const PrefService* pref_service,
50    const char* pref_name,
51    const NetworkState& network,
52    bool* network_is_managed) {
53  *network_is_managed = false;
54
55  if (!pref_service || network.guid().empty())
56    return scoped_ptr<ProxyConfigDictionary>();
57
58  if (!pref_service->IsManagedPreference(pref_name)) {
59    // No policy set.
60    return scoped_ptr<ProxyConfigDictionary>();
61  }
62
63  const base::ListValue* onc_policy = pref_service->GetList(pref_name);
64  if (!onc_policy) {
65    LOG(ERROR) << "Pref " << pref_name << " is managed, but no value is set.";
66    return scoped_ptr<ProxyConfigDictionary>();
67  }
68
69  const base::DictionaryValue* network_policy =
70      GetNetworkConfigByGUID(*onc_policy, network.guid());
71  if (!network_policy) {
72    // This network isn't managed by this policy.
73    return scoped_ptr<ProxyConfigDictionary>();
74  }
75
76  const base::DictionaryValue* proxy_policy = NULL;
77  network_policy->GetDictionaryWithoutPathExpansion(
78      onc::network_config::kProxySettings, &proxy_policy);
79  if (!proxy_policy) {
80    // This policy doesn't set a proxy for this network. Nonetheless, this
81    // disallows changes by the user.
82    *network_is_managed = true;
83    return scoped_ptr<ProxyConfigDictionary>();
84  }
85
86  scoped_ptr<base::DictionaryValue> proxy_dict =
87      onc::ConvertOncProxySettingsToProxyConfig(*proxy_policy);
88  *network_is_managed = true;
89  return make_scoped_ptr(new ProxyConfigDictionary(proxy_dict.get()));
90}
91
92void NotifyNetworkStateHandler(const std::string& service_path) {
93  if (NetworkHandler::IsInitialized()) {
94    NetworkHandler::Get()->network_state_handler()->RequestUpdateForNetwork(
95        service_path);
96  }
97}
98
99}  // namespace
100
101namespace proxy_config {
102
103scoped_ptr<ProxyConfigDictionary> GetProxyConfigForNetwork(
104    const PrefService* profile_prefs,
105    const PrefService* local_state_prefs,
106    const NetworkState& network,
107    onc::ONCSource* onc_source) {
108  VLOG(2) << "GetProxyConfigForNetwork network: " << network.path()
109          << " , guid: " << network.guid();
110  *onc_source = onc::ONC_SOURCE_NONE;
111  bool network_is_managed = false;
112
113  scoped_ptr<ProxyConfigDictionary> proxy_config =
114      GetProxyPolicy(profile_prefs,
115                     prefs::kOpenNetworkConfiguration,
116                     network,
117                     &network_is_managed);
118  if (network_is_managed) {
119    VLOG(1) << "Network " << network.path() << " is managed by user policy.";
120    *onc_source = onc::ONC_SOURCE_USER_POLICY;
121    return proxy_config.Pass();
122  }
123  proxy_config = GetProxyPolicy(local_state_prefs,
124                                prefs::kDeviceOpenNetworkConfiguration,
125                                network,
126                                &network_is_managed);
127  if (network_is_managed) {
128    VLOG(1) << "Network " << network.path() << " is managed by device policy.";
129    *onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
130    return proxy_config.Pass();
131  }
132
133  if (network.profile_path().empty())
134    return scoped_ptr<ProxyConfigDictionary>();
135
136  const NetworkProfile* profile = NetworkHandler::Get()
137      ->network_profile_handler()->GetProfileForPath(network.profile_path());
138  if (!profile) {
139    LOG(WARNING) << "Unknown profile_path '" << network.profile_path() << "'.";
140    return scoped_ptr<ProxyConfigDictionary>();
141  }
142  if (!profile_prefs && profile->type() == NetworkProfile::TYPE_USER) {
143    // This case occurs, for example, if called from the proxy config tracker
144    // created for the system request context and the signin screen. Both don't
145    // use profile prefs and shouldn't depend on the user's not shared proxy
146    // settings.
147    VLOG(1)
148        << "Don't use unshared settings for system context or signin screen.";
149    return scoped_ptr<ProxyConfigDictionary>();
150  }
151
152  // No policy set for this network, read instead the user's (shared or
153  // unshared) configuration.
154  const base::DictionaryValue& value = network.proxy_config();
155  if (value.empty())
156    return scoped_ptr<ProxyConfigDictionary>();
157  return make_scoped_ptr(new ProxyConfigDictionary(&value));
158}
159
160void SetProxyConfigForNetwork(const ProxyConfigDictionary& proxy_config,
161                              const NetworkState& network) {
162  chromeos::ShillServiceClient* shill_service_client =
163      DBusThreadManager::Get()->GetShillServiceClient();
164
165  ProxyPrefs::ProxyMode mode;
166  if (!proxy_config.GetMode(&mode) || mode == ProxyPrefs::MODE_DIRECT) {
167    // Return empty string for direct mode for portal check to work correctly.
168    // TODO(pneubeck): Consider removing this legacy code.
169    shill_service_client->ClearProperty(
170        dbus::ObjectPath(network.path()),
171        flimflam::kProxyConfigProperty,
172        base::Bind(&NotifyNetworkStateHandler, network.path()),
173        base::Bind(&network_handler::ShillErrorCallbackFunction,
174                   "SetProxyConfig.ClearProperty Failed",
175                   network.path(),
176                   network_handler::ErrorCallback()));
177  } else {
178    std::string proxy_config_str;
179    base::JSONWriter::Write(&proxy_config.GetDictionary(), &proxy_config_str);
180    shill_service_client->SetProperty(
181        dbus::ObjectPath(network.path()),
182        flimflam::kProxyConfigProperty,
183        base::StringValue(proxy_config_str),
184        base::Bind(&NotifyNetworkStateHandler, network.path()),
185        base::Bind(&network_handler::ShillErrorCallbackFunction,
186                   "SetProxyConfig.SetProperty Failed",
187                   network.path(),
188                   network_handler::ErrorCallback()));
189  }
190}
191
192void RegisterPrefs(PrefRegistrySimple* registry) {
193  registry->RegisterListPref(prefs::kDeviceOpenNetworkConfiguration);
194}
195
196void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
197  registry->RegisterBooleanPref(
198      prefs::kUseSharedProxies,
199      false,
200      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
201
202  registry->RegisterListPref(prefs::kOpenNetworkConfiguration,
203                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
204}
205
206}  // namespace proxy_config
207
208}  // namespace chromeos
209