blob: c34c23512d856a2790101b5aad5f4dd1d4cebaea [file] [log] [blame]
// Copyright 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 <stddef.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
#include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/network/fake_network_device_handler.h"
#include "chromeos/network/mock_managed_network_configuration_handler.h"
#include "chromeos/network/onc/onc_certificate_importer.h"
#include "chromeos/network/onc/onc_parsed_certificates.h"
#include "chromeos/network/onc/onc_test_utils.h"
#include "chromeos/network/onc/onc_utils.h"
#include "chromeos/policy_certificate_provider.h"
#include "chromeos/system/fake_statistics_provider.h"
#include "chromeos/system/statistics_provider.h"
#include "components/account_id/account_id.h"
#include "components/onc/onc_constants.h"
#include "components/policy/core/common/external_data_fetcher.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_service_impl.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_type.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util_nss.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::AnyNumber;
using testing::AtLeast;
using testing::Mock;
using testing::Ne;
using testing::Return;
using testing::StrictMock;
using testing::_;
namespace policy {
namespace {
const char kFakeUserEmail[] = "fake email";
const char kFakeUsernameHash[] = "fake hash";
const char kFakeSerialNumber[] = "FakeSerial";
const char kFakeAssetId[] = "FakeAssetId";
class FakeUser : public user_manager::User {
public:
FakeUser() : User(AccountId::FromUserEmail(kFakeUserEmail)) {
set_display_email(kFakeUserEmail);
set_username_hash(kFakeUsernameHash);
}
~FakeUser() override {}
// User overrides
user_manager::UserType GetType() const override {
return user_manager::USER_TYPE_REGULAR;
}
private:
DISALLOW_COPY_AND_ASSIGN(FakeUser);
};
class FakePolicyProvidedCertsObserver
: public chromeos::PolicyCertificateProvider::Observer {
public:
FakePolicyProvidedCertsObserver() {}
void OnPolicyProvidedCertsChanged(
const net::CertificateList& all_server_and_authority_certs,
const net::CertificateList& trust_anchors) override {
all_server_and_authority_certs_ = all_server_and_authority_certs;
trust_anchors_ = trust_anchors;
}
net::CertificateList all_server_and_authority_certs_;
net::CertificateList trust_anchors_;
private:
DISALLOW_COPY_AND_ASSIGN(FakePolicyProvidedCertsObserver);
};
class FakeNetworkDeviceHandler : public chromeos::FakeNetworkDeviceHandler {
public:
FakeNetworkDeviceHandler()
: allow_roaming_(false), mac_addr_randomization_(false) {}
void SetCellularAllowRoaming(bool allow_roaming) override {
allow_roaming_ = allow_roaming;
}
void SetMACAddressRandomizationEnabled(bool enabled) override {
mac_addr_randomization_ = enabled;
}
bool allow_roaming_;
bool mac_addr_randomization_;
private:
DISALLOW_COPY_AND_ASSIGN(FakeNetworkDeviceHandler);
};
class FakeCertificateImporter : public chromeos::onc::CertificateImporter {
public:
using OncParsedCertificates = chromeos::onc::OncParsedCertificates;
FakeCertificateImporter() : call_count_(0) {}
~FakeCertificateImporter() override {}
void SetExpectedONCClientCertificates(
const std::vector<OncParsedCertificates::ClientCertificate>&
expected_client_certificates) {
expected_client_certificates_ = expected_client_certificates;
}
unsigned int GetAndResetImportCount() {
unsigned int count = call_count_;
call_count_ = 0;
return count;
}
void ImportAllCertificatesUserInitiated(
const std::vector<OncParsedCertificates::ServerOrAuthorityCertificate>&
server_or_authority_certificates,
const std::vector<OncParsedCertificates::ClientCertificate>&
client_certificates,
DoneCallback done_callback) override {
// As policy-provided server and authority certificates are not permanently
// imported, only ImportClientCertificaates should be called.
// ImportAllCertificatesUserInitiated should never be called from
// UserNetworkConfigurationUpdater.
NOTREACHED();
}
void ImportClientCertificates(
const std::vector<OncParsedCertificates::ClientCertificate>&
client_certificates,
DoneCallback done_callback) override {
EXPECT_EQ(expected_client_certificates_, client_certificates);
++call_count_;
std::move(done_callback).Run(true);
}
private:
std::vector<OncParsedCertificates::ClientCertificate>
expected_client_certificates_;
net::ScopedCERTCertificateList onc_trusted_certificates_;
unsigned int call_count_;
DISALLOW_COPY_AND_ASSIGN(FakeCertificateImporter);
};
// Note: HexSSID 737369642D6E6F6E65 maps to "ssid-none".
// HexSSID 7465737431323334 maps to "test1234"
const char kFakeONC[] = R"(
{ "NetworkConfigurations": [
{ "GUID": "{485d6076-dd44-6b6d-69787465725f5040}",
"Type": "WiFi",
"Name": "My WiFi Network",
"WiFi": {
"HexSSID": "737369642D6E6F6E65",
"Security": "None" }
},
{ "GUID": "{guid-for-wifi-with-device-exp}",
"Type": "WiFi",
"Name": "My WiFi with device placeholder expansions",
"WiFi": {
"EAP": {
"Outer": "EAP-TLS",
"Identity": "${DEVICE_SERIAL_NUMBER}-${DEVICE_ASSET_ID}"
},
"HexSSID": "7465737431323334",
"Security": "WPA-EAP",
"SSID": "test1234",
}
}
],
"GlobalNetworkConfiguration": {
"AllowOnlyPolicyNetworksToAutoconnect": true,
},
"Certificates": [
{ "GUID": "{f998f760-272b-6939-4c2beffe428697ac}",
"PKCS12": "YWJj",
"Type": "Client" },
{ "GUID": "{d443ad0d-ea16-4301-9089-588115e2f5c4}",
"TrustBits": [
"Web"
],
"Type": "Authority",
"X509": "-----BEGIN CERTIFICATE-----\n
MIIC8zCCAdugAwIBAgIJALF9qhLor0+aMA0GCSqGSIb3DQEBBQUAMBcxFTATBgNV\n
BAMMDFRlc3QgUm9vdCBDQTAeFw0xNDA4MTQwMzA1MjlaFw0yNDA4MTEwMzA1Mjla\n
MBcxFTATBgNVBAMMDFRlc3QgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n
ADCCAQoCggEBALZJQeNCAVGofzx6cdP7zZE1F4QajvY2x9FwHfqG8267dm/oMi43\n
/TiSPWjkin1CMxRGG9wE9pFuVEDECgn97C1i4l7huiycwbFgTNrH+CJcgiBlQh5W\n
d3VP65AsSupXDiKNbJWsEerM1+72cA0J3aY1YV3Jdm2w8h6/MIbYd1I2lZcO0UbF\n
7YE9G7DyYZU8wUA4719dumGf7yucn4WJdHBj1XboNX7OAeHzERGQHA31/Y3OEGyt\n
fFUaIW/XLfR4FeovOL2RnjwdB0b1Q8GCi68SU2UZimlpZgay2gv6KgChKhWESfEB\n
v5swBtAVoB+dUZFH4VNf717swmF5whSfxOMCAwEAAaNCMEAwDwYDVR0TAQH/BAUw\n
AwEB/zAdBgNVHQ4EFgQUvPcw0TzA8nn675/JbFyT84poq4MwDgYDVR0PAQH/BAQD\n
AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBXByn7f+j/sObYWGrDkKE4HLTzaLHs6Ikj\n
JNeo8iHDYOSkSVwAv9/HgniAKxj3rd3QYl6nsMzwqrTOcBJZZWd2BQAYmv/EKhfj\n
8VXYvlxe68rLU4cQ1QkyNqdeQfRT2n5WYNJ+TpqlCF9ddennMMsi6e8ZSYOlI6H4\n
YEzlNtU5eBjxXr/OqgtTgSx4qQpr2xMQIRR/G3A9iRpAigYsXVAZYvnHRYnyPWYF\n
PX11W1UegEJyoZp8bQp09u6mIWw6mPt3gl/ya1bm3ZuOUPDGrv3qpgUHqSYGVrOy\n
2bI3oCE+eQYfuVG+9LFJTZC1M+UOx15bQMVqBNFDepRqpE9h/ILg\n
-----END CERTIFICATE-----" },
{ "GUID": "{dac8e282-8ff3-4bb9-a20f-b5ef22b2f83b}",
"Type": "Authority",
"X509": "-----BEGIN CERTIFICATE-----\n
MIIDvzCCAqegAwIBAgIBAzANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET\n
MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G\n
A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE3MDYwNTE3\n
MTA0NloXDTI3MDYwMzE3MTA0NlowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh\n
bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3Qg\n
Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n
AQoCggEBALS/0pcz5RNbd2W9cxp1KJtHWea3MOhGM21YW9ofCv/k5C3yHfiJ6GQu\n
9sPN16OO1/fN59gOEMPnVtL85ebTTuL/gk0YY4ewo97a7wo3e6y1t0PO8gc53xTp\n
w6RBPn5oRzSbe2HEGOYTzrO0puC6A+7k6+eq9G2+l1uqBpdQAdB4uNaSsOTiuUOI\n
ta4UZH1ScNQFHAkl1eJPyaiC20Exw75EbwvU/b/B7tlivzuPtQDI0d9dShOtceRL\n
X9HZckyD2JNAv2zNL2YOBNa5QygkySX9WXD+PfKpCk7Cm8TenldeXRYl5ni2REkp\n
nfa/dPuF1g3xZVjyK9aPEEnIAC2I4i0CAwEAAaOBgDB+MAwGA1UdEwEB/wQCMAAw\n
HQYDVR0OBBYEFODc4C8HiHQ6n9Mwo3GK+dal5aZTMB8GA1UdIwQYMBaAFJsmC4qY\n
qbsduR8c4xpAM+2OF4irMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAP\n
BgNVHREECDAGhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQB6FEQuUDRcC5jkX3aZ\n
uuTeZEqMVL7JXgvgFqzXsPb8zIdmxr/tEDfwXx2qDf2Dpxts7Fq4vqUwimK4qV3K\n
7heLnWV2+FBvV1eeSfZ7AQj+SURkdlyo42r41+t13QUf+Z0ftR9266LSWLKrukeI\n
Mxk73hOkm/u8enhTd00dy/FN9dOFBFHseVMspWNxIkdRILgOmiyfQNRgxNYdOf0e\n
EfELR8Hn6WjZ8wAbvO4p7RTrzu1c/RZ0M+NLkID56Brbl70GC2h5681LPwAOaZ7/\n
mWQ5kekSyJjmLfF12b+h9RVAt5MrXZgk2vNujssgGf4nbWh4KZyQ6qrs778ZdDLm\n
yfUn\n
-----END CERTIFICATE-----" }
],
"Type": "UnencryptedConfiguration"
})";
std::string ValueToString(const base::Value& value) {
std::stringstream str;
str << value;
return str.str();
}
// Selects only the client certificate at |client_certificate_index| from the
// certificates contained in |toplevel_onc|. Appends the selected certificate
// into |out_parsed_client_certificates|.
void SelectSingleClientCertificateFromOnc(
base::Value* toplevel_onc,
size_t client_certificate_index,
std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>*
out_parsed_client_certificates) {
base::ListValue* certs = nullptr;
toplevel_onc->FindKey(onc::toplevel_config::kCertificates)->GetAsList(&certs);
ASSERT_TRUE(certs);
ASSERT_TRUE(certs->GetList().size() > client_certificate_index);
base::ListValue selected_certs;
selected_certs.GetList().push_back(
certs->GetList()[client_certificate_index].Clone());
chromeos::onc::OncParsedCertificates parsed_selected_certs(selected_certs);
ASSERT_FALSE(parsed_selected_certs.has_error());
ASSERT_EQ(1u, parsed_selected_certs.client_certificates().size());
out_parsed_client_certificates->push_back(
parsed_selected_certs.client_certificates().front());
}
// Matcher to match base::Value.
MATCHER_P(IsEqualTo,
value,
std::string(negation ? "isn't" : "is") + " equal to " +
ValueToString(*value)) {
return value->Equals(&arg);
}
MATCHER(IsEmpty, std::string(negation ? "isn't" : "is") + " empty.") {
return arg.empty();
}
ACTION_P(SetCertificateList, list) {
if (arg2)
*arg2 = list;
return true;
}
} // namespace
class NetworkConfigurationUpdaterTest : public testing::Test {
protected:
NetworkConfigurationUpdaterTest() : certificate_importer_(NULL) {}
void SetUp() override {
fake_statistics_provider_.SetMachineStatistic(
chromeos::system::kSerialNumberKeyForTest, kFakeSerialNumber);
EXPECT_CALL(provider_, IsInitializationComplete(_))
.WillRepeatedly(Return(false));
provider_.Init();
PolicyServiceImpl::Providers providers;
providers.push_back(&provider_);
policy_service_ = std::make_unique<PolicyServiceImpl>(std::move(providers));
std::unique_ptr<base::Value> fake_toplevel_onc =
chromeos::onc::ReadDictionaryFromJson(kFakeONC);
base::DictionaryValue* global_config = nullptr;
fake_toplevel_onc
->FindKey(onc::toplevel_config::kGlobalNetworkConfiguration)
->GetAsDictionary(&global_config);
fake_global_network_config_.MergeDictionary(global_config);
base::ListValue* certs = nullptr;
fake_toplevel_onc->FindKey(onc::toplevel_config::kCertificates)
->GetAsList(&certs);
fake_certificates_ =
std::make_unique<chromeos::onc::OncParsedCertificates>(*certs);
certificate_importer_ = new FakeCertificateImporter;
client_certificate_importer_owned_.reset(certificate_importer_);
}
base::Value* GetExpectedFakeNetworkConfigs(::onc::ONCSource source) {
std::unique_ptr<base::Value> fake_toplevel_onc =
chromeos::onc::ReadDictionaryFromJson(kFakeONC);
fake_network_configs_ =
fake_toplevel_onc->FindKey(onc::toplevel_config::kNetworkConfigurations)
->Clone();
if (source == ::onc::ONC_SOURCE_DEVICE_POLICY) {
std::string expected_identity =
std::string(kFakeSerialNumber) + "-" + std::string(kFakeAssetId);
SetExpectedValueInNetworkConfig(
&fake_network_configs_, "{guid-for-wifi-with-device-exp}",
{"WiFi", "EAP", "Identity"}, base::Value(expected_identity));
}
return &fake_network_configs_;
}
base::Value* GetExpectedFakeGlobalNetworkConfig() {
return &fake_global_network_config_;
}
void TearDown() override {
network_configuration_updater_.reset();
provider_.Shutdown();
base::RunLoop().RunUntilIdle();
}
void MarkPolicyProviderInitialized() {
Mock::VerifyAndClearExpectations(&provider_);
EXPECT_CALL(provider_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
provider_.SetAutoRefresh();
provider_.RefreshPolicies();
base::RunLoop().RunUntilIdle();
}
void UpdateProviderPolicy(const PolicyMap& policy) {
provider_.UpdateChromePolicy(policy);
base::RunLoop().RunUntilIdle();
}
UserNetworkConfigurationUpdater*
CreateNetworkConfigurationUpdaterForUserPolicy(
bool allow_trusted_certs_from_policy,
bool set_client_cert_importer) {
UserNetworkConfigurationUpdater* updater =
UserNetworkConfigurationUpdater::CreateForUserPolicy(
&profile_,
allow_trusted_certs_from_policy,
fake_user_,
policy_service_.get(),
&network_config_handler_).release();
if (set_client_cert_importer) {
EXPECT_TRUE(client_certificate_importer_owned_);
updater->SetClientCertificateImporterForTest(
std::move(client_certificate_importer_owned_));
}
network_configuration_updater_.reset(updater);
return updater;
}
void CreateNetworkConfigurationUpdaterForDevicePolicy() {
auto testing_device_asset_id_getter =
base::BindRepeating([] { return std::string(kFakeAssetId); });
network_configuration_updater_ =
DeviceNetworkConfigurationUpdater::CreateForDevicePolicy(
policy_service_.get(), &network_config_handler_,
&network_device_handler_, chromeos::CrosSettings::Get(),
testing_device_asset_id_getter);
}
content::TestBrowserThreadBundle thread_bundle_;
std::unique_ptr<chromeos::onc::OncParsedCertificates> fake_certificates_;
StrictMock<chromeos::MockManagedNetworkConfigurationHandler>
network_config_handler_;
FakeNetworkDeviceHandler network_device_handler_;
chromeos::ScopedCrosSettingsTestHelper settings_helper_;
chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
// Ownership of client_certificate_importer_owned_ is passed to the
// NetworkConfigurationUpdater. When that happens, |certificate_importer_|
// continues to point to that instance but
// |client_certificate_importer_owned_| is released.
FakeCertificateImporter* certificate_importer_;
std::unique_ptr<chromeos::onc::CertificateImporter>
client_certificate_importer_owned_;
StrictMock<MockConfigurationPolicyProvider> provider_;
std::unique_ptr<PolicyServiceImpl> policy_service_;
FakeUser fake_user_;
TestingProfile profile_;
std::unique_ptr<NetworkConfigurationUpdater> network_configuration_updater_;
private:
void SetExpectedValueInNetworkConfig(
base::Value* network_configs,
base::StringPiece guid,
std::initializer_list<base::StringPiece> path,
base::Value value) {
for (base::Value& network_config : network_configs->GetList()) {
const base::Value* guid_value =
network_config.FindKey(::onc::network_config::kGUID);
if (!guid_value || guid_value->GetString() != guid)
continue;
network_config.SetPath(path, std::move(value));
break;
}
}
base::Value fake_network_configs_;
base::DictionaryValue fake_global_network_config_;
};
TEST_F(NetworkConfigurationUpdaterTest, CellularAllowRoaming) {
// Ignore network config updates.
EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _, _)).Times(AtLeast(1));
settings_helper_.ReplaceDeviceSettingsProviderWithStub();
settings_helper_.SetBoolean(chromeos::kSignedDataRoamingEnabled, false);
EXPECT_FALSE(network_device_handler_.allow_roaming_);
CreateNetworkConfigurationUpdaterForDevicePolicy();
MarkPolicyProviderInitialized();
settings_helper_.SetBoolean(chromeos::kSignedDataRoamingEnabled, true);
EXPECT_TRUE(network_device_handler_.allow_roaming_);
settings_helper_.SetBoolean(chromeos::kSignedDataRoamingEnabled, false);
EXPECT_FALSE(network_device_handler_.allow_roaming_);
}
TEST_F(NetworkConfigurationUpdaterTest, PolicyIsValidatedAndRepaired) {
std::unique_ptr<base::DictionaryValue> onc_repaired =
chromeos::onc::test_utils::ReadTestDictionary(
"repaired_toplevel_partially_invalid.onc");
base::ListValue* network_configs_repaired = NULL;
onc_repaired->GetListWithoutPathExpansion(
onc::toplevel_config::kNetworkConfigurations, &network_configs_repaired);
ASSERT_TRUE(network_configs_repaired);
base::DictionaryValue* global_config_repaired = NULL;
onc_repaired->GetDictionaryWithoutPathExpansion(
onc::toplevel_config::kGlobalNetworkConfiguration,
&global_config_repaired);
ASSERT_TRUE(global_config_repaired);
std::string onc_policy =
chromeos::onc::test_utils::ReadTestData("toplevel_partially_invalid.onc");
PolicyMap policy;
policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(onc_policy), nullptr);
UpdateProviderPolicy(policy);
EXPECT_CALL(network_config_handler_,
SetPolicy(onc::ONC_SOURCE_USER_POLICY,
_,
IsEqualTo(network_configs_repaired),
IsEqualTo(global_config_repaired)));
std::vector<chromeos::onc::OncParsedCertificates::ClientCertificate>
expected_client_certificates;
ASSERT_NO_FATAL_FAILURE(SelectSingleClientCertificateFromOnc(
onc_repaired.get(), 1 /* client_certificate_index */,
&expected_client_certificates));
certificate_importer_->SetExpectedONCClientCertificates(
expected_client_certificates);
CreateNetworkConfigurationUpdaterForUserPolicy(
false /* do not allow trusted certs from policy */,
true /* set certificate importer */);
MarkPolicyProviderInitialized();
EXPECT_EQ(1u, certificate_importer_->GetAndResetImportCount());
}
TEST_F(NetworkConfigurationUpdaterTest,
DoNotAllowTrustedCertificatesFromPolicy) {
EXPECT_CALL(network_config_handler_,
SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, _, _))
.Times(AnyNumber());
UserNetworkConfigurationUpdater* updater =
CreateNetworkConfigurationUpdaterForUserPolicy(
false /* do not allow trusted certs from policy */,
false /* set certificate importer */);
// Certificates with the "Web" trust flag set should not be forwarded to
// observers.
FakePolicyProvidedCertsObserver observer;
updater->AddPolicyProvidedCertsObserver(&observer);
PolicyMap policy;
policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(kFakeONC), nullptr);
UpdateProviderPolicy(policy);
MarkPolicyProviderInitialized();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(updater->GetWebTrustedCertificates().empty());
EXPECT_EQ(2u, updater->GetCertificatesWithoutWebTrust().size());
EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
EXPECT_TRUE(observer.trust_anchors_.empty());
updater->RemovePolicyProvidedCertsObserver(&observer);
}
TEST_F(NetworkConfigurationUpdaterTest,
AllowTrustedCertificatesFromPolicyInitially) {
// Ignore network configuration changes.
EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _, _))
.Times(AnyNumber());
UserNetworkConfigurationUpdater* updater =
CreateNetworkConfigurationUpdaterForUserPolicy(
true /* allow trusted certs from policy */,
false /* set certificate importer */);
// Certificates with the "Web" trust flag set should be forwarded to
// observers.
FakePolicyProvidedCertsObserver observer;
updater->AddPolicyProvidedCertsObserver(&observer);
PolicyMap policy;
policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(kFakeONC), nullptr);
UpdateProviderPolicy(policy);
MarkPolicyProviderInitialized();
base::RunLoop().RunUntilIdle();
// Certificates with the "Web" trust flag set will be returned.
EXPECT_EQ(1u, updater->GetWebTrustedCertificates().size());
EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust().size());
EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
EXPECT_EQ(1u, observer.trust_anchors_.size());
updater->RemovePolicyProvidedCertsObserver(&observer);
}
TEST_F(NetworkConfigurationUpdaterTest,
AllowTrustedCertificatesFromPolicyOnUpdate) {
// Ignore network configuration changes.
EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _, _))
.Times(AnyNumber());
// Start with an empty certificate list.
UserNetworkConfigurationUpdater* updater =
CreateNetworkConfigurationUpdaterForUserPolicy(
true /* allow trusted certs from policy */,
false /* set certificate importer */);
FakePolicyProvidedCertsObserver observer;
updater->AddPolicyProvidedCertsObserver(&observer);
MarkPolicyProviderInitialized();
base::RunLoop().RunUntilIdle();
// Verify that the returned certificate list is empty.
EXPECT_TRUE(updater->GetWebTrustedCertificates().empty());
EXPECT_TRUE(observer.trust_anchors_.empty());
EXPECT_TRUE(updater->GetCertificatesWithoutWebTrust().empty());
EXPECT_TRUE(updater->GetAllServerAndAuthorityCertificates().empty());
// Change to ONC policy with web trust certs.
PolicyMap policy;
policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(kFakeONC), nullptr);
UpdateProviderPolicy(policy);
base::RunLoop().RunUntilIdle();
// Certificates with the "Web" trust flag set will be returned and forwarded
// to observers.
EXPECT_EQ(1u, updater->GetWebTrustedCertificates().size());
EXPECT_EQ(1u, observer.trust_anchors_.size());
EXPECT_EQ(1u, updater->GetCertificatesWithoutWebTrust().size());
EXPECT_EQ(2u, updater->GetAllServerAndAuthorityCertificates().size());
updater->RemovePolicyProvidedCertsObserver(&observer);
}
TEST_F(NetworkConfigurationUpdaterTest,
DontImportCertificateBeforeCertificateImporterSet) {
PolicyMap policy;
policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(kFakeONC), nullptr);
UpdateProviderPolicy(policy);
::onc::ONCSource source = onc::ONC_SOURCE_USER_POLICY;
EXPECT_CALL(network_config_handler_,
SetPolicy(source, kFakeUsernameHash,
IsEqualTo(GetExpectedFakeNetworkConfigs(source)),
IsEqualTo(GetExpectedFakeGlobalNetworkConfig())));
UserNetworkConfigurationUpdater* updater =
CreateNetworkConfigurationUpdaterForUserPolicy(
true /* allow trusted certs from policy */,
false /* do not set certificate importer */);
MarkPolicyProviderInitialized();
Mock::VerifyAndClearExpectations(&network_config_handler_);
EXPECT_EQ(0u, certificate_importer_->GetAndResetImportCount());
certificate_importer_->SetExpectedONCClientCertificates(
fake_certificates_->client_certificates());
ASSERT_TRUE(client_certificate_importer_owned_);
updater->SetClientCertificateImporterForTest(
std::move(client_certificate_importer_owned_));
EXPECT_EQ(1u, certificate_importer_->GetAndResetImportCount());
}
TEST_F(NetworkConfigurationUpdaterTest, ReplaceDeviceOncPlaceholders) {
PolicyMap policy;
policy.Set(key::kDeviceOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(kFakeONC), nullptr);
UpdateProviderPolicy(policy);
::onc::ONCSource source = onc::ONC_SOURCE_DEVICE_POLICY;
EXPECT_CALL(network_config_handler_,
SetPolicy(source, std::string(),
IsEqualTo(GetExpectedFakeNetworkConfigs(source)),
IsEqualTo(GetExpectedFakeGlobalNetworkConfig())));
CreateNetworkConfigurationUpdaterForDevicePolicy();
MarkPolicyProviderInitialized();
}
class NetworkConfigurationUpdaterTestWithParam
: public NetworkConfigurationUpdaterTest,
public testing::WithParamInterface<const char*> {
protected:
// Returns the currently tested ONC source.
onc::ONCSource CurrentONCSource() {
if (GetParam() == key::kOpenNetworkConfiguration)
return onc::ONC_SOURCE_USER_POLICY;
DCHECK(GetParam() == key::kDeviceOpenNetworkConfiguration);
return onc::ONC_SOURCE_DEVICE_POLICY;
}
// Returns the expected username hash to push policies to
// ManagedNetworkConfigurationHandler.
std::string ExpectedUsernameHash() {
if (GetParam() == key::kOpenNetworkConfiguration)
return kFakeUsernameHash;
return std::string();
}
size_t ExpectedImportCertificatesCallCount() {
if (GetParam() == key::kOpenNetworkConfiguration)
return 1u;
return 0u;
}
void CreateNetworkConfigurationUpdater() {
if (GetParam() == key::kOpenNetworkConfiguration) {
CreateNetworkConfigurationUpdaterForUserPolicy(
false /* do not allow trusted certs from policy */,
true /* set certificate importer */);
} else {
CreateNetworkConfigurationUpdaterForDevicePolicy();
}
}
};
TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) {
PolicyMap policy;
policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(kFakeONC),
nullptr);
UpdateProviderPolicy(policy);
EXPECT_CALL(
network_config_handler_,
SetPolicy(CurrentONCSource(), ExpectedUsernameHash(),
IsEqualTo(GetExpectedFakeNetworkConfigs(CurrentONCSource())),
IsEqualTo(GetExpectedFakeGlobalNetworkConfig())));
certificate_importer_->SetExpectedONCClientCertificates(
fake_certificates_->client_certificates());
CreateNetworkConfigurationUpdater();
MarkPolicyProviderInitialized();
EXPECT_EQ(ExpectedImportCertificatesCallCount(),
certificate_importer_->GetAndResetImportCount());
}
TEST_P(NetworkConfigurationUpdaterTestWithParam,
PolicyNotSetBeforePolicyProviderInitialized) {
PolicyMap policy;
policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(kFakeONC),
nullptr);
UpdateProviderPolicy(policy);
CreateNetworkConfigurationUpdater();
Mock::VerifyAndClearExpectations(&network_config_handler_);
EXPECT_EQ(0u, certificate_importer_->GetAndResetImportCount());
EXPECT_CALL(
network_config_handler_,
SetPolicy(CurrentONCSource(), ExpectedUsernameHash(),
IsEqualTo(GetExpectedFakeNetworkConfigs(CurrentONCSource())),
IsEqualTo(GetExpectedFakeGlobalNetworkConfig())));
certificate_importer_->SetExpectedONCClientCertificates(
fake_certificates_->client_certificates());
MarkPolicyProviderInitialized();
EXPECT_EQ(ExpectedImportCertificatesCallCount(),
certificate_importer_->GetAndResetImportCount());
}
TEST_P(NetworkConfigurationUpdaterTestWithParam,
PolicyAppliedImmediatelyIfProvidersInitialized) {
MarkPolicyProviderInitialized();
PolicyMap policy;
policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(kFakeONC),
nullptr);
UpdateProviderPolicy(policy);
EXPECT_CALL(
network_config_handler_,
SetPolicy(CurrentONCSource(), ExpectedUsernameHash(),
IsEqualTo(GetExpectedFakeNetworkConfigs(CurrentONCSource())),
IsEqualTo(GetExpectedFakeGlobalNetworkConfig())));
certificate_importer_->SetExpectedONCClientCertificates(
fake_certificates_->client_certificates());
CreateNetworkConfigurationUpdater();
EXPECT_EQ(ExpectedImportCertificatesCallCount(),
certificate_importer_->GetAndResetImportCount());
}
TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) {
// Ignore the initial updates.
EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _, _)).Times(AtLeast(1));
CreateNetworkConfigurationUpdater();
MarkPolicyProviderInitialized();
Mock::VerifyAndClearExpectations(&network_config_handler_);
// The certificate importer is only called if the certificates changes. An
// empty policy does not count.
EXPECT_EQ(0u, certificate_importer_->GetAndResetImportCount());
// The Updater should update if policy changes.
EXPECT_CALL(
network_config_handler_,
SetPolicy(CurrentONCSource(), _,
IsEqualTo(GetExpectedFakeNetworkConfigs(CurrentONCSource())),
IsEqualTo(GetExpectedFakeGlobalNetworkConfig())));
certificate_importer_->SetExpectedONCClientCertificates(
fake_certificates_->client_certificates());
PolicyMap policy;
policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(kFakeONC),
nullptr);
UpdateProviderPolicy(policy);
Mock::VerifyAndClearExpectations(&network_config_handler_);
EXPECT_EQ(ExpectedImportCertificatesCallCount(),
certificate_importer_->GetAndResetImportCount());
// Another update is expected if the policy goes away.
EXPECT_CALL(network_config_handler_,
SetPolicy(CurrentONCSource(), _, IsEmpty(), IsEmpty()));
certificate_importer_->SetExpectedONCClientCertificates({});
policy.Erase(GetParam());
UpdateProviderPolicy(policy);
EXPECT_EQ(ExpectedImportCertificatesCallCount(),
certificate_importer_->GetAndResetImportCount());
}
INSTANTIATE_TEST_CASE_P(NetworkConfigurationUpdaterTestWithParamInstance,
NetworkConfigurationUpdaterTestWithParam,
testing::Values(key::kDeviceOpenNetworkConfiguration,
key::kOpenNetworkConfiguration));
} // namespace policy