diff options
author | pneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-19 20:35:07 +0000 |
---|---|---|
committer | pneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-19 20:35:07 +0000 |
commit | 79affb7effb751deed7336a1828de3cdc1fdde04 (patch) | |
tree | 8cf54f6061fd99dd1d4d43f491ea3f3164965613 | |
parent | eda0a0b16697dab1fc2d45d6cfe38652044b88d5 (diff) | |
download | chromium_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
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\"}}}" +} |