summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-27 19:26:47 +0000
committerpneubeck@chromium.org <pneubeck@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-27 19:26:47 +0000
commit339683804974a6c6fa6e7a368f0d2c45dec6139d (patch)
tree24fbc1d684b68e98df20efb5c486f253d2a8acdf
parent8ac9390be956d3ae676813f9ff84936cdbb9c932 (diff)
downloadchromium_src-339683804974a6c6fa6e7a368f0d2c45dec6139d.zip
chromium_src-339683804974a6c6fa6e7a368f0d2c45dec6139d.tar.gz
chromium_src-339683804974a6c6fa6e7a368f0d2c45dec6139d.tar.bz2
Implementation of a Translator between ONC and Shill.
The onc::Translator can either convert a hierarchical ONC dictionary into a flat Shill property list or the other way round. The implementation is not complete but supports VPN and Ethernet mostly. Later CLs will provide the complete support of ONC. This new code will not be in use, yet, but prepares for further changes to the network settings. BUG=147624 TBR=ben@chromium.org Review URL: https://chromiumcodereview.appspot.com/11222002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169709 0039d316-1c4b-4281-b951-d872f2087c98
-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",
+ }
+ }
+}