summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chromeos/network_settings/onc_signature.cc11
-rw-r--r--chrome/browser/chromeos/network_settings/onc_translation_tables.cc30
-rw-r--r--chrome/browser/chromeos/network_settings/onc_translation_tables.h24
-rw-r--r--chrome/browser/chromeos/network_settings/onc_translator.h45
-rw-r--r--chrome/browser/chromeos/network_settings/onc_translator_onc_to_shill.cc210
-rw-r--r--chrome/browser/chromeos/network_settings/onc_translator_shill_to_onc.cc231
-rw-r--r--chrome/browser/chromeos/network_settings/onc_translator_unittest.cc86
-rw-r--r--chrome/chrome_browser_chromeos.gypi5
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--chrome/test/data/chromeos/network_settings/shill_ethernet.json4
-rw-r--r--chrome/test/data/chromeos/network_settings/shill_l2tpipsec.json10
-rw-r--r--chrome/test/data/chromeos/network_settings/shill_openvpn.json25
-rw-r--r--chrome/test/data/chromeos/network_settings/valid_l2tpipsec.onc18
-rw-r--r--chrome/test/data/chromeos/network_settings/valid_openvpn.onc31
14 files changed, 727 insertions, 4 deletions
diff --git a/chrome/browser/chromeos/network_settings/onc_signature.cc b/chrome/browser/chromeos/network_settings/onc_signature.cc
index 4d332cf..ee8cf52 100644
--- a/chrome/browser/chromeos/network_settings/onc_signature.cc
+++ b/chrome/browser/chromeos/network_settings/onc_signature.cc
@@ -124,8 +124,8 @@ const OncFieldSignature openvpn_fields[] = {
&kBoolSignature },
{ vpn::kRemoteCertEKU, flimflam::kOpenVPNRemoteCertEKUProperty,
&kStringSignature },
- { vpn::kRemoteCertKU, flimflam::kOpenVPNRemoteCertKUProperty,
- &kStringListSignature },
+ // This field is converted during translation, see onc_translator_*.
+ { vpn::kRemoteCertKU, NULL, &kStringListSignature },
{ vpn::kRemoteCertTLS, flimflam::kOpenVPNRemoteCertTLSProperty,
&kStringSignature },
{ vpn::kRenegSec, flimflam::kOpenVPNRenegSecProperty, &kIntegerSignature },
@@ -152,7 +152,8 @@ const OncFieldSignature vpn_fields[] = {
{ vpn::kIPsec, NULL, &kIPsecSignature },
{ vpn::kL2TP, NULL, &kL2TPSignature },
{ vpn::kOpenVPN, NULL, &kOpenVPNSignature },
- { kType, flimflam::kProviderTypeProperty, &kStringSignature },
+ // This field is converted during translation, see onc_translator_*.
+ { kType, NULL, &kStringSignature },
{ NULL }
};
@@ -169,6 +170,7 @@ const OncFieldSignature ipconfig_fields[] = {
{ kNameServers, NULL, &kStringSignature },
{ ipconfig::kRoutingPrefix, NULL, &kIntegerSignature },
{ kSearchDomains, NULL, &kStringListSignature },
+ // This field is converted during translation, see onc_translator_*.
{ kType, NULL, &kStringSignature },
{ NULL }
};
@@ -217,7 +219,8 @@ const OncFieldSignature network_configuration_fields[] = {
{ kProxySettings, NULL, &kProxySettingsSignature },
{ kRemove, NULL, &kBoolSignature },
{ kSearchDomains, NULL, &kStringListSignature },
- { kType, flimflam::kTypeProperty, &kStringSignature },
+ // This field is converted during translation, see onc_translator_*.
+ { kType, NULL, &kStringSignature },
{ kVPN, NULL, &kVPNSignature },
{ kWiFi, NULL, &kWiFiSignature },
{ NULL }
diff --git a/chrome/browser/chromeos/network_settings/onc_translation_tables.cc b/chrome/browser/chromeos/network_settings/onc_translation_tables.cc
new file mode 100644
index 0000000..59633c4
--- /dev/null
+++ b/chrome/browser/chromeos/network_settings/onc_translation_tables.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/network_settings/onc_translation_tables.h"
+
+#include <cstddef>
+
+#include "chrome/browser/chromeos/cros/onc_constants.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+namespace onc {
+
+const StringTranslationEntry kNetworkTypeTable[] = {
+ { kEthernet, flimflam::kTypeEthernet },
+ { kWiFi, flimflam::kTypeWifi },
+ { kCellular, flimflam::kTypeCellular },
+ { kVPN, flimflam::kTypeVPN },
+ { NULL }
+};
+
+const StringTranslationEntry kVPNTypeTable[] = {
+ { vpn::kTypeL2TP_IPsec, flimflam::kProviderL2tpIpsec },
+ { vpn::kOpenVPN, flimflam::kProviderOpenVpn },
+ { NULL }
+};
+
+} // namespace onc
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/network_settings/onc_translation_tables.h b/chrome/browser/chromeos/network_settings/onc_translation_tables.h
new file mode 100644
index 0000000..66594d8
--- /dev/null
+++ b/chrome/browser/chromeos/network_settings/onc_translation_tables.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_NETWORK_SETTINGS_ONC_TRANSLATION_TABLES_H_
+#define CHROME_BROWSER_CHROMEOS_NETWORK_SETTINGS_ONC_TRANSLATION_TABLES_H_
+
+namespace chromeos {
+namespace onc {
+
+struct StringTranslationEntry {
+ const char* onc_value;
+ const char* shill_value;
+};
+
+// These tables contain the mapping from ONC strings to Shill strings.
+// These are NULL-terminated arrays.
+extern const StringTranslationEntry kNetworkTypeTable[];
+extern const StringTranslationEntry kVPNTypeTable[];
+
+} // namespace onc
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_NETWORK_SETTINGS_ONC_TRANSLATION_TABLES_H_
diff --git a/chrome/browser/chromeos/network_settings/onc_translator.h b/chrome/browser/chromeos/network_settings/onc_translator.h
new file mode 100644
index 0000000..900851f
--- /dev/null
+++ b/chrome/browser/chromeos/network_settings/onc_translator.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_NETWORK_SETTINGS_ONC_TRANSLATOR_H_
+#define CHROME_BROWSER_CHROMEOS_NETWORK_SETTINGS_ONC_TRANSLATOR_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace chromeos {
+namespace onc {
+
+struct OncValueSignature;
+
+// Translates a hierarchical ONC dictionary |onc_object| to a flat Shill
+// dictionary. The |signature| declares the type of |onc_object| and must point
+// to one of the signature objects in "onc_signature.h". The resulting Shill
+// dictionary is returned.
+//
+// This function is used to translate network settings from ONC to Shill's
+// format before sending them to Shill.
+scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill(
+ const OncValueSignature* signature,
+ const base::DictionaryValue& onc_object);
+
+// Translates a |shill_dictionary| to an ONC object according to the given
+// |onc_signature|. |onc_signature| must point to a signature object in
+// "onc_signature.h". The resulting ONC object is returned.
+//
+// This function is used to translate network settings coming from Shill to ONC
+// before sending them to the UI. The result doesn't have to be valid ONC, but
+// only a subset of it and includes only the values that are actually required
+// by the UI.
+scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
+ const base::DictionaryValue& shill_dictionary,
+ const OncValueSignature* onc_signature);
+
+} // namespace onc
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_NETWORK_SETTINGS_ONC_TRANSLATOR_H_
diff --git a/chrome/browser/chromeos/network_settings/onc_translator_onc_to_shill.cc b/chrome/browser/chromeos/network_settings/onc_translator_onc_to_shill.cc
new file mode 100644
index 0000000..2182dd5
--- /dev/null
+++ b/chrome/browser/chromeos/network_settings/onc_translator_onc_to_shill.cc
@@ -0,0 +1,210 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The implementation of TranslateONCObjectToShill is structured in two parts:
+// - The recursion through the existing ONC hierarchy
+// see TranslateONCHierarchy
+// - The local translation of an object depending on the associated signature
+// see LocalTranslator::TranslateFields
+
+#include "chrome/browser/chromeos/network_settings/onc_translator.h"
+
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/cros/onc_constants.h"
+#include "chrome/browser/chromeos/network_settings/onc_signature.h"
+#include "chrome/browser/chromeos/network_settings/onc_translation_tables.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+namespace onc {
+
+namespace {
+
+scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
+ std::string str;
+ if (!value.GetAsString(&str))
+ base::JSONWriter::Write(&value, &str);
+ return make_scoped_ptr(base::Value::CreateStringValue(str));
+}
+
+// This class is responsible to translate the local fields of the given
+// |onc_object| according to |onc_signature| into |shill_dictionary|. This
+// translation should consider (if possible) only fields of this ONC object and
+// not nested objects because recursion is handled by the calling function
+// TranslateONCHierarchy.
+class LocalTranslator {
+ public:
+ LocalTranslator(const OncValueSignature& onc_signature,
+ const base::DictionaryValue& onc_object,
+ base::DictionaryValue* shill_dictionary)
+ : onc_signature_(&onc_signature),
+ onc_object_(&onc_object),
+ shill_dictionary_(shill_dictionary) {
+ }
+
+ void TranslateFields();
+
+ private:
+ void TranslateOpenVPN();
+ void TranslateVPN();
+ void TranslateNetworkConfiguration();
+
+ // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
+ // translation (shill_property_name) is defined by |onc_signature_|.
+ void CopyFieldsAccordingToSignature();
+
+ // Adds |value| to |shill_dictionary| at the field shill_property_name given
+ // by the associated signature. Takes ownership of |value|. Does nothing if
+ // |value| is NULL or the property name cannot be read from the signature.
+ void AddValueAccordingToSignature(const std::string& onc_field_name,
+ scoped_ptr<base::Value> value);
+
+ // If existent, translates the entry at |onc_field_name| in |onc_object_|
+ // using |table|. It is an error if no matching table entry is found. Writes
+ // the result as entry at |shill_property_name| in |shill_dictionary_|.
+ void TranslateWithTableAndSet(const std::string& onc_field_name,
+ const StringTranslationEntry table[],
+ const std::string& shill_property_name);
+
+ const OncValueSignature* onc_signature_;
+ const base::DictionaryValue* onc_object_;
+ base::DictionaryValue* shill_dictionary_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalTranslator);
+};
+
+void LocalTranslator::TranslateFields() {
+ if (onc_signature_ == &kNetworkConfigurationSignature)
+ TranslateNetworkConfiguration();
+ else if (onc_signature_ == &kVPNSignature)
+ TranslateVPN();
+ else if (onc_signature_ == &kOpenVPNSignature)
+ TranslateOpenVPN();
+ else
+ CopyFieldsAccordingToSignature();
+}
+
+void LocalTranslator::TranslateOpenVPN() {
+ // Shill supports only one RemoteCertKU but ONC a list.
+ // Copy only the first entry if existing.
+ const base::ListValue* certKUs;
+ std::string certKU;
+ if (onc_object_->GetListWithoutPathExpansion(vpn::kRemoteCertKU, &certKUs) &&
+ certKUs->GetString(0, &certKU)) {
+ shill_dictionary_->SetStringWithoutPathExpansion(
+ flimflam::kOpenVPNRemoteCertKUProperty, certKU);
+ }
+
+ for (base::DictionaryValue::Iterator it(*onc_object_); it.HasNext();
+ it.Advance()) {
+ scoped_ptr<base::Value> translated;
+ if (it.key() == vpn::kSaveCredentials || it.key() == vpn::kRemoteCertKU) {
+ translated.reset(it.value().DeepCopy());
+ } else {
+ // Shill wants all Provider/VPN fields to be strings.
+ translated = ConvertValueToString(it.value());
+ }
+ AddValueAccordingToSignature(it.key(), translated.Pass());
+ }
+}
+
+void LocalTranslator::TranslateVPN() {
+ TranslateWithTableAndSet(kType, kVPNTypeTable,
+ flimflam::kProviderTypeProperty);
+ CopyFieldsAccordingToSignature();
+}
+
+void LocalTranslator::TranslateNetworkConfiguration() {
+ TranslateWithTableAndSet(kType, kNetworkTypeTable, flimflam::kTypeProperty);
+ CopyFieldsAccordingToSignature();
+}
+
+void LocalTranslator::CopyFieldsAccordingToSignature() {
+ for (base::DictionaryValue::Iterator it(*onc_object_); it.HasNext();
+ it.Advance()) {
+ AddValueAccordingToSignature(it.key(),
+ make_scoped_ptr(it.value().DeepCopy()));
+ }
+}
+
+void LocalTranslator::AddValueAccordingToSignature(
+ const std::string& onc_name,
+ scoped_ptr<base::Value> value) {
+ if (value.get() == NULL)
+ return;
+ const OncFieldSignature* field_signature =
+ GetFieldSignature(*onc_signature_, onc_name);
+ DCHECK(field_signature != NULL);
+ if (field_signature == NULL || field_signature->shill_property_name == NULL)
+ return;
+
+ shill_dictionary_->SetWithoutPathExpansion(
+ field_signature->shill_property_name, value.release());
+}
+
+void LocalTranslator::TranslateWithTableAndSet(
+ const std::string& onc_field_name,
+ const StringTranslationEntry table[],
+ const std::string& shill_property_name) {
+ std::string onc_value;
+ if (!onc_object_->GetStringWithoutPathExpansion(onc_field_name, &onc_value))
+ return;
+
+ for (int i = 0; table[i].onc_value != NULL; ++i) {
+ if (onc_value != table[i].onc_value)
+ continue;
+ shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name,
+ table[i].shill_value);
+ return;
+ }
+ // As we previously validate ONC, this case should never occur. If it still
+ // occurs, we should check here. Otherwise the failure will only show up much
+ // later in Shill.
+ LOG(ERROR) << "Value '" << onc_value << "' for field '"
+ << onc_field_name << "' cannot be translated to Shill";
+}
+
+// Iterates recursively over |onc_object| and its |signature|. At each object
+// applies the local translation using LocalTranslator::TranslateFields. The
+// results are written to |shill_dictionary|.
+void TranslateONCHierarchy(const OncValueSignature& signature,
+ const base::DictionaryValue& onc_object,
+ base::DictionaryValue* shill_dictionary) {
+ // Translates fields of |onc_object| and writes them to |shill_dictionary_|.
+ LocalTranslator translator(signature, onc_object, shill_dictionary);
+ translator.TranslateFields();
+
+ // Recurse into nested objects.
+ for (base::DictionaryValue::Iterator it(onc_object); it.HasNext();
+ it.Advance()) {
+ const base::DictionaryValue* inner_object;
+ if (!it.value().GetAsDictionary(&inner_object))
+ continue;
+
+ const OncFieldSignature* field_signature =
+ GetFieldSignature(signature, it.key());
+
+ TranslateONCHierarchy(*field_signature->value_signature, *inner_object,
+ shill_dictionary);
+ }
+}
+
+} // namespace
+
+scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill(
+ const OncValueSignature* onc_signature,
+ const base::DictionaryValue& onc_object) {
+ CHECK(onc_signature != NULL);
+ scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue);
+ TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get());
+ return shill_dictionary.Pass();
+}
+
+} // namespace onc
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/network_settings/onc_translator_shill_to_onc.cc b/chrome/browser/chromeos/network_settings/onc_translator_shill_to_onc.cc
new file mode 100644
index 0000000..b3c40de
--- /dev/null
+++ b/chrome/browser/chromeos/network_settings/onc_translator_shill_to_onc.cc
@@ -0,0 +1,231 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/network_settings/onc_translator.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/cros/onc_constants.h"
+#include "chrome/browser/chromeos/network_settings/onc_signature.h"
+#include "chrome/browser/chromeos/network_settings/onc_translation_tables.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+namespace onc {
+
+namespace {
+
+// Converts |str| to a base::Value of the given |type|. If the conversion fails,
+// returns NULL.
+scoped_ptr<base::Value> ConvertStringToValue(const std::string& str,
+ base::Value::Type type) {
+ base::Value* value;
+ if (type == base::Value::TYPE_STRING)
+ value = base::Value::CreateStringValue(str);
+ else
+ value = base::JSONReader::Read(str);
+
+ if (value == NULL || value->GetType() != type) {
+ delete value;
+ value = NULL;
+ }
+ return make_scoped_ptr(value);
+}
+
+// This class implements the translation of properties from the given
+// |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
+// recursive calls to TranslateShillServiceToONCPart, nested objects are
+// translated.
+class ShillToONCTranslator {
+ public:
+ ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
+ const OncValueSignature& onc_signature)
+ : shill_dictionary_(&shill_dictionary),
+ onc_signature_(&onc_signature) {
+ }
+
+ // Translates the associated Shill dictionary and creates an ONC object of the
+ // given signature.
+ scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
+
+ private:
+ void TranslateOpenVPN();
+ void TranslateVPN();
+ void TranslateNetworkConfiguration();
+
+ // Creates an ONC object from |shill_dictionary| according to the signature
+ // associated to |onc_field_name| and adds it to |onc_object_| at
+ // |onc_field_name|.
+ void TranslateAndAddNestedObject(const std::string& onc_field_name);
+
+ // Copies all entries from |shill_dictionary_| to |onc_object_| for which a
+ // translation (shill_property_name) is defined by |onc_signature_|.
+ void CopyPropertiesAccordingToSignature();
+
+ // If existent, translates the entry at |shill_property_name| in
+ // |shill_dictionary_| using |table|. It is an error if no matching table
+ // entry is found. Writes the result as entry at |onc_field_name| in
+ // |onc_object_|.
+ void TranslateWithTableAndSet(const std::string& shill_property_name,
+ const StringTranslationEntry table[],
+ const std::string& onc_field_name);
+
+ const base::DictionaryValue* shill_dictionary_;
+ const OncValueSignature* onc_signature_;
+ scoped_ptr<base::DictionaryValue> onc_object_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
+};
+
+scoped_ptr<base::DictionaryValue>
+ShillToONCTranslator::CreateTranslatedONCObject() {
+ onc_object_.reset(new base::DictionaryValue);
+ if (onc_signature_ == &kNetworkConfigurationSignature)
+ TranslateNetworkConfiguration();
+ else if (onc_signature_ == &kVPNSignature)
+ TranslateVPN();
+ else if (onc_signature_ == &kOpenVPNSignature)
+ TranslateOpenVPN();
+ else
+ CopyPropertiesAccordingToSignature();
+ return onc_object_.Pass();
+}
+
+void ShillToONCTranslator::TranslateOpenVPN() {
+ // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
+ // wraps the value into a list.
+ std::string certKU;
+ if (shill_dictionary_->GetStringWithoutPathExpansion(
+ flimflam::kOpenVPNRemoteCertKUProperty, &certKU)) {
+ scoped_ptr<base::ListValue> certKUs(new base::ListValue);
+ certKUs->AppendString(certKU);
+ onc_object_->SetWithoutPathExpansion(vpn::kRemoteCertKU, certKUs.release());
+ }
+
+ for (const OncFieldSignature* field_signature = onc_signature_->fields;
+ field_signature->onc_field_name != NULL; ++field_signature) {
+ const base::Value* shill_value;
+ if (field_signature->shill_property_name == NULL ||
+ !shill_dictionary_->GetWithoutPathExpansion(
+ field_signature->shill_property_name, &shill_value)) {
+ continue;
+ }
+
+ scoped_ptr<base::Value> translated;
+ std::string shill_str;
+ const std::string& onc_field_name = field_signature->onc_field_name;
+ if (onc_field_name == vpn::kSaveCredentials ||
+ onc_field_name == vpn::kRemoteCertKU) {
+ translated.reset(shill_value->DeepCopy());
+ } else if (shill_value->GetAsString(&shill_str)) {
+ // Shill wants all Provider/VPN fields to be strings. Translates these
+ // strings back to the correct ONC type.
+ translated = ConvertStringToValue(
+ shill_str,
+ field_signature->value_signature->onc_type);
+
+ if (translated.get() == NULL) {
+ LOG(ERROR) << "Shill property '" << field_signature->shill_property_name
+ << "' with value '" << shill_value
+ << "' couldn't be converted to base::Value::Type "
+ << field_signature->value_signature->onc_type;
+ }
+ } else {
+ LOG(ERROR) << "Shill property '" << field_signature->shill_property_name
+ << "' has value '" << shill_value
+ << "', but expected a string";
+ }
+ onc_object_->SetWithoutPathExpansion(onc_field_name, translated.release());
+ }
+}
+
+void ShillToONCTranslator::TranslateVPN() {
+ TranslateWithTableAndSet(flimflam::kProviderTypeProperty, kVPNTypeTable,
+ kType);
+ CopyPropertiesAccordingToSignature();
+
+ std::string vpn_type;
+ if (onc_object_->GetStringWithoutPathExpansion(kType, &vpn_type)) {
+ if (vpn_type == vpn::kTypeL2TP_IPsec) {
+ TranslateAndAddNestedObject(vpn::kIPsec);
+ TranslateAndAddNestedObject(vpn::kL2TP);
+ } else {
+ TranslateAndAddNestedObject(vpn_type);
+ }
+ }
+}
+
+void ShillToONCTranslator::TranslateAndAddNestedObject(
+ const std::string& onc_field_name) {
+ const OncFieldSignature* field_signature =
+ GetFieldSignature(*onc_signature_, onc_field_name);
+ ShillToONCTranslator nested_translator(*shill_dictionary_,
+ *field_signature->value_signature);
+ scoped_ptr<base::DictionaryValue> nested_object =
+ nested_translator.CreateTranslatedONCObject();
+ onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
+}
+
+void ShillToONCTranslator::TranslateNetworkConfiguration() {
+ TranslateWithTableAndSet(flimflam::kTypeProperty, kNetworkTypeTable, kType);
+ CopyPropertiesAccordingToSignature();
+
+ std::string network_type;
+ if (onc_object_->GetStringWithoutPathExpansion(kType, &network_type))
+ TranslateAndAddNestedObject(network_type);
+}
+
+void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
+ for (const OncFieldSignature* field_signature = onc_signature_->fields;
+ field_signature->onc_field_name != NULL; ++field_signature) {
+ const base::Value* shill_value;
+ if (field_signature->shill_property_name == NULL ||
+ !shill_dictionary_->GetWithoutPathExpansion(
+ field_signature->shill_property_name, &shill_value)) {
+ continue;
+ }
+ onc_object_->SetWithoutPathExpansion(
+ field_signature->onc_field_name, shill_value->DeepCopy());
+ }
+}
+
+void ShillToONCTranslator::TranslateWithTableAndSet(
+ const std::string& shill_property_name,
+ const StringTranslationEntry table[],
+ const std::string& onc_field_name) {
+ std::string shill_value;
+ if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
+ &shill_value)) {
+ return;
+ }
+
+ for (int i = 0; table[i].onc_value != NULL; ++i) {
+ if (shill_value != table[i].shill_value)
+ continue;
+ onc_object_->SetStringWithoutPathExpansion(onc_field_name,
+ table[i].onc_value);
+ return;
+ }
+ LOG(ERROR) << "Shill property '" << shill_property_name << "' with value '"
+ << shill_value << "' couldn't be translated to ONC";
+}
+
+} // namespace
+
+scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
+ const base::DictionaryValue& shill_dictionary,
+ const OncValueSignature* onc_signature) {
+ CHECK(onc_signature != NULL);
+
+ ShillToONCTranslator translator(shill_dictionary, *onc_signature);
+ return translator.CreateTranslatedONCObject();
+}
+
+} // namespace onc
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/network_settings/onc_translator_unittest.cc b/chrome/browser/chromeos/network_settings/onc_translator_unittest.cc
new file mode 100644
index 0000000..96a9f5c
--- /dev/null
+++ b/chrome/browser/chromeos/network_settings/onc_translator_unittest.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/network_settings/onc_translator.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/cros/onc_constants.h"
+#include "chrome/browser/chromeos/network_settings/onc_signature.h"
+#include "chrome/browser/chromeos/network_settings/onc_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace onc {
+
+// First parameter: Filename of source ONC.
+// Second parameter: Filename of expected translated Shill json.
+class ONCTranslatorOncToShillTest
+ : public ::testing::TestWithParam<std::pair<std::string, std::string> > {
+};
+
+// Test the translation from ONC to Shill json.
+TEST_P(ONCTranslatorOncToShillTest, Translate) {
+ std::string source_onc_filename = GetParam().first;
+ scoped_ptr<const base::DictionaryValue> onc_network(
+ test_utils::ReadTestDictionary(source_onc_filename));
+ std::string result_json_filename = GetParam().second;
+ scoped_ptr<const base::DictionaryValue> shill_network(
+ test_utils::ReadTestDictionary(result_json_filename));
+
+ scoped_ptr<base::DictionaryValue> translation(TranslateONCObjectToShill(
+ &kNetworkConfigurationSignature, *onc_network));
+
+ EXPECT_TRUE(test_utils::Equals(shill_network.get(), translation.get()));
+}
+
+// Test different network types, such that each ONC object type is tested at
+// least once.
+INSTANTIATE_TEST_CASE_P(
+ ONCTranslatorOncToShillTest,
+ ONCTranslatorOncToShillTest,
+ ::testing::Values(
+ std::make_pair("valid.onc", "shill_ethernet.json"),
+ std::make_pair("valid_l2tpipsec.onc", "shill_l2tpipsec.json"),
+ std::make_pair("valid_openvpn.onc", "shill_openvpn.json")));
+
+// Test the translation from Shill json to ONC.
+//
+// Note: This translation direction doesn't have to reconstruct all of the ONC
+// fields, as Chrome doesn't need all of a Service's properties.
+TEST(ONCTranslatorShillToOncTest, L2TPIPsec) {
+ scoped_ptr<base::DictionaryValue> onc_network(
+ test_utils::ReadTestDictionary("valid_l2tpipsec.onc"));
+
+ // These two fields are part of the ONC (and are required). However, they
+ // don't exist explicitly in the Shill dictionary. As there is no use-case
+ // yet, that requires to reconstruct these fields from a Shill dictionary, we
+ // don't require their translation.
+ onc_network->Remove("VPN.IPsec.AuthenticationType", NULL);
+ onc_network->Remove("VPN.IPsec.IKEVersion", NULL);
+
+ scoped_ptr<const base::DictionaryValue> shill_network(
+ test_utils::ReadTestDictionary("shill_l2tpipsec.json"));
+
+ scoped_ptr<base::DictionaryValue> translation(TranslateShillServiceToONCPart(
+ *shill_network, &kNetworkConfigurationSignature));
+
+ EXPECT_TRUE(test_utils::Equals(onc_network.get(), translation.get()));
+}
+
+TEST(ONCTranslatorShillToOncTest, OpenVPN) {
+ scoped_ptr<const base::DictionaryValue> onc_network(
+ test_utils::ReadTestDictionary("valid_openvpn.onc"));
+
+ scoped_ptr<const base::DictionaryValue> shill_network(
+ test_utils::ReadTestDictionary("shill_openvpn.json"));
+
+ scoped_ptr<base::DictionaryValue> translation(TranslateShillServiceToONCPart(
+ *shill_network, &kNetworkConfigurationSignature));
+
+ EXPECT_TRUE(test_utils::Equals(onc_network.get(), translation.get()));
+}
+
+} // namespace onc
+} // namespace chromeos
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 629564b..31ad993 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -516,6 +516,11 @@
'browser/chromeos/network_settings/onc_normalizer.h',
'browser/chromeos/network_settings/onc_signature.cc',
'browser/chromeos/network_settings/onc_signature.h',
+ 'browser/chromeos/network_settings/onc_translation_tables.cc',
+ 'browser/chromeos/network_settings/onc_translation_tables.h',
+ 'browser/chromeos/network_settings/onc_translator.h',
+ 'browser/chromeos/network_settings/onc_translator_shill_to_onc.cc',
+ 'browser/chromeos/network_settings/onc_translator_onc_to_shill.cc',
'browser/chromeos/network_settings/onc_validator.cc',
'browser/chromeos/network_settings/onc_validator.h',
'browser/chromeos/notifications/balloon_view_host_chromeos.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 5fc0ff2..fcc6f1b 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -613,6 +613,7 @@
'browser/chromeos/network_settings/onc_normalizer_unittest.cc',
'browser/chromeos/network_settings/onc_test_utils.cc',
'browser/chromeos/network_settings/onc_test_utils.h',
+ 'browser/chromeos/network_settings/onc_translator_unittest.cc',
'browser/chromeos/network_settings/onc_validator_unittest.cc',
'browser/chromeos/offline/offline_load_page_unittest.cc',
'browser/chromeos/preferences_unittest.cc',
diff --git a/chrome/test/data/chromeos/network_settings/shill_ethernet.json b/chrome/test/data/chromeos/network_settings/shill_ethernet.json
new file mode 100644
index 0000000..7754932
--- /dev/null
+++ b/chrome/test/data/chromeos/network_settings/shill_ethernet.json
@@ -0,0 +1,4 @@
+{ "GUID": "guid",
+ "Type": "ethernet",
+ "Name": "name",
+}
diff --git a/chrome/test/data/chromeos/network_settings/shill_l2tpipsec.json b/chrome/test/data/chromeos/network_settings/shill_l2tpipsec.json
new file mode 100644
index 0000000..f529a97
--- /dev/null
+++ b/chrome/test/data/chromeos/network_settings/shill_l2tpipsec.json
@@ -0,0 +1,10 @@
+{ "GUID": "guid",
+ "Type": "vpn",
+ "Name": "MyL2TPVPN",
+ "Provider.Host": "some.host.org",
+ "Provider.Type": "l2tpipsec",
+ "L2TPIPsec.PSK": "some_preshared_key",
+ "L2TPIPsec.User": "some username",
+ "L2TPIPsec.Password": "some password",
+ "SaveCredentials": true
+}
diff --git a/chrome/test/data/chromeos/network_settings/shill_openvpn.json b/chrome/test/data/chromeos/network_settings/shill_openvpn.json
new file mode 100644
index 0000000..1bf84ef
--- /dev/null
+++ b/chrome/test/data/chromeos/network_settings/shill_openvpn.json
@@ -0,0 +1,25 @@
+{
+ "GUID": "{a3860e83-f03d-4cb1-bafa-b22c9e746950}",
+ "Type": "vpn",
+ "Name": "google-dogfood",
+ "SaveCredentials": false,
+ "Provider.Type": "openvpn",
+ "Provider.Host": "v.ext.google.com",
+ "OpenVPN.AuthRetry": "interact",
+ "OpenVPN.User": "some username",
+ "OpenVPN.Password": "some password",
+ "OpenVPN.StaticChallenge": "Please enter token OTP",
+ "OpenVPN.CompLZO": "true",
+ "OpenVPN.ServerPollTimeout": "10",
+ "OpenVPN.RemoteCertKU": "e0",
+ "OpenVPN.CACertNSS": "{14ff4d51-64c1-4c86-a622-054d8e55e750}",
+ "OpenVPN.RemoteCertTLS": "server",
+ "OpenVPN.Port": "443",
+ "OpenVPN.TLSRemote": "v.ext.google.com",
+ "OpenVPN.KeyDirection": "1",
+ "OpenVPN.RenegSec": "0",
+ "OpenVPN.RemoteCertEKU": "TLS Web Server Authentication",
+ "OpenVPN.Proto": "udp",
+ "OpenVPN.PushPeerInfo": "true",
+ "OpenVPN.TLSAuthContents": "-----BEGIN OpenVPN Static key V1-----\nf8a19b8fddda3a38e06b883c48c83474\n0d1dfe7e5cadb2891387ac2d85198cdf\ne14274d03d12c4128c6c8967f84b1b39\n22452fb869280cde868bcf3932615927\nab1948d951c19183276fa249fd6e1e5f\nfc1c41400b59493a39cad872f5c7e777\n310d685d9c30abff7f206afc09cc99d9\ne40b2091e29af5b37d191628fba6d86e\n3a239b45b1b5a6be3229663ee7a7dc67\n2fa5be59fe7ceb41d2c78f94237c2185\n0aea1b06d739bca83240671167ddd2c2\n9cfd931df468536bfd1be99cd05160d8\n09ebfe4b8da88fb1923b19ad1abfc45e\n0402321e41af54e7d19ac95b1a7cec9a\nbf60a8eabcd5eecc84773af211477ee9\n9c988269638f9f1bb668028bb688dea2\nEND OpenVPN Static key V1-----\n"
+}
diff --git a/chrome/test/data/chromeos/network_settings/valid_l2tpipsec.onc b/chrome/test/data/chromeos/network_settings/valid_l2tpipsec.onc
new file mode 100644
index 0000000..0e0bc5f
--- /dev/null
+++ b/chrome/test/data/chromeos/network_settings/valid_l2tpipsec.onc
@@ -0,0 +1,18 @@
+{ "GUID": "guid",
+ "Type": "VPN",
+ "Name": "MyL2TPVPN",
+ "VPN": {
+ "Type": "L2TP-IPsec",
+ "Host": "some.host.org",
+ "IPsec": {
+ "AuthenticationType": "PSK",
+ "IKEVersion": 1,
+ "PSK": "some_preshared_key",
+ "SaveCredentials": true
+ },
+ "L2TP": {
+ "Username": "some username",
+ "Password": "some password"
+ }
+ }
+}
diff --git a/chrome/test/data/chromeos/network_settings/valid_openvpn.onc b/chrome/test/data/chromeos/network_settings/valid_openvpn.onc
new file mode 100644
index 0000000..512cb0e
--- /dev/null
+++ b/chrome/test/data/chromeos/network_settings/valid_openvpn.onc
@@ -0,0 +1,31 @@
+{
+ "GUID": "{a3860e83-f03d-4cb1-bafa-b22c9e746950}",
+ "Name": "google-dogfood",
+ "Type": "VPN",
+ "VPN": {
+ "Host": "v.ext.google.com",
+ "Type": "OpenVPN",
+ "OpenVPN": {
+ "AuthRetry": "interact",
+ "CompLZO": "true",
+ "KeyDirection": "1",
+ "Password": "some password",
+ "Port": 443,
+ "Proto": "udp",
+ "PushPeerInfo": true,
+ "RemoteCertEKU": "TLS Web Server Authentication",
+ "RemoteCertKU": [
+ "e0"
+ ],
+ "RemoteCertTLS": "server",
+ "RenegSec": 0,
+ "SaveCredentials": false,
+ "ServerCARef": "{14ff4d51-64c1-4c86-a622-054d8e55e750}",
+ "ServerPollTimeout": 10,
+ "StaticChallenge": "Please enter token OTP",
+ "TLSAuthContents": "-----BEGIN OpenVPN Static key V1-----\nf8a19b8fddda3a38e06b883c48c83474\n0d1dfe7e5cadb2891387ac2d85198cdf\ne14274d03d12c4128c6c8967f84b1b39\n22452fb869280cde868bcf3932615927\nab1948d951c19183276fa249fd6e1e5f\nfc1c41400b59493a39cad872f5c7e777\n310d685d9c30abff7f206afc09cc99d9\ne40b2091e29af5b37d191628fba6d86e\n3a239b45b1b5a6be3229663ee7a7dc67\n2fa5be59fe7ceb41d2c78f94237c2185\n0aea1b06d739bca83240671167ddd2c2\n9cfd931df468536bfd1be99cd05160d8\n09ebfe4b8da88fb1923b19ad1abfc45e\n0402321e41af54e7d19ac95b1a7cec9a\nbf60a8eabcd5eecc84773af211477ee9\n9c988269638f9f1bb668028bb688dea2\nEND OpenVPN Static key V1-----\n",
+ "TLSRemote": "v.ext.google.com",
+ "Username": "some username",
+ }
+ }
+}