summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-19 20:35:07 +0000
committerpneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-19 20:35:07 +0000
commit79affb7effb751deed7336a1828de3cdc1fdde04 (patch)
tree8cf54f6061fd99dd1d4d43f491ea3f3164965613
parenteda0a0b16697dab1fc2d45d6cfe38652044b88d5 (diff)
downloadchromium_src-79affb7effb751deed7336a1828de3cdc1fdde04.zip
chromium_src-79affb7effb751deed7336a1828de3cdc1fdde04.tar.gz
chromium_src-79affb7effb751deed7336a1828de3cdc1fdde04.tar.bz2
Adding policy support to the new network configuration stack.
Adapts in particular the ManagedNetworkConfigurationHandler, the networkingPrivate extension API and the network configuration extension. BUG=223869 TBR=thestig@chromium.org (for chrome_browser_chromeos.gypi) Review URL: https://chromiumcodereview.appspot.com/12676017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195267 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.cc5
-rw-r--r--chrome/browser/chromeos/cros/network_library_impl_base.cc4
-rw-r--r--chrome/browser/chromeos/cros/network_library_unittest.cc3
-rw-r--r--chrome/browser/chromeos/extensions/networking_private_api.cc59
-rw-r--r--chrome/browser/chromeos/extensions/networking_private_api.h24
-rw-r--r--chrome/browser/chromeos/extensions/networking_private_apitest.cc80
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc15
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater.cc158
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater.h86
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater_impl.cc104
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater_impl.h62
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc176
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h91
-rw-r--r--chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc (renamed from chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc)15
-rw-r--r--chrome/browser/extensions/extension_function_histogram_value.h1
-rw-r--r--chrome/browser/policy/browser_policy_connector.cc28
-rw-r--r--chrome/browser/resources/chromeos/network_configuration/config.html4
-rw-r--r--chrome/browser/resources/chromeos/network_configuration/js/main_config.js30
-rw-r--r--chrome/browser/resources/chromeos/network_configuration/js/network_config.js98
-rw-r--r--chrome/browser/resources/chromeos/network_configuration/js/network_status.js10
-rw-r--r--chrome/chrome_browser_chromeos.gypi5
-rw-r--r--chrome/chrome_tests_unit.gypi2
-rw-r--r--chrome/common/extensions/api/networking_private.json27
-rw-r--r--chrome/test/data/extensions/api_test/networking/test.js77
-rw-r--r--chromeos/chromeos.gyp3
-rw-r--r--chromeos/dbus/mock_shill_manager_client.cc2
-rw-r--r--chromeos/dbus/mock_shill_manager_client.h5
-rw-r--r--chromeos/dbus/mock_shill_profile_client.h1
-rw-r--r--chromeos/dbus/shill_device_client.h2
-rw-r--r--chromeos/dbus/shill_manager_client.cc63
-rw-r--r--chromeos/dbus/shill_manager_client.h13
-rw-r--r--chromeos/dbus/shill_manager_client_stub.cc49
-rw-r--r--chromeos/dbus/shill_manager_client_stub.h5
-rw-r--r--chromeos/dbus/shill_profile_client.cc6
-rw-r--r--chromeos/dbus/shill_profile_client.h17
-rw-r--r--chromeos/dbus/shill_profile_client_stub.cc125
-rw-r--r--chromeos/dbus/shill_profile_client_stub.h20
-rw-r--r--chromeos/dbus/shill_service_client.h2
-rw-r--r--chromeos/dbus/shill_service_client_stub.cc47
-rw-r--r--chromeos/dbus/shill_service_client_stub.h2
-rw-r--r--chromeos/network/managed_network_configuration_handler.cc756
-rw-r--r--chromeos/network/managed_network_configuration_handler.h47
-rw-r--r--chromeos/network/managed_network_configuration_handler_unittest.cc314
-rw-r--r--chromeos/network/network_configuration_handler.cc32
-rw-r--r--chromeos/network/network_state.cc4
-rw-r--r--chromeos/network/network_state.h2
-rw-r--r--chromeos/network/network_ui_data.cc24
-rw-r--r--chromeos/network/network_ui_data.h29
-rw-r--r--chromeos/network/onc/onc_constants.cc2
-rw-r--r--chromeos/network/onc/onc_constants.h8
-rw-r--r--chromeos/network/onc/onc_merger.cc201
-rw-r--r--chromeos/network/onc/onc_merger.h9
-rw-r--r--chromeos/network/onc/onc_merger_unittest.cc4
-rw-r--r--chromeos/network/onc/onc_signature.cc2
-rw-r--r--chromeos/network/onc/onc_translation_tables.cc2
-rw-r--r--chromeos/network/onc/onc_utils.cc1
-rw-r--r--chromeos/network/onc/onc_utils.h5
-rw-r--r--chromeos/network/onc/onc_utils_unittest.cc1
-rw-r--r--chromeos/test/data/network/augmented_merge.json2
-rw-r--r--chromeos/test/data/network/policy/policy_wifi1.onc16
-rw-r--r--chromeos/test/data/network/policy/shill_managed_wifi1.json13
-rw-r--r--chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json10
-rw-r--r--chromeos/test/data/network/policy/shill_policy_on_unmanaged_user_wifi1.json10
-rw-r--r--chromeos/test/data/network/policy/shill_unmanaged_user_wifi1.json10
64 files changed, 2543 insertions, 487 deletions
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 681f040..32d4d98 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -607,9 +607,8 @@ void ChromeBrowserMainPartsChromeos::PostProfileInit() {
// Make sure the NetworkConfigurationUpdater is ready so that it pushes ONC
// configuration before login.
- policy::BrowserPolicyConnector* connector =
- g_browser_process->browser_policy_connector();
- connector->GetNetworkConfigurationUpdater();
+ g_browser_process->browser_policy_connector()->
+ GetNetworkConfigurationUpdater();
// Make sure that wallpaper boot transition and other delays in OOBE
// are disabled for tests by default.
diff --git a/chrome/browser/chromeos/cros/network_library_impl_base.cc b/chrome/browser/chromeos/cros/network_library_impl_base.cc
index e412971..2acde2b 100644
--- a/chrome/browser/chromeos/cros/network_library_impl_base.cc
+++ b/chrome/browser/chromeos/cros/network_library_impl_base.cc
@@ -5,11 +5,11 @@
#include "chrome/browser/chromeos/cros/network_library_impl_base.h"
#include "base/bind.h"
-#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_vector.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
+#include "base/string_util.h"
#include "chrome/browser/chromeos/cros/network_constants.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/net/onc_utils.h"
@@ -24,9 +24,7 @@
#include "chromeos/network/onc/onc_validator.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/nss_util.h" // crypto::GetTPMTokenInfo() for 802.1X and VPN.
-#include "grit/generated_resources.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
-#include "ui/base/l10n/l10n_util.h"
using content::BrowserThread;
diff --git a/chrome/browser/chromeos/cros/network_library_unittest.cc b/chrome/browser/chromeos/cros/network_library_unittest.cc
index dab27f9..ccf54093 100644
--- a/chrome/browser/chromeos/cros/network_library_unittest.cc
+++ b/chrome/browser/chromeos/cros/network_library_unittest.cc
@@ -172,8 +172,7 @@ class NetworkLibraryStubTest : public ::testing::Test {
.Times(AnyNumber())
.WillRepeatedly(Return(true));
- std::string onc_blob =
- onc::test_utils::ReadTestData(onc_file);
+ std::string onc_blob = onc::test_utils::ReadTestData(onc_file);
scoped_ptr<base::Value> expected_value =
google_apis::test_util::LoadJSONFile(shill_json);
diff --git a/chrome/browser/chromeos/extensions/networking_private_api.cc b/chrome/browser/chromeos/extensions/networking_private_api.cc
index a90c6c2..e1dd6a6 100644
--- a/chrome/browser/chromeos/extensions/networking_private_api.cc
+++ b/chrome/browser/chromeos/extensions/networking_private_api.cc
@@ -32,14 +32,11 @@ bool NetworkingPrivateGetPropertiesFunction::RunImpl() {
scoped_ptr<api::GetProperties::Params> params =
api::GetProperties::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
- // The |network_guid| parameter is storing the service path.
- std::string service_path = params->network_guid;
ManagedNetworkConfigurationHandler::Get()->GetProperties(
- service_path,
- base::Bind(
- &NetworkingPrivateGetPropertiesFunction::GetPropertiesSuccess,
- this),
+ params->network_guid, // service path
+ base::Bind(&NetworkingPrivateGetPropertiesFunction::GetPropertiesSuccess,
+ this),
base::Bind(&NetworkingPrivateGetPropertiesFunction::GetPropertiesFailed,
this));
return true;
@@ -63,6 +60,44 @@ void NetworkingPrivateGetPropertiesFunction::GetPropertiesFailed(
}
////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateGetManagedPropertiesFunction
+
+NetworkingPrivateGetManagedPropertiesFunction::
+ ~NetworkingPrivateGetManagedPropertiesFunction() {
+}
+
+bool NetworkingPrivateGetManagedPropertiesFunction::RunImpl() {
+ scoped_ptr<api::GetManagedProperties::Params> params =
+ api::GetManagedProperties::Params::Create(*args_);
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ ManagedNetworkConfigurationHandler::Get()->GetManagedProperties(
+ params->network_guid, // service path
+ base::Bind(&NetworkingPrivateGetManagedPropertiesFunction::Success,
+ this),
+ base::Bind(&NetworkingPrivateGetManagedPropertiesFunction::Failure,
+ this));
+ return true;
+}
+
+void NetworkingPrivateGetManagedPropertiesFunction::Success(
+ const std::string& service_path,
+ const base::DictionaryValue& dictionary) {
+ base::DictionaryValue* network_properties = dictionary.DeepCopy();
+ network_properties->SetStringWithoutPathExpansion(onc::network_config::kGUID,
+ service_path);
+ SetResult(network_properties);
+ SendResponse(true);
+}
+
+void NetworkingPrivateGetManagedPropertiesFunction::Failure(
+ const std::string& error_name,
+ scoped_ptr<base::DictionaryValue> error_data) {
+ error_ = error_name;
+ SendResponse(false);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// NetworkingPrivateGetStateFunction
NetworkingPrivateGetStateFunction::
@@ -110,7 +145,7 @@ bool NetworkingPrivateSetPropertiesFunction::RunImpl() {
params->properties.ToValue());
ManagedNetworkConfigurationHandler::Get()->SetProperties(
- params->network_guid,
+ params->network_guid, // service path
*properties_dict,
base::Bind(&NetworkingPrivateSetPropertiesFunction::ResultCallback,
this),
@@ -210,11 +245,8 @@ bool NetworkingPrivateStartConnectFunction::RunImpl() {
api::StartConnect::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
- // The |network_guid| parameter is storing the service path.
- std::string service_path = params->network_guid;
-
ManagedNetworkConfigurationHandler::Get()->Connect(
- service_path,
+ params->network_guid, // service path
base::Bind(
&NetworkingPrivateStartConnectFunction::ConnectionStartSuccess,
this),
@@ -247,11 +279,8 @@ bool NetworkingPrivateStartDisconnectFunction::RunImpl() {
api::StartDisconnect::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
- // The |network_guid| parameter is storing the service path.
- std::string service_path = params->network_guid;
-
ManagedNetworkConfigurationHandler::Get()->Disconnect(
- service_path,
+ params->network_guid, // service path
base::Bind(
&NetworkingPrivateStartDisconnectFunction::DisconnectionStartSuccess,
this),
diff --git a/chrome/browser/chromeos/extensions/networking_private_api.h b/chrome/browser/chromeos/extensions/networking_private_api.h
index d5446d5..f014e9d 100644
--- a/chrome/browser/chromeos/extensions/networking_private_api.h
+++ b/chrome/browser/chromeos/extensions/networking_private_api.h
@@ -37,6 +37,30 @@ class NetworkingPrivateGetPropertiesFunction : public AsyncExtensionFunction {
DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateGetPropertiesFunction);
};
+// Implements the chrome.networkingPrivate.getManagedProperties method.
+class NetworkingPrivateGetManagedPropertiesFunction
+ : public AsyncExtensionFunction {
+ public:
+ NetworkingPrivateGetManagedPropertiesFunction() {}
+ DECLARE_EXTENSION_FUNCTION("networkingPrivate.getManagedProperties",
+ NETWORKINGPRIVATE_GETMANAGEDPROPERTIES);
+
+ protected:
+ virtual ~NetworkingPrivateGetManagedPropertiesFunction();
+
+ // AsyncExtensionFunction overrides.
+ virtual bool RunImpl() OVERRIDE;
+
+ private:
+ // Callbacks for ManagedNetworkConfigurationHandler::GetManagedProperties.
+ void Success(const std::string& service_path,
+ const base::DictionaryValue& result);
+ void Failure(const std::string& error_name,
+ scoped_ptr<base::DictionaryValue> error_data);
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateGetManagedPropertiesFunction);
+};
+
// Implements the chrome.networkingPrivate.getState method.
class NetworkingPrivateGetStateFunction : public AsyncExtensionFunction {
public:
diff --git a/chrome/browser/chromeos/extensions/networking_private_apitest.cc b/chrome/browser/chromeos/extensions/networking_private_apitest.cc
index f823111..ff13580 100644
--- a/chrome/browser/chromeos/extensions/networking_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/networking_private_apitest.cc
@@ -10,11 +10,18 @@
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_device_client.h"
+#include "chromeos/dbus/shill_profile_client.h"
#include "chromeos/dbus/shill_service_client.h"
+#include "chromeos/network/managed_network_configuration_handler.h"
+#include "chromeos/network/onc/onc_constants.h"
+#include "chromeos/network/onc/onc_utils.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
+const char kSharedProfilePath[] = "/profile/default";
+const char kUserProfilePath[] = "/profile/chronos/shill";
+
class ExtensionNetworkingPrivateApiTest : public ExtensionApiTest {
public:
// Whitelist the extension ID of the test extension.
@@ -61,6 +68,9 @@ class ExtensionNetworkingPrivateApiTest : public ExtensionApiTest {
flimflam::kTypeWifi, flimflam::kStateIdle,
add_to_watchlist);
service_test->SetServiceProperty("stub_wifi2",
+ flimflam::kGuidProperty,
+ base::StringValue("stub_wifi2"));
+ service_test->SetServiceProperty("stub_wifi2",
flimflam::kSecurityProperty,
base::StringValue(flimflam::kSecurityPsk));
service_test->SetServiceProperty("stub_wifi2",
@@ -142,10 +152,80 @@ IN_PROC_BROWSER_TEST_F(ExtensionNetworkingPrivateApiTest, GetState) {
}
IN_PROC_BROWSER_TEST_F(ExtensionNetworkingPrivateApiTest, SetProperties) {
+ scoped_ptr<base::DictionaryValue> empty_policy =
+ onc::ReadDictionaryFromJson(onc::kEmptyUnencryptedConfiguration);
+ ManagedNetworkConfigurationHandler::Get()->SetPolicy(
+ onc::ONC_SOURCE_USER_POLICY, *empty_policy);
+ ManagedNetworkConfigurationHandler::Get()->SetPolicy(
+ onc::ONC_SOURCE_DEVICE_POLICY, *empty_policy);
+ content::RunAllPendingInMessageLoop();
+
EXPECT_TRUE(RunNetworkingSubtest("setProperties")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionNetworkingPrivateApiTest,
+ GetManagedProperties) {
+ ShillServiceClient::TestInterface* service_test =
+ DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
+ const std::string uidata_blob =
+ "{ \"user_settings\": {"
+ " \"WiFi\": {"
+ " \"Passphrase\": \"top secret\","
+ " }"
+ " }"
+ "}";
+ service_test->SetServiceProperty("stub_wifi2",
+ flimflam::kGuidProperty,
+ base::StringValue("stub_wifi2"));
+ service_test->SetServiceProperty("stub_wifi2",
+ flimflam::kUIDataProperty,
+ base::StringValue(uidata_blob));
+ service_test->SetServiceProperty("stub_wifi2",
+ flimflam::kProfileProperty,
+ base::StringValue(kUserProfilePath));
+ service_test->SetServiceProperty("stub_wifi2",
+ flimflam::kAutoConnectProperty,
+ base::FundamentalValue(false));
+
+ ShillProfileClient::TestInterface* profile_test =
+ DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
+
+ profile_test->AddService("stub_wifi2");
+
+ content::RunAllPendingInMessageLoop();
+
+ const std::string user_policy_blob =
+ "{ \"NetworkConfigurations\": ["
+ " { \"GUID\": \"stub_wifi2\","
+ " \"Type\": \"WiFi\","
+ " \"Name\": \"My WiFi Network\","
+ " \"WiFi\": {"
+ " \"Passphrase\": \"passphrase\","
+ " \"Recommended\": [ \"AutoConnect\", \"Passphrase\" ],"
+ " \"SSID\": \"stub_wifi2\","
+ " \"Security\": \"WPA-PSK\""
+ " }"
+ " }"
+ " ],"
+ " \"Certificates\": [],"
+ " \"Type\": \"UnencryptedConfiguration\""
+ "}";
+ scoped_ptr<base::DictionaryValue> user_policy =
+ onc::ReadDictionaryFromJson(user_policy_blob);
+ ManagedNetworkConfigurationHandler::Get()->SetPolicy(
+ onc::ONC_SOURCE_USER_POLICY, *user_policy);
+
+ scoped_ptr<base::DictionaryValue> device_policy =
+ onc::ReadDictionaryFromJson(onc::kEmptyUnencryptedConfiguration);
+ ManagedNetworkConfigurationHandler::Get()->SetPolicy(
+ onc::ONC_SOURCE_DEVICE_POLICY, *device_policy);
+
+ content::RunAllPendingInMessageLoop();
+
+ EXPECT_TRUE(RunNetworkingSubtest("getManagedProperties")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionNetworkingPrivateApiTest,
OnNetworksChangedEventConnect) {
EXPECT_TRUE(RunNetworkingSubtest("onNetworksChangedEventConnect"))
<< message_;
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index 5fb93ec..63e3d35 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -74,6 +74,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/pref_names.h"
+#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager_client.h"
#include "content/public/browser/browser_thread.h"
@@ -131,7 +132,7 @@ class LoginUtilsImpl
// TODO(dzhioev): Disabled in tests for a while.
// TODO(dzhioev): Move prewarm out of LoginUtils.
if (g_browser_process &&
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
+ !CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType)) {
registrar_.Add(
this,
chrome::NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED,
@@ -437,14 +438,10 @@ void LoginUtilsImpl::InitProfilePreferences(Profile* user_profile) {
if (use_shared_proxies_pref->IsDefaultValue())
user_profile->GetPrefs()->SetBoolean(prefs::kUseSharedProxies, false);
- // Locally managed users do not have user policy initialized.
- if (!UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
- policy::NetworkConfigurationUpdater* network_configuration_updater =
- g_browser_process->browser_policy_connector()->
- GetNetworkConfigurationUpdater();
- if (network_configuration_updater)
- network_configuration_updater->OnUserPolicyInitialized();
- }
+ // Notify the network configuration updater that policies are initialized. If
+ // there is no policy, it will read an empty policy which is fine.
+ g_browser_process->browser_policy_connector()->
+ GetNetworkConfigurationUpdater()->OnUserPolicyInitialized();
RespectLocalePreference(user_profile);
}
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater.cc b/chrome/browser/chromeos/policy/network_configuration_updater.cc
index 3aca2a8..057a0c2 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater.cc
@@ -4,168 +4,12 @@
#include "chrome/browser/chromeos/policy/network_configuration_updater.h"
-#include <string>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/policy/policy_map.h"
-#include "chrome/common/chrome_switches.h"
-#include "chromeos/network/onc/onc_constants.h"
-#include "chromeos/network/onc/onc_utils.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/cert/cert_trust_anchor_provider.h"
-#include "net/cert/x509_certificate.h"
-#include "policy/policy_constants.h"
-
-using content::BrowserThread;
-
namespace policy {
-namespace {
-
-// A simple implementation of net::CertTrustAnchorProvider that returns a list
-// of certificates that can be set by the owner of this object.
-class CrosTrustAnchorProvider : public net::CertTrustAnchorProvider {
- public:
- CrosTrustAnchorProvider() {}
- virtual ~CrosTrustAnchorProvider() {}
-
- // CertTrustAnchorProvider overrides.
- virtual const net::CertificateList& GetAdditionalTrustAnchors() OVERRIDE {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return trust_anchors_;
- }
-
- void SetTrustAnchors(scoped_ptr<net::CertificateList> trust_anchors) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- trust_anchors_.swap(*trust_anchors);
- }
-
- private:
- net::CertificateList trust_anchors_;
-
- DISALLOW_COPY_AND_ASSIGN(CrosTrustAnchorProvider);
-};
-
-} // namespace
-
-NetworkConfigurationUpdater::NetworkConfigurationUpdater(
- PolicyService* policy_service,
- chromeos::NetworkLibrary* network_library)
- : policy_change_registrar_(
- policy_service, PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())),
- network_library_(network_library),
- user_policy_initialized_(false),
- allow_trusted_certificates_from_policy_(false),
- policy_service_(policy_service),
- cert_trust_provider_(new CrosTrustAnchorProvider()) {
- DCHECK(network_library_);
- policy_change_registrar_.Observe(
- key::kDeviceOpenNetworkConfiguration,
- base::Bind(&NetworkConfigurationUpdater::OnPolicyChanged,
- base::Unretained(this),
- chromeos::onc::ONC_SOURCE_DEVICE_POLICY));
- policy_change_registrar_.Observe(
- key::kOpenNetworkConfiguration,
- base::Bind(&NetworkConfigurationUpdater::OnPolicyChanged,
- base::Unretained(this),
- chromeos::onc::ONC_SOURCE_USER_POLICY));
-
- network_library_->AddNetworkProfileObserver(this);
-
- // Apply the current policies immediately.
- ApplyNetworkConfigurations();
+NetworkConfigurationUpdater::NetworkConfigurationUpdater() {
}
NetworkConfigurationUpdater::~NetworkConfigurationUpdater() {
- network_library_->RemoveNetworkProfileObserver(this);
- bool posted = BrowserThread::DeleteSoon(
- BrowserThread::IO, FROM_HERE, cert_trust_provider_);
- if (!posted)
- delete cert_trust_provider_;
-}
-
-void NetworkConfigurationUpdater::OnProfileListChanged() {
- VLOG(1) << "Network profile list changed, applying policies.";
- ApplyNetworkConfigurations();
-}
-
-void NetworkConfigurationUpdater::OnUserPolicyInitialized() {
- VLOG(1) << "User policy initialized, applying policies.";
- user_policy_initialized_ = true;
- ApplyNetworkConfigurations();
-}
-
-net::CertTrustAnchorProvider*
- NetworkConfigurationUpdater::GetCertTrustAnchorProvider() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return cert_trust_provider_;
-}
-
-void NetworkConfigurationUpdater::OnPolicyChanged(
- chromeos::onc::ONCSource onc_source,
- const base::Value* previous,
- const base::Value* current) {
- VLOG(1) << "Policy for ONC source "
- << chromeos::onc::GetSourceAsString(onc_source) << " changed.";
- ApplyNetworkConfigurations();
-}
-
-void NetworkConfigurationUpdater::ApplyNetworkConfigurations() {
- ApplyNetworkConfiguration(key::kDeviceOpenNetworkConfiguration,
- chromeos::onc::ONC_SOURCE_DEVICE_POLICY);
- if (user_policy_initialized_) {
- ApplyNetworkConfiguration(key::kOpenNetworkConfiguration,
- chromeos::onc::ONC_SOURCE_USER_POLICY);
- }
-}
-
-void NetworkConfigurationUpdater::ApplyNetworkConfiguration(
- const std::string& policy_key,
- chromeos::onc::ONCSource onc_source) {
- VLOG(1) << "Apply policy for ONC source "
- << chromeos::onc::GetSourceAsString(onc_source);
- const PolicyMap& policies = policy_service_->GetPolicies(
- PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
- const base::Value* policy_value = policies.GetValue(policy_key);
-
- std::string new_network_config;
- if (policy_value != NULL) {
- // If the policy is not a string, we issue a warning, but still clear the
- // network configuration.
- if (!policy_value->GetAsString(&new_network_config)) {
- LOG(WARNING) << "ONC policy for source "
- << chromeos::onc::GetSourceAsString(onc_source)
- << " is not a string value.";
- }
- }
-
- // An empty string is not a valid ONC and generates warnings and
- // errors. Replace by a valid empty configuration.
- if (new_network_config.empty())
- new_network_config = chromeos::onc::kEmptyUnencryptedConfiguration;
-
- scoped_ptr<net::CertificateList> web_trust_certs(new net::CertificateList());
- if (!network_library_->LoadOncNetworks(new_network_config, "", onc_source,
- web_trust_certs.get())) {
- LOG(ERROR) << "Errors occurred during the ONC policy application.";
- }
-
- CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY &&
- allow_trusted_certificates_from_policy_ &&
- command_line->HasSwitch(switches::kEnableWebTrustCerts)) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&CrosTrustAnchorProvider::SetTrustAnchors,
- base::Unretained(static_cast<CrosTrustAnchorProvider*>(
- cert_trust_provider_)),
- base::Passed(&web_trust_certs)));
- }
}
} // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater.h b/chrome/browser/chromeos/policy/network_configuration_updater.h
index 5872e8c..7063425 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater.h
+++ b/chrome/browser/chromeos/policy/network_configuration_updater.h
@@ -5,17 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_H_
-#include <string>
-
-#include "chrome/browser/chromeos/cros/network_constants.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/policy/policy_service.h"
-#include "chromeos/network/network_ui_data.h"
-#include "chromeos/network/onc/onc_constants.h"
-
-namespace base {
-class Value;
-}
+#include "base/basictypes.h"
namespace net {
class CertTrustAnchorProvider;
@@ -23,37 +13,26 @@ class CertTrustAnchorProvider;
namespace policy {
-class PolicyMap;
-
-// Keeps track of the network configuration policy settings and Shill's
-// profiles. Requests the NetworkLibrary to apply the ONC of the network
-// policies every time one of the relevant policies or Shill's profiles changes
-// or OnUserPolicyInitialized() is called. If the user policy is available,
-// always both the device and the user policy are applied. Otherwise only the
-// device policy is applied.
-class NetworkConfigurationUpdater
- : public chromeos::NetworkLibrary::NetworkProfileObserver {
+// Keeps track of the network configuration policy settings and pushes changes
+// to the respective configuration backend, which in turn writes configurations
+// to Shill.
+class NetworkConfigurationUpdater {
public:
- NetworkConfigurationUpdater(PolicyService* policy_service,
- chromeos::NetworkLibrary* network_library);
- virtual ~NetworkConfigurationUpdater();
-
- // NetworkProfileObserver overrides.
- virtual void OnProfileListChanged() OVERRIDE;
+ NetworkConfigurationUpdater() {}
+ virtual ~NetworkConfigurationUpdater() {}
// Notifies this updater that the user policy is initialized. Before this
- // function is called, the user policy is not applied. Afterwards, always both
- // device and user policy are applied as described in the class comment. This
- // function also triggers an immediate policy application of both device and
- // user policy.
- void OnUserPolicyInitialized();
+ // function is called, the user policy is not applied. This function may
+ // trigger immediate policy applications.
+ virtual void OnUserPolicyInitialized() = 0;
+
+ // TODO(pneubeck): Extract the following two certificate related functions
+ // into a separate CertificateUpdater.
// Web trust isn't given to certificates imported from ONC by default. Setting
// |allow| to true allows giving Web trust to the certificates that
// request it.
- void set_allow_trusted_certificates_from_policy(bool allow) {
- allow_trusted_certificates_from_policy_ = allow;
- }
+ virtual void set_allow_trusted_certificates_from_policy(bool allow) = 0;
// Returns a CertTrustAnchorProvider that provides the list of server and
// CA certificates with the Web trust flag set that were retrieved from the
@@ -62,44 +41,9 @@ class NetworkConfigurationUpdater
// on the IO thread. It is only valid as long as the
// NetworkConfigurationUpdater is valid; the NetworkConfigurationUpdater
// outlives all the profiles, and deletes the provider on the IO thread.
- net::CertTrustAnchorProvider* GetCertTrustAnchorProvider();
+ virtual net::CertTrustAnchorProvider* GetCertTrustAnchorProvider() = 0;
private:
- // Callback that's called by |policy_service_| if the respective ONC policy
- // changed.
- void OnPolicyChanged(chromeos::onc::ONCSource onc_source,
- const base::Value* previous,
- const base::Value* current);
-
- // Retrieves the ONC policies from |policy_service_| and pushes the
- // configurations to |network_library_|. Ensures that a device policy is
- // always overwritten by a user policy.
- void ApplyNetworkConfigurations();
-
- // Push the policy stored at |policy_key| for |onc_source| to
- // |network_library_|.
- void ApplyNetworkConfiguration(const std::string& policy_key,
- chromeos::onc::ONCSource onc_source);
-
- // Wraps the policy service we read network configuration from.
- PolicyChangeRegistrar policy_change_registrar_;
-
- // Network library to write network configuration to.
- chromeos::NetworkLibrary* network_library_;
-
- // Whether the user policy is already available.
- bool user_policy_initialized_;
-
- // Whether Web trust is allowed or not.
- bool allow_trusted_certificates_from_policy_;
-
- // The policy service storing the ONC policies.
- PolicyService* policy_service_;
-
- // An implementation of CertTrustAnchorProvider. Owned by the updater, but
- // lives on the IO thread.
- net::CertTrustAnchorProvider* cert_trust_provider_;
-
DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationUpdater);
};
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
new file mode 100644
index 0000000..a61acb9
--- /dev/null
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/network_configuration_updater_impl.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/debug/stack_trace.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chromeos/network/managed_network_configuration_handler.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "policy/policy_constants.h"
+
+namespace policy {
+
+NetworkConfigurationUpdaterImpl::NetworkConfigurationUpdaterImpl(
+ PolicyService* policy_service)
+ : user_policy_initialized_(false),
+ policy_change_registrar_(
+ policy_service, PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())),
+ policy_service_(policy_service) {
+ policy_change_registrar_.Observe(
+ key::kDeviceOpenNetworkConfiguration,
+ base::Bind(&NetworkConfigurationUpdaterImpl::OnPolicyChanged,
+ base::Unretained(this),
+ chromeos::onc::ONC_SOURCE_DEVICE_POLICY));
+ policy_change_registrar_.Observe(
+ key::kOpenNetworkConfiguration,
+ base::Bind(&NetworkConfigurationUpdaterImpl::OnPolicyChanged,
+ base::Unretained(this),
+ chromeos::onc::ONC_SOURCE_USER_POLICY));
+}
+
+NetworkConfigurationUpdaterImpl::~NetworkConfigurationUpdaterImpl() {
+}
+
+void NetworkConfigurationUpdaterImpl::OnUserPolicyInitialized() {
+ VLOG(1) << "User policy initialized.";
+ user_policy_initialized_ = true;
+ ApplyNetworkConfiguration(chromeos::onc::ONC_SOURCE_USER_POLICY);
+}
+
+net::CertTrustAnchorProvider*
+NetworkConfigurationUpdaterImpl::GetCertTrustAnchorProvider() {
+ return NULL;
+}
+
+void NetworkConfigurationUpdaterImpl::OnPolicyChanged(
+ chromeos::onc::ONCSource onc_source,
+ const base::Value* previous,
+ const base::Value* current) {
+ VLOG(1) << "Policy for ONC source "
+ << chromeos::onc::GetSourceAsString(onc_source) << " changed.";
+ VLOG(2) << "User policy is " << (user_policy_initialized_ ? "" : "not ")
+ << "initialized.";
+ ApplyNetworkConfiguration(onc_source);
+}
+
+void NetworkConfigurationUpdaterImpl::ApplyNetworkConfiguration(
+ chromeos::onc::ONCSource onc_source) {
+ VLOG(1) << "Apply policy for ONC source "
+ << chromeos::onc::GetSourceAsString(onc_source);
+
+ std::string policy_key;
+ if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY)
+ policy_key = key::kOpenNetworkConfiguration;
+ else
+ policy_key = key::kDeviceOpenNetworkConfiguration;
+
+ const PolicyMap& policies = policy_service_->GetPolicies(
+ PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
+ const base::Value* policy_value = policies.GetValue(policy_key);
+
+ if (!policy_value) {
+ VLOG(1) << "The policy value is NULL. Aborting.";
+ return;
+ }
+
+ std::string onc_blob;
+ if (!policy_value->GetAsString(&onc_blob)) {
+ LOG(ERROR) << "ONC policy " << policy_key << " is not a string value.";
+ return;
+ }
+ VLOG(2) << "The policy contains this ONC: " << onc_blob;
+
+ if (onc_blob.empty())
+ onc_blob = chromeos::onc::kEmptyUnencryptedConfiguration;
+
+ scoped_ptr<base::DictionaryValue> onc_dict =
+ chromeos::onc::ReadDictionaryFromJson(onc_blob);
+ if (!onc_dict) {
+ LOG(ERROR) << "ONC loaded from policy " << policy_key
+ << " is not a valid JSON dictionary.";
+ return;
+ }
+
+ chromeos::ManagedNetworkConfigurationHandler::Get()->SetPolicy(onc_source,
+ *onc_dict);
+}
+
+} // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl.h b/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
new file mode 100644
index 0000000..52a758b
--- /dev/null
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_H_
+
+#include <string>
+
+#include "chrome/browser/chromeos/policy/network_configuration_updater.h"
+#include "chrome/browser/policy/policy_service.h"
+#include "chromeos/network/onc/onc_constants.h"
+
+namespace base {
+class Value;
+}
+
+namespace policy {
+
+class PolicyMap;
+
+// This implementation pushes policies to the
+// ManagedNetworkConfigurationHandler. User policies are only pushed after
+// OnUserPolicyInitialized() was called.
+// TODO(pneubeck): Certificates are not implemented yet, they are silently
+// ignored.
+class NetworkConfigurationUpdaterImpl : public NetworkConfigurationUpdater {
+ public:
+ explicit NetworkConfigurationUpdaterImpl(PolicyService* policy_service);
+ virtual ~NetworkConfigurationUpdaterImpl();
+
+ // NetworkConfigurationUpdater overrides.
+
+ virtual void OnUserPolicyInitialized() OVERRIDE;
+ virtual void set_allow_trusted_certificates_from_policy(bool allow) OVERRIDE {
+ }
+ virtual net::CertTrustAnchorProvider* GetCertTrustAnchorProvider() OVERRIDE;
+
+ private:
+ // Callback that's called by |policy_service_| if the respective ONC policy
+ // changed.
+ void OnPolicyChanged(chromeos::onc::ONCSource onc_source,
+ const base::Value* previous,
+ const base::Value* current);
+
+ void ApplyNetworkConfiguration(chromeos::onc::ONCSource onc_source);
+
+ // Whether the user policy is already available.
+ bool user_policy_initialized_;
+
+ // Wraps the policy service we read network configuration from.
+ PolicyChangeRegistrar policy_change_registrar_;
+
+ // The policy service storing the ONC policies.
+ PolicyService* policy_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationUpdaterImpl);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_H_
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
new file mode 100644
index 0000000..32bfc5a
--- /dev/null
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/common/chrome_switches.h"
+#include "chromeos/network/onc/onc_constants.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/cert/cert_trust_anchor_provider.h"
+#include "net/cert/x509_certificate.h"
+#include "policy/policy_constants.h"
+
+using content::BrowserThread;
+
+namespace policy {
+
+namespace {
+
+// A simple implementation of net::CertTrustAnchorProvider that returns a list
+// of certificates that can be set by the owner of this object.
+class CrosTrustAnchorProvider : public net::CertTrustAnchorProvider {
+ public:
+ CrosTrustAnchorProvider() {}
+ virtual ~CrosTrustAnchorProvider() {}
+
+ // CertTrustAnchorProvider overrides.
+ virtual const net::CertificateList& GetAdditionalTrustAnchors() OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ return trust_anchors_;
+ }
+
+ void SetTrustAnchors(scoped_ptr<net::CertificateList> trust_anchors) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ trust_anchors_.swap(*trust_anchors);
+ }
+
+ private:
+ net::CertificateList trust_anchors_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrosTrustAnchorProvider);
+};
+
+} // namespace
+
+NetworkConfigurationUpdaterImplCros::NetworkConfigurationUpdaterImplCros(
+ PolicyService* policy_service,
+ chromeos::NetworkLibrary* network_library)
+ : policy_change_registrar_(
+ policy_service, PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())),
+ network_library_(network_library),
+ user_policy_initialized_(false),
+ allow_trusted_certificates_from_policy_(false),
+ policy_service_(policy_service),
+ cert_trust_provider_(new CrosTrustAnchorProvider()) {
+ DCHECK(network_library_);
+ policy_change_registrar_.Observe(
+ key::kDeviceOpenNetworkConfiguration,
+ base::Bind(&NetworkConfigurationUpdaterImplCros::OnPolicyChanged,
+ base::Unretained(this),
+ chromeos::onc::ONC_SOURCE_DEVICE_POLICY));
+ policy_change_registrar_.Observe(
+ key::kOpenNetworkConfiguration,
+ base::Bind(&NetworkConfigurationUpdaterImplCros::OnPolicyChanged,
+ base::Unretained(this),
+ chromeos::onc::ONC_SOURCE_USER_POLICY));
+
+ network_library_->AddNetworkProfileObserver(this);
+
+ // Apply the current policies immediately.
+ ApplyNetworkConfigurations();
+}
+
+NetworkConfigurationUpdaterImplCros::~NetworkConfigurationUpdaterImplCros() {
+ network_library_->RemoveNetworkProfileObserver(this);
+ bool posted = BrowserThread::DeleteSoon(
+ BrowserThread::IO, FROM_HERE, cert_trust_provider_);
+ if (!posted)
+ delete cert_trust_provider_;
+}
+
+void NetworkConfigurationUpdaterImplCros::OnProfileListChanged() {
+ VLOG(1) << "Network profile list changed, applying policies.";
+ ApplyNetworkConfigurations();
+}
+
+void NetworkConfigurationUpdaterImplCros::OnUserPolicyInitialized() {
+ VLOG(1) << "User policy initialized, applying policies.";
+ user_policy_initialized_ = true;
+ ApplyNetworkConfigurations();
+}
+
+void NetworkConfigurationUpdaterImplCros::
+set_allow_trusted_certificates_from_policy(bool allow) {
+ allow_trusted_certificates_from_policy_ = allow;
+}
+
+net::CertTrustAnchorProvider*
+ NetworkConfigurationUpdaterImplCros::GetCertTrustAnchorProvider() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return cert_trust_provider_;
+}
+
+void NetworkConfigurationUpdaterImplCros::OnPolicyChanged(
+ chromeos::onc::ONCSource onc_source,
+ const base::Value* previous,
+ const base::Value* current) {
+ VLOG(1) << "Policy for ONC source "
+ << chromeos::onc::GetSourceAsString(onc_source) << " changed.";
+ ApplyNetworkConfigurations();
+}
+
+void NetworkConfigurationUpdaterImplCros::ApplyNetworkConfigurations() {
+ ApplyNetworkConfiguration(key::kDeviceOpenNetworkConfiguration,
+ chromeos::onc::ONC_SOURCE_DEVICE_POLICY);
+ if (user_policy_initialized_) {
+ ApplyNetworkConfiguration(key::kOpenNetworkConfiguration,
+ chromeos::onc::ONC_SOURCE_USER_POLICY);
+ }
+}
+
+void NetworkConfigurationUpdaterImplCros::ApplyNetworkConfiguration(
+ const std::string& policy_key,
+ chromeos::onc::ONCSource onc_source) {
+ VLOG(1) << "Apply policy for ONC source "
+ << chromeos::onc::GetSourceAsString(onc_source);
+ const PolicyMap& policies = policy_service_->GetPolicies(
+ PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
+ const base::Value* policy_value = policies.GetValue(policy_key);
+
+ std::string new_network_config;
+ if (policy_value != NULL) {
+ // If the policy is not a string, we issue a warning, but still clear the
+ // network configuration.
+ if (!policy_value->GetAsString(&new_network_config)) {
+ LOG(WARNING) << "ONC policy for source "
+ << chromeos::onc::GetSourceAsString(onc_source)
+ << " is not a string value.";
+ }
+ }
+
+ // An empty string is not a valid ONC and generates warnings and
+ // errors. Replace by a valid empty configuration.
+ if (new_network_config.empty())
+ new_network_config = chromeos::onc::kEmptyUnencryptedConfiguration;
+
+ scoped_ptr<net::CertificateList> web_trust_certs(new net::CertificateList());
+ if (!network_library_->LoadOncNetworks(new_network_config, "", onc_source,
+ web_trust_certs.get())) {
+ LOG(ERROR) << "Errors occurred during the ONC policy application.";
+ }
+
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY &&
+ allow_trusted_certificates_from_policy_ &&
+ command_line->HasSwitch(switches::kEnableWebTrustCerts)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&CrosTrustAnchorProvider::SetTrustAnchors,
+ base::Unretained(static_cast<CrosTrustAnchorProvider*>(
+ cert_trust_provider_)),
+ base::Passed(&web_trust_certs)));
+ }
+}
+
+} // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h
new file mode 100644
index 0000000..fca611f
--- /dev/null
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_CROS_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_CROS_H_
+
+#include <string>
+
+#include "chrome/browser/chromeos/cros/network_constants.h"
+#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/policy/network_configuration_updater.h"
+#include "chrome/browser/policy/policy_service.h"
+#include "chromeos/network/network_ui_data.h"
+#include "chromeos/network/onc/onc_constants.h"
+
+namespace base {
+class Value;
+}
+
+namespace policy {
+
+class PolicyMap;
+
+// DEPRECATED: will be replaced by NetworkConfigurationImpl.
+// This implementation pushes policies through the NetworkLibrary. It applies
+// network policies every time one of the relevant policies or Shill's profiles
+// changed or OnUserPolicyInitialized() is called. If the user policy is
+// available, always both the device and the user policy are applied. Otherwise
+// only the device policy is applied.
+class NetworkConfigurationUpdaterImplCros
+ : public NetworkConfigurationUpdater,
+ public chromeos::NetworkLibrary::NetworkProfileObserver {
+ public:
+ NetworkConfigurationUpdaterImplCros(
+ PolicyService* policy_service,
+ chromeos::NetworkLibrary* network_library);
+ virtual ~NetworkConfigurationUpdaterImplCros();
+
+ // NetworkProfileObserver overrides.
+ virtual void OnProfileListChanged() OVERRIDE;
+
+ // NetworkConfigurationUpdater overrides.
+
+ // In this implementation, this function applies both device and user policy.
+ virtual void OnUserPolicyInitialized() OVERRIDE;
+ virtual void set_allow_trusted_certificates_from_policy(bool allow) OVERRIDE;
+ virtual net::CertTrustAnchorProvider* GetCertTrustAnchorProvider() OVERRIDE;
+
+ private:
+ // Callback that's called by |policy_service_| if the respective ONC policy
+ // changed.
+ void OnPolicyChanged(chromeos::onc::ONCSource onc_source,
+ const base::Value* previous,
+ const base::Value* current);
+
+ // Retrieves the ONC policies from |policy_service_| and pushes the
+ // configurations to |network_library_|. Ensures that a device policy is
+ // always overwritten by a user policy.
+ void ApplyNetworkConfigurations();
+
+ // Push the policy stored at |policy_key| for |onc_source| to
+ // |network_library_|.
+ void ApplyNetworkConfiguration(const std::string& policy_key,
+ chromeos::onc::ONCSource onc_source);
+
+ // Wraps the policy service we read network configuration from.
+ PolicyChangeRegistrar policy_change_registrar_;
+
+ // Network library to write network configuration to.
+ chromeos::NetworkLibrary* network_library_;
+
+ // Whether the user policy is already available.
+ bool user_policy_initialized_;
+
+ // Whether Web trust is allowed or not.
+ bool allow_trusted_certificates_from_policy_;
+
+ // The policy service storing the ONC policies.
+ PolicyService* policy_service_;
+
+ // An implementation of CertTrustAnchorProvider. Owned by the updater, but
+ // lives on the IO thread.
+ net::CertTrustAnchorProvider* cert_trust_provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationUpdaterImplCros);
+};
+
+} // namespace policy
+
+#endif // CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_CROS_H_
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc
index 1a6360ae..b1df657 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/chromeos/policy/network_configuration_updater.h"
+#include "chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h"
#include "base/command_line.h"
#include "base/file_util.h"
@@ -46,6 +46,7 @@ ACTION_P(SetCertificateList, list) {
} // namespace
+// Tests of NetworkConfigurationUpdaterImplCros
class NetworkConfigurationUpdaterTest
: public testing::TestWithParam<const char*>{
protected:
@@ -110,8 +111,8 @@ TEST_P(NetworkConfigurationUpdaterTest, InitialUpdates) {
device_onc, "", chromeos::onc::ONC_SOURCE_DEVICE_POLICY, _));
{
- NetworkConfigurationUpdater updater(policy_service_.get(),
- &network_library_);
+ NetworkConfigurationUpdaterImplCros updater(policy_service_.get(),
+ &network_library_);
Mock::VerifyAndClearExpectations(&network_library_);
// After the user policy is initialized, we always push both policies to the
@@ -145,8 +146,8 @@ TEST_P(NetworkConfigurationUpdaterTest, AllowTrustedCertificatesFromPolicy) {
EXPECT_CALL(network_library_, LoadOncNetworks(_, _, _, _))
.WillRepeatedly(SetCertificateList(empty_cert_list));
- NetworkConfigurationUpdater updater(policy_service_.get(),
- &network_library_);
+ NetworkConfigurationUpdaterImplCros updater(policy_service_.get(),
+ &network_library_);
net::CertTrustAnchorProvider* trust_provider =
updater.GetCertTrustAnchorProvider();
ASSERT_TRUE(trust_provider);
@@ -195,8 +196,8 @@ TEST_P(NetworkConfigurationUpdaterTest, PolicyChange) {
// Ignore the initial updates.
EXPECT_CALL(network_library_, LoadOncNetworks(_, _, _, _))
.Times(AnyNumber());
- NetworkConfigurationUpdater updater(policy_service_.get(),
- &network_library_);
+ NetworkConfigurationUpdaterImplCros updater(policy_service_.get(),
+ &network_library_);
updater.OnUserPolicyInitialized();
Mock::VerifyAndClearExpectations(&network_library_);
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index 0ce66c9..49e93e9 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -509,6 +509,7 @@ enum HistogramValue {
DEVELOPERPRIVATE_GETPROJECTSINFO,
DEVELOPERPRIVATE_LOADPROJECT,
COMMANDLINEPRIVATE_HASSWITCH,
+ NETWORKINGPRIVATE_GETMANAGEDPROPERTIES,
ENUM_BOUNDARY // Last entry: Add new entries above.
};
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index cafe4c5..ef7b93f 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -58,6 +58,8 @@
#include "chrome/browser/chromeos/policy/device_status_collector.h"
#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
#include "chrome/browser/chromeos/policy/network_configuration_updater.h"
+#include "chrome/browser/chromeos/policy/network_configuration_updater_impl.h"
+#include "chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h"
#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
#include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -305,11 +307,17 @@ void BrowserPolicyConnector::InitializeUserPolicy(
const std::string& user_name,
bool is_public_account,
bool wait_for_policy_fetch) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+
// If the user is managed then importing certificates from ONC policy is
// allowed, otherwise it's not. Update this flag once the user has signed in,
// and before user policy is loaded.
- GetNetworkConfigurationUpdater()->set_allow_trusted_certificates_from_policy(
- GetUserAffiliation(user_name) == USER_AFFILIATION_MANAGED);
+ if (!command_line->HasSwitch(
+ chromeos::switches::kUseNewNetworkConfigurationHandlers)) {
+ GetNetworkConfigurationUpdater()->
+ set_allow_trusted_certificates_from_policy(
+ GetUserAffiliation(user_name) == USER_AFFILIATION_MANAGED);
+ }
// Re-initializing user policy is disallowed for two reasons:
// (a) Existing profiles may hold pointers to |user_cloud_policy_manager_|.
@@ -317,8 +325,6 @@ void BrowserPolicyConnector::InitializeUserPolicy(
// correctly is impossible for re-initialization.
CHECK(!user_cloud_policy_manager_);
- CommandLine* command_line = CommandLine::ForCurrentProcess();
-
base::FilePath profile_dir;
CHECK(PathService::Get(chrome::DIR_USER_DATA, &profile_dir));
profile_dir = profile_dir.Append(
@@ -397,9 +403,17 @@ AppPackUpdater* BrowserPolicyConnector::GetAppPackUpdater() {
NetworkConfigurationUpdater*
BrowserPolicyConnector::GetNetworkConfigurationUpdater() {
if (!network_configuration_updater_) {
- network_configuration_updater_.reset(new NetworkConfigurationUpdater(
- GetPolicyService(),
- chromeos::CrosLibrary::Get()->GetNetworkLibrary()));
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(
+ chromeos::switches::kUseNewNetworkConfigurationHandlers)) {
+ network_configuration_updater_.reset(
+ new NetworkConfigurationUpdaterImpl(GetPolicyService()));
+ } else {
+ network_configuration_updater_.reset(
+ new NetworkConfigurationUpdaterImplCros(
+ GetPolicyService(),
+ chromeos::CrosLibrary::Get()->GetNetworkLibrary()));
+ }
}
return network_configuration_updater_.get();
}
diff --git a/chrome/browser/resources/chromeos/network_configuration/config.html b/chrome/browser/resources/chromeos/network_configuration/config.html
index 8238e17..26eb220 100644
--- a/chrome/browser/resources/chromeos/network_configuration/config.html
+++ b/chrome/browser/resources/chromeos/network_configuration/config.html
@@ -25,8 +25,8 @@
</div>
</div>
<div class="button-strip">
- <button id="close">
- Close
+ <button id="save">
+ Save
</button>
<button id="connect">
Connect
diff --git a/chrome/browser/resources/chromeos/network_configuration/js/main_config.js b/chrome/browser/resources/chromeos/network_configuration/js/main_config.js
index 6613339..d8be3f5 100644
--- a/chrome/browser/resources/chromeos/network_configuration/js/main_config.js
+++ b/chrome/browser/resources/chromeos/network_configuration/js/main_config.js
@@ -12,30 +12,40 @@ function showMessage(msg) {
}, 3000);
}
+function getShowMessageCallback(message) {
+ return function() {
+ var error = chrome.runtime.lastError;
+ if (error) {
+ showMessage(message + ': ' + error.message);
+ } else {
+ showMessage(message + ': Success!');
+ }
+ };
+}
+
function onPageLoad() {
var networkConfig = $('network-config');
network.config.NetworkConfig.decorate(networkConfig);
- $('close').onclick = function() {
- networkConfig.applyUserSettings();
+ $('save').onclick = function() {
+ chrome.networkingPrivate.setProperties(
+ networkConfig.networkId,
+ networkConfig.userSettings,
+ getShowMessageCallback('Set properties of ' + networkConfig.networkId));
};
$('connect').onclick = function() {
chrome.networkingPrivate.startConnect(
networkConfig.networkId,
- function() {
- showMessage('Successfully requested connect to ' +
- networkConfig.networkId + '!');
- });
+ getShowMessageCallback(
+ 'Requested connect to ' + networkConfig.networkId));
};
$('disconnect').onclick = function() {
chrome.networkingPrivate.startDisconnect(
networkConfig.networkId,
- function() {
- showMessage('Successfully requested disconnect from ' +
- networkConfig.networkId + '!');
- });
+ getShowMessageCallback(
+ 'Requested disconnect from ' + networkConfig.networkId));
};
}
diff --git a/chrome/browser/resources/chromeos/network_configuration/js/network_config.js b/chrome/browser/resources/chromeos/network_configuration/js/network_config.js
index 448101b..27ee065 100644
--- a/chrome/browser/resources/chromeos/network_configuration/js/network_config.js
+++ b/chrome/browser/resources/chromeos/network_configuration/js/network_config.js
@@ -10,33 +10,99 @@ cr.define('network.config', function() {
decorate: function() {
var params = parseQueryParams(window.location);
this.networkId_ = params.network;
- this.settingsArea_ = null;
+ this.activeArea_ = null;
+ this.userArea_ = null;
+ this.managedArea_ = null;
+ this.updateDom_();
this.fetchProperties_();
},
fetchProperties_: function() {
- chrome.networkingPrivate.getProperties(this.networkId_,
- this.updateDom.bind(this));
+ chrome.networkingPrivate.getProperties(
+ this.networkId_,
+ this.updateActiveSettings_.bind(this));
+ chrome.networkingPrivate.getManagedProperties(
+ this.networkId_,
+ this.updateManagedSettings_.bind(this));
+ },
+
+ stringifyJSON_: function(properties) {
+ return JSON.stringify(properties, undefined, 2);
+ },
+
+ updateActiveSettings_: function(properties) {
+ this.activeArea_.value = this.stringifyJSON_(properties);
+ },
+
+ updateManagedSettings_: function(properties) {
+ var error = chrome.runtime.lastError;
+ if (error) {
+ this.managedArea_.value = error.message;
+ this.userArea_.value = 'undefined';
+ } else {
+ this.managedArea_.value = this.stringifyJSON_(properties);
+ this.userArea_.value = this.stringifyJSON_(
+ this.extractUserSettings_(properties));
+ }
},
- updateDom: function(properties) {
+ extractUserSettings_: function(properties) {
+ if ('UserSetting' in properties)
+ return properties['UserSetting'];
+
+ if ('SharedSetting' in properties)
+ return properties['SharedSetting'];
+
+ var result = {};
+ for (var fieldName in properties) {
+ var entry = properties[fieldName];
+ if (typeof entry === 'object') {
+ var nestedResult = this.extractUserSettings_(entry);
+ if (nestedResult)
+ result[fieldName] = nestedResult;
+ }
+ }
+ if (Object.keys(result).length)
+ return result;
+ else
+ return undefined;
+ },
+
+ updateDom_: function() {
var div = document.createElement('div');
- var label = document.createElement('h4');
- label.textContent = 'User Settings';
- div.appendChild(label);
- var area = document.createElement('textarea');
- var str = JSON.stringify(properties, undefined, 2);
- area.value = str;
- div.appendChild(area);
+
+ this.activeArea_ = function() {
+ var label = document.createElement('h4');
+ label.textContent = 'Active Settings (getProperties)';
+ div.appendChild(label);
+ var area = document.createElement('textarea');
+ div.appendChild(area);
+ return area;
+ }();
+
+ this.userArea_ = function() {
+ var label = document.createElement('h4');
+ label.textContent = 'User Settings';
+ div.appendChild(label);
+ var area = document.createElement('textarea');
+ div.appendChild(area);
+ return area;
+ }();
+
+ this.managedArea_ = function() {
+ var label = document.createElement('h4');
+ label.textContent = 'Managed Settings (getManagedProperties)';
+ div.appendChild(label);
+ var area = document.createElement('textarea');
+ div.appendChild(area);
+ return area;
+ }();
this.appendChild(div);
- this.settingsArea_ = area;
},
- applyUserSettings: function() {
- chrome.networkingPrivate.setProperties(
- this.networkId_,
- JSON.parse(this.settingsArea_.value));
+ get userSettings() {
+ return JSON.parse(this.userArea_.value);
},
get networkId() {
diff --git a/chrome/browser/resources/chromeos/network_configuration/js/network_status.js b/chrome/browser/resources/chromeos/network_configuration/js/network_status.js
index cf84f93..a6bec2f7 100644
--- a/chrome/browser/resources/chromeos/network_configuration/js/network_status.js
+++ b/chrome/browser/resources/chromeos/network_configuration/js/network_status.js
@@ -37,11 +37,10 @@ cr.define('network.status', function() {
var bMinusA = [];
b.forEach(function(elB) {
var keyB = toKey(elB);
- if (inA[keyB]) {
+ if (inA[keyB])
delete inA[keyB];
- } else {
+ else
bMinusA.push(elB);
- }
});
var aMinusB = [];
for (var keyA in inA) {
@@ -574,6 +573,8 @@ cr.define('network.status', function() {
return button;
}
}
+ console.log('TechnologyButton for type ' + networkType +
+ ' requested but not found.');
return null;
},
@@ -620,10 +621,12 @@ cr.define('network.status', function() {
var addCallback = this.addNetworkCallback_.bind(this);
toAdd.forEach(function(id) {
+ console.log('NetworkStatus: Network ' + id + ' added.');
chrome.networkingPrivate.getProperties(id, addCallback);
});
toRemove.forEach(function(id) {
+ console.log('NetworkStatus: Network ' + id + ' removed.');
delete this.networkByID_[id];
}, this);
@@ -637,6 +640,7 @@ cr.define('network.status', function() {
onNetworksChanged_: function(networkIDs) {
var updateCallback = this.updateNetworkCallback_.bind(this);
networkIDs.forEach(function(id) {
+ console.log('NetworkStatus: Network ' + id + ' changed.');
chrome.networkingPrivate.getProperties(id, updateCallback);
});
},
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 1b8d404..2367758 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -592,8 +592,11 @@
'browser/chromeos/policy/enrollment_status_chromeos.h',
'browser/chromeos/policy/enterprise_install_attributes.cc',
'browser/chromeos/policy/enterprise_install_attributes.h',
- 'browser/chromeos/policy/network_configuration_updater.cc',
'browser/chromeos/policy/network_configuration_updater.h',
+ 'browser/chromeos/policy/network_configuration_updater_impl.cc',
+ 'browser/chromeos/policy/network_configuration_updater_impl.h',
+ 'browser/chromeos/policy/network_configuration_updater_impl_cros.cc',
+ 'browser/chromeos/policy/network_configuration_updater_impl_cros.h',
'browser/chromeos/policy/policy_cert_verifier.cc',
'browser/chromeos/policy/policy_cert_verifier.h',
'browser/chromeos/policy/proxy_policy_provider.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 1e9853f..d713109 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -627,7 +627,7 @@
'browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc',
'browser/chromeos/policy/device_local_account_policy_service_unittest.cc',
'browser/chromeos/policy/enterprise_install_attributes_unittest.cc',
- 'browser/chromeos/policy/network_configuration_updater_unittest.cc',
+ 'browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc',
'browser/chromeos/policy/proxy_policy_provider_unittest.cc',
'browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc',
'browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc',
diff --git a/chrome/common/extensions/api/networking_private.json b/chrome/common/extensions/api/networking_private.json
index 6245a31..ebb1109 100644
--- a/chrome/common/extensions/api/networking_private.json
+++ b/chrome/common/extensions/api/networking_private.json
@@ -16,6 +16,11 @@
"additionalProperties": { "type": "any" }
},
{
+ "id": "ManagedNetworkProperties",
+ "type": "object",
+ "additionalProperties": { "type": "any" }
+ },
+ {
"id": "VerificationProperties",
"type": "object",
"properties": {
@@ -66,6 +71,28 @@
]
},
{
+ "name": "getManagedProperties",
+ "description": "Gets the merged properties of the network with id networkGuid from the sources: User settings, shared settings, user policy, device policy and the currently active settings.",
+ "parameters": [
+ {
+ "name": "networkGuid",
+ "type": "string",
+ "description": "The unique identifier of the network to get properties from."
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "parameters": [
+ {
+ "name": "properties",
+ "$ref": "ManagedNetworkProperties",
+ "description": "Results of the query for managed network properties."
+ }
+ ]
+ }
+ ]
+ },
+ {
"name": "getState",
"description": "Gets the cached read-only properties of the network with id networkGuid. This is meant to be a higher performance function than getProperties, which requires a round trip to query the networking subsystem. It only returns a subset of the properties returned by getProperties.",
"parameters": [
diff --git a/chrome/test/data/extensions/api_test/networking/test.js b/chrome/test/data/extensions/api_test/networking/test.js
index 6df1e910..0892c4e 100644
--- a/chrome/test/data/extensions/api_test/networking/test.js
+++ b/chrome/test/data/extensions/api_test/networking/test.js
@@ -25,7 +25,7 @@ var privateHelpers = {
var collectProperties = function(properties) {
var finishTest = function() {
chrome.networkingPrivate.onNetworksChanged.removeListener(
- self.watchForConnect);
+ self.onNetworkChange);
done();
};
var expectedState = expectedStates.pop();
@@ -35,18 +35,19 @@ var privateHelpers = {
};
this.onNetworkChange = function(changes) {
assertEq([network], changes);
- chrome.networkingPrivate.getProperties(network,
- collectProperties.bind(undefined));
+ chrome.networkingPrivate.getProperties(
+ network,
+ callbackPass(collectProperties));
};
chrome.networkingPrivate.onNetworksChanged.addListener(
- this.onNetworkChange);
+ this.onNetworkChange);
},
listListener: function(network, expected, done) {
var self = this;
this.listenForChanges = function(list) {
assertEq(expected, list);
chrome.networkingPrivate.onNetworkListChanged.removeListener(
- self.listenForChanges);
+ self.listenForChanges);
done();
};
}
@@ -78,7 +79,6 @@ var availableTests = [
chrome.networkingPrivate.getVisibleNetworks(
"All",
callbackPass(function(result) {
- assertTrue(!!result);
assertEq([{
"ConnectionState": "Connected",
"GUID": "stub_ethernet",
@@ -109,6 +109,7 @@ var availableTests = [
},
{
"Cellular": {
+ "ActivateOverNonCellularNetwork": false,
"ActivationState": "not-activated",
"NetworkTechnology": "GSM",
"RoamingState": "home"
@@ -133,7 +134,6 @@ var availableTests = [
chrome.networkingPrivate.getVisibleNetworks(
"WiFi",
callbackPass(function(result) {
- assertTrue(!!result);
assertEq([{
"ConnectionState": "Connected",
"GUID": "stub_wifi1",
@@ -176,7 +176,6 @@ var availableTests = [
chrome.networkingPrivate.getProperties(
"stub_wifi2",
callbackPass(function(result) {
- assertTrue(!!result);
assertEq({
"ConnectionState": "NotConnected",
"GUID": "stub_wifi2",
@@ -190,22 +189,70 @@ var availableTests = [
}, result);
}));
},
+ function getManagedProperties() {
+ chrome.networkingPrivate.getManagedProperties(
+ "stub_wifi2",
+ callbackPass(function(result) {
+ assertEq({
+ "ConnectionState": {
+ "Active": "NotConnected",
+ "Effective": "Unmanaged"
+ },
+ "GUID": "stub_wifi2",
+ "Name": {
+ "Active": "wifi2_PSK",
+ "Effective": "UserPolicy",
+ "UserPolicy": "My WiFi Network"
+ },
+ "Type": {
+ "Active": "WiFi",
+ "Effective": "UserPolicy",
+ "UserPolicy": "WiFi"
+ },
+ "WiFi": {
+ "AutoConnect": {
+ "Active": false,
+ "UserEditable": true
+ },
+ "Passphrase": {
+ "Effective": "UserSetting",
+ "UserEditable": true,
+ "UserSetting": "FAKE_CREDENTIAL_VPaJDV9x"
+ },
+ "SSID": {
+ "Active": "stub_wifi2",
+ "Effective": "UserPolicy",
+ "UserPolicy": "stub_wifi2"
+ },
+ "Security": {
+ "Active": "WPA-PSK",
+ "Effective": "UserPolicy",
+ "UserPolicy": "WPA-PSK"
+ },
+ "SignalStrength": {
+ "Active": 80,
+ "Effective": "Unmanaged"
+ }
+ }
+ }, result);
+ }));
+ },
function setProperties() {
var done = chrome.test.callbackAdded();
chrome.networkingPrivate.getProperties(
"stub_wifi2",
- function(result) {
+ callbackPass(function(result) {
result.WiFi.Security = "WEP-PSK";
chrome.networkingPrivate.setProperties("stub_wifi2", result,
- function() {
+ callbackPass(function() {
chrome.networkingPrivate.getProperties(
"stub_wifi2",
- function(result) {
+ callbackPass(function(result) {
assertEq("WEP-PSK", result.WiFi.Security);
done();
- });
- });
- });
+ }));
+ }));
+ }));
},
function getState() {
chrome.networkingPrivate.getState(
@@ -213,7 +260,7 @@ var availableTests = [
callbackPass(function(result) {
assertEq({
"ConnectionState": "NotConnected",
- "GUID": "",
+ "GUID": "stub_wifi2",
"Name": "wifi2_PSK",
"Type": "WiFi",
"WiFi": {
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index 4831537..5f9df89 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -365,6 +365,8 @@
'dbus/mock_system_clock_client.h',
'dbus/mock_update_engine_client.cc',
'dbus/mock_update_engine_client.h',
+ 'dbus/shill_profile_client_stub.cc',
+ 'dbus/shill_profile_client_stub.h',
'disks/mock_disk_mount_manager.cc',
'disks/mock_disk_mount_manager.h',
'ime/mock_component_extension_ime_manager_delegate.cc',
@@ -461,6 +463,7 @@
'login/login_state_unittest.cc',
'network/cros_network_functions_unittest.cc',
'network/geolocation_handler_unittest.cc',
+ 'network/managed_network_configuration_handler_unittest.cc',
'network/network_change_notifier_chromeos_unittest.cc',
'network/network_configuration_handler_unittest.cc',
'network/network_event_log_unittest.cc',
diff --git a/chromeos/dbus/mock_shill_manager_client.cc b/chromeos/dbus/mock_shill_manager_client.cc
index 2016e2b..309b48e 100644
--- a/chromeos/dbus/mock_shill_manager_client.cc
+++ b/chromeos/dbus/mock_shill_manager_client.cc
@@ -4,6 +4,8 @@
#include "chromeos/dbus/mock_shill_manager_client.h"
+#include "dbus/object_path.h"
+
namespace chromeos {
MockShillManagerClient::MockShillManagerClient() {}
diff --git a/chromeos/dbus/mock_shill_manager_client.h b/chromeos/dbus/mock_shill_manager_client.h
index 57f2449..d507762 100644
--- a/chromeos/dbus/mock_shill_manager_client.h
+++ b/chromeos/dbus/mock_shill_manager_client.h
@@ -41,6 +41,11 @@ class MockShillManagerClient : public ShillManagerClient {
MOCK_METHOD3(ConfigureService, void(const base::DictionaryValue& properties,
const ObjectPathCallback& callback,
const ErrorCallback& error_callback));
+ MOCK_METHOD4(ConfigureServiceForProfile,
+ void(const dbus::ObjectPath& profile_path,
+ const base::DictionaryValue& properties,
+ const ObjectPathCallback& callback,
+ const ErrorCallback& error_callback));
MOCK_METHOD3(GetService, void(const base::DictionaryValue& properties,
const ObjectPathCallback& callback,
const ErrorCallback& error_callback));
diff --git a/chromeos/dbus/mock_shill_profile_client.h b/chromeos/dbus/mock_shill_profile_client.h
index 078bb60..b18a843 100644
--- a/chromeos/dbus/mock_shill_profile_client.h
+++ b/chromeos/dbus/mock_shill_profile_client.h
@@ -39,6 +39,7 @@ class MockShillProfileClient : public ShillProfileClient {
const std::string& entry_path,
const base::Closure& callback,
const ErrorCallback& error_callback));
+ MOCK_METHOD0(GetTestInterface, TestInterface*());
};
} // namespace chromeos
diff --git a/chromeos/dbus/shill_device_client.h b/chromeos/dbus/shill_device_client.h
index e865753..6a3fb35 100644
--- a/chromeos/dbus/shill_device_client.h
+++ b/chromeos/dbus/shill_device_client.h
@@ -55,7 +55,7 @@ class CHROMEOS_EXPORT ShillDeviceClient {
virtual std::string GetDevicePathForType(const std::string& type) = 0;
protected:
- ~TestInterface() {}
+ virtual ~TestInterface() {}
};
virtual ~ShillDeviceClient();
diff --git a/chromeos/dbus/shill_manager_client.cc b/chromeos/dbus/shill_manager_client.cc
index 1be4bf2..c5f05ff 100644
--- a/chromeos/dbus/shill_manager_client.cc
+++ b/chromeos/dbus/shill_manager_client.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/chromeos/chromeos_version.h"
+#include "base/logging.h"
#include "base/message_loop.h"
#include "base/values.h"
#include "chromeos/dbus/shill_manager_client_stub.h"
@@ -21,13 +22,41 @@ namespace chromeos {
namespace {
+const char kIncompleteServiceProperties[] = "Error.IncompleteServiceProperties";
+const char kIncompleteServicePropertiesMessage[] =
+ "Service properties are incomplete.";
+
// Returns whether the properties have the required keys or not.
-bool AreServicePropertiesValid(const base::DictionaryValue& properties) {
- if (properties.HasKey(flimflam::kGuidProperty))
+bool AreServicePropertiesValidWithMode(
+ const base::DictionaryValue& properties,
+ const ShillManagerClient::ErrorCallback& error_callback) {
+ if (properties.HasKey(flimflam::kGuidProperty) ||
+ (properties.HasKey(flimflam::kTypeProperty) &&
+ properties.HasKey(flimflam::kSecurityProperty) &&
+ properties.HasKey(flimflam::kModeProperty) &&
+ properties.HasKey(flimflam::kSSIDProperty))) {
return true;
- return properties.HasKey(flimflam::kTypeProperty) &&
- properties.HasKey(flimflam::kSecurityProperty) &&
- properties.HasKey(flimflam::kSSIDProperty);
+ }
+ error_callback.Run(kIncompleteServiceProperties,
+ kIncompleteServicePropertiesMessage);
+ return false;
+}
+
+// DEPRECATED: Keep this only for backward compatibility with NetworkLibrary.
+// Returns whether the properties have the required keys or not.
+// TODO(pneubeck): remove this once NetworkLibrary is gone (crbug/230799).
+bool AreServicePropertiesValid(
+ const base::DictionaryValue& properties,
+ const ShillManagerClient::ErrorCallback& error_callback) {
+ if (properties.HasKey(flimflam::kGuidProperty) ||
+ (properties.HasKey(flimflam::kTypeProperty) &&
+ properties.HasKey(flimflam::kSecurityProperty) &&
+ properties.HasKey(flimflam::kSSIDProperty))) {
+ return true;
+ }
+ error_callback.Run(kIncompleteServiceProperties,
+ kIncompleteServicePropertiesMessage);
+ return false;
}
// Appends a string-to-variant dictionary to the writer.
@@ -146,7 +175,10 @@ class ShillManagerClientImpl : public ShillManagerClient {
const base::DictionaryValue& properties,
const ObjectPathCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
- DCHECK(AreServicePropertiesValid(properties));
+ if (!AreServicePropertiesValid(properties, error_callback)) {
+ NOTREACHED() << kIncompleteServicePropertiesMessage;
+ return;
+ }
dbus::MethodCall method_call(flimflam::kFlimflamManagerInterface,
flimflam::kConfigureServiceFunction);
dbus::MessageWriter writer(&method_call);
@@ -156,6 +188,25 @@ class ShillManagerClientImpl : public ShillManagerClient {
error_callback);
}
+ virtual void ConfigureServiceForProfile(
+ const dbus::ObjectPath& profile_path,
+ const base::DictionaryValue& properties,
+ const ObjectPathCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE {
+ if (!AreServicePropertiesValidWithMode(properties, error_callback)) {
+ NOTREACHED() << kIncompleteServicePropertiesMessage;
+ return;
+ }
+ dbus::MethodCall method_call(flimflam::kFlimflamManagerInterface,
+ shill::kConfigureServiceForProfileFunction);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendObjectPath(dbus::ObjectPath(profile_path));
+ AppendServicePropertiesDictionary(&writer, properties);
+ helper_.CallObjectPathMethodWithErrorCallback(&method_call,
+ callback,
+ error_callback);
+ }
+
virtual void GetService(
const base::DictionaryValue& properties,
const ObjectPathCallback& callback,
diff --git a/chromeos/dbus/shill_manager_client.h b/chromeos/dbus/shill_manager_client.h
index a67113d..80116bd 100644
--- a/chromeos/dbus/shill_manager_client.h
+++ b/chromeos/dbus/shill_manager_client.h
@@ -8,14 +8,15 @@
#include <string>
#include "base/basictypes.h"
-#include "base/callback.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/dbus/dbus_client_implementation_type.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
#include "chromeos/dbus/shill_client_helper.h"
namespace dbus {
class Bus;
+class ObjectPath;
} // namespace dbus
@@ -59,7 +60,7 @@ class CHROMEOS_EXPORT ShillManagerClient {
virtual void ClearProperties() = 0;
protected:
- ~TestInterface() {}
+ virtual ~TestInterface() {}
};
virtual ~ShillManagerClient();
@@ -125,6 +126,14 @@ class CHROMEOS_EXPORT ShillManagerClient {
const ObjectPathCallback& callback,
const ErrorCallback& error_callback) = 0;
+ // Calls ConfigureServiceForProfile method.
+ // |callback| is called with the created service if the method call succeeds.
+ virtual void ConfigureServiceForProfile(
+ const dbus::ObjectPath& profile_path,
+ const base::DictionaryValue& properties,
+ const ObjectPathCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
// Calls GetService method.
// |callback| is called after the method call succeeds.
virtual void GetService(const base::DictionaryValue& properties,
diff --git a/chromeos/dbus/shill_manager_client_stub.cc b/chromeos/dbus/shill_manager_client_stub.cc
index 9350076..d77dab6 100644
--- a/chromeos/dbus/shill_manager_client_stub.cc
+++ b/chromeos/dbus/shill_manager_client_stub.cc
@@ -12,6 +12,7 @@
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_device_client.h"
+#include "chromeos/dbus/shill_profile_client.h"
#include "chromeos/dbus/shill_property_changed_observer.h"
#include "chromeos/dbus/shill_service_client.h"
#include "dbus/bus.h"
@@ -182,9 +183,6 @@ void ShillManagerClientStub::ConfigureService(
if (callback.is_null())
return;
- // For the purposes of this stub, we're going to assume that the GUID property
- // is set to the service path because we don't want to re-implement Shill's
- // property matching magic here.
ShillServiceClient::TestInterface* service_client =
DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
@@ -199,34 +197,57 @@ void ShillManagerClientStub::ConfigureService(
return;
}
+ // For the purposes of this stub, we're going to assume that the GUID property
+ // is set to the service path because we don't want to re-implement Shill's
+ // property matching magic here.
+ std::string service_path = guid;
+
std::string ipconfig_path;
properties.GetString(shill::kIPConfigProperty, &ipconfig_path);
- // Add the service to the service client stub if not already there.
- service_client->AddServiceWithIPConfig(guid, guid, type, flimflam::kStateIdle,
- ipconfig_path, true);
// Merge the new properties with existing properties, if any.
- scoped_ptr<base::DictionaryValue> merged_properties;
const base::DictionaryValue* existing_properties =
- service_client->GetServiceProperties(guid);
- if (existing_properties) {
- merged_properties.reset(existing_properties->DeepCopy());
- } else {
- merged_properties.reset(new base::DictionaryValue);
+ service_client->GetServiceProperties(service_path);
+ if (!existing_properties) {
+ // Add a new service to the service client stub because none exists, yet.
+ service_client->AddServiceWithIPConfig(service_path, guid, type,
+ flimflam::kStateIdle, ipconfig_path,
+ true); // Add service to watch list.
+ existing_properties = service_client->GetServiceProperties(service_path);
}
+
+ scoped_ptr<base::DictionaryValue> merged_properties(
+ existing_properties->DeepCopy());
merged_properties->MergeDictionary(&properties);
// Now set all the properties.
for (base::DictionaryValue::Iterator iter(*merged_properties);
!iter.IsAtEnd(); iter.Advance()) {
- service_client->SetServiceProperty(guid, iter.key(), iter.value());
+ service_client->SetServiceProperty(service_path, iter.key(), iter.value());
}
+ ShillProfileClient::TestInterface* profile_test =
+ DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
+ profile_test->AddService(service_path);
+
MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(callback, dbus::ObjectPath(guid)));
+ FROM_HERE, base::Bind(callback, dbus::ObjectPath(service_path)));
+}
+
+void ShillManagerClientStub::ConfigureServiceForProfile(
+ const dbus::ObjectPath& profile_path,
+ const base::DictionaryValue& properties,
+ const ObjectPathCallback& callback,
+ const ErrorCallback& error_callback) {
+ std::string profile_property;
+ properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty,
+ &profile_property);
+ CHECK(profile_property == profile_path.value());
+ ConfigureService(properties, callback, error_callback);
}
+
void ShillManagerClientStub::GetService(
const base::DictionaryValue& properties,
const ObjectPathCallback& callback,
diff --git a/chromeos/dbus/shill_manager_client_stub.h b/chromeos/dbus/shill_manager_client_stub.h
index f80362f..314713f 100644
--- a/chromeos/dbus/shill_manager_client_stub.h
+++ b/chromeos/dbus/shill_manager_client_stub.h
@@ -50,6 +50,11 @@ class ShillManagerClientStub : public ShillManagerClient,
const base::DictionaryValue& properties,
const ObjectPathCallback& callback,
const ErrorCallback& error_callback) OVERRIDE;
+ virtual void ConfigureServiceForProfile(
+ const dbus::ObjectPath& profile_path,
+ const base::DictionaryValue& properties,
+ const ObjectPathCallback& callback,
+ const ErrorCallback& error_callback) OVERRIDE;
virtual void GetService(
const base::DictionaryValue& properties,
const ObjectPathCallback& callback,
diff --git a/chromeos/dbus/shill_profile_client.cc b/chromeos/dbus/shill_profile_client.cc
index a86ff78..511a22e 100644
--- a/chromeos/dbus/shill_profile_client.cc
+++ b/chromeos/dbus/shill_profile_client.cc
@@ -20,12 +20,10 @@ namespace chromeos {
namespace {
-// The ShillProfileClient implementation.
class ShillProfileClientImpl : public ShillProfileClient {
public:
explicit ShillProfileClientImpl(dbus::Bus* bus);
- /////////////////////////////////////
// ShillProfileClient overrides.
virtual void AddPropertyChangedObserver(
const dbus::ObjectPath& profile_path,
@@ -51,6 +49,10 @@ class ShillProfileClientImpl : public ShillProfileClient {
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
+ virtual TestInterface* GetTestInterface() OVERRIDE {
+ return NULL;
+ }
+
private:
typedef std::map<std::string, ShillClientHelper*> HelperMap;
diff --git a/chromeos/dbus/shill_profile_client.h b/chromeos/dbus/shill_profile_client.h
index 2c45ac7..4d653ff 100644
--- a/chromeos/dbus/shill_profile_client.h
+++ b/chromeos/dbus/shill_profile_client.h
@@ -41,6 +41,20 @@ class CHROMEOS_EXPORT ShillProfileClient {
DictionaryValueCallbackWithoutStatus;
typedef ShillClientHelper::ErrorCallback ErrorCallback;
+ // Interface for setting up services for testing. Accessed through
+ // GetTestInterface(), only implemented in the stub implementation.
+ class TestInterface {
+ public:
+ virtual void AddProfile(const std::string& profile_path) = 0;
+ virtual void AddEntry(const std::string& profile_path,
+ const std::string& entry_path,
+ const base::DictionaryValue& properties) = 0;
+ virtual bool AddService(const std::string& service_path) = 0;
+
+ protected:
+ virtual ~TestInterface() {}
+ };
+
virtual ~ShillProfileClient();
// Factory function, creates a new instance which is owned by the caller.
@@ -79,6 +93,9 @@ class CHROMEOS_EXPORT ShillProfileClient {
const base::Closure& callback,
const ErrorCallback& error_callback) = 0;
+ // Returns an interface for testing (stub only), or returns NULL.
+ virtual TestInterface* GetTestInterface() = 0;
+
protected:
// Create() should be used instead.
ShillProfileClient();
diff --git a/chromeos/dbus/shill_profile_client_stub.cc b/chromeos/dbus/shill_profile_client_stub.cc
index 9b427bb..e249cd5 100644
--- a/chromeos/dbus/shill_profile_client_stub.cc
+++ b/chromeos/dbus/shill_profile_client_stub.cc
@@ -5,10 +5,13 @@
#include "chromeos/dbus/shill_profile_client_stub.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/message_loop.h"
#include "base/stl_util.h"
#include "base/values.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_property_changed_observer.h"
+#include "chromeos/dbus/shill_service_client.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
@@ -17,7 +20,38 @@
namespace chromeos {
-ShillProfileClientStub::ShillProfileClientStub() : weak_ptr_factory_(this) {
+namespace {
+
+void PassEmptyDictionary(
+ const ShillProfileClient::DictionaryValueCallbackWithoutStatus& callback) {
+ base::DictionaryValue dictionary;
+ if (callback.is_null())
+ return;
+ callback.Run(dictionary);
+}
+
+void PassDictionary(
+ const ShillProfileClient::DictionaryValueCallbackWithoutStatus& callback,
+ const base::DictionaryValue* dictionary) {
+ if (callback.is_null())
+ return;
+ callback.Run(*dictionary);
+}
+
+base::DictionaryValue* GetOrCreateDictionary(const std::string& key,
+ base::DictionaryValue* dict) {
+ base::DictionaryValue* nested_dict = NULL;
+ dict->GetDictionaryWithoutPathExpansion(key, &nested_dict);
+ if (!nested_dict) {
+ nested_dict = new base::DictionaryValue;
+ dict->SetWithoutPathExpansion(key, nested_dict);
+ }
+ return nested_dict;
+}
+
+} // namespace
+
+ShillProfileClientStub::ShillProfileClientStub() {
}
ShillProfileClientStub::~ShillProfileClientStub() {
@@ -37,13 +71,21 @@ void ShillProfileClientStub::GetProperties(
const dbus::ObjectPath& profile_path,
const DictionaryValueCallbackWithoutStatus& callback,
const ErrorCallback& error_callback) {
- if (callback.is_null())
+ base::DictionaryValue* profile = GetProfile(profile_path, error_callback);
+ if (!profile)
return;
+
+ scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue);
+ base::ListValue* entry_paths = new base::ListValue;
+ properties->SetWithoutPathExpansion(flimflam::kEntriesProperty, entry_paths);
+ for (base::DictionaryValue::Iterator it(*profile); !it.IsAtEnd();
+ it.Advance()) {
+ entry_paths->AppendString(it.key());
+ }
+
MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&ShillProfileClientStub::PassEmptyDictionaryValue,
- weak_ptr_factory_.GetWeakPtr(),
- callback));
+ base::Bind(&PassDictionary, callback, base::Owned(properties.release())));
}
void ShillProfileClientStub::GetEntry(
@@ -51,28 +93,83 @@ void ShillProfileClientStub::GetEntry(
const std::string& entry_path,
const DictionaryValueCallbackWithoutStatus& callback,
const ErrorCallback& error_callback) {
- if (callback.is_null())
+ base::DictionaryValue* profile = GetProfile(profile_path, error_callback);
+ if (!profile)
+ return;
+
+ base::DictionaryValue* entry = NULL;
+ profile->GetDictionaryWithoutPathExpansion(entry_path, &entry);
+ if (!entry) {
+ error_callback.Run("Error.InvalidProfileEntry", "Invalid profile entry");
return;
+ }
+
MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&ShillProfileClientStub::PassEmptyDictionaryValue,
- weak_ptr_factory_.GetWeakPtr(),
- callback));
+ base::Bind(&PassDictionary, callback, base::Owned(entry->DeepCopy())));
}
void ShillProfileClientStub::DeleteEntry(const dbus::ObjectPath& profile_path,
const std::string& entry_path,
const base::Closure& callback,
const ErrorCallback& error_callback) {
- if (callback.is_null())
+ base::DictionaryValue* profile = GetProfile(profile_path, error_callback);
+ if (!profile)
return;
+
+ if (!profile->RemoveWithoutPathExpansion(entry_path, NULL)) {
+ error_callback.Run("Error.InvalidProfileEntry", "Invalid profile entry");
+ return;
+ }
+
MessageLoop::current()->PostTask(FROM_HERE, callback);
}
-void ShillProfileClientStub::PassEmptyDictionaryValue(
- const DictionaryValueCallbackWithoutStatus& callback) const {
- base::DictionaryValue dictionary;
- callback.Run(dictionary);
+ShillProfileClient::TestInterface* ShillProfileClientStub::GetTestInterface() {
+ return this;
+}
+
+void ShillProfileClientStub::AddProfile(const std::string& profile_path) {
+ profile_entries_.SetWithoutPathExpansion(profile_path,
+ new base::DictionaryValue);
+}
+
+void ShillProfileClientStub::AddEntry(const std::string& profile_path,
+ const std::string& entry_path,
+ const base::DictionaryValue& properties) {
+ base::DictionaryValue* profile = GetOrCreateDictionary(profile_path,
+ &profile_entries_);
+ profile->SetWithoutPathExpansion(entry_path,
+ properties.DeepCopy());
+}
+
+bool ShillProfileClientStub::AddService(const std::string& service_path) {
+ ShillServiceClient::TestInterface* service_test =
+ DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
+ const base::DictionaryValue* properties =
+ service_test->GetServiceProperties(service_path);
+ std::string profile_path;
+ if (!properties)
+ return false;
+
+ properties->GetStringWithoutPathExpansion(flimflam::kProfileProperty,
+ &profile_path);
+ if (profile_path.empty())
+ return false;
+
+ AddEntry(profile_path, service_path, *properties);
+ return true;
+}
+
+base::DictionaryValue* ShillProfileClientStub::GetProfile(
+ const dbus::ObjectPath& profile_path,
+ const ErrorCallback& error_callback) {
+ base::DictionaryValue* profile = NULL;
+ profile_entries_.GetDictionaryWithoutPathExpansion(profile_path.value(),
+ &profile);
+ if (!profile)
+ error_callback.Run("Error.InvalidProfile", "Invalid profile");
+ return profile;
}
} // namespace chromeos
diff --git a/chromeos/dbus/shill_profile_client_stub.h b/chromeos/dbus/shill_profile_client_stub.h
index b26b5a7..efc86ce 100644
--- a/chromeos/dbus/shill_profile_client_stub.h
+++ b/chromeos/dbus/shill_profile_client_stub.h
@@ -13,7 +13,8 @@
namespace chromeos {
// A stub implementation of ShillProfileClient.
-class ShillProfileClientStub : public ShillProfileClient {
+class ShillProfileClientStub : public ShillProfileClient,
+ public ShillProfileClient::TestInterface {
public:
ShillProfileClientStub();
virtual ~ShillProfileClientStub();
@@ -37,14 +38,21 @@ class ShillProfileClientStub : public ShillProfileClient {
const std::string& entry_path,
const base::Closure& callback,
const ErrorCallback& error_callback) OVERRIDE;
+ virtual ShillProfileClient::TestInterface* GetTestInterface() OVERRIDE;
+
+ // ShillProfileClient::TestInterface overrides.
+ virtual void AddProfile(const std::string& profile_path) OVERRIDE;
+ virtual void AddEntry(const std::string& profile_path,
+ const std::string& entry_path,
+ const base::DictionaryValue& properties) OVERRIDE;
+ virtual bool AddService(const std::string& service_path) OVERRIDE;
private:
- void PassEmptyDictionaryValue(
- const DictionaryValueCallbackWithoutStatus& callback) const;
+ base::DictionaryValue* GetProfile(const dbus::ObjectPath& profile_path,
+ const ErrorCallback& error_callback);
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<ShillProfileClientStub> weak_ptr_factory_;
+ // This maps profile path -> entry path -> Shill properties.
+ base::DictionaryValue profile_entries_;
DISALLOW_COPY_AND_ASSIGN(ShillProfileClientStub);
};
diff --git a/chromeos/dbus/shill_service_client.h b/chromeos/dbus/shill_service_client.h
index 05713be..1a96fa4 100644
--- a/chromeos/dbus/shill_service_client.h
+++ b/chromeos/dbus/shill_service_client.h
@@ -64,7 +64,7 @@ class CHROMEOS_EXPORT ShillServiceClient {
virtual void ClearServices() = 0;
protected:
- ~TestInterface() {}
+ virtual ~TestInterface() {}
};
virtual ~ShillServiceClient();
diff --git a/chromeos/dbus/shill_service_client_stub.cc b/chromeos/dbus/shill_service_client_stub.cc
index 3b8f1de..677f9d6 100644
--- a/chromeos/dbus/shill_service_client_stub.cc
+++ b/chromeos/dbus/shill_service_client_stub.cc
@@ -32,6 +32,13 @@ void PassStubListValue(const ShillServiceClient::ListValueCallback& callback,
callback.Run(*value);
}
+void PassStubServiceProperties(
+ const ShillServiceClient::DictionaryValueCallback& callback,
+ DBusMethodCallStatus call_status,
+ const base::DictionaryValue* properties) {
+ callback.Run(call_status, *properties);
+}
+
} // namespace
ShillServiceClientStub::ShillServiceClientStub() : weak_ptr_factory_(this) {
@@ -62,12 +69,29 @@ void ShillServiceClientStub::GetProperties(
const DictionaryValueCallback& callback) {
if (callback.is_null())
return;
+
+ base::DictionaryValue* nested_dict = NULL;
+ scoped_ptr<base::DictionaryValue> result_properties;
+ DBusMethodCallStatus call_status;
+ stub_services_.GetDictionaryWithoutPathExpansion(service_path.value(),
+ &nested_dict);
+ if (nested_dict) {
+ result_properties.reset(nested_dict->DeepCopy());
+ // Remove credentials that Shill wouldn't send.
+ result_properties->RemoveWithoutPathExpansion(flimflam::kPassphraseProperty,
+ NULL);
+ call_status = DBUS_METHOD_CALL_SUCCESS;
+ } else {
+ result_properties.reset(new base::DictionaryValue);
+ call_status = DBUS_METHOD_CALL_FAILURE;
+ }
+
MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&ShillServiceClientStub::PassStubServiceProperties,
- weak_ptr_factory_.GetWeakPtr(),
- service_path,
- callback));
+ base::Bind(&PassStubServiceProperties,
+ callback,
+ call_status,
+ base::Owned(result_properties.release())));
}
void ShillServiceClientStub::SetProperty(const dbus::ObjectPath& service_path,
@@ -77,7 +101,7 @@ void ShillServiceClientStub::SetProperty(const dbus::ObjectPath& service_path,
const ErrorCallback& error_callback) {
base::DictionaryValue* dict = NULL;
if (!stub_services_.GetDictionaryWithoutPathExpansion(
- service_path.value(), &dict)) {
+ service_path.value(), &dict)) {
error_callback.Run("Error.InvalidService", "Invalid Service");
return;
}
@@ -374,19 +398,6 @@ void ShillServiceClientStub::SetDefaultProperties() {
add_to_watchlist);
}
-void ShillServiceClientStub::PassStubServiceProperties(
- const dbus::ObjectPath& service_path,
- const DictionaryValueCallback& callback) {
- base::DictionaryValue* dict = NULL;
- if (!stub_services_.GetDictionaryWithoutPathExpansion(
- service_path.value(), &dict)) {
- base::DictionaryValue empty_dictionary;
- callback.Run(DBUS_METHOD_CALL_FAILURE, empty_dictionary);
- return;
- }
- callback.Run(DBUS_METHOD_CALL_SUCCESS, *dict);
-}
-
void ShillServiceClientStub::NotifyObserversPropertyChanged(
const dbus::ObjectPath& service_path,
const std::string& property) {
diff --git a/chromeos/dbus/shill_service_client_stub.h b/chromeos/dbus/shill_service_client_stub.h
index 507f95f..2e9bfdd 100644
--- a/chromeos/dbus/shill_service_client_stub.h
+++ b/chromeos/dbus/shill_service_client_stub.h
@@ -91,8 +91,6 @@ class ShillServiceClientStub : public ShillServiceClient,
typedef ObserverList<ShillPropertyChangedObserver> PropertyObserverList;
void SetDefaultProperties();
- void PassStubServiceProperties(const dbus::ObjectPath& service_path,
- const DictionaryValueCallback& callback);
void NotifyObserversPropertyChanged(const dbus::ObjectPath& service_path,
const std::string& property);
base::DictionaryValue* GetModifiableServiceProperties(
diff --git a/chromeos/network/managed_network_configuration_handler.cc b/chromeos/network/managed_network_configuration_handler.cc
index c88a15e..e41d011 100644
--- a/chromeos/network/managed_network_configuration_handler.cc
+++ b/chromeos/network/managed_network_configuration_handler.cc
@@ -9,21 +9,30 @@
#include "base/bind.h"
#include "base/guid.h"
+#include "base/json/json_writer.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
#include "base/values.h"
#include "chromeos/dbus/dbus_method_call_status.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_manager_client.h"
+#include "chromeos/dbus/shill_profile_client.h"
#include "chromeos/dbus/shill_service_client.h"
#include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_event_log.h"
+#include "chromeos/network/network_handler_callbacks.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/network_ui_data.h"
#include "chromeos/network/onc/onc_constants.h"
+#include "chromeos/network/onc/onc_merger.h"
#include "chromeos/network/onc/onc_signature.h"
#include "chromeos/network/onc/onc_translator.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "chromeos/network/onc/onc_validator.h"
#include "dbus/object_path.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
@@ -37,13 +46,35 @@ const char kLogModule[] = "ManagedNetworkConfigurationHandler";
// These are error strings used for error callbacks. None of these error
// messages are user-facing: they should only appear in logs.
+const char kInvalidUserSettingsMessage[] = "User settings are invalid.";
+const char kInvalidUserSettings[] = "Error.InvalidUserSettings";
+const char kNetworkAlreadyConfiguredMessage[] =
+ "Network is already configured.";
+const char kNetworkAlreadyConfigured[] = "Error.NetworkAlreadyConfigured";
+const char kPoliciesNotInitializedMessage[] = "Policies not initialized.";
+const char kPoliciesNotInitialized[] = "Error.PoliciesNotInitialized";
const char kServicePath[] = "servicePath";
const char kSetOnUnconfiguredNetworkMessage[] =
"Unable to modify properties of an unconfigured network.";
const char kSetOnUnconfiguredNetwork[] = "Error.SetCalledOnUnconfiguredNetwork";
+const char kUIDataErrorMessage[] = "UI data contains errors.";
+const char kUIDataError[] = "Error.UIData";
const char kUnknownServicePathMessage[] = "Service path is unknown.";
const char kUnknownServicePath[] = "Error.UnknownServicePath";
+enum ProfileType {
+ PROFILE_NONE, // Not in any profile.
+ PROFILE_SHARED, // In the shared profile, shared by all users on device.
+ PROFILE_USER // In the user profile, not visible to other users.
+};
+
+const char kSharedProfilePath[] = "/profile/default";
+const char kUserProfilePath[] = "/profile/chronos/shill";
+
+// This fake credential contains a random postfix which is extremly unlikely to
+// be used by any user.
+const char kFakeCredential[] = "FAKE_CREDENTIAL_VPaJDV9x";
+
void RunErrorCallback(const std::string& service_path,
const std::string& error_name,
const std::string& error_message,
@@ -57,7 +88,212 @@ void RunErrorCallback(const std::string& service_path,
error_message)));
}
-void TranslatePropertiesAndRunCallback(
+// Returns the NetworkUIData parsed from the UIData property of
+// |shill_dictionary|. If parsing fails or the field doesn't exist, returns
+// NULL.
+scoped_ptr<NetworkUIData> GetUIData(
+ const base::DictionaryValue& shill_dictionary) {
+ std::string ui_data_blob;
+ if (shill_dictionary.GetStringWithoutPathExpansion(
+ flimflam::kUIDataProperty,
+ &ui_data_blob) &&
+ !ui_data_blob.empty()) {
+ scoped_ptr<base::DictionaryValue> ui_data_dict =
+ onc::ReadDictionaryFromJson(ui_data_blob);
+ if (ui_data_dict)
+ return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
+ else
+ LOG(ERROR) << "UIData is not a valid JSON dictionary.";
+ }
+ return scoped_ptr<NetworkUIData>();
+}
+
+// Sets the UIData property in |shill_dictionary| to the serialization of
+// |ui_data|.
+void SetUIData(const NetworkUIData& ui_data,
+ base::DictionaryValue* shill_dictionary) {
+ base::DictionaryValue ui_data_dict;
+ ui_data.FillDictionary(&ui_data_dict);
+ std::string ui_data_blob;
+ base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
+ shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
+ ui_data_blob);
+}
+
+// A dummy callback to ignore the result of Shill calls.
+void IgnoreString(const std::string& str) {
+}
+
+void LogErrorWithDict(const tracked_objects::Location& from_where,
+ const std::string& error_name,
+ const scoped_ptr<base::DictionaryValue> error_data) {
+ LOG(ERROR) << from_where.ToString() << ": " << error_name;
+}
+
+void LogErrorMessage(const tracked_objects::Location& from_where,
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(ERROR) << from_where.ToString() << ": " << error_message;
+}
+
+// Removes all kFakeCredential values from sensitive fields (determined by
+// onc::FieldIsCredential) of |onc_object|.
+void RemoveFakeCredentials(
+ const onc::OncValueSignature& signature,
+ base::DictionaryValue* onc_object) {
+ base::DictionaryValue::Iterator it(*onc_object);
+ while (!it.IsAtEnd()) {
+ base::Value* value = NULL;
+ std::string field_name = it.key();
+ // We need the non-const entry to remove nested values but DictionaryValue
+ // has no non-const iterator.
+ onc_object->GetWithoutPathExpansion(field_name, &value);
+ // Advance before delete.
+ it.Advance();
+
+ // If |value| is a dictionary, recurse.
+ base::DictionaryValue* nested_object = NULL;
+ if (value->GetAsDictionary(&nested_object)) {
+ const onc::OncFieldSignature* field_signature =
+ onc::GetFieldSignature(signature, field_name);
+
+ RemoveFakeCredentials(*field_signature->value_signature,
+ nested_object);
+ continue;
+ }
+
+ // If |value| is a string, check if it is a fake credential.
+ std::string string_value;
+ if (value->GetAsString(&string_value) &&
+ onc::FieldIsCredential(signature, field_name)) {
+ if (string_value == kFakeCredential) {
+ // The value wasn't modified by the UI, thus we remove the field to keep
+ // the existing value that is stored in Shill.
+ onc_object->RemoveWithoutPathExpansion(field_name, NULL);
+ }
+ // Otherwise, the value is set and modified by the UI, thus we keep that
+ // value to overwrite whatever is stored in Shill.
+ }
+ }
+}
+
+// Creates a Shill property dictionary from the given arguments. The resulting
+// dictionary will be sent to Shill by the caller. Depending on the profile
+// path, |policy| is interpreted as the user or device policy and |settings| as
+// the user or shared settings.
+scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
+ const std::string& profile_path,
+ const std::string& guid,
+ const base::DictionaryValue* policy,
+ const base::DictionaryValue* settings) {
+ scoped_ptr<base::DictionaryValue> effective;
+
+ onc::ONCSource onc_source;
+ if (policy) {
+ if (profile_path == kSharedProfilePath) {
+ effective = onc::MergeSettingsAndPoliciesToEffective(
+ NULL, // no user policy
+ policy, // device policy
+ NULL, // no user settings
+ settings); // shared settings
+ onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
+ } else {
+ effective = onc::MergeSettingsAndPoliciesToEffective(
+ policy, // user policy
+ NULL, // no device policy
+ settings, // user settings
+ NULL); // no shared settings
+ onc_source = onc::ONC_SOURCE_USER_POLICY;
+ }
+ } else if (settings) {
+ effective.reset(settings->DeepCopy());
+ // TODO(pneubeck): change to source ONC_SOURCE_USER
+ onc_source = onc::ONC_SOURCE_NONE;
+ } else {
+ NOTREACHED();
+ onc_source = onc::ONC_SOURCE_NONE;
+ }
+
+ RemoveFakeCredentials(onc::kNetworkConfigurationSignature,
+ effective.get());
+
+ effective->SetStringWithoutPathExpansion(onc::network_config::kGUID, guid);
+
+ scoped_ptr<base::DictionaryValue> shill_dictionary(
+ onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
+ *effective));
+
+ shill_dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
+ profile_path);
+
+ scoped_ptr<NetworkUIData> ui_data;
+ if (policy)
+ ui_data = CreateUIDataFromONC(onc_source, *policy);
+ else
+ ui_data.reset(new NetworkUIData());
+
+ if (settings) {
+ // Shill doesn't know that sensitive data is contained in the UIData
+ // property and might write it into logs or other insecure places. Thus, we
+ // have to remove or mask credentials.
+ //
+ // Shill's GetProperties doesn't return credentials. Masking credentials
+ // instead of just removing them, allows remembering if a credential is set
+ // or not.
+ scoped_ptr<base::DictionaryValue> sanitized_settings(
+ onc::MaskCredentialsInOncObject(onc::kNetworkConfigurationSignature,
+ *settings,
+ kFakeCredential));
+ ui_data->set_user_settings(sanitized_settings.Pass());
+ }
+
+ SetUIData(*ui_data, shill_dictionary.get());
+
+ VLOG(2) << "Created Shill properties: " << *shill_dictionary;
+
+ return shill_dictionary.Pass();
+}
+
+// Returns true if |policy| matches |onc_network_part|. This is should be the
+// only such matching function within Chrome. Shill does such matching in
+// several functions for network identification. For compatibility, we currently
+// should stick to Shill's matching behavior.
+bool IsPolicyMatching(const base::DictionaryValue& policy,
+ const base::DictionaryValue& onc_network_part) {
+ std::string policy_type;
+ policy.GetStringWithoutPathExpansion(onc::network_config::kType,
+ &policy_type);
+ std::string network_type;
+ onc_network_part.GetStringWithoutPathExpansion(onc::network_config::kType,
+ &network_type);
+ if (policy_type != network_type)
+ return false;
+
+ if (network_type != onc::network_type::kWiFi)
+ return false;
+
+ std::string policy_ssid;
+ policy.GetStringWithoutPathExpansion(onc::wifi::kSSID, &policy_ssid);
+ std::string network_ssid;
+ onc_network_part.GetStringWithoutPathExpansion(onc::wifi::kSSID,
+ &network_ssid);
+ return (policy_ssid == network_ssid);
+}
+
+// Returns the policy of |policies| matching |onc_network_part|, if any
+// exists. Returns NULL otherwise.
+const base::DictionaryValue* FindMatchingPolicy(
+ const ManagedNetworkConfigurationHandler::PolicyMap &policies,
+ const base::DictionaryValue& onc_network_part) {
+ for (ManagedNetworkConfigurationHandler::PolicyMap::const_iterator it =
+ policies.begin(); it != policies.end(); ++it) {
+ if (IsPolicyMatching(*it->second, onc_network_part))
+ return it->second;
+ }
+ return NULL;
+}
+
+void TranslatePropertiesToOncAndRunCallback(
const network_handler::DictionaryResultCallback& callback,
const std::string& service_path,
const base::DictionaryValue& shill_properties) {
@@ -94,20 +330,107 @@ ManagedNetworkConfigurationHandler* ManagedNetworkConfigurationHandler::Get() {
return g_configuration_handler_instance;
}
+void ManagedNetworkConfigurationHandler::GetManagedProperties(
+ const std::string& service_path,
+ const network_handler::DictionaryResultCallback& callback,
+ const network_handler::ErrorCallback& error_callback) {
+ if (!user_policies_initialized_ || !device_policies_initialized_) {
+ RunErrorCallback(service_path,
+ kPoliciesNotInitialized,
+ kPoliciesNotInitializedMessage,
+ error_callback);
+ return;
+ }
+ NetworkConfigurationHandler::Get()->GetProperties(
+ service_path,
+ base::Bind(
+ &ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback),
+ error_callback);
+}
+
+void ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback(
+ const network_handler::DictionaryResultCallback& callback,
+ const network_handler::ErrorCallback& error_callback,
+ const std::string& service_path,
+ const base::DictionaryValue& shill_properties) {
+ std::string profile_path;
+ ProfileType profile_type = PROFILE_NONE;
+ if (shill_properties.GetStringWithoutPathExpansion(
+ flimflam::kProfileProperty, &profile_path)) {
+ if (profile_path == kSharedProfilePath)
+ profile_type = PROFILE_SHARED;
+ else if (!profile_path.empty())
+ profile_type = PROFILE_USER;
+ } else {
+ VLOG(1) << "No profile path for service " << service_path << ".";
+ }
+
+ scoped_ptr<NetworkUIData> ui_data = GetUIData(shill_properties);
+
+ const base::DictionaryValue* user_settings = NULL;
+ const base::DictionaryValue* shared_settings = NULL;
+
+ if (ui_data) {
+ if (profile_type == PROFILE_SHARED)
+ shared_settings = ui_data->user_settings();
+ else if (profile_type == PROFILE_USER)
+ user_settings = ui_data->user_settings();
+ } else if (profile_type != PROFILE_NONE) {
+ LOG(WARNING) << "Service " << service_path << " of profile "
+ << profile_path << " contains no or no valid UIData.";
+ // TODO(pneubeck): add a conversion of user configured entries of old
+ // ChromeOS versions. We will have to use a heuristic to determine which
+ // properties _might_ be user configured.
+ }
+
+ scoped_ptr<base::DictionaryValue> active_settings(
+ onc::TranslateShillServiceToONCPart(
+ shill_properties,
+ &onc::kNetworkWithStateSignature));
+
+ std::string guid;
+ active_settings->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+ &guid);
+
+ const base::DictionaryValue* user_policy = NULL;
+ const base::DictionaryValue* device_policy = NULL;
+ if (!guid.empty()) {
+ // We already checked that the policies were initialized. No need to do that
+ // again.
+ if (profile_type == PROFILE_SHARED)
+ device_policy = device_policies_by_guid_[guid];
+ else if (profile_type == PROFILE_USER)
+ user_policy = user_policies_by_guid_[guid];
+ }
+
+ // This call also removes credentials from policies.
+ scoped_ptr<base::DictionaryValue> augmented_properties =
+ onc::MergeSettingsAndPoliciesToAugmented(
+ onc::kNetworkConfigurationSignature,
+ user_policy,
+ device_policy,
+ user_settings,
+ shared_settings,
+ active_settings.get());
+ callback.Run(service_path, *augmented_properties);
+}
+
void ManagedNetworkConfigurationHandler::GetProperties(
const std::string& service_path,
const network_handler::DictionaryResultCallback& callback,
const network_handler::ErrorCallback& error_callback) const {
- // TODO(pneubeck): Merge with policies.
NetworkConfigurationHandler::Get()->GetProperties(
service_path,
- base::Bind(&TranslatePropertiesAndRunCallback, callback),
+ base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
error_callback);
}
void ManagedNetworkConfigurationHandler::SetProperties(
const std::string& service_path,
- const base::DictionaryValue& properties,
+ const base::DictionaryValue& user_settings,
const base::Closure& callback,
const network_handler::ErrorCallback& error_callback) const {
const NetworkState* state =
@@ -118,20 +441,70 @@ void ManagedNetworkConfigurationHandler::SetProperties(
kUnknownServicePath,
kUnknownServicePathMessage,
error_callback);
+ return;
}
+
std::string guid = state->guid();
if (guid.empty()) {
+ // TODO(pneubeck): create an initial configuration in this case. As for
+ // CreateConfiguration, user settings from older ChromeOS versions have to
+ // determined here.
RunErrorCallback(service_path,
kSetOnUnconfiguredNetwork,
kSetOnUnconfiguredNetworkMessage,
error_callback);
+ return;
+ }
+
+ // Validate the ONC dictionary. We are liberal and ignore unknown field
+ // names. User settings are only partial ONC, thus we ignore missing fields.
+ onc::Validator validator(false, // Ignore unknown fields.
+ false, // Ignore invalid recommended field names.
+ false, // Ignore missing fields.
+ false); // This ONC does not comes from policy.
+
+ onc::Validator::Result validation_result;
+ scoped_ptr<base::DictionaryValue> validated_user_settings =
+ validator.ValidateAndRepairObject(
+ &onc::kNetworkConfigurationSignature,
+ user_settings,
+ &validation_result);
+
+ if (validation_result == onc::Validator::INVALID) {
+ LOG(ERROR) << "ONC user settings are invalid and couldn't be repaired.";
+ RunErrorCallback(service_path,
+ kInvalidUserSettings,
+ kInvalidUserSettingsMessage,
+ error_callback);
+ return;
}
+ if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
+ LOG(WARNING) << "Validation of ONC user settings produced warnings.";
- // TODO(pneubeck): Enforce policies.
+ VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
+ << state->profile_path();
+
+ const PolicyMap* policies_by_guid =
+ GetPoliciesForProfile(state->profile_path());
+
+ if (!policies_by_guid) {
+ RunErrorCallback(service_path,
+ kPoliciesNotInitialized,
+ kPoliciesNotInitializedMessage,
+ error_callback);
+ return;
+ }
+
+ const base::DictionaryValue* policy = NULL;
+ PolicyMap::const_iterator it = policies_by_guid->find(guid);
+ if (it != policies_by_guid->end())
+ policy = it->second;
+
+ VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
scoped_ptr<base::DictionaryValue> shill_dictionary(
- onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
- properties));
+ CreateShillConfiguration(state->profile_path(), guid, policy,
+ &user_settings));
NetworkConfigurationHandler::Get()->SetProperties(service_path,
*shill_dictionary,
@@ -143,8 +516,6 @@ void ManagedNetworkConfigurationHandler::Connect(
const std::string& service_path,
const base::Closure& callback,
const network_handler::ErrorCallback& error_callback) const {
- // TODO(pneubeck): Update the user profile with tracked/followed settings of
- // the shared profile.
NetworkConfigurationHandler::Get()->Connect(service_path,
callback,
error_callback);
@@ -163,25 +534,35 @@ void ManagedNetworkConfigurationHandler::CreateConfiguration(
const base::DictionaryValue& properties,
const network_handler::StringResultCallback& callback,
const network_handler::ErrorCallback& error_callback) const {
- scoped_ptr<base::DictionaryValue> modified_properties(
- properties.DeepCopy());
+ std::string profile_path = kUserProfilePath;
+ const PolicyMap* policies_by_guid = GetPoliciesForProfile(profile_path);
- // If there isn't already a GUID attached to these properties, then
- // generate one and add it.
- std::string guid;
- if (!properties.GetString(onc::network_config::kGUID, &guid)) {
- guid = base::GenerateGUID();
- modified_properties->SetStringWithoutPathExpansion(
- onc::network_config::kGUID, guid);
- } else {
- NOTREACHED(); // TODO(pneubeck): Return an error using error_callback.
+ if (!policies_by_guid) {
+ RunErrorCallback("",
+ kPoliciesNotInitialized,
+ kPoliciesNotInitializedMessage,
+ error_callback);
+ return;
+ }
+
+ if (FindMatchingPolicy(*policies_by_guid, properties)) {
+ RunErrorCallback("",
+ kNetworkAlreadyConfigured,
+ kNetworkAlreadyConfiguredMessage,
+ error_callback);
}
- // TODO(pneubeck): Enforce policies.
+ // TODO(pneubeck): In case of WiFi, check that no other configuration for the
+ // same {SSID, mode, security} exists. We don't support such multiple
+ // configurations, yet.
+
+ // Generate a new GUID for this configuration. Ignore the maybe provided GUID
+ // in |properties| as it is not our own and from an untrusted source.
+ std::string guid = base::GenerateGUID();
scoped_ptr<base::DictionaryValue> shill_dictionary(
- onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
- properties));
+ CreateShillConfiguration(profile_path, guid, NULL /*no policy*/,
+ &properties));
NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary,
callback,
@@ -197,10 +578,337 @@ void ManagedNetworkConfigurationHandler::RemoveConfiguration(
error_callback);
}
-ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler() {
+// This class compares (entry point is Run()) |modified_policies| with the
+// existing entries in the provided Shill profile |profile|. It fetches all
+// entries in parallel (GetProfileProperties), compares each entry with the
+// current policies (GetEntry) and adds all missing policies
+// (~PolicyApplicator).
+class ManagedNetworkConfigurationHandler::PolicyApplicator
+ : public base::RefCounted<PolicyApplicator> {
+ public:
+ typedef ManagedNetworkConfigurationHandler::PolicyMap PolicyMap;
+
+ // |modified_policies| must not be NULL and will be empty afterwards.
+ PolicyApplicator(base::WeakPtr<ManagedNetworkConfigurationHandler> handler,
+ const std::string& profile,
+ std::set<std::string>* modified_policies)
+ : handler_(handler),
+ profile_path_(profile) {
+ remaining_policies_.swap(*modified_policies);
+ }
+
+ void Run() {
+ DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
+ dbus::ObjectPath(profile_path_),
+ base::Bind(&PolicyApplicator::GetProfileProperties, this),
+ base::Bind(&LogErrorMessage, FROM_HERE));
+ }
+
+ private:
+ friend class base::RefCounted<PolicyApplicator>;
+
+ void GetProfileProperties(const base::DictionaryValue& profile_properties) {
+ if (!handler_) {
+ LOG(WARNING) << "Handler destructed during policy application to profile "
+ << profile_path_;
+ return;
+ }
+
+ VLOG(2) << "Received properties for profile " << profile_path_;
+ const base::ListValue* entries = NULL;
+ if (!profile_properties.GetListWithoutPathExpansion(
+ flimflam::kEntriesProperty, &entries)) {
+ LOG(ERROR) << "Profile " << profile_path_
+ << " doesn't contain the property "
+ << flimflam::kEntriesProperty;
+ return;
+ }
+
+ for (base::ListValue::const_iterator it = entries->begin();
+ it != entries->end(); ++it) {
+ std::string entry;
+ (*it)->GetAsString(&entry);
+
+ std::ostringstream entry_failure;
+ DBusThreadManager::Get()->GetShillProfileClient()->GetEntry(
+ dbus::ObjectPath(profile_path_),
+ entry,
+ base::Bind(&PolicyApplicator::GetEntry, this, entry),
+ base::Bind(&LogErrorMessage, FROM_HERE));
+ }
+ }
+
+ void GetEntry(const std::string& entry,
+ const base::DictionaryValue& entry_properties) {
+ if (!handler_) {
+ LOG(WARNING) << "Handler destructed during policy application to profile "
+ << profile_path_;
+ return;
+ }
+
+ VLOG(2) << "Received properties for entry " << entry << " of profile "
+ << profile_path_;
+
+ scoped_ptr<base::DictionaryValue> onc_part(
+ onc::TranslateShillServiceToONCPart(
+ entry_properties,
+ &onc::kNetworkWithStateSignature));
+
+ std::string old_guid;
+ if (!onc_part->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+ &old_guid)) {
+ LOG(WARNING) << "Entry " << entry << " of profile " << profile_path_
+ << " doesn't contain a GUID.";
+ // This might be an entry of an older ChromeOS version. Assume it to be
+ // unmanaged.
+ return;
+ }
+
+ scoped_ptr<NetworkUIData> ui_data = GetUIData(entry_properties);
+ if (!ui_data) {
+ VLOG(1) << "Entry " << entry << " of profile " << profile_path_
+ << " contains no or no valid UIData.";
+ // This might be an entry of an older ChromeOS version. Assume it to be
+ // unmanaged.
+ return;
+ }
+
+ bool was_managed =
+ (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY ||
+ ui_data->onc_source() == onc::ONC_SOURCE_USER_POLICY);
+
+ // The relevant policy must have been initialized, otherwise we hadn't Run
+ // this PolicyApplicator.
+ const PolicyMap& policies_by_guid =
+ *handler_->GetPoliciesForProfile(profile_path_);
+
+ const base::DictionaryValue* new_policy = NULL;
+ if (was_managed) {
+ // If we have a GUID that might match a current policy, do a lookup using
+ // that GUID at first. In particular this is necessary, as some networks
+ // can't be matched to policies by properties (e.g. VPN).
+ PolicyMap::const_iterator it = policies_by_guid.find(old_guid);
+ if (it != policies_by_guid.end())
+ new_policy = it->second;
+ }
+
+ if (!new_policy) {
+ // If we didn't find a policy by GUID, still a new policy might match.
+ new_policy = FindMatchingPolicy(policies_by_guid, *onc_part);
+ }
+
+ if (new_policy) {
+ std::string new_guid;
+ new_policy->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+ &new_guid);
+
+ VLOG_IF(1, was_managed && old_guid != new_guid)
+ << "Updating configuration previously managed by policy " << old_guid
+ << " with new policy " << new_guid << ".";
+ VLOG_IF(1, !was_managed)
+ << "Applying policy " << new_guid << " to previously unmanaged "
+ << "configuration.";
+
+ if (old_guid == new_guid &&
+ remaining_policies_.find(new_guid) == remaining_policies_.end()) {
+ VLOG(1) << "Not updating existing managed configuration with guid "
+ << new_guid << " because the policy didn't change.";
+ } else {
+ VLOG_IF(1, old_guid == new_guid)
+ << "Updating previously managed configuration with the updated "
+ << "policy " << new_guid << ".";
+
+ // Update the existing configuration with the maybe changed
+ // policy. Thereby the GUID might change.
+ scoped_ptr<base::DictionaryValue> shill_dictionary =
+ CreateShillConfiguration(profile_path_, new_guid, new_policy,
+ ui_data->user_settings());
+ NetworkConfigurationHandler::Get()->CreateConfiguration(
+ *shill_dictionary,
+ base::Bind(&IgnoreString),
+ base::Bind(&LogErrorWithDict, FROM_HERE));
+ remaining_policies_.erase(new_guid);
+ }
+ } else if (was_managed) {
+ VLOG(1) << "Removing configuration previously managed by policy "
+ << old_guid << ", because the policy was removed.";
+
+ // Remove the entry, because the network was managed but isn't anymore.
+ // Note: An alternative might be to preserve the user settings, but it's
+ // unclear which values originating the policy should be removed.
+ DeleteEntry(entry);
+ } else {
+ VLOG(2) << "Ignore unmanaged entry.";
+
+ // The entry wasn't managed and doesn't match any current policy. Thus
+ // leave it as it is.
+ }
+ }
+
+ void DeleteEntry(const std::string& entry) {
+ DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
+ dbus::ObjectPath(profile_path_),
+ entry,
+ base::Bind(&base::DoNothing),
+ base::Bind(&LogErrorMessage, FROM_HERE));
+ }
+
+ virtual ~PolicyApplicator() {
+ if (remaining_policies_.empty())
+ return;
+
+ VLOG(2) << "Create new managed network configurations in profile"
+ << profile_path_ << ".";
+ // All profile entries were compared to policies. |configureGUIDs_| contains
+ // all matched policies. From the remainder of policies, new configurations
+ // have to be created.
+
+ // The relevant policy must have been initialized, otherwise we hadn't Run
+ // this PolicyApplicator.
+ const PolicyMap& policies_by_guid =
+ *handler_->GetPoliciesForProfile(profile_path_);
+
+ for (std::set<std::string>::iterator it = remaining_policies_.begin();
+ it != remaining_policies_.end(); ++it) {
+ PolicyMap::const_iterator policy_it = policies_by_guid.find(*it);
+ if (policy_it == policies_by_guid.end()) {
+ LOG(ERROR) << "Policy " << *it << " doesn't exist anymore.";
+ continue;
+ }
+
+ const base::DictionaryValue* policy = policy_it->second;
+
+ VLOG(1) << "Creating new configuration managed by policy " << *it
+ << " in profile " << profile_path_ << ".";
+
+ scoped_ptr<base::DictionaryValue> shill_dictionary =
+ CreateShillConfiguration(profile_path_, *it, policy, NULL);
+ NetworkConfigurationHandler::Get()->CreateConfiguration(
+ *shill_dictionary,
+ base::Bind(&IgnoreString),
+ base::Bind(&LogErrorWithDict, FROM_HERE));
+ }
+ }
+
+ std::set<std::string> remaining_policies_;
+ base::WeakPtr<ManagedNetworkConfigurationHandler> handler_;
+ std::string profile_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyApplicator);
+};
+
+void ManagedNetworkConfigurationHandler::SetPolicy(
+ onc::ONCSource onc_source,
+ const base::DictionaryValue& toplevel_onc) {
+ VLOG(1) << "Setting policies for ONC source "
+ << onc::GetSourceAsString(onc_source) << ".";
+
+ // Validate the ONC dictionary. We are liberal and ignore unknown field
+ // names and ignore invalid field names in kRecommended arrays.
+ onc::Validator validator(false, // Ignore unknown fields.
+ false, // Ignore invalid recommended field names.
+ true, // Fail on missing fields.
+ true); // This ONC comes from policy.
+ validator.SetOncSource(onc_source);
+
+ onc::Validator::Result validation_result;
+ scoped_ptr<base::DictionaryValue> onc_validated =
+ validator.ValidateAndRepairObject(
+ &onc::kToplevelConfigurationSignature,
+ toplevel_onc,
+ &validation_result);
+
+ if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
+ LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source)
+ << " produced warnings.";
+ } else if (validation_result == onc::Validator::INVALID ||
+ onc_validated == NULL) {
+ LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
+ << " is invalid and couldn't be repaired.";
+ return;
+ }
+
+ PolicyMap* policies;
+ std::string profile;
+ if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
+ policies = &user_policies_by_guid_;
+ profile = kUserProfilePath;
+ user_policies_initialized_ = true;
+ } else {
+ policies = &device_policies_by_guid_;
+ profile = kSharedProfilePath;
+ device_policies_initialized_ = true;
+ }
+
+ PolicyMap old_policies;
+ policies->swap(old_policies);
+
+ // This stores all GUIDs of policies that have changed or are new.
+ std::set<std::string> modified_policies;
+
+ base::ListValue* network_configurations = NULL;
+ onc_validated->GetListWithoutPathExpansion(
+ onc::toplevel_config::kNetworkConfigurations,
+ &network_configurations);
+
+ if (network_configurations) {
+ while (!network_configurations->empty()) {
+ base::Value* network_value = NULL;
+ // Passes ownership of network_value.
+ network_configurations->Remove(network_configurations->GetSize() - 1,
+ &network_value);
+ const base::DictionaryValue* network = NULL;
+ network_value->GetAsDictionary(&network);
+ std::string guid;
+ network->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+ &guid);
+
+ const base::DictionaryValue* old_entry = old_policies[guid];
+ const base::DictionaryValue*& new_entry = (*policies)[guid];
+ if (new_entry) {
+ LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
+ << " contains several entries for the same GUID "
+ << guid << ".";
+ delete new_entry;
+ }
+ new_entry = network;
+
+ if (!old_entry || !old_entry->Equals(new_entry)) {
+ modified_policies.insert(guid);
+ }
+ }
+ }
+
+ STLDeleteValues(&old_policies);
+
+ scoped_refptr<PolicyApplicator> applicator = new PolicyApplicator(
+ weak_ptr_factory_.GetWeakPtr(),
+ profile,
+ &modified_policies);
+ applicator->Run();
+}
+
+const ManagedNetworkConfigurationHandler::PolicyMap*
+ManagedNetworkConfigurationHandler::GetPoliciesForProfile(
+ const std::string& profile) const {
+ if (profile == kSharedProfilePath) {
+ if (device_policies_initialized_)
+ return &device_policies_by_guid_;
+ } else if (user_policies_initialized_) {
+ return &user_policies_by_guid_;
+ }
+ return NULL;
+}
+
+ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler()
+ : user_policies_initialized_(false),
+ device_policies_initialized_(false),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}
ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() {
+ STLDeleteValues(&user_policies_by_guid_);
+ STLDeleteValues(&device_policies_by_guid_);
}
} // namespace chromeos
diff --git a/chromeos/network/managed_network_configuration_handler.h b/chromeos/network/managed_network_configuration_handler.h
index 76fd02c..5b53fff 100644
--- a/chromeos/network/managed_network_configuration_handler.h
+++ b/chromeos/network/managed_network_configuration_handler.h
@@ -5,14 +5,16 @@
#ifndef CHROMEOS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_H_
#define CHROMEOS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_H_
+#include <map>
#include <string>
-#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/gtest_prod_util.h"
+#include "base/memory/weak_ptr.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/network/network_handler_callbacks.h"
+#include "chromeos/network/onc/onc_constants.h"
namespace base {
class DictionaryValue;
@@ -21,7 +23,7 @@ class DictionaryValue;
namespace chromeos {
// The ManagedNetworkConfigurationHandler class is used to create and configure
-// networks in ChromeOS using ONC.
+// networks in ChromeOS using ONC and takes care of network policies.
//
// Its interface exposes only ONC and should decouple users from Shill.
// Internally it translates ONC to Shill dictionaries and calls through to the
@@ -44,11 +46,11 @@ namespace chromeos {
// error, including a symbolic name for the error and often some error message
// that is suitable for logging. None of the error message text is meant for
// user consumption.
-//
-// TODO(pneubeck): Enforce network policies.
class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler {
public:
+ typedef std::map<std::string, const base::DictionaryValue*> PolicyMap;
+
// Initializes the singleton.
static void Initialize();
@@ -67,6 +69,13 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler {
const network_handler::DictionaryResultCallback& callback,
const network_handler::ErrorCallback& error_callback) const;
+ // Provides the managed properties of the network with |service_path| to
+ // |callback|.
+ void GetManagedProperties(
+ const std::string& service_path,
+ const network_handler::DictionaryResultCallback& callback,
+ const network_handler::ErrorCallback& error_callback);
+
// Sets the user's settings of an already configured network with
// |service_path|. A network can be initially configured by calling
// CreateConfiguration or if it is managed by a policy. The given properties
@@ -74,7 +83,7 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler {
// properties.
void SetProperties(
const std::string& service_path,
- const base::DictionaryValue& properties,
+ const base::DictionaryValue& user_settings,
const base::Closure& callback,
const network_handler::ErrorCallback& error_callback) const;
@@ -109,10 +118,38 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler {
const base::Closure& callback,
const network_handler::ErrorCallback& error_callback) const;
+ // Only to be called by NetworkConfigurationUpdater or from tests.
+ // Sets |toplevel_onc| as the current policy of |onc_source|. The network
+ // configurations of the policy will be applied (not necessarily immediately)
+ // to Shill's profiles and enforced in future configurations until the policy
+ // associated with |onc_source| is changed again with this function.
+ void SetPolicy(onc::ONCSource onc_source,
+ const base::DictionaryValue& toplevel_onc);
+
private:
+ class PolicyApplicator;
+
ManagedNetworkConfigurationHandler();
~ManagedNetworkConfigurationHandler();
+ void GetManagedPropertiesCallback(
+ const network_handler::DictionaryResultCallback& callback,
+ const network_handler::ErrorCallback& error_callback,
+ const std::string& service_path,
+ const base::DictionaryValue& shill_properties);
+
+ const PolicyMap* GetPoliciesForProfile(const std::string& profile) const;
+
+ // The entries of these maps are owned by this class and are explicitly
+ // deleted where necessary.
+ PolicyMap user_policies_by_guid_;
+ PolicyMap device_policies_by_guid_;
+ bool user_policies_initialized_;
+ bool device_policies_initialized_;
+
+ // For Shill client callbacks
+ base::WeakPtrFactory<ManagedNetworkConfigurationHandler> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ManagedNetworkConfigurationHandler);
};
diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc
new file mode 100644
index 0000000..49c150a
--- /dev/null
+++ b/chromeos/network/managed_network_configuration_handler_unittest.cc
@@ -0,0 +1,314 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/network/managed_network_configuration_handler.h"
+
+#include <iostream>
+#include <sstream>
+
+#include "base/message_loop.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/mock_dbus_thread_manager.h"
+#include "chromeos/dbus/mock_shill_manager_client.h"
+#include "chromeos/dbus/mock_shill_profile_client.h"
+#include "chromeos/dbus/mock_shill_service_client.h"
+#include "chromeos/dbus/shill_profile_client_stub.h"
+#include "chromeos/network/network_configuration_handler.h"
+#include "chromeos/network/onc/onc_test_utils.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "dbus/object_path.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+using ::testing::_;
+
+namespace test_utils = ::chromeos::onc::test_utils;
+
+namespace {
+
+std::string ValueToString(const base::Value* value) {
+ std::stringstream str;
+ str << *value;
+ return str.str();
+}
+
+// Matcher to match base::Value.
+MATCHER_P(IsEqualTo,
+ value,
+ std::string(negation ? "isn't" : "is") + " equal to " +
+ ValueToString(value)) {
+ return value->Equals(&arg);
+}
+
+} // namespace
+
+
+namespace chromeos {
+
+class ManagedNetworkConfigurationHandlerTest : public testing::Test {
+ public:
+ ManagedNetworkConfigurationHandlerTest() {
+ }
+
+ virtual ~ManagedNetworkConfigurationHandlerTest() {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ MockDBusThreadManager* dbus_thread_manager = new MockDBusThreadManager;
+ EXPECT_CALL(*dbus_thread_manager, GetSystemBus())
+ .WillRepeatedly(Return(static_cast<dbus::Bus*>(NULL)));
+ DBusThreadManager::InitializeForTesting(dbus_thread_manager);
+
+ EXPECT_CALL(*dbus_thread_manager, GetShillManagerClient())
+ .WillRepeatedly(Return(&mock_manager_client_));
+ EXPECT_CALL(*dbus_thread_manager, GetShillServiceClient())
+ .WillRepeatedly(Return(&mock_service_client_));
+ EXPECT_CALL(*dbus_thread_manager, GetShillProfileClient())
+ .WillRepeatedly(Return(&mock_profile_client_));
+
+ ON_CALL(mock_profile_client_, GetProperties(_,_,_))
+ .WillByDefault(Invoke(&stub_profile_client_,
+ &ShillProfileClientStub::GetProperties));
+
+ ON_CALL(mock_profile_client_, GetEntry(_,_,_,_))
+ .WillByDefault(Invoke(&stub_profile_client_,
+ &ShillProfileClientStub::GetEntry));
+
+ NetworkConfigurationHandler::Initialize();
+ ManagedNetworkConfigurationHandler::Initialize();
+ message_loop_.RunUntilIdle();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ ManagedNetworkConfigurationHandler::Shutdown();
+ NetworkConfigurationHandler::Shutdown();
+ DBusThreadManager::Shutdown();
+ }
+
+ void SetUpEntry(const std::string& path_to_shill_json,
+ const std::string& profile_path,
+ const std::string& entry_path) {
+ stub_profile_client_.AddEntry(
+ profile_path,
+ entry_path,
+ *test_utils::ReadTestDictionary(path_to_shill_json));
+ }
+
+ void SetPolicy(onc::ONCSource onc_source,
+ const std::string& path_to_onc) {
+ scoped_ptr<base::DictionaryValue> policy;
+ if (path_to_onc.empty())
+ policy = onc::ReadDictionaryFromJson(onc::kEmptyUnencryptedConfiguration);
+ else
+ policy = test_utils::ReadTestDictionary(path_to_onc);
+
+ managed_handler()->SetPolicy(onc::ONC_SOURCE_USER_POLICY, *policy);
+ }
+
+ ManagedNetworkConfigurationHandler* managed_handler() {
+ return ManagedNetworkConfigurationHandler::Get();
+ }
+
+ protected:
+ StrictMock<MockShillManagerClient> mock_manager_client_;
+ StrictMock<MockShillServiceClient> mock_service_client_;
+ StrictMock<MockShillProfileClient> mock_profile_client_;
+ ShillProfileClientStub stub_profile_client_;
+ MessageLoop message_loop_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ManagedNetworkConfigurationHandlerTest);
+};
+
+TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyManageUnconfigured) {
+ scoped_ptr<base::DictionaryValue> expected_shill_properties =
+ test_utils::ReadTestDictionary(
+ "policy/shill_policy_on_unconfigured_wifi1.json");
+
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(dbus::ObjectPath("/profile/chronos/shill"),
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_manager_client_,
+ ConfigureServiceForProfile(
+ dbus::ObjectPath("/profile/chronos/shill"),
+ IsEqualTo(expected_shill_properties.get()),
+ _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "policy/policy_wifi1.onc");
+ message_loop_.RunUntilIdle();
+}
+
+TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmodified) {
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(_, _, _)).Times(1);
+
+ EXPECT_CALL(mock_manager_client_,
+ ConfigureServiceForProfile(_, _, _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "policy/policy_wifi1.onc");
+ message_loop_.RunUntilIdle();
+ Mock::VerifyAndClearExpectations(&mock_profile_client_);
+ Mock::VerifyAndClearExpectations(&mock_manager_client_);
+
+ SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json",
+ "/profile/chronos/shill",
+ "some_entry_path");
+
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(_, _, _)).Times(1);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetEntry(dbus::ObjectPath("/profile/chronos/shill"),
+ "some_entry_path",
+ _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "policy/policy_wifi1.onc");
+ message_loop_.RunUntilIdle();
+}
+
+TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyManageUnmanaged) {
+ SetUpEntry("policy/shill_unmanaged_user_wifi1.json",
+ "/profile/chronos/shill",
+ "old_entry_path");
+
+ scoped_ptr<base::DictionaryValue> expected_shill_properties =
+ test_utils::ReadTestDictionary(
+ "policy/shill_policy_on_unmanaged_user_wifi1.json");
+
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(dbus::ObjectPath("/profile/chronos/shill"),
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetEntry(dbus::ObjectPath("/profile/chronos/shill"),
+ "old_entry_path",
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_manager_client_,
+ ConfigureServiceForProfile(
+ dbus::ObjectPath("/profile/chronos/shill"),
+ IsEqualTo(expected_shill_properties.get()),
+ _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "policy/policy_wifi1.onc");
+ message_loop_.RunUntilIdle();
+}
+
+TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUpdateManagedNewGUID) {
+ SetUpEntry("policy/shill_managed_wifi1.json",
+ "/profile/chronos/shill",
+ "old_entry_path");
+
+ scoped_ptr<base::DictionaryValue> expected_shill_properties =
+ test_utils::ReadTestDictionary(
+ "policy/shill_policy_on_unmanaged_user_wifi1.json");
+
+ // The passphrase isn't sent again, because it's configured by the user and
+ // Shill doesn't sent it on GetProperties calls.
+ expected_shill_properties->RemoveWithoutPathExpansion(
+ flimflam::kPassphraseProperty, NULL);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(dbus::ObjectPath("/profile/chronos/shill"),
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetEntry(dbus::ObjectPath("/profile/chronos/shill"),
+ "old_entry_path",
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_manager_client_,
+ ConfigureServiceForProfile(
+ dbus::ObjectPath("/profile/chronos/shill"),
+ IsEqualTo(expected_shill_properties.get()),
+ _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "policy/policy_wifi1.onc");
+ message_loop_.RunUntilIdle();
+}
+
+TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyReapplyToManaged) {
+ SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json",
+ "/profile/chronos/shill",
+ "old_entry_path");
+
+ scoped_ptr<base::DictionaryValue> expected_shill_properties =
+ test_utils::ReadTestDictionary(
+ "policy/shill_policy_on_unmanaged_user_wifi1.json");
+
+ // The passphrase isn't sent again, because it's configured by the user and
+ // Shill doesn't sent it on GetProperties calls.
+ expected_shill_properties->RemoveWithoutPathExpansion(
+ flimflam::kPassphraseProperty, NULL);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(dbus::ObjectPath("/profile/chronos/shill"),
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetEntry(dbus::ObjectPath("/profile/chronos/shill"),
+ "old_entry_path",
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_manager_client_,
+ ConfigureServiceForProfile(
+ dbus::ObjectPath("/profile/chronos/shill"),
+ IsEqualTo(expected_shill_properties.get()),
+ _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "policy/policy_wifi1.onc");
+ message_loop_.RunUntilIdle();
+}
+
+TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyUnmanageManaged) {
+ SetUpEntry("policy/shill_policy_on_unmanaged_user_wifi1.json",
+ "/profile/chronos/shill",
+ "old_entry_path");
+
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(dbus::ObjectPath("/profile/chronos/shill"),
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetEntry(dbus::ObjectPath("/profile/chronos/shill"),
+ "old_entry_path",
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_profile_client_,
+ DeleteEntry(dbus::ObjectPath("/profile/chronos/shill"),
+ "old_entry_path",
+ _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "");
+ message_loop_.RunUntilIdle();
+}
+
+TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmanaged) {
+ SetUpEntry("policy/shill_unmanaged_user_wifi1.json",
+ "/profile/chronos/shill",
+ "old_entry_path");
+
+ EXPECT_CALL(mock_profile_client_,
+ GetProperties(dbus::ObjectPath("/profile/chronos/shill"),
+ _, _)).Times(1);
+
+ EXPECT_CALL(mock_profile_client_,
+ GetEntry(dbus::ObjectPath("/profile/chronos/shill"),
+ "old_entry_path",
+ _, _)).Times(1);
+
+ SetPolicy(onc::ONC_SOURCE_USER_POLICY, "");
+ message_loop_.RunUntilIdle();
+}
+
+} // namespace chromeos
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc
index 17c691f..ee950d3 100644
--- a/chromeos/network/network_configuration_handler.cc
+++ b/chromeos/network/network_configuration_handler.cc
@@ -17,6 +17,7 @@
#include "chromeos/dbus/shill_manager_client.h"
#include "chromeos/dbus/shill_service_client.h"
#include "dbus/object_path.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
@@ -193,11 +194,32 @@ void NetworkConfigurationHandler::CreateConfiguration(
const base::DictionaryValue& properties,
const network_handler::StringResultCallback& callback,
const network_handler::ErrorCallback& error_callback) const {
- DBusThreadManager::Get()->GetShillManagerClient()->GetService(
- properties,
- base::Bind(&RunCreateNetworkCallback, callback),
- base::Bind(&network_handler::ShillErrorCallbackFunction,
- kLogModule, "", error_callback));
+ ShillManagerClient* manager =
+ DBusThreadManager::Get()->GetShillManagerClient();
+
+ std::string type;
+ properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, &type);
+ // Shill supports ConfigureServiceForProfile only for network type WiFi. In
+ // all other cases, we have to rely on GetService for now. This is
+ // unproblematic for VPN (user profile only), but will lead to inconsistencies
+ // with WiMax, for example.
+ if (type == flimflam::kTypeWifi) {
+ std::string profile;
+ properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty,
+ &profile);
+ manager->ConfigureServiceForProfile(
+ dbus::ObjectPath(profile),
+ properties,
+ base::Bind(&RunCreateNetworkCallback, callback),
+ base::Bind(&network_handler::ShillErrorCallbackFunction,
+ kLogModule, "", error_callback));
+ } else {
+ manager->GetService(
+ properties,
+ base::Bind(&RunCreateNetworkCallback, callback),
+ base::Bind(&network_handler::ShillErrorCallbackFunction,
+ kLogModule, "", error_callback));
+ }
}
void NetworkConfigurationHandler::RemoveConfiguration(
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc
index 8355028..4ab8b17 100644
--- a/chromeos/network/network_state.cc
+++ b/chromeos/network/network_state.cc
@@ -75,6 +75,8 @@ bool NetworkState::PropertyChanged(const std::string& key,
return GetStringValue(key, value, &device_path_);
} else if (key == flimflam::kGuidProperty) {
return GetStringValue(key, value, &guid_);
+ } else if (key == flimflam::kProfileProperty) {
+ return GetStringValue(key, value, &profile_path_);
} else if (key == shill::kActivateOverNonCellularNetworkProperty) {
return GetBooleanValue(key, value, &activate_over_non_cellular_networks_);
} else if (key == shill::kOutOfCreditsProperty) {
@@ -121,6 +123,8 @@ void NetworkState::GetProperties(base::DictionaryValue* dictionary) const {
dictionary->SetStringWithoutPathExpansion(flimflam::kDeviceProperty,
device_path());
dictionary->SetStringWithoutPathExpansion(flimflam::kGuidProperty, guid());
+ dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
+ profile_path());
dictionary->SetBooleanWithoutPathExpansion(
shill::kActivateOverNonCellularNetworkProperty,
activate_over_non_cellular_networks());
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h
index d43def6..3b7d283 100644
--- a/chromeos/network/network_state.h
+++ b/chromeos/network/network_state.h
@@ -43,6 +43,7 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
const std::string& device_path() const { return device_path_; }
const std::string& guid() const { return guid_; }
const std::string& connection_state() const { return connection_state_; }
+ const std::string& profile_path() const { return profile_path_; }
const std::string& error() const { return error_; }
bool auto_connect() const { return auto_connect_; }
bool favorite() const { return favorite_; }
@@ -86,6 +87,7 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
std::string device_path_;
std::string guid_;
std::string connection_state_;
+ std::string profile_path_;
std::string error_;
bool auto_connect_;
bool favorite_;
diff --git a/chromeos/network/network_ui_data.cc b/chromeos/network/network_ui_data.cc
index 3345895..a80ee3e 100644
--- a/chromeos/network/network_ui_data.cc
+++ b/chromeos/network/network_ui_data.cc
@@ -14,6 +14,7 @@ namespace chromeos {
const char NetworkUIData::kKeyONCSource[] = "onc_source";
const char NetworkUIData::kKeyCertificatePattern[] = "certificate_pattern";
const char NetworkUIData::kKeyCertificateType[] = "certificate_type";
+const char NetworkUIData::kKeyUserSettings[] = "user_settings";
namespace {
@@ -61,13 +62,27 @@ Enum StringToEnum(const StringEnumEntry<Enum>(& table)[N],
return fallback;
}
-}
+} // namespace
NetworkUIData::NetworkUIData()
: onc_source_(onc::ONC_SOURCE_NONE),
certificate_type_(CLIENT_CERT_TYPE_NONE) {
}
+NetworkUIData::NetworkUIData(const NetworkUIData& other) {
+ *this = other;
+}
+
+NetworkUIData& NetworkUIData::operator=(const NetworkUIData& other) {
+ certificate_pattern_ = other.certificate_pattern_;
+ onc_source_ = other.onc_source_;
+ certificate_type_ = other.certificate_type_;
+ if (other.user_settings_)
+ user_settings_.reset(other.user_settings_->DeepCopy());
+ policy_guid_ = other.policy_guid_;
+ return *this;
+}
+
NetworkUIData::NetworkUIData(const DictionaryValue& dict) {
std::string source;
dict.GetString(kKeyONCSource, &source);
@@ -88,6 +103,10 @@ NetworkUIData::NetworkUIData(const DictionaryValue& dict) {
certificate_type_ = CLIENT_CERT_TYPE_NONE;
}
}
+
+ const DictionaryValue* user_settings = NULL;
+ if (dict.GetDictionary(kKeyUserSettings, &user_settings))
+ user_settings_.reset(user_settings->DeepCopy());
}
NetworkUIData::~NetworkUIData() {
@@ -110,6 +129,9 @@ void NetworkUIData::FillDictionary(base::DictionaryValue* dict) const {
certificate_pattern_.CreateAsDictionary());
}
}
+ if (user_settings_)
+ dict->SetWithoutPathExpansion(kKeyUserSettings,
+ user_settings_->DeepCopy());
}
namespace {
diff --git a/chromeos/network/network_ui_data.h b/chromeos/network/network_ui_data.h
index 2c93a9f..b65987e 100644
--- a/chromeos/network/network_ui_data.h
+++ b/chromeos/network/network_ui_data.h
@@ -25,8 +25,6 @@ enum ClientCertType {
CLIENT_CERT_TYPE_PATTERN = 2
};
-class NetworkPropertyUIData;
-
// Helper for accessing and setting values in the network's UI data dictionary.
// Accessing values is done via static members that take the network as an
// argument. In order to fill a UI data dictionary, construct an instance, set
@@ -39,6 +37,8 @@ class NetworkPropertyUIData;
class CHROMEOS_EXPORT NetworkUIData {
public:
NetworkUIData();
+ NetworkUIData(const NetworkUIData& other);
+ NetworkUIData& operator=(const NetworkUIData& other);
explicit NetworkUIData(const base::DictionaryValue& dict);
~NetworkUIData();
@@ -61,26 +61,41 @@ class CHROMEOS_EXPORT NetworkUIData {
return onc_source_ == onc::ONC_SOURCE_DEVICE_POLICY ||
onc_source_ == onc::ONC_SOURCE_USER_POLICY;
}
+ const base::DictionaryValue* user_settings() const {
+ return user_settings_.get();
+ }
+ void set_user_settings(scoped_ptr<base::DictionaryValue> dict) {
+ user_settings_ = dict.Pass();
+ }
+ const std::string& policy_guid() const {
+ return policy_guid_;
+ }
+ void set_policy_guid(const std::string& guid) {
+ policy_guid_ = guid;
+ }
// Fills in |dict| with the currently configured values. This will write the
// keys appropriate for Network::ui_data() as defined below (kKeyXXX).
void FillDictionary(base::DictionaryValue* dict) const;
- // Key for storing source of the ONC network, which is an integer according to
- // enum ONCSource.
+ // Key for storing source of the ONC network.
static const char kKeyONCSource[];
- // Key for storing certificate pattern for this network (if any).
+ // Key for storing the certificate pattern.
static const char kKeyCertificatePattern[];
- // Key for storing certificate type for this network (if any), which is one of
- // "pattern", "ref", or "none", according to ClientCertType.
+ // Key for storing the certificate type.
static const char kKeyCertificateType[];
+ // Key for storing the user settings.
+ static const char kKeyUserSettings[];
+
private:
CertificatePattern certificate_pattern_;
onc::ONCSource onc_source_;
ClientCertType certificate_type_;
+ scoped_ptr<base::DictionaryValue> user_settings_;
+ std::string policy_guid_;
};
// Creates a NetworkUIData object from |onc_network|, which has to be a valid
diff --git a/chromeos/network/onc/onc_constants.cc b/chromeos/network/onc/onc_constants.cc
index 0fbc7a5..46414bf 100644
--- a/chromeos/network/onc/onc_constants.cc
+++ b/chromeos/network/onc/onc_constants.cc
@@ -9,7 +9,9 @@ namespace chromeos {
// Constants for ONC properties.
namespace onc {
+const char kAugmentationActiveSetting[] = "Active";
const char kAugmentationEffectiveSetting[] = "Effective";
+const char kAugmentationUnmanaged[] = "Unmanaged";
const char kAugmentationUserPolicy[] = "UserPolicy";
const char kAugmentationDevicePolicy[] = "DevicePolicy";
const char kAugmentationUserSetting[] = "UserSetting";
diff --git a/chromeos/network/onc/onc_constants.h b/chromeos/network/onc/onc_constants.h
index 1d1ccf9..76325b1 100644
--- a/chromeos/network/onc/onc_constants.h
+++ b/chromeos/network/onc/onc_constants.h
@@ -21,7 +21,15 @@ enum ONCSource {
// These keys are used to augment the dictionary resulting from merging the
// different settings and policies.
+
+// The setting that Shill declared to be using. For example, if no policy and no
+// user setting exists, Shill might still report a property like network
+// security options or a SSID.
+CHROMEOS_EXPORT extern const char kAugmentationActiveSetting[];
+// The one of different setting sources (user/device policy, user/shared
+// settings) that has highest priority over the others.
CHROMEOS_EXPORT extern const char kAugmentationEffectiveSetting[];
+CHROMEOS_EXPORT extern const char kAugmentationUnmanaged[];
CHROMEOS_EXPORT extern const char kAugmentationUserPolicy[];
CHROMEOS_EXPORT extern const char kAugmentationDevicePolicy[];
CHROMEOS_EXPORT extern const char kAugmentationUserSetting[];
diff --git a/chromeos/network/onc/onc_merger.cc b/chromeos/network/onc/onc_merger.cc
index 8403f91..e7703d3 100644
--- a/chromeos/network/onc/onc_merger.cc
+++ b/chromeos/network/onc/onc_merger.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/values.h"
#include "chromeos/network/onc/onc_constants.h"
+#include "chromeos/network/onc/onc_signature.h"
namespace chromeos {
namespace onc {
@@ -96,7 +97,7 @@ class MergeListOfDictionaries {
(*it_inner)->GetDictionaryWithoutPathExpansion(key, &nested_dict);
nested_dicts.push_back(nested_dict);
}
- DictionaryPtr merged_dict(MergeDictionaries(nested_dicts));
+ DictionaryPtr merged_dict(MergeNestedDictionaries(key, nested_dicts));
if (!merged_dict->empty())
merged_value = merged_dict.Pass();
} else {
@@ -108,7 +109,7 @@ class MergeListOfDictionaries {
(*it_inner)->GetWithoutPathExpansion(key, &value);
values.push_back(value);
}
- merged_value = MergeListOfValues(values);
+ merged_value = MergeListOfValues(key, values);
}
if (merged_value)
@@ -124,8 +125,14 @@ class MergeListOfDictionaries {
// values is the same as of the given dictionaries |dicts|. If a dictionary
// doesn't contain a path then it's value is NULL.
virtual scoped_ptr<base::Value> MergeListOfValues(
+ const std::string& key,
const std::vector<const base::Value*>& values) = 0;
+ virtual DictionaryPtr MergeNestedDictionaries(const std::string& key,
+ const DictPtrs &dicts) {
+ return MergeDictionaries(dicts);
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(MergeListOfDictionaries);
};
@@ -136,12 +143,15 @@ class MergeSettingsAndPolicies : public MergeListOfDictionaries {
struct ValueParams {
const base::Value* user_policy;
const base::Value* device_policy;
- const base::Value* user_settings;
- const base::Value* shared_settings;
+ const base::Value* user_setting;
+ const base::Value* shared_setting;
+ const base::Value* active_setting;
bool user_editable;
bool device_editable;
};
+ MergeSettingsAndPolicies() {}
+
// Merge the provided dictionaries. For each path in any of the dictionaries,
// MergeValues is called. Its results are collected in a new dictionary which
// is then returned. The resulting dictionary never contains empty
@@ -150,7 +160,8 @@ class MergeSettingsAndPolicies : public MergeListOfDictionaries {
const base::DictionaryValue* user_policy,
const base::DictionaryValue* device_policy,
const base::DictionaryValue* user_settings,
- const base::DictionaryValue* shared_settings) {
+ const base::DictionaryValue* shared_settings,
+ const base::DictionaryValue* active_settings) {
hasUserPolicy_ = (user_policy != NULL);
hasDevicePolicy_ = (device_policy != NULL);
@@ -167,6 +178,7 @@ class MergeSettingsAndPolicies : public MergeListOfDictionaries {
dicts[kDevicePolicyIndex] = device_policy;
dicts[kUserSettingsIndex] = user_settings;
dicts[kSharedSettingsIndex] = shared_settings;
+ dicts[kActiveSettingsIndex] = active_settings;
dicts[kUserEditableIndex] = user_editable.get();
dicts[kDeviceEditableIndex] = device_editable.get();
return MergeListOfDictionaries::MergeDictionaries(dicts);
@@ -176,7 +188,8 @@ class MergeSettingsAndPolicies : public MergeListOfDictionaries {
// This function is called by MergeDictionaries for each list of values that
// are located at the same path in each of the dictionaries. Implementations
// can use the Has*Policy functions.
- virtual scoped_ptr<base::Value> MergeValues(ValueParams values) = 0;
+ virtual scoped_ptr<base::Value> MergeValues(const std::string& key,
+ const ValueParams& values) = 0;
// Whether a user policy was provided.
bool HasUserPolicy() {
@@ -190,6 +203,7 @@ class MergeSettingsAndPolicies : public MergeListOfDictionaries {
// MergeListOfDictionaries override.
virtual scoped_ptr<base::Value> MergeListOfValues(
+ const std::string& key,
const std::vector<const base::Value*>& values) OVERRIDE {
bool user_editable = !HasUserPolicy();
if (values[kUserEditableIndex])
@@ -202,11 +216,12 @@ class MergeSettingsAndPolicies : public MergeListOfDictionaries {
ValueParams params;
params.user_policy = values[kUserPolicyIndex];
params.device_policy = values[kDevicePolicyIndex];
- params.user_settings = values[kUserSettingsIndex];
- params.shared_settings = values[kSharedSettingsIndex];
+ params.user_setting = values[kUserSettingsIndex];
+ params.shared_setting = values[kSharedSettingsIndex];
+ params.active_setting = values[kActiveSettingsIndex];
params.user_editable = user_editable;
params.device_editable = device_editable;
- return MergeValues(params);
+ return MergeValues(key, params);
}
private:
@@ -215,17 +230,24 @@ class MergeSettingsAndPolicies : public MergeListOfDictionaries {
kDevicePolicyIndex,
kUserSettingsIndex,
kSharedSettingsIndex,
+ kActiveSettingsIndex,
kUserEditableIndex,
kDeviceEditableIndex,
kLastIndex
};
bool hasUserPolicy_, hasDevicePolicy_;
+
+ DISALLOW_COPY_AND_ASSIGN(MergeSettingsAndPolicies);
};
// Call MergeDictionaries to merge policies and settings to the effective
-// values. See the description of MergeSettingsAndPoliciesToEffective.
+// values. This ignores the active settings of Shill. See the description of
+// MergeSettingsAndPoliciesToEffective.
class MergeToEffective : public MergeSettingsAndPolicies {
+ public:
+ MergeToEffective() {}
+
protected:
// Merges |values| to the effective value (Mandatory policy overwrites user
// settings overwrites shared settings overwrites recommended policy). |which|
@@ -234,7 +256,9 @@ class MergeToEffective : public MergeSettingsAndPolicies {
// pointer and set |which| to kAugmentationUserPolicy, which means that the
// user policy didn't set a value but also didn't recommend it, thus enforcing
// the empty value.
- scoped_ptr<base::Value> MergeValues(ValueParams values, std::string* which) {
+ scoped_ptr<base::Value> MergeValues(const std::string& key,
+ const ValueParams& values,
+ std::string* which) {
const base::Value* result = NULL;
which->clear();
if (!values.user_editable) {
@@ -243,11 +267,11 @@ class MergeToEffective : public MergeSettingsAndPolicies {
} else if (!values.device_editable) {
result = values.device_policy;
*which = kAugmentationDevicePolicy;
- } else if (values.user_settings) {
- result = values.user_settings;
+ } else if (values.user_setting) {
+ result = values.user_setting;
*which = kAugmentationUserSetting;
- } else if (values.shared_settings) {
- result = values.shared_settings;
+ } else if (values.shared_setting) {
+ result = values.shared_setting;
*which = kAugmentationSharedSetting;
} else if (values.user_policy) {
result = values.user_policy;
@@ -266,53 +290,129 @@ class MergeToEffective : public MergeSettingsAndPolicies {
// MergeSettingsAndPolicies override.
virtual scoped_ptr<base::Value> MergeValues(
- ValueParams values) OVERRIDE {
+ const std::string& key,
+ const ValueParams& values) OVERRIDE {
std::string which;
- return MergeValues(values, &which);
+ return MergeValues(key, values, &which);
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MergeToEffective);
};
// Call MergeDictionaries to merge policies and settings to an augmented
// dictionary which contains a dictionary for each value in the original
// dictionaries. See the description of MergeSettingsAndPoliciesToAugmented.
class MergeToAugmented : public MergeToEffective {
+ public:
+ MergeToAugmented() {}
+
+ DictionaryPtr MergeDictionaries(
+ const OncValueSignature& signature,
+ const base::DictionaryValue* user_policy,
+ const base::DictionaryValue* device_policy,
+ const base::DictionaryValue* user_settings,
+ const base::DictionaryValue* shared_settings,
+ const base::DictionaryValue* active_settings) {
+ signature_ = &signature;
+ return MergeToEffective::MergeDictionaries(user_policy,
+ device_policy,
+ user_settings,
+ shared_settings,
+ active_settings);
+ }
+
protected:
// MergeSettingsAndPolicies override.
virtual scoped_ptr<base::Value> MergeValues(
- ValueParams values) OVERRIDE {
+ const std::string& key,
+ const ValueParams& values) OVERRIDE {
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
- std::string which_effective;
- MergeToEffective::MergeValues(values, &which_effective).reset();
- if (!which_effective.empty()) {
- result->SetStringWithoutPathExpansion(kAugmentationEffectiveSetting,
- which_effective);
- }
- if (values.user_policy) {
- result->SetWithoutPathExpansion(kAugmentationUserPolicy,
- values.user_policy->DeepCopy());
- }
- if (values.device_policy) {
- result->SetWithoutPathExpansion(kAugmentationDevicePolicy,
- values.device_policy->DeepCopy());
- }
- if (values.user_settings) {
- result->SetWithoutPathExpansion(kAugmentationUserSetting,
- values.user_settings->DeepCopy());
- }
- if (values.shared_settings) {
- result->SetWithoutPathExpansion(kAugmentationSharedSetting,
- values.shared_settings->DeepCopy());
+ if (values.active_setting) {
+ result->SetWithoutPathExpansion(kAugmentationActiveSetting,
+ values.active_setting->DeepCopy());
}
- if (HasUserPolicy() && values.user_editable) {
- result->SetBooleanWithoutPathExpansion(kAugmentationUserEditable,
- values.user_editable);
- }
- if (HasDevicePolicy() && values.device_editable) {
- result->SetBooleanWithoutPathExpansion(kAugmentationDeviceEditable,
- values.device_editable);
+
+ const OncFieldSignature* field = NULL;
+ if (signature_)
+ field = GetFieldSignature(*signature_, key);
+
+ if (field) {
+ // This field is part of the provided ONCSignature, thus it can be
+ // controlled by policy.
+ std::string which_effective;
+ MergeToEffective::MergeValues(key, values, &which_effective).reset();
+ if (!which_effective.empty()) {
+ result->SetStringWithoutPathExpansion(kAugmentationEffectiveSetting,
+ which_effective);
+ }
+ bool is_credential = onc::FieldIsCredential(*signature_, key);
+
+ // Prevent credentials from being forwarded in cleartext to
+ // UI. User/shared credentials are not stored separately, so they cannot
+ // leak here.
+ if (!is_credential) {
+ if (values.user_policy) {
+ result->SetWithoutPathExpansion(kAugmentationUserPolicy,
+ values.user_policy->DeepCopy());
+ }
+ if (values.device_policy) {
+ result->SetWithoutPathExpansion(kAugmentationDevicePolicy,
+ values.device_policy->DeepCopy());
+ }
+ }
+ if (values.user_setting) {
+ result->SetWithoutPathExpansion(kAugmentationUserSetting,
+ values.user_setting->DeepCopy());
+ }
+ if (values.shared_setting) {
+ result->SetWithoutPathExpansion(kAugmentationSharedSetting,
+ values.shared_setting->DeepCopy());
+ }
+ if (HasUserPolicy() && values.user_editable) {
+ result->SetBooleanWithoutPathExpansion(kAugmentationUserEditable,
+ true);
+ }
+ if (HasDevicePolicy() && values.device_editable) {
+ result->SetBooleanWithoutPathExpansion(kAugmentationDeviceEditable,
+ true);
+ }
+ } else {
+ // This field is not part of the provided ONCSignature, thus it cannot be
+ // controlled by policy.
+ result->SetStringWithoutPathExpansion(kAugmentationEffectiveSetting,
+ kAugmentationUnmanaged);
}
+ if (result->empty())
+ result.reset();
return result.PassAs<base::Value>();
}
+
+ // MergeListOfDictionaries override.
+ virtual DictionaryPtr MergeNestedDictionaries(
+ const std::string& key,
+ const DictPtrs &dicts) OVERRIDE {
+ DictionaryPtr result;
+ if (signature_) {
+ const OncValueSignature* enclosing_signature = signature_;
+ signature_ = NULL;
+
+ const OncFieldSignature* field =
+ GetFieldSignature(*enclosing_signature, key);
+ if (field)
+ signature_ = field->value_signature;
+ result = MergeToEffective::MergeNestedDictionaries(key, dicts);
+
+ signature_ = enclosing_signature;
+ } else {
+ result = MergeToEffective::MergeNestedDictionaries(key, dicts);
+ }
+ return result.Pass();
+ }
+
+ private:
+ const OncValueSignature* signature_;
+ DISALLOW_COPY_AND_ASSIGN(MergeToAugmented);
};
} // namespace
@@ -324,17 +424,20 @@ DictionaryPtr MergeSettingsAndPoliciesToEffective(
const base::DictionaryValue* shared_settings) {
MergeToEffective merger;
return merger.MergeDictionaries(
- user_policy, device_policy, user_settings, shared_settings);
+ user_policy, device_policy, user_settings, shared_settings, NULL);
}
DictionaryPtr MergeSettingsAndPoliciesToAugmented(
+ const OncValueSignature& signature,
const base::DictionaryValue* user_policy,
const base::DictionaryValue* device_policy,
const base::DictionaryValue* user_settings,
- const base::DictionaryValue* shared_settings) {
+ const base::DictionaryValue* shared_settings,
+ const base::DictionaryValue* active_settings) {
MergeToAugmented merger;
return merger.MergeDictionaries(
- user_policy, device_policy, user_settings, shared_settings);
+ signature, user_policy, device_policy, user_settings, shared_settings,
+ active_settings);
}
} // namespace onc
diff --git a/chromeos/network/onc/onc_merger.h b/chromeos/network/onc/onc_merger.h
index b3d4e43..35e97fd 100644
--- a/chromeos/network/onc/onc_merger.h
+++ b/chromeos/network/onc/onc_merger.h
@@ -15,6 +15,8 @@ class DictionaryValue;
namespace chromeos {
namespace onc {
+struct OncValueSignature;
+
// Merges the given |user_settings| and |shared_settings| settings with the
// given |user_policy| and |device_policy| settings. Each can be omitted by
// providing a NULL pointer. Each dictionary has to be part of a valid ONC
@@ -36,13 +38,16 @@ MergeSettingsAndPoliciesToEffective(
// dictionaries contains the onc::kAugmentations* fields (see onc_constants.h)
// for which a value is available. The onc::kAugmentationEffectiveSetting field
// contains the field name of the field containing the effective field that
-// overrides all other values.
+// overrides all other values. Credentials from policies are not written to the
+// result.
CHROMEOS_EXPORT scoped_ptr<base::DictionaryValue>
MergeSettingsAndPoliciesToAugmented(
+ const OncValueSignature& signature,
const base::DictionaryValue* user_policy,
const base::DictionaryValue* device_policy,
const base::DictionaryValue* user_settings,
- const base::DictionaryValue* shared_settings);
+ const base::DictionaryValue* shared_settings,
+ const base::DictionaryValue* active_settings);
} // namespace onc
} // namespace chromeos
diff --git a/chromeos/network/onc/onc_merger_unittest.cc b/chromeos/network/onc/onc_merger_unittest.cc
index b6187fd..f0dbdc5 100644
--- a/chromeos/network/onc/onc_merger_unittest.cc
+++ b/chromeos/network/onc/onc_merger_unittest.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/values.h"
#include "chromeos/network/onc/onc_constants.h"
+#include "chromeos/network/onc/onc_signature.h"
#include "chromeos/network/onc/onc_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -146,7 +147,8 @@ TEST_F(ONCMergerTest, MergeToAugmented) {
scoped_ptr<base::DictionaryValue> expected_augmented =
test_utils::ReadTestDictionary("augmented_merge.json");
scoped_ptr<base::DictionaryValue> merged(MergeSettingsAndPoliciesToAugmented(
- policy_.get(), device_policy_.get(), user_.get(), NULL));
+ kNetworkConfigurationSignature, policy_.get(), device_policy_.get(),
+ user_.get(), NULL, NULL));
EXPECT_TRUE(test_utils::Equals(expected_augmented.get(), merged.get()));
}
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index 964eb4d..aee54bb 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -195,7 +195,7 @@ const OncFieldSignature wifi_with_state_fields[] = {
const OncFieldSignature cellular_with_state_fields[] = {
{ kRecommended, &kRecommendedSignature },
- { cellular::kActivateOverNonCellularNetwork, &kStringSignature },
+ { cellular::kActivateOverNonCellularNetwork, &kBoolSignature },
{ cellular::kActivationState, &kStringSignature },
{ cellular::kAllowRoaming, &kStringSignature },
{ cellular::kAPN, &kStringSignature },
diff --git a/chromeos/network/onc/onc_translation_tables.cc b/chromeos/network/onc/onc_translation_tables.cc
index 74a2f94..8496aeb 100644
--- a/chromeos/network/onc/onc_translation_tables.cc
+++ b/chromeos/network/onc/onc_translation_tables.cc
@@ -190,11 +190,13 @@ const StringTranslationEntry kVPNTypeTable[] = {
{ NULL }
};
+// The first matching line is chosen.
const StringTranslationEntry kWiFiSecurityTable[] = {
{ wifi::kNone, flimflam::kSecurityNone },
{ wifi::kWEP_PSK, flimflam::kSecurityWep },
{ wifi::kWPA_PSK, flimflam::kSecurityPsk },
{ wifi::kWPA_EAP, flimflam::kSecurity8021x },
+ { wifi::kWPA_PSK, flimflam::kSecurityRsn },
{ NULL }
};
diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
index b8c42ec..c14a2a0 100644
--- a/chromeos/network/onc/onc_utils.cc
+++ b/chromeos/network/onc/onc_utils.cc
@@ -11,6 +11,7 @@
#include "base/values.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/onc/onc_mapper.h"
+#include "chromeos/network/onc/onc_signature.h"
#include "crypto/encryptor.h"
#include "crypto/hmac.h"
#include "crypto/symmetric_key.h"
diff --git a/chromeos/network/onc/onc_utils.h b/chromeos/network/onc/onc_utils.h
index c431466..1d4e28f 100644
--- a/chromeos/network/onc/onc_utils.h
+++ b/chromeos/network/onc/onc_utils.h
@@ -11,7 +11,6 @@
#include "base/memory/scoped_ptr.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/network/onc/onc_constants.h"
-#include "chromeos/network/onc/onc_signature.h"
namespace base {
class DictionaryValue;
@@ -20,6 +19,8 @@ class DictionaryValue;
namespace chromeos {
namespace onc {
+struct OncValueSignature;
+
// A valid but empty (no networks and no certificates) and unencrypted
// configuration.
CHROMEOS_EXPORT extern const char kEmptyUnencryptedConfiguration[];
@@ -68,7 +69,7 @@ CHROMEOS_EXPORT void ExpandStringsInOncObject(
// by |mask|. To find sensitive fields, signature and field name are checked
// with the function FieldIsCredential().
CHROMEOS_EXPORT scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
- const onc::OncValueSignature& signature,
+ const OncValueSignature& signature,
const base::DictionaryValue& onc_object,
const std::string& mask);
diff --git a/chromeos/network/onc/onc_utils_unittest.cc b/chromeos/network/onc/onc_utils_unittest.cc
index 98ef4df..97a0cb2 100644
--- a/chromeos/network/onc/onc_utils_unittest.cc
+++ b/chromeos/network/onc/onc_utils_unittest.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/values.h"
+#include "chromeos/network/onc/onc_signature.h"
#include "chromeos/network/onc/onc_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/test/data/network/augmented_merge.json b/chromeos/test/data/network/augmented_merge.json
index 60ae5b0..fbd90ba 100644
--- a/chromeos/test/data/network/augmented_merge.json
+++ b/chromeos/test/data/network/augmented_merge.json
@@ -61,9 +61,7 @@
"UserPolicy": 1
},
"PSK": {
- "DevicePolicy": "sharedkey",
"Effective": "UserPolicy",
- "UserPolicy": "sharedkey"
}
},
"OpenVPN": {
diff --git a/chromeos/test/data/network/policy/policy_wifi1.onc b/chromeos/test/data/network/policy/policy_wifi1.onc
new file mode 100644
index 0000000..e601c95
--- /dev/null
+++ b/chromeos/test/data/network/policy/policy_wifi1.onc
@@ -0,0 +1,16 @@
+{
+ "NetworkConfigurations": [
+ {
+ "GUID": "policy_wifi1",
+ "Type": "WiFi",
+ "Name": "Managed wifi1",
+ "WiFi": {
+ "Passphrase": "policy's passphrase",
+ "Recommended": [ "AutoConnect", "Passphrase" ],
+ "SSID": "wifi1",
+ "Security": "WPA-PSK"
+ }
+ }
+ ],
+ "Type": "UnencryptedConfiguration"
+}
diff --git a/chromeos/test/data/network/policy/shill_managed_wifi1.json b/chromeos/test/data/network/policy/shill_managed_wifi1.json
new file mode 100644
index 0000000..031e5cb
--- /dev/null
+++ b/chromeos/test/data/network/policy/shill_managed_wifi1.json
@@ -0,0 +1,13 @@
+{
+ "EAP.EAP": "TLS",
+ "EAP.Identity": "${LOGIN_ID}@my.domain.com",
+ "EAP.UseSystemCAs": true,
+ "GUID": "policy2_wifi1",
+ "Mode": "managed",
+ "Passphrase": "user's passphrase",
+ "Profile": "/profile/chronos/shill",
+ "SSID": "wifi1",
+ "Security": "802_1x",
+ "Type": "wifi",
+ "UIData": "{\"onc_source\":\"user_policy\",\"user_settings\":{\"WiFi\":{\"Passphrase\":\"FAKE_CREDENTIAL_VPaJDV9x\"}}}"
+}
diff --git a/chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json b/chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json
new file mode 100644
index 0000000..2a01694
--- /dev/null
+++ b/chromeos/test/data/network/policy/shill_policy_on_unconfigured_wifi1.json
@@ -0,0 +1,10 @@
+{
+ "GUID": "policy_wifi1",
+ "Mode": "managed",
+ "Passphrase": "policy's passphrase",
+ "Profile": "/profile/chronos/shill",
+ "SSID": "wifi1",
+ "Security": "psk",
+ "Type": "wifi",
+ "UIData": "{\"onc_source\":\"user_policy\"}"
+}
diff --git a/chromeos/test/data/network/policy/shill_policy_on_unmanaged_user_wifi1.json b/chromeos/test/data/network/policy/shill_policy_on_unmanaged_user_wifi1.json
new file mode 100644
index 0000000..0d0cbcc
--- /dev/null
+++ b/chromeos/test/data/network/policy/shill_policy_on_unmanaged_user_wifi1.json
@@ -0,0 +1,10 @@
+{
+ "GUID": "policy_wifi1",
+ "Mode": "managed",
+ "Passphrase": "user's passphrase",
+ "Profile": "/profile/chronos/shill",
+ "SSID": "wifi1",
+ "Security": "psk",
+ "Type": "wifi",
+ "UIData": "{\"onc_source\":\"user_policy\",\"user_settings\":{\"WiFi\":{\"Passphrase\":\"FAKE_CREDENTIAL_VPaJDV9x\"}}}"
+}
diff --git a/chromeos/test/data/network/policy/shill_unmanaged_user_wifi1.json b/chromeos/test/data/network/policy/shill_unmanaged_user_wifi1.json
new file mode 100644
index 0000000..45cbe90
--- /dev/null
+++ b/chromeos/test/data/network/policy/shill_unmanaged_user_wifi1.json
@@ -0,0 +1,10 @@
+{
+ "GUID": "{unmanaged_user_wifi1}",
+ "Mode": "managed",
+ "Passphrase": "user's passphrase",
+ "Profile": "/profile/chronos/shill",
+ "SSID": "wifi1",
+ "Security": "psk",
+ "Type": "wifi",
+ "UIData": "{\"user_settings\":{\"WiFi\":{\"Passphrase\":\"user's passphrase\"}}}"
+}