Commit b2429689 authored by Alexander Hendrich's avatar Alexander Hendrich Committed by Commit Bot

Refactored network blocking

Moved logic for network->IsManagedByNetwork() and
network->blocked_by_policy() to NetworkState, which gets set and
updated by the NetworkStateHandler.
The ManagedNetworkConfigurationHandler updates the NetworkStateHandler
if any network blocking policy changes.

Bug: none
Change-Id: Iad25d242c7a5d191912ba3a15181da987d6bb6e0
Reviewed-on: https://chromium-review.googlesource.com/1122396
Commit-Queue: Alexander Hendrich <hendrich@chromium.org>
Reviewed-by: default avatarCait Phillips <caitkp@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579727}
parent cc9d77d6
......@@ -558,13 +558,7 @@ void NetworkListView::UpdateNetworkIcons() {
handler->GetNetworkStateFromGuid(info->guid);
if (!network)
continue;
bool prohibited_by_policy =
Shell::Get()->session_controller()->IsActiveUserSessionStarted() &&
NetworkHandler::Get()
->managed_network_configuration_handler()
->IsNetworkBlockedByPolicy(network->type(), network->guid(),
network->profile_path(),
network->GetHexSsid());
bool prohibited_by_policy = network->blocked_by_policy();
info->label = network_icon::GetLabelForNetwork(
network, network_icon::ICON_TYPE_MENU_LIST);
info->image =
......@@ -806,14 +800,7 @@ views::View* NetworkListView::CreatePolicyView(const NetworkInfo& info) {
const chromeos::NetworkState* network =
NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid(
info.guid);
if (!network)
return nullptr;
const base::DictionaryValue* policy =
NetworkHandler::Get()
->managed_network_configuration_handler()
->FindPolicyByGuidAndProfile(network->guid(), network->profile_path(),
nullptr /* onc_source */);
if (!policy)
if (!network || !network->IsManagedByPolicy())
return nullptr;
views::ImageView* controlled_icon = TrayPopupUtils::CreateMainImageView();
......
......@@ -637,6 +637,8 @@ static_library("test_support") {
"network/mock_managed_network_configuration_handler.h",
"network/mock_network_device_handler.cc",
"network/mock_network_device_handler.h",
"network/mock_network_state_handler.cc",
"network/mock_network_state_handler.h",
"network/network_state_test.cc",
"network/network_state_test.h",
"network/onc/onc_test_utils.cc",
......
......@@ -166,11 +166,10 @@ void AutoConnectHandler::ConnectToNetworkRequested(
}
void AutoConnectHandler::PoliciesApplied(const std::string& userhash) {
if (userhash.empty()) {
if (userhash.empty())
device_policy_applied_ = true;
} else {
else
user_policy_applied_ = true;
}
DisconnectIfPolicyRequires();
......@@ -283,110 +282,50 @@ void AutoConnectHandler::CheckBestConnection() {
}
void AutoConnectHandler::DisconnectIfPolicyRequires() {
// Only block networks in a user session.
if (!LoginState::Get()->IsUserLoggedIn())
return;
// Wait for both user and device policy to be applied before disconnecting.
// The device policy holds the policies, which might cause the network to get
// disconnected. The user policy might hold a valid network configuration,
// which prevents the network from being disconnected.
if (!user_policy_applied_ || !device_policy_applied_)
return;
const base::DictionaryValue* global_network_config =
managed_configuration_handler_->GetGlobalConfigFromPolicy(
std::string() /* no username hash, device policy */);
if (!global_network_config)
// Wait for both (user & device) policies to be applied. The device policy
// holds all the policies, which might require disconnects, while the user
// policy might whitelist some networks again. This also ensures that we only
// disconnect from blocked networks in user sessions.
if (!device_policy_applied_ || !user_policy_applied_)
return;
DisconnectAndRemoveBlacklistedNetworks();
const base::Value* connect_value = global_network_config->FindKeyOfType(
::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
base::Value::Type::BOOLEAN);
bool only_policy_connect = connect_value ? connect_value->GetBool() : false;
const base::Value* autoconnect_value = global_network_config->FindKeyOfType(
::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
base::Value::Type::BOOLEAN);
bool only_policy_autoconnect =
autoconnect_value ? autoconnect_value->GetBool() : false;
// Reset |applied_autoconnect_policy_| if auto-connect policy is disabled.
if (!only_policy_autoconnect)
applied_autoconnect_policy_ = false;
if (only_policy_connect) {
// Disconnect and remove network configurations for all unmanaged networks.
DisconnectFromAllUnmanagedWiFiNetworks(true, false);
} else if (only_policy_autoconnect && !applied_autoconnect_policy_) {
// Disconnect and disable auto-connect for all unmanaged networks.
DisconnectFromAllUnmanagedWiFiNetworks(false, true);
applied_autoconnect_policy_ = true;
}
}
void AutoConnectHandler::DisconnectAndRemoveBlacklistedNetworks() {
NET_LOG_DEBUG("DisconnectAndRemoveBlacklistedNetworks", "");
const base::DictionaryValue* global_network_config =
managed_configuration_handler_->GetGlobalConfigFromPolicy(
std::string() /* no username hash, device policy */);
const base::Value* blacklist_value = global_network_config->FindKeyOfType(
::onc::global_network_config::kBlacklistedHexSSIDs,
base::Value::Type::LIST);
if (!blacklist_value || blacklist_value->GetList().empty())
return; // No blacklisted WiFi networks set.
std::set<std::string> blacklist;
for (const base::Value& hex_ssid_value : blacklist_value->GetList())
blacklist.insert(hex_ssid_value.GetString());
std::vector<std::string> blacklisted_hex_ssids =
managed_configuration_handler_->GetBlacklistedHexSSIDs();
bool only_managed =
managed_configuration_handler_->AllowOnlyPolicyNetworksToConnect();
bool only_managed_autoconnect =
managed_configuration_handler_->AllowOnlyPolicyNetworksToAutoconnect();
NetworkStateHandler::NetworkStateList networks;
network_state_handler_->GetNetworkListByType(NetworkTypePattern::WiFi(),
false, false, 0, &networks);
for (const NetworkState* network : networks) {
if (blacklist.find(network->GetHexSsid()) == blacklist.end())
continue;
const bool is_managed =
managed_configuration_handler_->FindPolicyByGuidAndProfile(
network->guid(), network->profile_path(), nullptr /* onc_source */);
if (is_managed)
continue;
if (network->IsConnectingOrConnected())
DisconnectNetwork(network->path());
// Enforce the autoconnect-policy only once.
if (applied_autoconnect_policy_)
only_managed_autoconnect = false;
else
applied_autoconnect_policy_ = only_managed_autoconnect;
if (network->IsInProfile())
RemoveNetworkConfigurationForNetwork(network->path());
// Early exit if no policy is set that requires any disconnects.
if (!only_managed && !only_managed_autoconnect &&
blacklisted_hex_ssids.empty()) {
return;
}
}
void AutoConnectHandler::DisconnectFromAllUnmanagedWiFiNetworks(
bool remove_configuration,
bool disable_auto_connect) {
NET_LOG_DEBUG("DisconnectFromAllUnmanagedWiFiNetworks", "");
NetworkStateHandler::NetworkStateList networks;
network_state_handler_->GetNetworkListByType(NetworkTypePattern::WiFi(),
false, false, 0, &networks);
for (const NetworkState* network : networks) {
const bool is_managed =
managed_configuration_handler_->FindPolicyByGuidAndProfile(
network->guid(), network->profile_path(), nullptr /* onc_source */);
if (is_managed)
if (network->IsManagedByPolicy())
continue;
if (network->IsConnectingOrConnected())
DisconnectNetwork(network->path());
if (network->IsInProfile()) {
if (remove_configuration)
if (network->blocked_by_policy()) {
// Disconnect & remove configuration.
if (network->IsConnectingOrConnected())
DisconnectNetwork(network->path());
if (network->IsInProfile())
RemoveNetworkConfigurationForNetwork(network->path());
else if (disable_auto_connect)
} else if (only_managed_autoconnect) {
// Disconnect & disable auto-connect.
if (network->IsConnectingOrConnected())
DisconnectNetwork(network->path());
if (network->IsInProfile())
DisableAutoconnectForWiFiNetwork(network->path());
}
}
......
......@@ -77,33 +77,18 @@ class CHROMEOS_EXPORT AutoConnectHandler : public LoginState::Observer,
// This function is called whenever the logged in state changes or when a new
// policy is applied. Once both device and user policy have been applied and
// either of AllowOnlyPolicyNetworksToConnect or
// either of AllowOnlyPolicyNetworksToConnect,
// AllowOnlyPolicyNetworksToConnectIfAvailable or
// AllowOnlyPolicyNetworksToAutoconnect is enabled, we disconnect from all
// connecting/connected unmanaged networks and either remove the network
// configuration (for AllowOnlyPolicyNetworksToConnect) or only disable
// auto-connect (for AllowOnlyPolicyNetworksToAutoconnect) for all aunmanaged
// configuration (for AllowOnlyPolicyNetworksToConnect*) or only disable
// auto-connect (for AllowOnlyPolicyNetworksToAutoconnect) for all unmanaged
// networks (see |DisconnectFromAllUnmanagedWiFiNetworks(...)|).
// For the AllowOnlyPolicyNetworksToAutoconnect policy we only disconnect once
// to allow managed networks to auto-connect and prevent disconnects with
// manually connected unmanaged networks on every policy update.
void DisconnectIfPolicyRequires();
// Disconnects from all currently connected/connecting blacklisted WiFis. Also
// removes the corresponding network configuration for all blacklisted
// networks to prevent Shill from re-connecting to them (e.g. during
// ConnectToBestService).
void DisconnectAndRemoveBlacklistedNetworks();
// Disconnects from all currently connected/connecting unmanaged WiFis.
// When |remove_configuration|==true, we also remove the corresponding network
// configuration for all unmanaged networks from Shill.
// When |disable_auto_connect|==true, we also disable auto-connect for all
// unmanaged networks in Shill.
// With both options we can prevent Shill from re-connecting to the unmanaged
// networks when looking for a best service to connect to.
void DisconnectFromAllUnmanagedWiFiNetworks(bool remove_configuration,
bool disable_auto_connect);
// Disconnects the connection to the network represented by |service_path|.
void DisconnectNetwork(const std::string& service_path);
......
......@@ -480,7 +480,7 @@ TEST_F(AutoConnectHandlerTest,
::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
base::Value(true));
// Applying the policy which restricts autoconnect should disconnect from the
// Applying the policy which restricts connections should disconnect from the
// shared, unmanaged network.
// Because no best service is set, the fake implementation of
// ConnectToBestServices will be a no-op.
......
......@@ -158,15 +158,14 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler {
const std::string& profile_path,
::onc::ONCSource* onc_source) const = 0;
// Returns true if the provided network is blocked by policy. This can occur,
// by either 'BlacklistedHexSSIDs' or 'AllowOnlyPolicyNetworksToConnect',
// which are both specified in ONC's global configuration. Both policies only
// apply to WiFi networks and can be bypassed by providing a network
// configuration with an ONC policy.
virtual bool IsNetworkBlockedByPolicy(const std::string& type,
const std::string& guid,
const std::string& profile_path,
const std::string& hex_ssid) const = 0;
// Return true if the AllowOnlyPolicyNetworksToConnect policy is enabled.
virtual bool AllowOnlyPolicyNetworksToConnect() const = 0;
// Return true if the AllowOnlyPolicyNetworksToAutoconnect policy is enabled.
virtual bool AllowOnlyPolicyNetworksToAutoconnect() const = 0;
// Return the list of blacklisted WiFi networks (identified by HexSSIDs).
virtual std::vector<std::string> GetBlacklistedHexSSIDs() const = 0;
private:
DISALLOW_ASSIGN(ManagedNetworkConfigurationHandler);
......
......@@ -716,6 +716,16 @@ void ManagedNetworkConfigurationHandlerImpl::OnPoliciesApplied(
queued_modified_policies_.erase(userhash);
ApplyOrQueuePolicies(userhash, &modified_policies);
} else {
if (userhash.empty())
device_policy_applied_ = true;
else
user_policy_applied_ = true;
if (device_policy_applied_ && user_policy_applied_) {
network_state_handler_->UpdateBlockedNetworks(
AllowOnlyPolicyNetworksToConnect(), GetBlacklistedHexSSIDs());
}
for (auto& observer : observers_)
observer.PoliciesApplied(userhash);
}
......@@ -801,44 +811,52 @@ ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
return policy;
}
bool ManagedNetworkConfigurationHandlerImpl::IsNetworkBlockedByPolicy(
const std::string& type,
const std::string& guid,
const std::string& profile_path,
const std::string& hex_ssid) const {
// Only apply blocking to WiFi networks.
if (!NetworkTypePattern::WiFi().MatchesType(type))
bool ManagedNetworkConfigurationHandlerImpl::AllowOnlyPolicyNetworksToConnect()
const {
const base::DictionaryValue* global_network_config =
GetGlobalConfigFromPolicy(
std::string() /* no username hash, device policy */);
if (!global_network_config)
return false;
// Policies to block WiFis are located in the |global_network_config|.
const base::Value* managed_only_value = global_network_config->FindKeyOfType(
::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
base::Value::Type::BOOLEAN);
return managed_only_value && managed_only_value->GetBool();
}
bool ManagedNetworkConfigurationHandlerImpl::
AllowOnlyPolicyNetworksToAutoconnect() const {
const base::DictionaryValue* global_network_config =
GetGlobalConfigFromPolicy(
std::string() /* no username hash, device policy */);
if (!global_network_config)
return false;
// Check if the network is managed. Managed networks are always allowed.
bool is_managed =
FindPolicyByGuidAndProfile(guid, profile_path, nullptr /* onc_source */);
if (is_managed)
return false;
const base::Value* autoconnect_value = global_network_config->FindKeyOfType(
::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
base::Value::Type::BOOLEAN);
return autoconnect_value && autoconnect_value->GetBool();
}
std::vector<std::string>
ManagedNetworkConfigurationHandlerImpl::GetBlacklistedHexSSIDs() const {
const base::DictionaryValue* global_network_config =
GetGlobalConfigFromPolicy(
std::string() /* no username hash, device policy */);
if (!global_network_config)
return std::vector<std::string>();
// Check if the network is blacklisted.
const base::Value* blacklist_value = global_network_config->FindKeyOfType(
::onc::global_network_config::kBlacklistedHexSSIDs,
base::Value::Type::LIST);
if (blacklist_value && !blacklist_value->GetList().empty() &&
base::ContainsValue(blacklist_value->GetList(), base::Value(hex_ssid)))
return true;
// Check if only managed networks are allowed.
const base::Value* managed_only_value = global_network_config->FindKeyOfType(
::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
base::Value::Type::BOOLEAN);
if (managed_only_value && managed_only_value->GetBool())
return true;
if (!blacklist_value)
return std::vector<std::string>();
return false;
std::vector<std::string> blacklisted_hex_ssids;
for (const base::Value& entry : blacklist_value->GetList())
blacklisted_hex_ssids.push_back(entry.GetString());
return blacklisted_hex_ssids;
}
const ManagedNetworkConfigurationHandlerImpl::Policies*
......@@ -863,6 +881,8 @@ ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
network_profile_handler_(NULL),
network_configuration_handler_(NULL),
network_device_handler_(NULL),
user_policy_applied_(false),
device_policy_applied_(false),
weak_ptr_factory_(this) {
CHECK(base::ThreadTaskRunnerHandle::IsSet());
}
......
......@@ -98,10 +98,9 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandlerImpl
const std::string& profile_path,
onc::ONCSource* onc_source) const override;
bool IsNetworkBlockedByPolicy(const std::string& type,
const std::string& guid,
const std::string& profile_path,
const std::string& hex_ssid) const override;
bool AllowOnlyPolicyNetworksToConnect() const override;
bool AllowOnlyPolicyNetworksToAutoconnect() const override;
std::vector<std::string> GetBlacklistedHexSSIDs() const override;
// NetworkProfileObserver overrides
void OnProfileAdded(const NetworkProfile& profile) override;
......@@ -236,6 +235,9 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandlerImpl
base::ObserverList<NetworkPolicyObserver, true> observers_;
bool user_policy_applied_;
bool device_policy_applied_;
// For Shill client callbacks
base::WeakPtrFactory<ManagedNetworkConfigurationHandlerImpl>
weak_ptr_factory_;
......
......@@ -17,11 +17,11 @@
#include "chromeos/dbus/fake_shill_profile_client.h"
#include "chromeos/dbus/fake_shill_service_client.h"
#include "chromeos/network/managed_network_configuration_handler_impl.h"
#include "chromeos/network/mock_network_state_handler.h"
#include "chromeos/network/network_configuration_handler.h"
#include "chromeos/network/network_policy_observer.h"
#include "chromeos/network/network_profile_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/onc/onc_signature.h"
#include "chromeos/network/onc/onc_test_utils.h"
#include "chromeos/network/onc/onc_utils.h"
......@@ -90,7 +90,7 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
ManagedNetworkConfigurationHandlerTest() {
DBusThreadManager::Initialize();
network_state_handler_ = NetworkStateHandler::InitializeForTest();
network_state_handler_ = MockNetworkStateHandler::InitializeForTest();
network_profile_handler_ = std::make_unique<TestNetworkProfileHandler>();
network_configuration_handler_.reset(
NetworkConfigurationHandler::InitializeForTest(
......@@ -207,7 +207,7 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
base::MessageLoop message_loop_;
TestNetworkPolicyObserver policy_observer_;
std::unique_ptr<NetworkStateHandler> network_state_handler_;
std::unique_ptr<MockNetworkStateHandler> network_state_handler_;
std::unique_ptr<TestNetworkProfileHandler> network_profile_handler_;
std::unique_ptr<NetworkConfigurationHandler> network_configuration_handler_;
std::unique_ptr<ManagedNetworkConfigurationHandlerImpl>
......@@ -619,9 +619,8 @@ TEST_F(ManagedNetworkConfigurationHandlerTest, AutoConnectDisallowed) {
// Apply the user policy with global autoconnect config and expect that
// autoconnect is disabled in the network's profile entry.
SetPolicy(::onc::ONC_SOURCE_USER_POLICY,
kUser1,
"policy/policy_disallow_autoconnect.onc");
SetPolicy(::onc::ONC_SOURCE_USER_POLICY, kUser1,
"policy/policy_allow_only_policy_networks_to_autoconnect.onc");
base::RunLoop().RunUntilIdle();
const base::DictionaryValue* properties =
......@@ -692,4 +691,66 @@ TEST_F(ManagedNetworkConfigurationHandlerTest,
base::RunLoop().RunUntilIdle();
}
TEST_F(ManagedNetworkConfigurationHandlerTest,
AllowOnlyPolicyNetworksToConnect) {
InitializeStandardProfiles();
// Check transfer to NetworkStateHandler
EXPECT_CALL(*network_state_handler_,
UpdateBlockedNetworks(true, std::vector<std::string>()))
.Times(1);
// Set 'AllowOnlyPolicyNetworksToConnect' policy and a random user policy.
SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, std::string(),
"policy/policy_allow_only_policy_networks_to_connect.onc");
SetPolicy(::onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
base::RunLoop().RunUntilIdle();
// Check ManagedNetworkConfigurationHandler policy accessors.
EXPECT_TRUE(managed_handler()->AllowOnlyPolicyNetworksToConnect());
EXPECT_FALSE(managed_handler()->AllowOnlyPolicyNetworksToAutoconnect());
EXPECT_TRUE(managed_handler()->GetBlacklistedHexSSIDs().empty());
}
TEST_F(ManagedNetworkConfigurationHandlerTest,
AllowOnlyPolicyNetworksToAutoconnect) {
InitializeStandardProfiles();
// Check transfer to NetworkStateHandler
EXPECT_CALL(*network_state_handler_,
UpdateBlockedNetworks(false, std::vector<std::string>()))
.Times(1);
// Set 'AllowOnlyPolicyNetworksToAutoconnect' policy and a random user policy.
SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, std::string(),
"policy/policy_allow_only_policy_networks_to_autoconnect.onc");
SetPolicy(::onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
base::RunLoop().RunUntilIdle();
// Check ManagedNetworkConfigurationHandler policy accessors.
EXPECT_FALSE(managed_handler()->AllowOnlyPolicyNetworksToConnect());
EXPECT_TRUE(managed_handler()->AllowOnlyPolicyNetworksToAutoconnect());
EXPECT_TRUE(managed_handler()->GetBlacklistedHexSSIDs().empty());
}
TEST_F(ManagedNetworkConfigurationHandlerTest, GetBlacklistedHexSSIDs) {
InitializeStandardProfiles();
std::vector<std::string> blacklist = {"476F6F676C65477565737450534B"};
// Check transfer to NetworkStateHandler
EXPECT_CALL(*network_state_handler_, UpdateBlockedNetworks(false, blacklist))
.Times(1);
// Set 'BlacklistedHexSSIDs' policy and a random user policy.
SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY, std::string(),
"policy/policy_blacklisted_hex_ssids.onc");
SetPolicy(::onc::ONC_SOURCE_USER_POLICY, kUser1, "policy/policy_wifi1.onc");
base::RunLoop().RunUntilIdle();
// Check ManagedNetworkConfigurationHandler policy accessors.
EXPECT_FALSE(managed_handler()->AllowOnlyPolicyNetworksToConnect());
EXPECT_FALSE(managed_handler()->AllowOnlyPolicyNetworksToAutoconnect());
EXPECT_EQ(blacklist, managed_handler()->GetBlacklistedHexSSIDs());
}
} // namespace chromeos
......@@ -75,11 +75,9 @@ class CHROMEOS_EXPORT MockManagedNetworkConfigurationHandler
const base::DictionaryValue*(const std::string& guid,
const std::string& profile_path,
::onc::ONCSource* onc_source));
MOCK_CONST_METHOD4(IsNetworkBlockedByPolicy,
bool(const std::string& type,
const std::string& guid,
const std::string& profile_path,
const std::string& hex_ssid));
MOCK_CONST_METHOD0(AllowOnlyPolicyNetworksToConnect, bool());
MOCK_CONST_METHOD0(AllowOnlyPolicyNetworksToAutoconnect, bool());
MOCK_CONST_METHOD0(GetBlacklistedHexSSIDs, std::vector<std::string>());
private:
DISALLOW_COPY_AND_ASSIGN(MockManagedNetworkConfigurationHandler);
......
// Copyright 2018 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/mock_network_state_handler.h"
namespace chromeos {
MockNetworkStateHandler::MockNetworkStateHandler() = default;
MockNetworkStateHandler::~MockNetworkStateHandler() = default;
// static
std::unique_ptr<MockNetworkStateHandler>
MockNetworkStateHandler::InitializeForTest() {
auto handler = std::make_unique<testing::NiceMock<MockNetworkStateHandler>>();
handler->InitShillPropertyHandler();
return handler;
}
} // namespace chromeos
// Copyright 2018 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 CHROMEOS_NETWORK_MOCK_NETWORK_STATE_HANDLER_H_
#define CHROMEOS_NETWORK_MOCK_NETWORK_STATE_HANDLER_H_
#include "chromeos/network/network_state_handler.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace chromeos {
class CHROMEOS_EXPORT MockNetworkStateHandler : public NetworkStateHandler {
public:
MockNetworkStateHandler();
virtual ~MockNetworkStateHandler();
// Constructs and initializes an instance for testing.
static std::unique_ptr<MockNetworkStateHandler> InitializeForTest();
// NetworkStateHandler overrides
MOCK_METHOD2(UpdateBlockedNetworks,
void(bool, const std::vector<std::string>&));
private:
DISALLOW_COPY_AND_ASSIGN(MockNetworkStateHandler);
};
} // namespace chromeos
#endif // CHROMEOS_NETWORK_MOCK_NETWORK_STATE_HANDLER_H_
\ No newline at end of file
......@@ -55,6 +55,8 @@ const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
"cert-load-timeout";
const char NetworkConnectionHandler::kErrorBlockedByPolicy[] =
"blocked-by-policy";
const char NetworkConnectionHandler::kErrorHexSsidRequired[] =
"hex-ssid-required";
const char NetworkConnectionHandler::kErrorActivateFailed[] = "activate-failed";
const char NetworkConnectionHandler::kErrorEnabledOrDisabledWhenNotAvailable[] =
"not-available";
......
......@@ -91,6 +91,9 @@ class CHROMEOS_EXPORT NetworkConnectionHandler {
// Trying to configure a network that is blocked by policy.
static const char kErrorBlockedByPolicy[];
// The HexSSID is missing.
static const char kErrorHexSsidRequired[];
// Network activation failed.
static const char kErrorActivateFailed[];
......
......@@ -300,9 +300,7 @@ void NetworkConnectionHandlerImpl::ConnectToNetwork(
// Connect immediately to 'connectable' networks.
// TODO(stevenjb): Shill needs to properly set Connectable for VPN.
if (network && network->connectable() && network->type() != shill::kTypeVPN) {
if (logged_in_ && managed_configuration_handler_->IsNetworkBlockedByPolicy(
network->type(), network->guid(),
network->profile_path(), network->GetHexSsid())) {
if (network->blocked_by_policy()) {
InvokeConnectErrorCallback(service_path, error_callback,
kErrorBlockedByPolicy);
return;
......@@ -465,12 +463,21 @@ void NetworkConnectionHandlerImpl::VerifyConfiguredAndConnect(
managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile,
&onc_source);
if (type == shill::kTypeWifi) {
// Check if network is blocked by policy.
if (type == shill::kTypeWifi &&
onc_source != ::onc::ONCSource::ONC_SOURCE_DEVICE_POLICY &&
onc_source != ::onc::ONCSource::ONC_SOURCE_USER_POLICY) {
const base::Value* hex_ssid_value = service_properties.FindKeyOfType(
shill::kWifiHexSsid, base::Value::Type::STRING);
if (hex_ssid_value && logged_in_ &&
managed_configuration_handler_->IsNetworkBlockedByPolicy(
type, guid, profile, hex_ssid_value->GetString())) {
if (!hex_ssid_value) {
ErrorCallbackForPendingRequest(service_path, kErrorHexSsidRequired);
return;
}
std::string hex_ssid = hex_ssid_value->GetString();
std::vector<std::string> blacklisted_hex_ssids =
managed_configuration_handler_->GetBlacklistedHexSSIDs();
if (managed_configuration_handler_->AllowOnlyPolicyNetworksToConnect() ||
base::ContainsValue(blacklisted_hex_ssids, hex_ssid)) {
ErrorCallbackForPendingRequest(service_path, kErrorBlockedByPolicy);
return;
}
......
......@@ -362,6 +362,7 @@ TEST_F(NetworkConnectionHandlerImplTest,
::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
base::Value(true));
SetupPolicy("[]", global_config, false /* load as device policy */);
SetupPolicy("[]", base::DictionaryValue(), true /* load as user policy */);
LoginToRegularUser();
Connect(kWifi0);
EXPECT_EQ(NetworkConnectionHandler::kErrorBlockedByPolicy,
......@@ -383,6 +384,7 @@ TEST_F(NetworkConnectionHandlerImplTest,
global_config.SetKey(::onc::global_network_config::kBlacklistedHexSSIDs,
base::Value(blacklist));
SetupPolicy("[]", global_config, false /* load as device policy */);
SetupPolicy("[]", base::DictionaryValue(), true /* load as user policy */);
LoginToRegularUser();
......
......@@ -14,6 +14,7 @@
#include "base/values.h"
#include "chromeos/network/network_profile_handler.h"
#include "chromeos/network/network_type_pattern.h"
#include "chromeos/network/network_ui_data.h"
#include "chromeos/network/network_util.h"
#include "chromeos/network/onc/onc_utils.h"
#include "chromeos/network/shill_property_util.h"
......@@ -194,6 +195,13 @@ bool NetworkState::PropertyChanged(const std::string& key,
return true;
} else if (key == shill::kTetheringProperty) {
return GetStringValue(key, value, &tethering_state_);
} else if (key == shill::kUIDataProperty) {
std::unique_ptr<NetworkUIData> ui_data =
chromeos::shill_property_util::GetUIDataFromValue(value);
if (!ui_data)
return false;
onc_source_ = ui_data->onc_source();
return true;
}
return false;
}
......@@ -371,6 +379,11 @@ void NetworkState::set_connection_state(const std::string connection_state) {
connection_state_ = connection_state;
}
bool NetworkState::IsManagedByPolicy() const {
return onc_source_ == ::onc::ONCSource::ONC_SOURCE_DEVICE_POLICY ||
onc_source_ == ::onc::ONCSource::ONC_SOURCE_USER_POLICY;
}
bool NetworkState::IsUsingMobileData() const {
return type() == shill::kTypeCellular || type() == chromeos::kTypeTether ||
tethering_state() == shill::kTetheringConfirmedState;
......
......@@ -79,6 +79,7 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
const std::string& error() const { return error_; }
const std::string& last_error() const { return last_error_; }
void clear_last_error() { last_error_.clear(); }
::onc::ONCSource onc_source() const { return onc_source_; }
// Returns |connection_state_| if visible, kStateDisconnect otherwise.
std::string connection_state() const;
......@@ -102,6 +103,10 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
void set_signal_strength(int signal_strength) {
signal_strength_ = signal_strength;
}
bool blocked_by_policy() const { return blocked_by_policy_; }
void set_blocked_by_policy(bool blocked_by_policy) {
blocked_by_policy_ = blocked_by_policy;
}
// Wifi property accessors
const std::string& eap_method() const { return eap_method_; }
......@@ -136,6 +141,10 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
const std::string& tether_guid() const { return tether_guid_; }
void set_tether_guid(const std::string& guid) { tether_guid_ = guid; }
// Returns true if the network is managed by policy (determined by
// |onc_source_|).
bool IsManagedByPolicy() const;
// Returns true if current connection is using mobile data.
bool IsUsingMobileData() const;
......@@ -223,6 +232,7 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
std::string profile_path_;
std::vector<uint8_t> raw_ssid_; // Unknown encoding. Not necessarily UTF-8.
int priority_ = 0;
::onc::ONCSource onc_source_ = ::onc::ONC_SOURCE_UNKNOWN;
// Reflects the current Shill Service.Error property. This might get cleared
// by Shill shortly after a failure.
......@@ -243,6 +253,7 @@ class CHROMEOS_EXPORT NetworkState : public ManagedState {
int signal_strength_ = 0;
std::string bssid_; // For ARC
int frequency_ = 0; // For ARC
bool blocked_by_policy_ = false;
// Cellular properties, used for icons, Connect, and Activation.
std::string network_technology_;
......
......@@ -126,6 +126,25 @@ void NetworkStateHandler::InitShillPropertyHandler() {
shill_property_handler_->Init();
}
void NetworkStateHandler::UpdateBlockedNetworks(
bool only_managed,
const std::vector<std::string>& blacklisted_hex_ssids) {
if (allow_only_policy_networks_to_connect_ == only_managed &&
blacklisted_hex_ssids_ == blacklisted_hex_ssids) {
return;
}
allow_only_policy_networks_to_connect_ = only_managed;
blacklisted_hex_ssids_ = blacklisted_hex_ssids;
for (auto iter = network_list_.begin(); iter != network_list_.end(); ++iter) {
NetworkState* network = (*iter)->AsNetworkState();
if (!network->Matches(NetworkTypePattern::WiFi()))
continue;
if (UpdateBlockedByPolicy(network))
NotifyNetworkPropertiesUpdated(network);
}
}
// static
std::unique_ptr<NetworkStateHandler> NetworkStateHandler::InitializeForTest() {
auto handler = base::WrapUnique(new NetworkStateHandler());
......@@ -872,6 +891,17 @@ void NetworkStateHandler::EnsureTetherDeviceState() {
device_list_.push_back(std::move(tether_device_state));
}
bool NetworkStateHandler::UpdateBlockedByPolicy(NetworkState* network) const {
bool prev_blocked_by_policy = network->blocked_by_policy();
bool blocked_by_policy =
network->Matches(NetworkTypePattern::WiFi()) &&
!network->IsManagedByPolicy() &&
(allow_only_policy_networks_to_connect_ ||
base::ContainsValue(blacklisted_hex_ssids_, network->GetHexSsid()));
network->set_blocked_by_policy(blocked_by_policy);
return prev_blocked_by_policy != blocked_by_policy;
}
void NetworkStateHandler::GetDeviceList(DeviceStateList* list) const {
GetDeviceListByType(NetworkTypePattern::Default(), list);
}
......@@ -1164,6 +1194,7 @@ void NetworkStateHandler::UpdateNetworkStateProperties(
if (network->PropertyChanged(iter.key(), iter.value()))
network_property_updated = true;
}
network_property_updated |= UpdateBlockedByPolicy(network);
network_property_updated |= network->InitialPropertiesReceived(properties);
UpdateGuid(network);
......@@ -1196,6 +1227,7 @@ void NetworkStateHandler::UpdateNetworkServiceProperty(
bool prev_is_captive_portal = network->is_captive_portal();
std::string prev_profile_path = network->profile_path();
changed |= network->PropertyChanged(key, value);
changed |= UpdateBlockedByPolicy(network);
if (!changed)
return;
......
......@@ -355,6 +355,12 @@ class CHROMEOS_EXPORT NetworkStateHandler
void SetLastErrorForTest(const std::string& service_path,
const std::string& error);
// Sets |allow_only_policy_networks_to_connect_| and |blacklisted_hex_ssids_|
// and calls |UpdateBlockedByPolicy()| for each network state.
virtual void UpdateBlockedNetworks(
bool only_managed,
const std::vector<std::string>& blacklisted_hex_ssids);
// Constructs and initializes an instance for testing.
static std::unique_ptr<NetworkStateHandler> InitializeForTest();
......@@ -426,6 +432,8 @@ class CHROMEOS_EXPORT NetworkStateHandler
typedef std::map<std::string, std::string> SpecifierGuidMap;
friend class NetworkStateHandlerTest;
FRIEND_TEST_ALL_PREFIXES(NetworkStateHandlerTest, NetworkStateHandlerStub);
FRIEND_TEST_ALL_PREFIXES(NetworkStateHandlerTest, BlockedByPolicyBlacklisted);
FRIEND_TEST_ALL_PREFIXES(NetworkStateHandlerTest, BlockedByPolicyOnlyManaged);
// Sorts the network list. Called when all network updates have been received,
// or when the network list is requested but the list is in an unsorted state.
......@@ -541,6 +549,11 @@ class CHROMEOS_EXPORT NetworkStateHandler
// it is not present in |device_list_| if it is TECHNOLOGY_UNAVAILABLE.
void EnsureTetherDeviceState();
// Updates the network's |blocked_by_policy_| depending on
// |allow_only_policy_networks_to_connect_| and |blacklisted_hex_ssids_|.
// Returns true if the value changed.
bool UpdateBlockedByPolicy(NetworkState* network) const;
// Shill property handler instance, owned by this class.
std::unique_ptr<internal::ShillPropertyHandler> shill_property_handler_;
......@@ -590,6 +603,11 @@ class CHROMEOS_EXPORT NetworkStateHandler
// Ensure that we do not delete any networks while notifying observers.
bool notifying_network_observers_ = false;
// Policies which control WiFi blocking (Controlled from
// |ManagedNetworkConfigurationHandler| by calling |UpdateBlockedNetworks()|).
bool allow_only_policy_networks_to_connect_ = false;
std::vector<std::string> blacklisted_hex_ssids_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(NetworkStateHandler);
......
......@@ -29,6 +29,7 @@
#include "chromeos/network/device_state.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler_observer.h"
#include "chromeos/network/network_ui_data.h"
#include "chromeos/network/tether_constants.h"
#include "dbus/object_path.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -1875,4 +1876,61 @@ TEST_F(NetworkStateHandlerTest, UpdateCaptivePortalProvider) {
EXPECT_EQ(kProviderName, info->name);
}
TEST_F(NetworkStateHandlerTest, BlockedByPolicyBlacklisted) {
NetworkState* wifi1 = network_state_handler_->GetModifiableNetworkState(
kShillManagerClientStubDefaultWifi);
NetworkState* wifi2 = network_state_handler_->GetModifiableNetworkState(
kShillManagerClientStubWifi2);
EXPECT_FALSE(wifi1->IsManagedByPolicy());
EXPECT_FALSE(wifi2->IsManagedByPolicy());
EXPECT_FALSE(wifi1->blocked_by_policy());
EXPECT_FALSE(wifi2->blocked_by_policy());
std::vector<std::string> blacklist;
blacklist.push_back(wifi1->GetHexSsid());
network_state_handler_->UpdateBlockedNetworks(false, blacklist);
EXPECT_TRUE(wifi1->blocked_by_policy());
EXPECT_FALSE(wifi2->blocked_by_policy());
std::unique_ptr<NetworkUIData> ui_data =
NetworkUIData::CreateFromONC(::onc::ONCSource::ONC_SOURCE_USER_POLICY);
network_state_handler_->UpdateNetworkServiceProperty(
wifi1->path(), shill::kUIDataProperty, base::Value(ui_data->GetAsJson()));
EXPECT_TRUE(wifi1->IsManagedByPolicy());
EXPECT_FALSE(wifi2->IsManagedByPolicy());
EXPECT_FALSE(wifi1->blocked_by_policy());
EXPECT_FALSE(wifi2->blocked_by_policy());
}
TEST_F(NetworkStateHandlerTest, BlockedByPolicyOnlyManaged) {
NetworkState* wifi1 = network_state_handler_->GetModifiableNetworkState(
kShillManagerClientStubDefaultWifi);
NetworkState* wifi2 = network_state_handler_->GetModifiableNetworkState(
kShillManagerClientStubWifi2);
EXPECT_FALSE(wifi1->IsManagedByPolicy());
EXPECT_FALSE(wifi2->IsManagedByPolicy());
EXPECT_FALSE(wifi1->blocked_by_policy());
EXPECT_FALSE(wifi2->blocked_by_policy());
network_state_handler_->UpdateBlockedNetworks(true,
std::vector<std::string>());
EXPECT_TRUE(wifi1->blocked_by_policy());
EXPECT_TRUE(wifi2->blocked_by_policy());
std::unique_ptr<NetworkUIData> ui_data =
NetworkUIData::CreateFromONC(::onc::ONCSource::ONC_SOURCE_USER_POLICY);
network_state_handler_->UpdateNetworkServiceProperty(
wifi1->path(), shill::kUIDataProperty, base::Value(ui_data->GetAsJson()));
EXPECT_TRUE(wifi1->IsManagedByPolicy());
EXPECT_FALSE(wifi2->IsManagedByPolicy());
EXPECT_FALSE(wifi1->blocked_by_policy());
EXPECT_TRUE(wifi2->blocked_by_policy());
}
} // namespace chromeos
{
"NetworkConfigurations": [
],
"GlobalNetworkConfiguration": {
"AllowOnlyPolicyNetworksToConnect": true
},
"Type": "UnencryptedConfiguration"
}
{
"NetworkConfigurations": [
],
"GlobalNetworkConfiguration": {
"BlacklistedHexSSIDs": ["476F6F676C65477565737450534B"]
},
"Type": "UnencryptedConfiguration"
}
......@@ -113,13 +113,18 @@ class FakeManagedNetworkConfigurationHandler
NOTIMPLEMENTED();
return nullptr;
}
bool IsNetworkBlockedByPolicy(const std::string& type,
const std::string& guid,
const std::string& profile_path,
const std::string& hex_ssid) const override {
bool AllowOnlyPolicyNetworksToConnect() const override {
NOTIMPLEMENTED();
return false;
}
bool AllowOnlyPolicyNetworksToAutoconnect() const override {
NOTIMPLEMENTED();
return false;
}
std::vector<std::string> GetBlacklistedHexSSIDs() const override {
NOTIMPLEMENTED();
return std::vector<std::string>();
}
bool create_configuration_called() const {
return create_configuration_called_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment