| Index: chrome/browser/chromeos/network_settings/onc_validator.cc | 
| diff --git a/chrome/browser/chromeos/network_settings/onc_validator.cc b/chrome/browser/chromeos/network_settings/onc_validator.cc | 
| index ec4922797a060dbcef90e6a6490000da59e9260f..dbbc548db3c7bbdd2d0f9ba3bea60d8ea3a7658e 100644 | 
| --- a/chrome/browser/chromeos/network_settings/onc_validator.cc | 
| +++ b/chrome/browser/chromeos/network_settings/onc_validator.cc | 
| @@ -7,15 +7,47 @@ | 
| #include <algorithm> | 
| #include <string> | 
|  | 
| +#include "base/json/json_writer.h" | 
| #include "base/logging.h" | 
| +#include "base/string_number_conversions.h" | 
| #include "base/string_util.h" | 
| +#include "base/utf_string_conversions.h" | 
| #include "base/values.h" | 
| #include "chrome/browser/chromeos/cros/onc_constants.h" | 
| #include "chrome/browser/chromeos/network_settings/onc_signature.h" | 
| +#include "grit/generated_resources.h" | 
| +#include "ui/base/l10n/l10n_util.h" | 
|  | 
| namespace chromeos { | 
| namespace onc { | 
|  | 
| +namespace { | 
| + | 
| +string16 ValueToString(const base::Value& value) { | 
| +  std::string json; | 
| +  base::JSONWriter::Write(&value, &json); | 
| +  return UTF8ToUTF16(json); | 
| +} | 
| + | 
| +// Copied from policy/configuration_policy_handler.cc. | 
| +// TODO(pneubeck): move to a common place like base/. | 
| +string16 ValueTypeToString(Value::Type type) { | 
| +  static const char* strings[] = { | 
| +    "null", | 
| +    "boolean", | 
| +    "integer", | 
| +    "double", | 
| +    "string", | 
| +    "binary", | 
| +    "dictionary", | 
| +    "list" | 
| +  }; | 
| +  DCHECK(static_cast<size_t>(type) < arraysize(strings)); | 
| +  return ASCIIToUTF16(strings[type]); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| Validator::Validator( | 
| bool error_on_unknown_field, | 
| bool error_on_wrong_recommended, | 
| @@ -32,29 +64,45 @@ Validator::~Validator() { | 
|  | 
| scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject( | 
| const OncValueSignature* object_signature, | 
| -    const base::DictionaryValue& onc_object) { | 
| +    const base::DictionaryValue& onc_object, | 
| +    std::string* messages) { | 
| CHECK(object_signature != NULL); | 
| +  messages_.clear(); | 
| +  bool error = false; | 
| scoped_ptr<base::Value> result_value = | 
| -      MapValue(*object_signature, onc_object); | 
| +      MapValue(*object_signature, onc_object, &error); | 
| +  if (error) | 
| +    result_value.reset(); | 
| + | 
| base::DictionaryValue* result_dict = NULL; | 
| if (result_value.get() != NULL) { | 
| result_value.release()->GetAsDictionary(&result_dict); | 
| CHECK(result_dict != NULL); | 
| } | 
|  | 
| +  if (messages) | 
| +    *messages = JoinMessages(); | 
| + | 
| return make_scoped_ptr(result_dict); | 
| } | 
|  | 
| scoped_ptr<base::Value> Validator::MapValue( | 
| const OncValueSignature& signature, | 
| -    const base::Value& onc_value) { | 
| +    const base::Value& onc_value, | 
| +    bool* error) { | 
| if (onc_value.GetType() != signature.onc_type) { | 
| DVLOG(1) << "Wrong type. Expected " << signature.onc_type | 
| << ", but found " << onc_value.GetType(); | 
| +    AddError(l10n_util::GetStringFUTF8( | 
| +        IDS_NETWORK_CONFIG_ERROR_VALUE_HAS_WRONG_TYPE, | 
| +        ValueToString(onc_value), ValueTypeToString(signature.onc_type), | 
| +        ValueTypeToString(onc_value.GetType()))); | 
| +    *error = true; | 
| return scoped_ptr<base::Value>(); | 
| } | 
|  | 
| -  scoped_ptr<base::Value> repaired = Mapper::MapValue(signature, onc_value); | 
| +  scoped_ptr<base::Value> repaired = | 
| +      Mapper::MapValue(signature, onc_value, error); | 
| if (repaired.get() != NULL) | 
| CHECK_EQ(repaired->GetType(), signature.onc_type); | 
| return repaired.Pass(); | 
| @@ -62,11 +110,14 @@ scoped_ptr<base::Value> Validator::MapValue( | 
|  | 
| scoped_ptr<base::DictionaryValue> Validator::MapObject( | 
| const OncValueSignature& signature, | 
| -    const base::DictionaryValue& onc_object) { | 
| +    const base::DictionaryValue& onc_object, | 
| +    bool* error) { | 
| scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue); | 
|  | 
| bool valid; | 
| -  if (&signature == &kNetworkConfigurationSignature) | 
| +  if (&signature == &kToplevelConfigurationSignature) | 
| +    valid = ValidateToplevelConfiguration(onc_object, repaired.get()); | 
| +  else if (&signature == &kNetworkConfigurationSignature) | 
| valid = ValidateNetworkConfiguration(onc_object, repaired.get()); | 
| else if (&signature == &kEthernetSignature) | 
| valid = ValidateEthernet(onc_object, repaired.get()); | 
| @@ -93,10 +144,51 @@ scoped_ptr<base::DictionaryValue> Validator::MapObject( | 
| else | 
| valid = ValidateObjectDefault(signature, onc_object, repaired.get()); | 
|  | 
| -  if (valid) | 
| +  if (valid) { | 
| return repaired.Pass(); | 
| -  else | 
| +  } else { | 
| +    *error = true; | 
| return scoped_ptr<base::DictionaryValue>(); | 
| +  } | 
| +} | 
| + | 
| +scoped_ptr<base::Value> Validator::MapField( | 
| +    const std::string& field_name, | 
| +    const OncValueSignature& object_signature, | 
| +    const base::Value& onc_value, | 
| +    bool* found_unknown_field, | 
| +    bool* error) { | 
| +  path_.push_back(field_name); | 
| +  bool current_field_unknown = false; | 
| +  scoped_ptr<base::Value> result = Mapper::MapField( | 
| +      field_name, object_signature, onc_value, ¤t_field_unknown, error); | 
| + | 
| +  DCHECK_EQ(field_name, path_.back()); | 
| +  path_.pop_back(); | 
| + | 
| +  if (current_field_unknown) { | 
| +    *found_unknown_field = true; | 
| +    DVLOG(1) << (error_on_unknown_field_ ? "Error" : "Warning") | 
| +             << ": Unknown field name '" << field_name << "'."; | 
| +    AddMessage(error_on_unknown_field_, l10n_util::GetStringFUTF8( | 
| +        IDS_NETWORK_CONFIG_ERROR_UNKNOWN_FIELD_NAME, | 
| +        UTF8ToUTF16(field_name))); | 
| +  } | 
| + | 
| +  return result.Pass(); | 
| +} | 
| + | 
| +scoped_ptr<base::Value> Validator::MapEntry(int index, | 
| +                                            const OncValueSignature& signature, | 
| +                                            const base::Value& onc_value, | 
| +                                            bool* error) { | 
| +  std::string str = base::IntToString(index); | 
| +  path_.push_back(str); | 
| +  scoped_ptr<base::Value> result = Mapper::MapEntry(index, signature, | 
| +                                                    onc_value, error); | 
| +  DCHECK_EQ(str, path_.back()); | 
| +  path_.pop_back(); | 
| +  return result.Pass(); | 
| } | 
|  | 
| bool Validator::ValidateObjectDefault( | 
| @@ -107,17 +199,15 @@ bool Validator::ValidateObjectDefault( | 
| bool nested_error_occured = false; | 
| MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured, | 
| result); | 
| -  if (nested_error_occured) | 
| -    return false; | 
|  | 
| -  if (found_unknown_field) { | 
| -    if (error_on_unknown_field_) { | 
| -      DVLOG(1) << "Unknown field name. Aborting."; | 
| -      return false; | 
| -    } | 
| -    DVLOG(1) << "Unknown field name. Ignoring."; | 
| +  if (found_unknown_field && error_on_unknown_field_) { | 
| +    DVLOG(1) << "Unknown field names are errors: Aborting."; | 
| +    return false; | 
| } | 
|  | 
| +  if (nested_error_occured) | 
| +    return false; | 
| + | 
| return ValidateRecommendedField(signature, result); | 
| } | 
|  | 
| @@ -140,8 +230,11 @@ bool Validator::ValidateRecommendedField( | 
| recommended.reset(recommended_list); | 
|  | 
| if (!managed_onc_) { | 
| +    AddWarning(l10n_util::GetStringFUTF8( | 
| +        IDS_NETWORK_CONFIG_ERROR_UNEXPECTED_FIELD_IN_UNMANAGED_CONFIG, | 
| +        ASCIIToUTF16(onc::kRecommended))); | 
| DVLOG(1) << "Found a " << onc::kRecommended | 
| -             << " field in unmanaged ONC. Removing it."; | 
| +             << " field in an unmanaged ONC. Removing it."; | 
| return true; | 
| } | 
|  | 
| @@ -169,8 +262,11 @@ bool Validator::ValidateRecommendedField( | 
| } | 
|  | 
| if (found_error) { | 
| +      AddMessage(error_on_wrong_recommended_, l10n_util::GetStringFUTF8( | 
| +          IDS_NETWORK_CONFIG_ERROR_UNKNOWN_FIELD_RECOMMENDED, | 
| +          ASCIIToUTF16(field_name))); | 
| DVLOG(1) << "Found " << error_cause << " field name '" << field_name | 
| -               << "' in kRecommended array. " | 
| +               << "' in a " << onc::kRecommended << " array. " | 
| << (error_on_wrong_recommended_ ? "Aborting." : "Ignoring."); | 
| if (error_on_wrong_recommended_) | 
| return false; | 
| @@ -185,44 +281,42 @@ bool Validator::ValidateRecommendedField( | 
| return true; | 
| } | 
|  | 
| -namespace { | 
| +bool Validator::ValidateToplevelConfiguration( | 
| +    const base::DictionaryValue& onc_object, | 
| +    base::DictionaryValue* result) { | 
| +  if (!ValidateObjectDefault(kToplevelConfigurationSignature, | 
| +                             onc_object, result)) { | 
| +    return false; | 
| +  } | 
|  | 
| -std::string JoinStringRange(const char** range_begin, | 
| -                            const char** range_end, | 
| -                            const std::string& separator) { | 
| -  std::vector<std::string> string_vector; | 
| -  std::copy(range_begin, range_end, std::back_inserter(string_vector)); | 
| -  return JoinString(string_vector, separator); | 
| -} | 
| +  static const char* kValidTypes[] = | 
| +      { kUnencryptedConfiguration, kEncryptedConfiguration, NULL }; | 
| +  if (FieldExistsAndHasNoValueOf(*result, kType, kValidTypes)) | 
| +    return false; | 
|  | 
| -bool RequireAnyOf(const std::string &actual, const char** valid_values) { | 
| -  const char** it = valid_values; | 
| -  for (; *it != NULL; ++it) { | 
| -    if (actual == *it) | 
| -      return true; | 
| -  } | 
| -  DVLOG(1) << "Found " << actual << ", but expected one of " | 
| -           << JoinStringRange(valid_values, it, ", "); | 
| -  return false; | 
| -} | 
| +  bool allRequiredExist = true; | 
|  | 
| -bool IsInRange(int actual, int lower_bound, int upper_bound) { | 
| -  if (lower_bound <= actual && actual <= upper_bound) | 
| -    return true; | 
| -  DVLOG(1) << "Found " << actual << ", which is out of range [" << lower_bound | 
| -           << ", " << upper_bound << "]"; | 
| -  return false; | 
| -} | 
| +  // Not part of the ONC spec yet: | 
| +  // We don't require the type field and default to UnencryptedConfiguration. | 
| +  std::string type = kUnencryptedConfiguration; | 
| +  result->GetStringWithoutPathExpansion(kType, &type); | 
| +  if (type == kUnencryptedConfiguration && | 
| +      !result->HasKey(kNetworkConfigurations) && | 
| +      !result->HasKey(kCertificates)) { | 
| +    DVLOG(1) << "Neither " << kNetworkConfigurations << " nor " | 
| +             << kCertificates << " present."; | 
| + | 
| +    AddMessage(error_on_missing_field_, | 
| +               l10n_util::GetStringFUTF8( | 
| +                   IDS_NETWORK_CONFIG_ERROR_NETWORKS_OR_CERTS_REQUIRED, | 
| +                   ASCIIToUTF16(kNetworkConfigurations), | 
| +                   ASCIIToUTF16(kCertificates))); | 
| +    allRequiredExist = false; | 
| +  } | 
|  | 
| -bool RequireField(const base::DictionaryValue& dict, std::string key) { | 
| -  if (dict.HasKey(key)) | 
| -    return true; | 
| -  DVLOG(1) << "Required field " << key << " missing."; | 
| -  return false; | 
| +  return !error_on_missing_field_ || allRequiredExist; | 
| } | 
|  | 
| -}  // namespace | 
| - | 
| bool Validator::ValidateNetworkConfiguration( | 
| const base::DictionaryValue& onc_object, | 
| base::DictionaryValue* result) { | 
| @@ -231,12 +325,9 @@ bool Validator::ValidateNetworkConfiguration( | 
| return false; | 
| } | 
|  | 
| -  std::string type; | 
| static const char* kValidTypes[] = { kEthernet, kVPN, kWiFi, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kType, &type) && | 
| -      !RequireAnyOf(type, kValidTypes)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, kType, kValidTypes)) | 
| return false; | 
| -  } | 
|  | 
| bool allRequiredExist = RequireField(*result, kGUID); | 
|  | 
| @@ -245,6 +336,9 @@ bool Validator::ValidateNetworkConfiguration( | 
| if (!remove) { | 
| allRequiredExist &= RequireField(*result, kName); | 
| allRequiredExist &= RequireField(*result, kType); | 
| + | 
| +    std::string type; | 
| +    result->GetStringWithoutPathExpansion(kType, &type); | 
| allRequiredExist &= type.empty() || RequireField(*result, type); | 
| } | 
|  | 
| @@ -258,14 +352,15 @@ bool Validator::ValidateEthernet( | 
| if (!ValidateObjectDefault(kEthernetSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string auth; | 
| static const char* kValidAuthentications[] = { kNone, k8021X, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kAuthentication, &auth) && | 
| -      !RequireAnyOf(auth, kValidAuthentications)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, kAuthentication, | 
| +                                 kValidAuthentications)) { | 
| return false; | 
| } | 
|  | 
| bool allRequiredExist = true; | 
| +  std::string auth; | 
| +  result->GetStringWithoutPathExpansion(kAuthentication, &auth); | 
| if (auth == k8021X) | 
| allRequiredExist &= RequireField(*result, kEAP); | 
|  | 
| @@ -279,19 +374,17 @@ bool Validator::ValidateIPConfig( | 
| if (!ValidateObjectDefault(kIPConfigSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string type; | 
| static const char* kValidTypes[] = { kIPv4, kIPv6, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(ipconfig::kType, &type) && | 
| -      !RequireAnyOf(type, kValidTypes)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, ipconfig::kType, kValidTypes)) | 
| return false; | 
| -  } | 
|  | 
| -  int routing_prefix; | 
| +  std::string type; | 
| +  result->GetStringWithoutPathExpansion(ipconfig::kType, &type); | 
| int lower_bound = 1; | 
| // In case of missing type, choose higher upper_bound. | 
| int upper_bound = (type == kIPv4) ? 32 : 128; | 
| -  if (result->GetIntegerWithoutPathExpansion(kRoutingPrefix, &routing_prefix) && | 
| -      !IsInRange(routing_prefix, lower_bound, upper_bound)) { | 
| +  if (FieldExistsAndIsNotInRange(*result, kRoutingPrefix, | 
| +                                 lower_bound, upper_bound)) { | 
| return false; | 
| } | 
|  | 
| @@ -309,16 +402,16 @@ bool Validator::ValidateWiFi( | 
| if (!ValidateObjectDefault(kWiFiSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string security; | 
| static const char* kValidSecurities[] = | 
| { kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kSecurity, &security) && | 
| -      !RequireAnyOf(security, kValidSecurities)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, kSecurity, kValidSecurities)) | 
| return false; | 
| -  } | 
|  | 
| bool allRequiredExist = RequireField(*result, kSecurity) & | 
| RequireField(*result, kSSID); | 
| + | 
| +  std::string security; | 
| +  result->GetStringWithoutPathExpansion(kSecurity, &security); | 
| if (security == kWEP_8021X || security == kWPA_EAP) | 
| allRequiredExist &= RequireField(*result, kEAP); | 
| else if (security == kWEP_PSK || security == kWPA_PSK) | 
| @@ -334,16 +427,14 @@ bool Validator::ValidateVPN( | 
| if (!ValidateObjectDefault(kVPNSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string type; | 
| static const char* kValidTypes[] = | 
| { kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(vpn::kType, &type) && | 
| -      !RequireAnyOf(type, kValidTypes)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, vpn::kType, kValidTypes)) | 
| return false; | 
| -  } | 
|  | 
| bool allRequiredExist = RequireField(*result, vpn::kType); | 
| - | 
| +  std::string type; | 
| +  result->GetStringWithoutPathExpansion(vpn::kType, &type); | 
| if (type == kOpenVPN) { | 
| allRequiredExist &= RequireField(*result, kOpenVPN); | 
| } else if (type == kIPsec) { | 
| @@ -364,26 +455,24 @@ bool Validator::ValidateIPsec( | 
| if (!ValidateObjectDefault(kIPsecSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string auth; | 
| static const char* kValidAuthentications[] = { kPSK, kCert, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kAuthenticationType, &auth) && | 
| -      !RequireAnyOf(auth, kValidAuthentications)) { | 
| -    return false; | 
| -  } | 
| - | 
| -  std::string cert_type; | 
| static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && | 
| -      !RequireAnyOf(cert_type, kValidCertTypes)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, kAuthenticationType, | 
| +                                 kValidAuthentications) | | 
| +      FieldExistsAndHasNoValueOf(*result, kClientCertType, kValidCertTypes)) { | 
| return false; | 
| } | 
|  | 
| bool allRequiredExist = RequireField(*result, kAuthenticationType) & | 
| RequireField(*result, kIKEVersion); | 
| +  std::string auth; | 
| +  result->GetStringWithoutPathExpansion(kAuthenticationType, &auth); | 
| if (auth == kCert) { | 
| allRequiredExist &= RequireField(*result, kClientCertType) & | 
| RequireField(*result, kServerCARef); | 
| } | 
| +  std::string cert_type; | 
| +  result->GetStringWithoutPathExpansion(kClientCertType, &cert_type); | 
| if (cert_type == kPattern) | 
| allRequiredExist &= RequireField(*result, kClientCertPattern); | 
| else if (cert_type == kRef) | 
| @@ -401,31 +490,23 @@ bool Validator::ValidateOpenVPN( | 
| if (!ValidateObjectDefault(kOpenVPNSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string auth_retry; | 
| static const char* kValidAuthRetryValues[] = | 
| { openvpn::kNone, kInteract, kNoInteract, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kAuthRetry, &auth_retry) && | 
| -      !RequireAnyOf(auth_retry, kValidAuthRetryValues)) { | 
| -    return false; | 
| -  } | 
| - | 
| -  std::string cert_type; | 
| static const char* kValidCertTypes[] = | 
| { certificate::kNone, kRef, kPattern, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && | 
| -      !RequireAnyOf(cert_type, kValidCertTypes)) { | 
| -    return false; | 
| -  } | 
| - | 
| -  std::string cert_tls; | 
| static const char* kValidCertTlsValues[] = | 
| { openvpn::kNone, openvpn::kServer, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kRemoteCertTLS, &cert_tls) && | 
| -      !RequireAnyOf(cert_tls, kValidCertTlsValues)) { | 
| + | 
| +  if (FieldExistsAndHasNoValueOf(*result, kAuthRetry, kValidAuthRetryValues) | | 
| +      FieldExistsAndHasNoValueOf(*result, kClientCertType, kValidCertTypes) | | 
| +      FieldExistsAndHasNoValueOf(*result, kRemoteCertTLS, | 
| +                                 kValidCertTlsValues)) { | 
| return false; | 
| } | 
|  | 
| bool allRequiredExist = RequireField(*result, kClientCertType); | 
| +  std::string cert_type; | 
| +  result->GetStringWithoutPathExpansion(kClientCertType, &cert_type); | 
| if (cert_type == kPattern) | 
| allRequiredExist &= RequireField(*result, kClientCertPattern); | 
| else if (cert_type == kRef) | 
| @@ -458,15 +539,13 @@ bool Validator::ValidateProxySettings(const base::DictionaryValue& onc_object, | 
| if (!ValidateObjectDefault(kProxySettingsSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string type; | 
| static const char* kValidTypes[] = { kDirect, kManual, kPAC, kWPAD, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(proxy::kType, &type) && | 
| -      !RequireAnyOf(type, kValidTypes)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, proxy::kType, kValidTypes)) | 
| return false; | 
| -  } | 
|  | 
| bool allRequiredExist = RequireField(*result, proxy::kType); | 
| - | 
| +  std::string type; | 
| +  result->GetStringWithoutPathExpansion(proxy::kType, &type); | 
| if (type == kManual) | 
| allRequiredExist &= RequireField(*result, kManual); | 
| else if (type == kPAC) | 
| @@ -494,32 +573,22 @@ bool Validator::ValidateEAP(const base::DictionaryValue& onc_object, | 
| if (!ValidateObjectDefault(kEAPSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string inner; | 
| static const char* kValidInnerValues[] = | 
| { kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kInner, &inner) && | 
| -      !RequireAnyOf(inner, kValidInnerValues)) { | 
| -    return false; | 
| -  } | 
| - | 
| -  std::string outer; | 
| static const char* kValidOuterValues[] = | 
| { kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA, | 
| NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kOuter, &outer) && | 
| -      !RequireAnyOf(outer, kValidOuterValues)) { | 
| -    return false; | 
| -  } | 
| - | 
| -  std::string cert_type; | 
| static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && | 
| -      !RequireAnyOf(cert_type, kValidCertTypes )) { | 
| + | 
| +  if (FieldExistsAndHasNoValueOf(*result, kInner, kValidInnerValues) | | 
| +      FieldExistsAndHasNoValueOf(*result, kOuter, kValidOuterValues) | | 
| +      FieldExistsAndHasNoValueOf(*result, kClientCertType, kValidCertTypes)) { | 
| return false; | 
| } | 
|  | 
| bool allRequiredExist = RequireField(*result, kOuter); | 
| - | 
| +  std::string cert_type; | 
| +  result->GetStringWithoutPathExpansion(kClientCertType, &cert_type); | 
| if (cert_type == kPattern) | 
| allRequiredExist &= RequireField(*result, kClientCertPattern); | 
| else if (cert_type == kRef) | 
| @@ -535,12 +604,9 @@ bool Validator::ValidateCertificate( | 
| if (!ValidateObjectDefault(kCertificateSignature, onc_object, result)) | 
| return false; | 
|  | 
| -  std::string type; | 
| static const char* kValidTypes[] = { kClient, kServer, kAuthority, NULL }; | 
| -  if (result->GetStringWithoutPathExpansion(certificate::kType, &type) && | 
| -      !RequireAnyOf(type, kValidTypes)) { | 
| +  if (FieldExistsAndHasNoValueOf(*result, certificate::kType, kValidTypes)) | 
| return false; | 
| -  } | 
|  | 
| bool allRequiredExist = RequireField(*result, kGUID); | 
|  | 
| @@ -549,6 +615,8 @@ bool Validator::ValidateCertificate( | 
| if (!remove) { | 
| allRequiredExist &= RequireField(*result, certificate::kType); | 
|  | 
| +    std::string type; | 
| +    result->GetStringWithoutPathExpansion(certificate::kType, &type); | 
| if (type == kClient) | 
| allRequiredExist &= RequireField(*result, kPKCS12); | 
| else if (type == kServer || type == kAuthority) | 
| @@ -558,5 +626,105 @@ bool Validator::ValidateCertificate( | 
| return !error_on_missing_field_ || allRequiredExist; | 
| } | 
|  | 
| +namespace { | 
| + | 
| +std::string JoinStringRange(const char** range_begin, | 
| +                            const char** range_end, | 
| +                            const std::string& separator) { | 
| +  std::vector<std::string> string_vector; | 
| +  std::copy(range_begin, range_end, std::back_inserter(string_vector)); | 
| +  return JoinString(string_vector, separator); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +bool Validator::FieldExistsAndHasNoValueOf(const base::DictionaryValue& object, | 
| +                                           const std::string &field_name, | 
| +                                           const char** valid_values) { | 
| +  std::string actual_value; | 
| +  if (!object.GetStringWithoutPathExpansion(field_name, &actual_value)) | 
| +    return false; | 
| + | 
| +  const char** it = valid_values; | 
| +  for (; *it != NULL; ++it) { | 
| +    if (actual_value == *it) | 
| +      return false; | 
| +  } | 
| +  std::string valid_values_str = | 
| +      "[" + JoinStringRange(valid_values, it, ", ") + "]"; | 
| +  path_.push_back(field_name); | 
| +  AddError(l10n_util::GetStringFUTF8( | 
| +      IDS_NETWORK_CONFIG_ERROR_INVALID_VALUE, | 
| +      UTF8ToUTF16(actual_value), | 
| +      UTF8ToUTF16(valid_values_str))); | 
| +  path_.pop_back(); | 
| +  DVLOG(1) << "Found " << actual_value << ", but expected one of " | 
| +           << valid_values_str; | 
| +  return true; | 
| +} | 
| + | 
| +bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object, | 
| +                                           const std::string &field_name, | 
| +                                           int lower_bound, | 
| +                                           int upper_bound) { | 
| +  int actual_value; | 
| +  if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value)) | 
| +    return false; | 
| + | 
| +  if (lower_bound <= actual_value && actual_value <= upper_bound) | 
| +    return false; | 
| +  path_.push_back(field_name); | 
| +  AddError(l10n_util::GetStringFUTF8( | 
| +      IDS_NETWORK_CONFIG_ERROR_VALUE_OUT_OF_RANGE, | 
| +      base::IntToString16(actual_value), | 
| +      base::IntToString16(lower_bound), | 
| +      base::IntToString16(upper_bound))); | 
| +  path_.pop_back(); | 
| +  DVLOG(1) << "Found " << actual_value << ", which is out of range [" | 
| +           << lower_bound << ", " << upper_bound << "]"; | 
| +  return true; | 
| +} | 
| + | 
| +bool Validator::RequireField(const base::DictionaryValue& dict, | 
| +                             const std::string& field_name) { | 
| +  if (dict.HasKey(field_name)) | 
| +    return true; | 
| +  AddError(l10n_util::GetStringFUTF8( | 
| +      IDS_NETWORK_CONFIG_ERROR_REQUIRED_FIELD_MISSING, | 
| +      UTF8ToUTF16(field_name))); | 
| +  DVLOG(1) << "Required field " << field_name << " missing."; | 
| +  return false; | 
| +} | 
| + | 
| +void Validator::AddWarning(const std::string& msg) { | 
| +  AddMessage(false, msg); | 
| +} | 
| + | 
| +void Validator::AddError(const std::string& msg) { | 
| +  AddMessage(true, msg); | 
| +} | 
| + | 
| +void Validator::AddMessage(bool is_error, const std::string& sub_message) { | 
| +  std::string message; | 
| +  if (path_.empty()) { | 
| +    int message_id = is_error ? IDS_NETWORK_CONFIG_ERROR_AT_TOPLEVEL | 
| +        : IDS_NETWORK_CONFIG_WARNING_AT_TOPLEVEL; | 
| +    message = l10n_util::GetStringUTF8(message_id); | 
| +  } else { | 
| +    int message_id = is_error ? | 
| +        IDS_NETWORK_CONFIG_ERROR_AT_PATH : | 
| +        IDS_NETWORK_CONFIG_WARNING_AT_PATH; | 
| +    message = l10n_util::GetStringFUTF8(message_id, | 
| +                                        ASCIIToUTF16(JoinString(path_, "."))); | 
| +  } | 
| +  message.append(" "); | 
| +  message.append(sub_message); | 
| +  messages_.push_back(message); | 
| +} | 
| + | 
| +std::string Validator::JoinMessages() { | 
| +  return JoinString(messages_, "\n"); | 
| +} | 
| + | 
| }  // namespace onc | 
| }  // namespace chromeos | 
|  |