summaryrefslogtreecommitdiffstats
path: root/chromeos
diff options
context:
space:
mode:
authorpneubeck@google.com <pneubeck@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-26 15:02:51 +0000
committerpneubeck@google.com <pneubeck@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-26 15:02:51 +0000
commit7d7f2bb88febe255663805c93e16adba63e468d8 (patch)
tree052d719ae0d5eb34a95e844c63a0ec49e0806616 /chromeos
parent3103670a5994d88e64b84f56808f904b034b0546 (diff)
downloadchromium_src-7d7f2bb88febe255663805c93e16adba63e468d8.zip
chromium_src-7d7f2bb88febe255663805c93e16adba63e468d8.tar.gz
chromium_src-7d7f2bb88febe255663805c93e16adba63e468d8.tar.bz2
Extract certificate policy application from NetworkLibrary.
This is mostly a refactoring: - Import of certificates is handled by a new CertifcateHandler, which will get more functionality like resolving CertificatePatterns in upcoming commits. - Policy validation moved into NetworkConfigurationUpdater and net_internals, because it covers both certificates and networks. The only functional change is that certificate policies should now also work if ManagedNetworkConfigurationHandler is used instead of NetworkLibrary. BUG=223869 Review URL: https://codereview.chromium.org/14192017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@196735 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos')
-rw-r--r--chromeos/chromeos.gyp20
-rw-r--r--chromeos/network/certificate_handler.cc38
-rw-r--r--chromeos/network/certificate_handler.h38
-rw-r--r--chromeos/network/managed_network_configuration_handler.cc78
-rw-r--r--chromeos/network/managed_network_configuration_handler.h8
-rw-r--r--chromeos/network/managed_network_configuration_handler_unittest.cc6
-rw-r--r--chromeos/network/mock_certificate_handler.cc15
-rw-r--r--chromeos/network/mock_certificate_handler.h28
-rw-r--r--chromeos/network/onc/onc_certificate_importer_unittest.cc60
-rw-r--r--chromeos/network/onc/onc_utils.cc88
-rw-r--r--chromeos/network/onc/onc_utils.h13
-rw-r--r--chromeos/network/onc/onc_validator_unittest.cc7
-rw-r--r--chromeos/test/data/network/invalid_settings_with_repairs.json47
-rw-r--r--chromeos/test/data/network/repaired_toplevel_partially_invalid.onc45
14 files changed, 404 insertions, 87 deletions
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index 3b5eb3d..4b6a7bb 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -211,6 +211,8 @@
'ime/xkeyboard.h',
'login/login_state.cc',
'login/login_state.h',
+ 'network/certificate_handler.cc',
+ 'network/certificate_handler.h',
'network/certificate_pattern.cc',
'network/certificate_pattern.h',
'network/cros_network_functions.cc',
@@ -342,6 +344,14 @@
'dbus/mock_cryptohome_client.h',
'dbus/mock_dbus_thread_manager.cc',
'dbus/mock_dbus_thread_manager.h',
+ 'dbus/mock_gsm_sms_client.cc',
+ 'dbus/mock_gsm_sms_client.h',
+ 'dbus/mock_image_burner_client.cc',
+ 'dbus/mock_image_burner_client.h',
+ 'dbus/mock_power_manager_client.cc',
+ 'dbus/mock_power_manager_client.h',
+ 'dbus/mock_session_manager_client.cc',
+ 'dbus/mock_session_manager_client.h',
'dbus/mock_shill_device_client.cc',
'dbus/mock_shill_device_client.h',
'dbus/mock_shill_ipconfig_client.cc',
@@ -352,14 +362,6 @@
'dbus/mock_shill_profile_client.h',
'dbus/mock_shill_service_client.cc',
'dbus/mock_shill_service_client.h',
- 'dbus/mock_gsm_sms_client.cc',
- 'dbus/mock_gsm_sms_client.h',
- 'dbus/mock_image_burner_client.cc',
- 'dbus/mock_image_burner_client.h',
- 'dbus/mock_power_manager_client.cc',
- 'dbus/mock_power_manager_client.h',
- 'dbus/mock_session_manager_client.cc',
- 'dbus/mock_session_manager_client.h',
'dbus/mock_system_clock_client.cc',
'dbus/mock_system_clock_client.h',
'dbus/mock_update_engine_client.cc',
@@ -370,6 +372,8 @@
'disks/mock_disk_mount_manager.h',
'ime/mock_component_extension_ime_manager_delegate.cc',
'ime/mock_component_extension_ime_manager_delegate.h',
+ 'network/mock_certificate_handler.cc',
+ 'network/mock_certificate_handler.h',
'network/onc/onc_test_utils.cc',
'network/onc/onc_test_utils.h',
],
diff --git a/chromeos/network/certificate_handler.cc b/chromeos/network/certificate_handler.cc
new file mode 100644
index 0000000..d471813
--- /dev/null
+++ b/chromeos/network/certificate_handler.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/network/certificate_handler.h"
+
+#include "base/values.h"
+#include "chromeos/network/onc/onc_certificate_importer.h"
+#include "chromeos/network/onc/onc_utils.h"
+
+namespace chromeos {
+
+CertificateHandler::CertificateHandler() {
+}
+
+CertificateHandler::~CertificateHandler() {
+}
+
+bool CertificateHandler::ImportCertificates(
+ const base::ListValue& certificates,
+ onc::ONCSource source,
+ net::CertificateList* onc_trusted_certificates) {
+ VLOG(2) << "ONC file has " << certificates.GetSize() << " certificates";
+
+ // Web trust is only granted to certificates imported by the user.
+ bool allow_trust_imports = source == onc::ONC_SOURCE_USER_IMPORT;
+ onc::CertificateImporter cert_importer(allow_trust_imports);
+ if (cert_importer.ParseAndStoreCertificates(
+ certificates, onc_trusted_certificates) !=
+ onc::CertificateImporter::IMPORT_OK) {
+ LOG(ERROR) << "Cannot parse some of the certificates in the ONC from "
+ << onc::GetSourceAsString(source);
+ return false;
+ }
+ return true;
+}
+
+} // namespace chromeos
diff --git a/chromeos/network/certificate_handler.h b/chromeos/network/certificate_handler.h
new file mode 100644
index 0000000..7b899d2
--- /dev/null
+++ b/chromeos/network/certificate_handler.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_NETWORK_CERTIFICATE_HANDLER_H_
+#define CHROMEOS_NETWORK_CERTIFICATE_HANDLER_H_
+
+#include "chromeos/chromeos_export.h"
+#include "chromeos/network/onc/onc_constants.h"
+#include "net/cert/x509_certificate.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT CertificateHandler {
+ public:
+ CertificateHandler();
+ virtual ~CertificateHandler();
+
+ // Import the |certificates|, which must be a list of ONC Certificate objects.
+ // If |onc_trusted_certificates| is not NULL, it will be filled with the list
+ // of certificates that requested the TrustBit "Web". Returns true if all
+ // certificates were imported successfully.
+ virtual bool ImportCertificates(
+ const base::ListValue& certificates,
+ onc::ONCSource source,
+ net::CertificateList* onc_trusted_certificates);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CertificateHandler);
+};
+
+} // namespace chromeos
+
+#endif // CHROMEOS_NETWORK_CERTIFICATE_HANDLER_H_
diff --git a/chromeos/network/managed_network_configuration_handler.cc b/chromeos/network/managed_network_configuration_handler.cc
index 58ab03f..a7e7d62 100644
--- a/chromeos/network/managed_network_configuration_handler.cc
+++ b/chromeos/network/managed_network_configuration_handler.cc
@@ -799,35 +799,10 @@ class ManagedNetworkConfigurationHandler::PolicyApplicator
void ManagedNetworkConfigurationHandler::SetPolicy(
onc::ONCSource onc_source,
- const base::DictionaryValue& toplevel_onc) {
+ const base::ListValue& network_configs_onc) {
VLOG(1) << "Setting policies for ONC source "
<< onc::GetSourceAsString(onc_source) << ".";
- // Validate the ONC dictionary. We are liberal and ignore unknown field
- // names and ignore invalid field names in kRecommended arrays.
- onc::Validator validator(false, // Ignore unknown fields.
- false, // Ignore invalid recommended field names.
- true, // Fail on missing fields.
- true); // This ONC comes from policy.
- validator.SetOncSource(onc_source);
-
- onc::Validator::Result validation_result;
- scoped_ptr<base::DictionaryValue> onc_validated =
- validator.ValidateAndRepairObject(
- &onc::kToplevelConfigurationSignature,
- toplevel_onc,
- &validation_result);
-
- if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
- LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source)
- << " produced warnings.";
- } else if (validation_result == onc::Validator::INVALID ||
- onc_validated == NULL) {
- LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
- << " is invalid and couldn't be repaired.";
- return;
- }
-
PolicyMap* policies;
std::string profile;
if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
@@ -846,37 +821,28 @@ void ManagedNetworkConfigurationHandler::SetPolicy(
// This stores all GUIDs of policies that have changed or are new.
std::set<std::string> modified_policies;
- base::ListValue* network_configurations = NULL;
- onc_validated->GetListWithoutPathExpansion(
- onc::toplevel_config::kNetworkConfigurations,
- &network_configurations);
-
- if (network_configurations) {
- while (!network_configurations->empty()) {
- base::Value* network_value = NULL;
- // Passes ownership of network_value.
- network_configurations->Remove(network_configurations->GetSize() - 1,
- &network_value);
- const base::DictionaryValue* network = NULL;
- network_value->GetAsDictionary(&network);
- std::string guid;
- network->GetStringWithoutPathExpansion(onc::network_config::kGUID,
- &guid);
-
- const base::DictionaryValue* old_entry = old_policies[guid];
- const base::DictionaryValue*& new_entry = (*policies)[guid];
- if (new_entry) {
- LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
- << " contains several entries for the same GUID "
- << guid << ".";
- delete new_entry;
- }
- new_entry = network;
-
- if (!old_entry || !old_entry->Equals(new_entry)) {
- modified_policies.insert(guid);
- }
+ for (base::ListValue::const_iterator it = network_configs_onc.begin();
+ it != network_configs_onc.end(); ++it) {
+ const base::DictionaryValue* network = NULL;
+ (*it)->GetAsDictionary(&network);
+ DCHECK(network);
+
+ std::string guid;
+ network->GetStringWithoutPathExpansion(onc::network_config::kGUID, &guid);
+ DCHECK(!guid.empty());
+
+ if (policies->count(guid) > 0) {
+ LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
+ << " contains several entries for the same GUID "
+ << guid << ".";
+ delete (*policies)[guid];
}
+ const base::DictionaryValue* new_entry = network->DeepCopy();
+ (*policies)[guid] = new_entry;
+
+ const base::DictionaryValue* old_entry = old_policies[guid];
+ if (!old_entry || !old_entry->Equals(new_entry))
+ modified_policies.insert(guid);
}
STLDeleteValues(&old_policies);
diff --git a/chromeos/network/managed_network_configuration_handler.h b/chromeos/network/managed_network_configuration_handler.h
index 5b53fff..e563fe4 100644
--- a/chromeos/network/managed_network_configuration_handler.h
+++ b/chromeos/network/managed_network_configuration_handler.h
@@ -18,6 +18,7 @@
namespace base {
class DictionaryValue;
+class ListValue;
}
namespace chromeos {
@@ -118,13 +119,14 @@ class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler {
const base::Closure& callback,
const network_handler::ErrorCallback& error_callback) const;
- // Only to be called by NetworkConfigurationUpdater or from tests.
- // Sets |toplevel_onc| as the current policy of |onc_source|. The network
+ // Only to be called by NetworkConfigurationUpdater or from tests. Sets
+ // |network_configs_onc| as the current policy of |onc_source|. The network
// configurations of the policy will be applied (not necessarily immediately)
// to Shill's profiles and enforced in future configurations until the policy
// associated with |onc_source| is changed again with this function.
+ // This function doesn't validate the policy. The caller must ensure validity.
void SetPolicy(onc::ONCSource onc_source,
- const base::DictionaryValue& toplevel_onc);
+ const base::ListValue& network_configs_onc);
private:
class PolicyApplicator;
diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc
index 49c150a..def9204 100644
--- a/chromeos/network/managed_network_configuration_handler_unittest.cc
+++ b/chromeos/network/managed_network_configuration_handler_unittest.cc
@@ -111,7 +111,11 @@ class ManagedNetworkConfigurationHandlerTest : public testing::Test {
else
policy = test_utils::ReadTestDictionary(path_to_onc);
- managed_handler()->SetPolicy(onc::ONC_SOURCE_USER_POLICY, *policy);
+ base::ListValue* network_configs = NULL;
+ policy->GetListWithoutPathExpansion(
+ onc::toplevel_config::kNetworkConfigurations, &network_configs);
+
+ managed_handler()->SetPolicy(onc::ONC_SOURCE_USER_POLICY, *network_configs);
}
ManagedNetworkConfigurationHandler* managed_handler() {
diff --git a/chromeos/network/mock_certificate_handler.cc b/chromeos/network/mock_certificate_handler.cc
new file mode 100644
index 0000000..8ff080f
--- /dev/null
+++ b/chromeos/network/mock_certificate_handler.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/network/mock_certificate_handler.h"
+
+namespace chromeos {
+
+MockCertificateHandler::MockCertificateHandler() {
+}
+
+MockCertificateHandler::~MockCertificateHandler() {
+}
+
+} // namespace chromeos
diff --git a/chromeos/network/mock_certificate_handler.h b/chromeos/network/mock_certificate_handler.h
new file mode 100644
index 0000000..a73b7a2
--- /dev/null
+++ b/chromeos/network/mock_certificate_handler.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_NETWORK_MOCK_CERTIFICATE_HANDLER_H_
+#define CHROMEOS_NETWORK_MOCK_CERTIFICATE_HANDLER_H_
+
+#include "base/values.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/network/certificate_handler.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT MockCertificateHandler : public CertificateHandler {
+ public:
+ MockCertificateHandler();
+ virtual ~MockCertificateHandler();
+ MOCK_METHOD3(ImportCertificates, bool(const base::ListValue&,
+ onc::ONCSource,
+ net::CertificateList*));
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCertificateHandler);
+};
+
+} // chromeos
+
+#endif // CHROMEOS_NETWORK_MOCK_CERTIFICATE_HANDLER_H_
diff --git a/chromeos/network/onc/onc_certificate_importer_unittest.cc b/chromeos/network/onc/onc_certificate_importer_unittest.cc
index 14106d1..1fbb633 100644
--- a/chromeos/network/onc/onc_certificate_importer_unittest.cc
+++ b/chromeos/network/onc/onc_certificate_importer_unittest.cc
@@ -66,50 +66,63 @@ class ONCCertificateImporterTest : public testing::Test {
ASSERT_TRUE(slot_->os_module_handle());
// Test db should be empty at start of test.
- EXPECT_EQ(0ul, ListCertsInSlot(slot_->os_module_handle()).size());
+ EXPECT_EQ(0ul, ListCertsInSlot().size());
}
virtual void TearDown() {
- EXPECT_TRUE(CleanupSlotContents(slot_->os_module_handle()));
- EXPECT_EQ(0ul, ListCertsInSlot(slot_->os_module_handle()).size());
+ EXPECT_TRUE(CleanupSlotContents());
+ EXPECT_EQ(0ul, ListCertsInSlot().size());
}
virtual ~ONCCertificateImporterTest() {}
protected:
- void AddCertificateFromFile(std::string filename,
- net::CertType expected_type,
- std::string* guid) {
+ void AddCertificatesFromFile(
+ std::string filename,
+ CertificateImporter::ParseResult expected_parse_result) {
scoped_ptr<base::DictionaryValue> onc =
test_utils::ReadTestDictionary(filename);
+ base::Value* certificates_value = NULL;
base::ListValue* certificates = NULL;
- onc->GetListWithoutPathExpansion(toplevel_config::kCertificates,
- &certificates);
-
- base::DictionaryValue* certificate = NULL;
- certificates->GetDictionary(0, &certificate);
- certificate->GetStringWithoutPathExpansion(certificate::kGUID, guid);
+ onc->RemoveWithoutPathExpansion(toplevel_config::kCertificates,
+ &certificates_value);
+ certificates_value->GetAsList(&certificates);
+ onc_certificates_.reset(certificates);
web_trust_certificates_.clear();
CertificateImporter importer(true /* allow web trust */);
- EXPECT_EQ(CertificateImporter::IMPORT_OK,
+ EXPECT_EQ(expected_parse_result,
importer.ParseAndStoreCertificates(*certificates,
&web_trust_certificates_));
result_list_.clear();
+ result_list_ = ListCertsInSlot();
+ }
+
+ void AddCertificateFromFile(std::string filename,
+ net::CertType expected_type,
+ std::string* guid) {
+ AddCertificatesFromFile(filename, CertificateImporter::IMPORT_OK);
+ EXPECT_EQ(1ul, result_list_.size());
+
+ base::DictionaryValue* certificate = NULL;
+ onc_certificates_->GetDictionary(0, &certificate);
+ certificate->GetStringWithoutPathExpansion(certificate::kGUID, guid);
+
CertificateImporter::ListCertsWithNickname(*guid, &result_list_);
ASSERT_EQ(1ul, result_list_.size());
EXPECT_EQ(expected_type, GetCertType(result_list_[0]->os_cert_handle()));
}
+ scoped_ptr<base::ListValue> onc_certificates_;
scoped_refptr<net::CryptoModule> slot_;
net::CertificateList result_list_;
net::CertificateList web_trust_certificates_;
private:
- net::CertificateList ListCertsInSlot(PK11SlotInfo* slot) {
+ net::CertificateList ListCertsInSlot() {
net::CertificateList result;
- CERTCertList* cert_list = PK11_ListCertsInSlot(slot);
+ CERTCertList* cert_list = PK11_ListCertsInSlot(slot_->os_module_handle());
for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
!CERT_LIST_END(node, cert_list);
node = CERT_LIST_NEXT(node)) {
@@ -123,9 +136,9 @@ class ONCCertificateImporterTest : public testing::Test {
return result;
}
- bool CleanupSlotContents(PK11SlotInfo* slot) {
+ bool CleanupSlotContents() {
bool ok = true;
- net::CertificateList certs = ListCertsInSlot(slot);
+ net::CertificateList certs = ListCertsInSlot();
for (size_t i = 0; i < certs.size(); ++i) {
if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(certs[i]))
ok = false;
@@ -136,6 +149,19 @@ class ONCCertificateImporterTest : public testing::Test {
crypto::ScopedTestNSSDB test_nssdb_;
};
+TEST_F(ONCCertificateImporterTest, MultipleCertificates) {
+ AddCertificatesFromFile("managed_toplevel2.onc",
+ CertificateImporter::IMPORT_OK);
+ EXPECT_EQ(onc_certificates_->GetSize(), result_list_.size());
+}
+
+TEST_F(ONCCertificateImporterTest, MultipleCertificatesWithFailures) {
+ AddCertificatesFromFile("toplevel_partially_invalid.onc",
+ CertificateImporter::IMPORT_INCOMPLETE);
+ EXPECT_EQ(2ul, onc_certificates_->GetSize());
+ EXPECT_EQ(1ul, result_list_.size());
+}
+
TEST_F(ONCCertificateImporterTest, AddClientCertificate) {
std::string guid;
AddCertificateFromFile("certificate-client.onc", net::USER_CERT, &guid);
diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
index c14a2a0..1b31c9d 100644
--- a/chromeos/network/onc/onc_utils.cc
+++ b/chromeos/network/onc/onc_utils.cc
@@ -7,11 +7,14 @@
#include "base/base64.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
+#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chromeos/network/network_event_log.h"
#include "chromeos/network/onc/onc_mapper.h"
#include "chromeos/network/onc/onc_signature.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "chromeos/network/onc/onc_validator.h"
#include "crypto/encryptor.h"
#include "crypto/hmac.h"
#include "crypto/symmetric_key.h"
@@ -211,6 +214,8 @@ void ExpandStringsInOncObject(
const OncFieldSignature* field_signature =
GetFieldSignature(signature, it.key());
+ if (!field_signature)
+ continue;
ExpandStringsInOncObject(*field_signature->value_signature,
substitution, inner_object);
@@ -255,12 +260,93 @@ class OncMaskValues : public onc::Mapper {
} // namespace
-CHROMEOS_EXPORT scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
+scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
const onc::OncValueSignature& signature,
const base::DictionaryValue& onc_object,
const std::string& mask) {
return OncMaskValues::Mask(signature, onc_object, mask);
}
+bool ParseAndValidateOncForImport(
+ const std::string& onc_blob,
+ chromeos::onc::ONCSource onc_source,
+ const std::string& passphrase,
+ base::ListValue* network_configs,
+ base::ListValue* certificates) {
+ certificates->Clear();
+ network_configs->Clear();
+ if (onc_blob.empty())
+ return true;
+
+ scoped_ptr<base::DictionaryValue> toplevel_onc =
+ onc::ReadDictionaryFromJson(onc_blob);
+ if (toplevel_onc.get() == NULL) {
+ LOG(ERROR) << "ONC loaded from " << onc::GetSourceAsString(onc_source)
+ << " is not a valid JSON dictionary.";
+ return false;
+ }
+
+ // Check and see if this is an encrypted ONC file. If so, decrypt it.
+ std::string onc_type;
+ toplevel_onc->GetStringWithoutPathExpansion(onc::toplevel_config::kType,
+ &onc_type);
+ if (onc_type == onc::toplevel_config::kEncryptedConfiguration) {
+ toplevel_onc = onc::Decrypt(passphrase, *toplevel_onc);
+ if (toplevel_onc.get() == NULL) {
+ LOG(ERROR) << "Couldn't decrypt the ONC from "
+ << onc::GetSourceAsString(onc_source);
+ return false;
+ }
+ }
+
+ bool from_policy = (onc_source == onc::ONC_SOURCE_USER_POLICY ||
+ onc_source == onc::ONC_SOURCE_DEVICE_POLICY);
+
+ // Validate the ONC dictionary. We are liberal and ignore unknown field
+ // names and ignore invalid field names in kRecommended arrays.
+ onc::Validator validator(false, // Ignore unknown fields.
+ false, // Ignore invalid recommended field names.
+ true, // Fail on missing fields.
+ from_policy);
+ validator.SetOncSource(onc_source);
+
+ onc::Validator::Result validation_result;
+ toplevel_onc = validator.ValidateAndRepairObject(
+ &onc::kToplevelConfigurationSignature,
+ *toplevel_onc,
+ &validation_result);
+
+ if (from_policy) {
+ UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
+ validation_result == onc::Validator::VALID);
+ }
+
+ bool success = true;
+ if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
+ LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source)
+ << " produced warnings.";
+ success = false;
+ } else if (validation_result == onc::Validator::INVALID ||
+ toplevel_onc == NULL) {
+ LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
+ << " is invalid and couldn't be repaired.";
+ return false;
+ }
+
+ base::ListValue* validated_certs = NULL;
+ if (toplevel_onc->GetListWithoutPathExpansion(
+ onc::toplevel_config::kCertificates, &validated_certs)) {
+ certificates->Swap(validated_certs);
+ }
+
+ base::ListValue* validated_networks = NULL;
+ if (toplevel_onc->GetListWithoutPathExpansion(
+ onc::toplevel_config::kNetworkConfigurations, &validated_networks)) {
+ network_configs->Swap(validated_networks);
+ }
+
+ return success;
+}
+
} // namespace onc
} // namespace chromeos
diff --git a/chromeos/network/onc/onc_utils.h b/chromeos/network/onc/onc_utils.h
index 1d4e28f..6a6d273 100644
--- a/chromeos/network/onc/onc_utils.h
+++ b/chromeos/network/onc/onc_utils.h
@@ -14,6 +14,7 @@
namespace base {
class DictionaryValue;
+class ListValue;
}
namespace chromeos {
@@ -73,6 +74,18 @@ CHROMEOS_EXPORT scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
const base::DictionaryValue& onc_object,
const std::string& mask);
+// Decrypts |onc_blob| with |passphrase| if necessary. Clears |network_configs|
+// and |certificates| and fills them with the validated NetworkConfigurations
+// and Certificates of |onc_blob|. Returns false if any validation errors or
+// warnings occurred. Still, some networks or certificates might be added to the
+// output lists and should be further processed by the caller.
+CHROMEOS_EXPORT bool ParseAndValidateOncForImport(
+ const std::string& onc_blob,
+ chromeos::onc::ONCSource onc_source,
+ const std::string& passphrase,
+ base::ListValue* network_configs,
+ base::ListValue* certificates);
+
} // namespace onc
} // namespace chromeos
diff --git a/chromeos/network/onc/onc_validator_unittest.cc b/chromeos/network/onc/onc_validator_unittest.cc
index cf7bfdc..d839466 100644
--- a/chromeos/network/onc/onc_validator_unittest.cc
+++ b/chromeos/network/onc/onc_validator_unittest.cc
@@ -285,7 +285,12 @@ INSTANTIATE_TEST_CASE_P(
&kNetworkConfigurationSignature,
false),
RepairParams("",
- "network-nested-state-field-repaired"))));
+ "network-nested-state-field-repaired")),
+ std::make_pair(OncParams("toplevel-with-repairable-networks",
+ &kToplevelConfigurationSignature,
+ false,
+ ONC_SOURCE_DEVICE_POLICY),
+ RepairParams("", "toplevel-with-repaired-networks"))));
// Strict and liberal validator repair identically.
INSTANTIATE_TEST_CASE_P(
diff --git a/chromeos/test/data/network/invalid_settings_with_repairs.json b/chromeos/test/data/network/invalid_settings_with_repairs.json
index 1e03c6f..34c9ce1 100644
--- a/chromeos/test/data/network/invalid_settings_with_repairs.json
+++ b/chromeos/test/data/network/invalid_settings_with_repairs.json
@@ -271,5 +271,52 @@
{ "GUID": "3",
"PKCS12": "abc" ,
"Type": "Client" } ]
+ },
+ "toplevel-with-repaired-networks": {
+ "NetworkConfigurations":
+ [ { "GUID": "{485d6076-dd44-6b6d-69787465725f5045}",
+ "Type": "WiFi",
+ "Name": "My WiFi Network",
+ "WiFi": {
+ "SSID": "ssid-none",
+ "Security": "None" }
+ },
+ { "GUID": "{485d6076-dd44-6b6d-69787465725f5046}",
+ "Type": "WiFi",
+ "Name": "My WiFi Network2",
+ "WiFi": {
+ "Passphrase": "12345678",
+ "SSID": "ssid-wpa",
+ "Security": "WPA-PSK" }
+ }
+ ],
+ "Certificates": [],
+ "Type": "UnencryptedConfiguration",
+ },
+ "toplevel-with-repairable-networks": {
+ "NetworkConfigurations":
+ [ { "GUID": "{485d6076-dd44-6b6d-69787465725f5045}",
+ "Type": "WiFi",
+ "Name": "My WiFi Network",
+ "UnknownField1": "Value1",
+ "UnknownField2": {
+ "UnknownSubField": "Value2" },
+ "WiFi": {
+ "SSID": "ssid-none",
+ "Security": "None" }
+ },
+ { "GUID": "{485d6076-dd44-6b6d-69787465725f5046}",
+ "Type": "WiFi",
+ "Name": "My WiFi Network2",
+ "WiFi": {
+ "Passphrase": "12345678",
+ "SSID": "ssid-wpa",
+ "UnknownField1": "Value1",
+ "Security": "WPA-PSK" }
+ }
+ ],
+ "Certificates": [],
+ "Type": "UnencryptedConfiguration",
+ "UnknownField3": [],
}
}
diff --git a/chromeos/test/data/network/repaired_toplevel_partially_invalid.onc b/chromeos/test/data/network/repaired_toplevel_partially_invalid.onc
new file mode 100644
index 0000000..7758838
--- /dev/null
+++ b/chromeos/test/data/network/repaired_toplevel_partially_invalid.onc
@@ -0,0 +1,45 @@
+{ "Type": "UnencryptedConfiguration",
+ "NetworkConfigurations":
+ [ { "GUID": "123",
+ "Type": "VPN",
+ "Name": "testopenvpn",
+ "IPConfigs": [
+ { "Type": "IPv4",
+ "IPAddress": "127.0.0.1",
+ "RoutingPrefix": 32 }
+ ],
+ "VPN": {
+ "Host": "policys host",
+ "Recommended": ["Host"],
+ "Type": "OpenVPN",
+ "OpenVPN": {
+ "Port": 1194,
+ "Username": "abc ${LOGIN_ID} def",
+ "Recommended": [ "Username", "Password" ],
+ "ClientCertType": "Pattern",
+ "ClientCertPattern": {
+ "IssuerCARef": [ "openvpn-test-ca" ],
+ "Recommended": [ "EnrollmentURI", "IssuerCARef" ]
+ }
+ },
+ "IPsec": {
+ "AuthenticationType": "PSK",
+ "PSK": "sharedkey",
+ "IKEVersion": 1
+ }
+ }
+ }
+ ],
+ "Certificates": [
+ {
+ "GUID": "{f998f760-272b-6939-4c2beffe428697ac}",
+ "PKCS12": "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",
+ "Type": "Client"
+ },
+ {
+ "GUID": "{456}",
+ "PKCS12": "ERROR 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",
+ "Type": "Client"
+ }
+ ]
+}