summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chromeos/network/managed_network_configuration_handler_impl.cc59
-rw-r--r--chromeos/network/managed_network_configuration_handler_unittest.cc104
-rw-r--r--chromeos/network/policy_applicator.cc59
-rw-r--r--chromeos/network/policy_applicator.h8
-rw-r--r--chromeos/network/policy_util.cc160
-rw-r--r--chromeos/network/policy_util.h30
-rw-r--r--chromeos/test/data/network/policy/managed_onc_disallow_autoconnect_on_unmanaged_wifi2.onc21
7 files changed, 347 insertions, 94 deletions
diff --git a/chromeos/network/managed_network_configuration_handler_impl.cc b/chromeos/network/managed_network_configuration_handler_impl.cc
index 21c225a..a2a58ca 100644
--- a/chromeos/network/managed_network_configuration_handler_impl.cc
+++ b/chromeos/network/managed_network_configuration_handler_impl.cc
@@ -149,15 +149,9 @@ void ManagedNetworkConfigurationHandlerImpl::SendManagedProperties(
shill_property_util::GetUIDataFromProperties(*shill_properties);
const base::DictionaryValue* user_settings = NULL;
- const base::DictionaryValue* shared_settings = NULL;
if (ui_data && profile) {
- if (profile->type() == NetworkProfile::TYPE_SHARED)
- shared_settings = ui_data->user_settings();
- else if (profile->type() == NetworkProfile::TYPE_USER)
- user_settings = ui_data->user_settings();
- else
- NOTREACHED();
+ user_settings = ui_data->user_settings();
} else if (profile) {
NET_LOG_ERROR("Service contains empty or invalid UIData", service_path);
// TODO(pneubeck): add a conversion of user configured entries of old
@@ -174,34 +168,26 @@ void ManagedNetworkConfigurationHandlerImpl::SendManagedProperties(
active_settings->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
&guid);
- const base::DictionaryValue* user_policy = NULL;
- const base::DictionaryValue* device_policy = NULL;
- if (!guid.empty() && profile) {
+ const base::DictionaryValue* network_policy = NULL;
+ const base::DictionaryValue* global_policy = NULL;
+ if (profile) {
const Policies* policies = GetPoliciesForProfile(*profile);
if (!policies) {
InvokeErrorCallback(
service_path, error_callback, kPoliciesNotInitialized);
return;
}
- const base::DictionaryValue* policy =
- GetByGUID(policies->per_network_config, guid);
- if (profile->type() == NetworkProfile::TYPE_SHARED)
- device_policy = policy;
- else if (profile->type() == NetworkProfile::TYPE_USER)
- user_policy = policy;
- else
- NOTREACHED();
+ if (!guid.empty())
+ network_policy = GetByGUID(policies->per_network_config, guid);
+ global_policy = &policies->global_network_config;
}
- // 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());
+ scoped_ptr<base::DictionaryValue> augmented_properties(
+ policy_util::CreateManagedONC(global_policy,
+ network_policy,
+ user_settings,
+ active_settings.get(),
+ profile));
callback.Run(service_path, *augmented_properties);
}
@@ -297,13 +283,17 @@ void ManagedNetworkConfigurationHandlerImpl::SetProperties(
if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
LOG(WARNING) << "Validation of ONC user settings produced warnings.";
- const base::DictionaryValue* policy =
+ const base::DictionaryValue* network_policy =
GetByGUID(policies->per_network_config, guid);
- VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
+ VLOG(2) << "This configuration is " << (network_policy ? "" : "not ")
+ << "managed.";
scoped_ptr<base::DictionaryValue> shill_dictionary(
- policy_util::CreateShillConfiguration(
- *profile, guid, policy, validated_user_settings.get()));
+ policy_util::CreateShillConfiguration(*profile,
+ guid,
+ &policies->global_network_config,
+ network_policy,
+ validated_user_settings.get()));
network_configuration_handler_->SetProperties(
service_path, *shill_dictionary, callback, error_callback);
@@ -341,8 +331,11 @@ void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
// in |properties| as it is not our own and from an untrusted source.
std::string guid = base::GenerateGUID();
scoped_ptr<base::DictionaryValue> shill_dictionary(
- policy_util::CreateShillConfiguration(
- *profile, guid, NULL /*no policy*/, &properties));
+ policy_util::CreateShillConfiguration(*profile,
+ guid,
+ NULL, // no global policy
+ NULL, // no network policy
+ &properties));
network_configuration_handler_->CreateConfiguration(
*shill_dictionary, callback, error_callback);
diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc
index b4ec1cc..7a32886 100644
--- a/chromeos/network/managed_network_configuration_handler_unittest.cc
+++ b/chromeos/network/managed_network_configuration_handler_unittest.cc
@@ -14,6 +14,7 @@
#include "chromeos/dbus/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_client_helper.h"
#include "chromeos/network/managed_network_configuration_handler_impl.h"
#include "chromeos/network/network_configuration_handler.h"
@@ -130,6 +131,27 @@ class ShillProfileTestClient {
std::map<std::string, std::string> profile_to_user_;
};
+class ShillServiceTestClient {
+ public:
+ typedef ShillClientHelper::DictionaryValueCallback DictionaryValueCallback;
+ void SetFakeProperties(const base::DictionaryValue& service_properties) {
+ service_properties_.Clear();
+ service_properties_.MergeDictionary(&service_properties);
+ }
+
+ void GetProperties(const dbus::ObjectPath& service_path,
+ const DictionaryValueCallback& callback) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback,
+ DBUS_METHOD_CALL_SUCCESS,
+ base::ConstRef(service_properties_)));
+ }
+
+ protected:
+ base::DictionaryValue service_properties_;
+};
+
class TestNetworkProfileHandler : public NetworkProfileHandler {
public:
TestNetworkProfileHandler() {
@@ -151,7 +173,8 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
public:
ManagedNetworkConfigurationHandlerTest()
: mock_manager_client_(NULL),
- mock_profile_client_(NULL) {
+ mock_profile_client_(NULL),
+ mock_service_client_(NULL) {
}
virtual ~ManagedNetworkConfigurationHandlerTest() {
@@ -162,10 +185,13 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
DBusThreadManager::GetSetterForTesting();
mock_manager_client_ = new StrictMock<MockShillManagerClient>();
mock_profile_client_ = new StrictMock<MockShillProfileClient>();
+ mock_service_client_ = new StrictMock<MockShillServiceClient>();
dbus_setter->SetShillManagerClient(
scoped_ptr<ShillManagerClient>(mock_manager_client_).Pass());
dbus_setter->SetShillProfileClient(
scoped_ptr<ShillProfileClient>(mock_profile_client_).Pass());
+ dbus_setter->SetShillServiceClient(
+ scoped_ptr<ShillServiceClient>(mock_service_client_).Pass());
SetNetworkConfigurationHandlerExpectations();
@@ -177,6 +203,10 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
.WillByDefault(Invoke(&profiles_stub_,
&ShillProfileTestClient::GetEntry));
+ ON_CALL(*mock_service_client_, GetProperties(_,_))
+ .WillByDefault(Invoke(&services_stub_,
+ &ShillServiceTestClient::GetProperties));
+
network_profile_handler_.reset(new TestNetworkProfileHandler());
network_configuration_handler_.reset(
NetworkConfigurationHandler::InitializeForTest(
@@ -209,9 +239,12 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
profiles_stub_.AddProfile(kUser1ProfilePath, kUser1);
network_profile_handler_->
AddProfileForTest(NetworkProfile(kUser1ProfilePath, kUser1));
- network_profile_handler_->
- AddProfileForTest(NetworkProfile(
- NetworkProfileHandler::GetSharedProfilePath(), std::string()));
+
+ profiles_stub_.AddProfile(NetworkProfileHandler::GetSharedProfilePath(),
+ std::string() /* no userhash */);
+ network_profile_handler_->AddProfileForTest(
+ NetworkProfile(NetworkProfileHandler::GetSharedProfilePath(),
+ std::string() /* no userhash */));
}
void SetUpEntry(const std::string& path_to_shill_json,
@@ -259,16 +292,44 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
return managed_network_configuration_handler_.get();
}
+ void GetManagedProperties(const std::string& userhash,
+ const std::string& service_path) {
+ managed_handler()->GetManagedProperties(
+ userhash,
+ service_path,
+ base::Bind(
+ &ManagedNetworkConfigurationHandlerTest::GetPropertiesCallback,
+ base::Unretained(this)),
+ base::Bind(&ManagedNetworkConfigurationHandlerTest::UnexpectedError));
+ }
+
+ void GetPropertiesCallback(const std::string& service_path,
+ const base::DictionaryValue& dictionary) {
+ get_properties_service_path_ = service_path;
+ get_properties_result_.Clear();
+ get_properties_result_.MergeDictionary(&dictionary);
+ }
+
+ static void UnexpectedError(const std::string& error_name,
+ scoped_ptr<base::DictionaryValue> error_data) {
+ ASSERT_FALSE(true);
+ }
+
protected:
MockShillManagerClient* mock_manager_client_;
MockShillProfileClient* mock_profile_client_;
+ MockShillServiceClient* mock_service_client_;
ShillProfileTestClient profiles_stub_;
+ ShillServiceTestClient services_stub_;
scoped_ptr<TestNetworkProfileHandler> network_profile_handler_;
scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_;
scoped_ptr<ManagedNetworkConfigurationHandlerImpl>
managed_network_configuration_handler_;
base::MessageLoop message_loop_;
+ std::string get_properties_service_path_;
+ base::DictionaryValue get_properties_result_;
+
private:
DISALLOW_COPY_AND_ASSIGN(ManagedNetworkConfigurationHandlerTest);
};
@@ -660,10 +721,13 @@ TEST_F(ManagedNetworkConfigurationHandlerTest, SetPolicyIgnoreUnmanaged) {
TEST_F(ManagedNetworkConfigurationHandlerTest, AutoConnectDisallowed) {
InitializeStandardProfiles();
+ // Setup an unmanaged network.
SetUpEntry("policy/shill_unmanaged_wifi2.json",
kUser1ProfilePath,
"wifi2_entry_path");
+ // Apply the user policy with global autoconnect config and expect that
+ // autoconnect is disabled in the network's profile entry.
EXPECT_CALL(*mock_profile_client_,
GetProperties(dbus::ObjectPath(kUser1ProfilePath), _, _));
@@ -685,6 +749,38 @@ TEST_F(ManagedNetworkConfigurationHandlerTest, AutoConnectDisallowed) {
kUser1,
"policy/policy_disallow_autoconnect.onc");
message_loop_.RunUntilIdle();
+
+ // Verify that GetManagedProperties correctly augments the properties with the
+ // global config from the user policy.
+
+ // GetManagedProperties requires the device policy to be set or explicitly
+ // unset.
+ EXPECT_CALL(*mock_profile_client_,
+ GetProperties(dbus::ObjectPath(
+ NetworkProfileHandler::GetSharedProfilePath()),
+ _,
+ _));
+ managed_handler()->SetPolicy(
+ ::onc::ONC_SOURCE_DEVICE_POLICY,
+ std::string(), // no userhash
+ base::ListValue(), // no device network policy
+ base::DictionaryValue()); // no device global config
+
+ services_stub_.SetFakeProperties(*expected_shill_properties);
+ EXPECT_CALL(*mock_service_client_,
+ GetProperties(dbus::ObjectPath(
+ "wifi2"),_));
+
+ GetManagedProperties(kUser1, "wifi2");
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ("wifi2", get_properties_service_path_);
+
+ scoped_ptr<base::DictionaryValue> expected_managed_onc =
+ test_utils::ReadTestDictionary(
+ "policy/managed_onc_disallow_autoconnect_on_unmanaged_wifi2.onc");
+ EXPECT_TRUE(onc::test_utils::Equals(expected_managed_onc.get(),
+ &get_properties_result_));
}
TEST_F(ManagedNetworkConfigurationHandlerTest, LateProfileLoading) {
diff --git a/chromeos/network/policy_applicator.cc b/chromeos/network/policy_applicator.cc
index 8b45c40..bd81d7d 100644
--- a/chromeos/network/policy_applicator.cc
+++ b/chromeos/network/policy_applicator.cc
@@ -172,8 +172,11 @@ void PolicyApplicator::GetEntryCallback(
const base::DictionaryValue* user_settings =
ui_data ? ui_data->user_settings() : NULL;
scoped_ptr<base::DictionaryValue> new_shill_properties =
- policy_util::CreateShillConfiguration(
- profile_, new_guid, new_policy, user_settings);
+ policy_util::CreateShillConfiguration(profile_,
+ new_guid,
+ &global_network_config_,
+ new_policy,
+ user_settings);
// A new policy has to be applied to this profile entry. In order to keep
// implicit state of Shill like "connected successfully before", keep the
// entry if a policy is reapplied (e.g. after reboot) or is updated.
@@ -204,7 +207,8 @@ void PolicyApplicator::GetEntryCallback(
// At first ENTRY1 and ENTRY2 should be removed, then the new config be
// written and the result should be:
// { {GUID=X, SSID=Y, USER_SETTINGS=X} }
- WriteNewShillConfiguration(*new_shill_properties, *new_policy, true);
+ WriteNewShillConfiguration(
+ *new_shill_properties, *new_policy, true /* write later */);
remaining_policies_.erase(new_guid);
}
} else if (was_managed) {
@@ -219,8 +223,8 @@ void PolicyApplicator::GetEntryCallback(
// The entry wasn't managed and doesn't match any current policy. Global
// network settings have to be applied.
base::DictionaryValue shill_properties_to_update;
- GetPropertiesForUnmanagedEntry(entry_properties,
- &shill_properties_to_update);
+ policy_util::SetShillPropertiesForGlobalPolicy(
+ entry_properties, global_network_config_, &shill_properties_to_update);
if (shill_properties_to_update.empty()) {
VLOG(2) << "Ignore unmanaged entry.";
// Calling a SetProperties of Shill with an empty dictionary is a no op.
@@ -266,37 +270,6 @@ void PolicyApplicator::WriteNewShillConfiguration(
handler_->CreateConfigurationFromPolicy(shill_dictionary);
}
-void PolicyApplicator::GetPropertiesForUnmanagedEntry(
- const base::DictionaryValue& entry_properties,
- base::DictionaryValue* properties_to_update) const {
- // kAllowOnlyPolicyNetworksToAutoconnect is currently the only global config.
-
- std::string type;
- entry_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
- if (NetworkTypePattern::Ethernet().MatchesType(type))
- return; // Autoconnect for Ethernet cannot be configured.
-
- // By default all networks are allowed to autoconnect.
- bool only_policy_autoconnect = false;
- global_network_config_.GetBooleanWithoutPathExpansion(
- ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
- &only_policy_autoconnect);
- if (!only_policy_autoconnect)
- return;
-
- bool old_autoconnect = false;
- if (entry_properties.GetBooleanWithoutPathExpansion(
- shill::kAutoConnectProperty, &old_autoconnect) &&
- !old_autoconnect) {
- // Autoconnect is already explictly disabled. No need to set it again.
- return;
- }
- // If autconnect is not explicitly set yet, it might automatically be enabled
- // by Shill. To prevent that, disable it explicitly.
- properties_to_update->SetBooleanWithoutPathExpansion(
- shill::kAutoConnectProperty, false);
-}
-
PolicyApplicator::~PolicyApplicator() {
ApplyRemainingPolicies();
STLDeleteValues(&all_policies_);
@@ -331,16 +304,20 @@ void PolicyApplicator::ApplyRemainingPolicies() {
// remaining policies, new configurations have to be created.
for (std::set<std::string>::iterator it = remaining_policies_.begin();
it != remaining_policies_.end(); ++it) {
- const base::DictionaryValue* policy = GetByGUID(all_policies_, *it);
- DCHECK(policy);
+ const base::DictionaryValue* network_policy = GetByGUID(all_policies_, *it);
+ DCHECK(network_policy);
VLOG(1) << "Creating new configuration managed by policy " << *it
<< " in profile " << profile_.ToDebugString() << ".";
scoped_ptr<base::DictionaryValue> shill_dictionary =
- policy_util::CreateShillConfiguration(
- profile_, *it, policy, NULL /* no user settings */);
- WriteNewShillConfiguration(*shill_dictionary, *policy, false);
+ policy_util::CreateShillConfiguration(profile_,
+ *it,
+ &global_network_config_,
+ network_policy,
+ NULL /* no user settings */);
+ WriteNewShillConfiguration(
+ *shill_dictionary, *network_policy, false /* write now */);
}
}
diff --git a/chromeos/network/policy_applicator.h b/chromeos/network/policy_applicator.h
index db9ed52..b9401a4 100644
--- a/chromeos/network/policy_applicator.h
+++ b/chromeos/network/policy_applicator.h
@@ -80,14 +80,6 @@ class PolicyApplicator : public base::RefCounted<PolicyApplicator> {
const base::DictionaryValue& policy,
bool write_later);
- // Adds properties to |properties_to_update|, which are enforced on an
- // unamaged network by the global network config of the policy.
- // |entry_properties| are the network's current properties read from its
- // profile entry.
- void GetPropertiesForUnmanagedEntry(
- const base::DictionaryValue& entry_properties,
- base::DictionaryValue* properties_to_update) const;
-
// Called once all Profile entries are processed. Calls
// ApplyRemainingPolicies.
virtual ~PolicyApplicator();
diff --git a/chromeos/network/policy_util.cc b/chromeos/network/policy_util.cc
index 7e27d97..33fc05a 100644
--- a/chromeos/network/policy_util.cc
+++ b/chromeos/network/policy_util.cc
@@ -125,26 +125,172 @@ bool IsPolicyMatching(const base::DictionaryValue& policy,
return false;
}
+base::DictionaryValue* GetOrCreateDictionary(const std::string& key,
+ base::DictionaryValue* dict) {
+ base::DictionaryValue* inner_dict = NULL;
+ if (!dict->GetDictionaryWithoutPathExpansion(key, &inner_dict)) {
+ inner_dict = new base::DictionaryValue;
+ dict->SetWithoutPathExpansion(key, inner_dict);
+ }
+ return inner_dict;
+}
+
+base::DictionaryValue* GetOrCreateNestedDictionary(
+ const std::string& key1,
+ const std::string& key2,
+ base::DictionaryValue* dict) {
+ base::DictionaryValue* inner_dict = GetOrCreateDictionary(key1, dict);
+ return GetOrCreateDictionary(key2, inner_dict);
+}
+
+void ApplyGlobalAutoconnectPolicy(
+ NetworkProfile::Type profile_type,
+ base::DictionaryValue* augmented_onc_network) {
+ base::DictionaryValue* type_dictionary = NULL;
+ augmented_onc_network->GetDictionaryWithoutPathExpansion(
+ ::onc::network_config::kType, &type_dictionary);
+ std::string type;
+ if (!type_dictionary ||
+ !type_dictionary->GetStringWithoutPathExpansion(
+ ::onc::kAugmentationActiveSetting, &type) ||
+ type.empty()) {
+ LOG(ERROR) << "ONC dictionary with no Type.";
+ return;
+ }
+
+ // Managed dictionaries don't contain empty dictionaries (see onc_merger.cc),
+ // so add the Autoconnect dictionary in case Shill didn't report a value.
+ base::DictionaryValue* auto_connect_dictionary = NULL;
+ if (type == ::onc::network_type::kWiFi) {
+ auto_connect_dictionary =
+ GetOrCreateNestedDictionary(::onc::network_config::kWiFi,
+ ::onc::wifi::kAutoConnect,
+ augmented_onc_network);
+ } else if (type == ::onc::network_type::kVPN) {
+ auto_connect_dictionary =
+ GetOrCreateNestedDictionary(::onc::network_config::kVPN,
+ ::onc::vpn::kAutoConnect,
+ augmented_onc_network);
+ } else {
+ return; // Network type without auto-connect property.
+ }
+
+ std::string policy_source;
+ if (profile_type == NetworkProfile::TYPE_USER)
+ policy_source = ::onc::kAugmentationUserPolicy;
+ else if(profile_type == NetworkProfile::TYPE_SHARED)
+ policy_source = ::onc::kAugmentationDevicePolicy;
+ else
+ NOTREACHED();
+
+ auto_connect_dictionary->SetBooleanWithoutPathExpansion(policy_source, false);
+ auto_connect_dictionary->SetStringWithoutPathExpansion(
+ ::onc::kAugmentationEffectiveSetting, policy_source);
+}
+
} // namespace
+scoped_ptr<base::DictionaryValue> CreateManagedONC(
+ const base::DictionaryValue* global_policy,
+ const base::DictionaryValue* network_policy,
+ const base::DictionaryValue* user_settings,
+ const base::DictionaryValue* active_settings,
+ const NetworkProfile* profile) {
+ const base::DictionaryValue* user_policy = NULL;
+ const base::DictionaryValue* device_policy = NULL;
+ const base::DictionaryValue* nonshared_user_settings = NULL;
+ const base::DictionaryValue* shared_user_settings = NULL;
+
+ if (profile) {
+ if (profile->type() == NetworkProfile::TYPE_SHARED) {
+ device_policy = network_policy;
+ shared_user_settings = user_settings;
+ } else if (profile->type() == NetworkProfile::TYPE_USER) {
+ user_policy = network_policy;
+ nonshared_user_settings = user_settings;
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ // This call also removes credentials from policies.
+ scoped_ptr<base::DictionaryValue> augmented_onc_network =
+ onc::MergeSettingsAndPoliciesToAugmented(
+ onc::kNetworkConfigurationSignature,
+ user_policy,
+ device_policy,
+ nonshared_user_settings,
+ shared_user_settings,
+ active_settings);
+
+ // If present, apply the Autoconnect policy only to networks that are not
+ // managed by policy.
+ if (!network_policy && global_policy && profile) {
+ bool allow_only_policy_autoconnect = false;
+ global_policy->GetBooleanWithoutPathExpansion(
+ ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
+ &allow_only_policy_autoconnect);
+ if (allow_only_policy_autoconnect) {
+ ApplyGlobalAutoconnectPolicy(profile->type(),
+ augmented_onc_network.get());
+ }
+ }
+
+ return augmented_onc_network.Pass();
+}
+
+void SetShillPropertiesForGlobalPolicy(
+ const base::DictionaryValue& shill_dictionary,
+ const base::DictionaryValue& global_network_policy,
+ base::DictionaryValue* shill_properties_to_update) {
+ // kAllowOnlyPolicyNetworksToAutoconnect is currently the only global config.
+
+ std::string type;
+ shill_dictionary.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
+ if (NetworkTypePattern::Ethernet().MatchesType(type))
+ return; // Autoconnect for Ethernet cannot be configured.
+
+ // By default all networks are allowed to autoconnect.
+ bool only_policy_autoconnect = false;
+ global_network_policy.GetBooleanWithoutPathExpansion(
+ ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
+ &only_policy_autoconnect);
+ if (!only_policy_autoconnect)
+ return;
+
+ bool old_autoconnect = false;
+ if (shill_dictionary.GetBooleanWithoutPathExpansion(
+ shill::kAutoConnectProperty, &old_autoconnect) &&
+ !old_autoconnect) {
+ // Autoconnect is already explictly disabled. No need to set it again.
+ return;
+ }
+
+ // If autconnect is not explicitly set yet, it might automatically be enabled
+ // by Shill. To prevent that, disable it explicitly.
+ shill_properties_to_update->SetBooleanWithoutPathExpansion(
+ shill::kAutoConnectProperty, false);
+}
+
scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
const NetworkProfile& profile,
const std::string& guid,
- const base::DictionaryValue* policy,
+ const base::DictionaryValue* global_policy,
+ const base::DictionaryValue* network_policy,
const base::DictionaryValue* user_settings) {
scoped_ptr<base::DictionaryValue> effective;
::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE;
- if (policy) {
+ if (network_policy) {
if (profile.type() == NetworkProfile::TYPE_SHARED) {
effective = onc::MergeSettingsAndPoliciesToEffective(
NULL, // no user policy
- policy, // device policy
+ network_policy, // device policy
NULL, // no user settings
user_settings); // shared settings
onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
} else if (profile.type() == NetworkProfile::TYPE_USER) {
effective = onc::MergeSettingsAndPoliciesToEffective(
- policy, // user policy
+ network_policy, // user policy
NULL, // no device policy
user_settings, // user settings
NULL); // no shared settings
@@ -178,6 +324,12 @@ scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
shill_dictionary->SetStringWithoutPathExpansion(shill::kProfileProperty,
profile.path);
+ if (!network_policy && global_policy) {
+ // The network isn't managed. Global network policies have to be applied.
+ SetShillPropertiesForGlobalPolicy(
+ *shill_dictionary, *global_policy, shill_dictionary.get());
+ }
+
scoped_ptr<NetworkUIData> ui_data(NetworkUIData::CreateFromONC(onc_source));
if (user_settings) {
diff --git a/chromeos/network/policy_util.h b/chromeos/network/policy_util.h
index 73701e3..841c001 100644
--- a/chromeos/network/policy_util.h
+++ b/chromeos/network/policy_util.h
@@ -22,15 +22,37 @@ namespace policy_util {
typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
+// Creates a managed ONC dictionary from the given arguments. Depending on the
+// profile type, the policies are assumed to come from the user or device policy
+// and and |user_settings| to be the user's non-shared or shared settings.
+// Each of the arguments can be NULL.
+// TODO(pneubeck): Add documentation of the returned format, see
+// https://crbug.com/408990 .
+scoped_ptr<base::DictionaryValue> CreateManagedONC(
+ const base::DictionaryValue* global_policy,
+ const base::DictionaryValue* network_policy,
+ const base::DictionaryValue* user_settings,
+ const base::DictionaryValue* active_settings,
+ const NetworkProfile* profile);
+
+// Adds properties to |shill_properties_to_update|, which are enforced on an
+// unamaged network by the global config |global_network_policy| of the policy.
+// |shill_dictionary| are the network's current properties read from Shill.
+void SetShillPropertiesForGlobalPolicy(
+ const base::DictionaryValue& shill_dictionary,
+ const base::DictionaryValue& global_network_policy,
+ base::DictionaryValue* shill_properties_to_update);
+
// Creates a Shill property dictionary from the given arguments. The resulting
// dictionary will be sent to Shill by the caller. Depending on the profile
-// type, |policy| is interpreted as the user or device policy and
-// |user_settings| as the user or shared settings. |policy| or |user_settings|
-// can be NULL, but not both.
+// type, |network_policy| is interpreted as the user or device policy and
+// |user_settings| as the user or shared settings. |network_policy| or
+// |user_settings| can be NULL, but not both.
scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
const NetworkProfile& profile,
const std::string& guid,
- const base::DictionaryValue* policy,
+ const base::DictionaryValue* global_policy,
+ const base::DictionaryValue* network_policy,
const base::DictionaryValue* user_settings);
// Returns the policy from |policies| matching |actual_network|, if any exists.
diff --git a/chromeos/test/data/network/policy/managed_onc_disallow_autoconnect_on_unmanaged_wifi2.onc b/chromeos/test/data/network/policy/managed_onc_disallow_autoconnect_on_unmanaged_wifi2.onc
new file mode 100644
index 0000000..d8c252a9
--- /dev/null
+++ b/chromeos/test/data/network/policy/managed_onc_disallow_autoconnect_on_unmanaged_wifi2.onc
@@ -0,0 +1,21 @@
+{
+ "Name": {
+ "Active": "wifi2"
+ },
+ "Type": {
+ "Active": "WiFi"
+ },
+ "WiFi": {
+ "AutoConnect": {
+ "Active": false,
+ "Effective": "UserPolicy",
+ "UserPolicy": false
+ },
+ "SSID": {
+ "Active": "wifi2"
+ },
+ "Security": {
+ "Active": "WPA-PSK"
+ }
+ }
+}