Commit 0d40d8ac authored by lukasza's avatar lukasza Committed by Commit bot

Malformed PortRange or ThirdPartyAuthConfig should trigger OnPolicyError.

Before this change a malformed value of RemoteAccessHostUdpPortRange policy
(i.e. "123456-blah") was ignored and a default value was used.  Similarily for
the 3 third-party-auth-config policies (RemoteAccessHostTokenUrl,
...TokenValidationUrl and ...TokenValidationCertificateIssuer) we were falling
back to a secure default, but not reporting a policy error.  After this change
such malformed values will trigger an OnPolicyError callback.

Notes:
- Guaranteeing that PolicyWatcher always returns valid policy values, removes
  the need for a "rejecting" Me2MeHostAuthenticatorFactory.
- Moving PortRange and ThirdPartyAuthConfig to separate compilation units
  helps readability elsewhere + encourages better unit tests coverage.
- Initially I tried to wrap all policies in a new ChromotingPolicies class,
  but eventually went back to prevalidating and passing base::DictionaryValue.
  - Arguments for using ChromotingPolicies:
    - Helps avoid overtesting in policy_watcher_unittests.cc (i.e. helps focus
      the tests on a single policy value).
  - Arguments for using base::DictionaryValue:
    - Minimizes changes.
    - Keeps things simple (as opposed to having to introduce a custom
      equivalent of optional<T> [nothing similar present in Chromium AFAICT]).
  - Neutral:
    - Strong-typing of ChromotingPolicies didn't help readability as much as I
      expected and hoped for.

BUG=427513
TEST=remoting_unittests

Review URL: https://codereview.chromium.org/966433002

Cr-Commit-Position: refs/heads/master@{#318910}
parent 3a2bce8a
...@@ -229,8 +229,10 @@ void It2MeHost::FinishConnect() { ...@@ -229,8 +229,10 @@ void It2MeHost::FinishConnect() {
protocol::NetworkSettings::NAT_TRAVERSAL_FULL : protocol::NetworkSettings::NAT_TRAVERSAL_FULL :
protocol::NetworkSettings::NAT_TRAVERSAL_DISABLED); protocol::NetworkSettings::NAT_TRAVERSAL_DISABLED);
if (!nat_traversal_enabled_) { if (!nat_traversal_enabled_) {
network_settings.min_port = protocol::NetworkSettings::kDefaultMinPort; network_settings.port_range.min_port =
network_settings.max_port = protocol::NetworkSettings::kDefaultMaxPort; protocol::NetworkSettings::kDefaultMinPort;
network_settings.port_range.max_port =
protocol::NetworkSettings::kDefaultMaxPort;
} }
// Create the host. // Create the host.
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include "components/policy/core/common/schema_registry.h" #include "components/policy/core/common/schema_registry.h"
#include "policy/policy_constants.h" #include "policy/policy_constants.h"
#include "remoting/host/dns_blackhole_checker.h" #include "remoting/host/dns_blackhole_checker.h"
#include "remoting/host/third_party_auth_config.h"
#include "remoting/protocol/port_range.h"
#if !defined(NDEBUG) #if !defined(NDEBUG)
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
...@@ -44,15 +46,15 @@ namespace { ...@@ -44,15 +46,15 @@ namespace {
// Copies all policy values from one dictionary to another, using values from // Copies all policy values from one dictionary to another, using values from
// |default_values| if they are not set in |from|. // |default_values| if they are not set in |from|.
scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults( scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults(
const base::DictionaryValue* from, const base::DictionaryValue& from,
const base::DictionaryValue* default_values) { const base::DictionaryValue& default_values) {
scoped_ptr<base::DictionaryValue> to(default_values->DeepCopy()); scoped_ptr<base::DictionaryValue> to(default_values.DeepCopy());
for (base::DictionaryValue::Iterator i(*default_values); !i.IsAtEnd(); for (base::DictionaryValue::Iterator i(default_values); !i.IsAtEnd();
i.Advance()) { i.Advance()) {
const base::Value* value = nullptr; const base::Value* value = nullptr;
// If the policy isn't in |from|, use the default. // If the policy isn't in |from|, use the default.
if (!from->Get(i.key(), &value)) { if (!from.Get(i.key(), &value)) {
continue; continue;
} }
...@@ -63,8 +65,8 @@ scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults( ...@@ -63,8 +65,8 @@ scoped_ptr<base::DictionaryValue> CopyValuesAndAddDefaults(
#if !defined(NDEBUG) #if !defined(NDEBUG)
// Replace values with those specified in DebugOverridePolicies, if present. // Replace values with those specified in DebugOverridePolicies, if present.
std::string policy_overrides; std::string policy_overrides;
if (from->GetString(key::kRemoteAccessHostDebugOverridePolicies, if (from.GetString(key::kRemoteAccessHostDebugOverridePolicies,
&policy_overrides)) { &policy_overrides)) {
scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides)); scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides));
const base::DictionaryValue* override_values; const base::DictionaryValue* override_values;
if (value && value->GetAsDictionary(&override_values)) { if (value && value->GetAsDictionary(&override_values)) {
...@@ -92,6 +94,56 @@ scoped_ptr<policy::SchemaRegistry> CreateSchemaRegistry() { ...@@ -92,6 +94,56 @@ scoped_ptr<policy::SchemaRegistry> CreateSchemaRegistry() {
return schema_registry.Pass(); return schema_registry.Pass();
} }
scoped_ptr<base::DictionaryValue> CopyChromotingPoliciesIntoDictionary(
const policy::PolicyMap& current) {
const char kPolicyNameSubstring[] = "RemoteAccessHost";
scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue());
for (auto it = current.begin(); it != current.end(); ++it) {
const std::string& key = it->first;
const base::Value* value = it->second.value;
// Copying only Chromoting-specific policies helps avoid false alarms
// raised by NormalizePolicies below (such alarms shutdown the host).
// TODO(lukasza): Removing this somewhat brittle filtering will be possible
// after having separate, Chromoting-specific schema.
if (key.find(kPolicyNameSubstring) != std::string::npos) {
policy_dict->Set(key, value->DeepCopy());
}
}
return policy_dict.Pass();
}
// Takes a dictionary containing only 1) recognized policy names and 2)
// well-typed policy values and further verifies policy contents.
bool VerifyWellformedness(const base::DictionaryValue& changed_policies) {
// Verify ThirdPartyAuthConfig policy.
ThirdPartyAuthConfig not_used;
switch (ThirdPartyAuthConfig::Parse(changed_policies, &not_used)) {
case ThirdPartyAuthConfig::NoPolicy:
case ThirdPartyAuthConfig::ParsingSuccess:
break; // Well-formed.
case ThirdPartyAuthConfig::InvalidPolicy:
return false; // Malformed.
default:
NOTREACHED();
return false;
}
// Verify UdpPortRange policy.
std::string udp_port_range_string;
PortRange udp_port_range;
if (changed_policies.GetString(policy::key::kRemoteAccessHostUdpPortRange,
&udp_port_range_string)) {
if (!PortRange::Parse(udp_port_range_string, &udp_port_range)) {
return false;
}
}
// Report that all the policies were well-formed.
return true;
}
} // namespace } // namespace
void PolicyWatcher::StartWatching( void PolicyWatcher::StartWatching(
...@@ -114,36 +166,6 @@ void PolicyWatcher::StartWatching( ...@@ -114,36 +166,6 @@ void PolicyWatcher::StartWatching(
} }
} }
void PolicyWatcher::UpdatePolicies(
const base::DictionaryValue* new_policies_raw) {
DCHECK(CalledOnValidThread());
// Use default values for any missing policies.
scoped_ptr<base::DictionaryValue> new_policies =
CopyValuesAndAddDefaults(new_policies_raw, default_values_.get());
// Find the changed policies.
scoped_ptr<base::DictionaryValue> changed_policies(
new base::DictionaryValue());
base::DictionaryValue::Iterator iter(*new_policies);
while (!iter.IsAtEnd()) {
base::Value* old_policy;
if (!(old_policies_->Get(iter.key(), &old_policy) &&
old_policy->Equals(&iter.value()))) {
changed_policies->Set(iter.key(), iter.value().DeepCopy());
}
iter.Advance();
}
// Save the new policies.
old_policies_.swap(new_policies);
// Notify our client of the changed policies.
if (!changed_policies->empty()) {
policy_updated_callback_.Run(changed_policies.Pass());
}
}
void PolicyWatcher::SignalPolicyError() { void PolicyWatcher::SignalPolicyError() {
old_policies_->Clear(); old_policies_->Clear();
policy_error_callback_.Run(); policy_error_callback_.Run();
...@@ -201,24 +223,7 @@ const policy::Schema* PolicyWatcher::GetPolicySchema() const { ...@@ -201,24 +223,7 @@ const policy::Schema* PolicyWatcher::GetPolicySchema() const {
return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace()); return owned_schema_registry_->schema_map()->GetSchema(GetPolicyNamespace());
} }
void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, bool PolicyWatcher::NormalizePolicies(base::DictionaryValue* policy_dict) {
const policy::PolicyMap& previous,
const policy::PolicyMap& current) {
const char kPolicyNamePrefix[] = "RemoteAccessHost";
scoped_ptr<base::DictionaryValue> policy_dict(new base::DictionaryValue());
for (auto it = current.begin(); it != current.end(); ++it) {
const std::string& key = it->first;
const base::Value* value = it->second.value;
// Copying only Chromoting-specific policies helps avoid false alarms
// raised by Schema::Normalize below (such alarms shutdown the host).
// TODO(lukasza): Removing this somewhat brittle filtering will be possible
// after having separate, Chromoting-specific schema.
if (key.find(kPolicyNamePrefix) != std::string::npos) {
policy_dict->Set(key, value->DeepCopy());
}
}
// Allowing unrecognized policy names allows presence of // Allowing unrecognized policy names allows presence of
// 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }), // 1) comments (i.e. JSON of the form: { "_comment": "blah", ... }),
// 2) policies intended for future/newer versions of the host, // 2) policies intended for future/newer versions of the host,
...@@ -231,16 +236,95 @@ void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns, ...@@ -231,16 +236,95 @@ void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns,
std::string error; std::string error;
bool changed = false; bool changed = false;
const policy::Schema* schema = GetPolicySchema(); const policy::Schema* schema = GetPolicySchema();
if (schema->Normalize(policy_dict.get(), strategy, &path, &error, &changed)) { if (schema->Normalize(policy_dict, strategy, &path, &error, &changed)) {
if (changed) { if (changed) {
LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path LOG(WARNING) << "Unknown (unrecognized or unsupported) policy: " << path
<< ": " << error; << ": " << error;
} }
UpdatePolicies(policy_dict.get()); return true;
} else { } else {
LOG(ERROR) << "Invalid policy contents: " << path << ": " << error; LOG(ERROR) << "Invalid policy contents: " << path << ": " << error;
return false;
}
}
namespace {
void CopyDictionaryValue(const base::DictionaryValue& from,
base::DictionaryValue& to,
std::string key) {
const base::Value* value;
if (from.Get(key, &value)) {
to.Set(key, value->DeepCopy());
}
}
} // namespace
scoped_ptr<base::DictionaryValue>
PolicyWatcher::StoreNewAndReturnChangedPolicies(
scoped_ptr<base::DictionaryValue> new_policies) {
// Find the changed policies.
scoped_ptr<base::DictionaryValue> changed_policies(
new base::DictionaryValue());
base::DictionaryValue::Iterator iter(*new_policies);
while (!iter.IsAtEnd()) {
base::Value* old_policy;
if (!(old_policies_->Get(iter.key(), &old_policy) &&
old_policy->Equals(&iter.value()))) {
changed_policies->Set(iter.key(), iter.value().DeepCopy());
}
iter.Advance();
}
// If one of ThirdPartyAuthConfig policies changed, we need to include all.
if (changed_policies->HasKey(key::kRemoteAccessHostTokenUrl) ||
changed_policies->HasKey(key::kRemoteAccessHostTokenValidationUrl) ||
changed_policies->HasKey(
key::kRemoteAccessHostTokenValidationCertificateIssuer)) {
CopyDictionaryValue(*new_policies, *changed_policies,
key::kRemoteAccessHostTokenUrl);
CopyDictionaryValue(*new_policies, *changed_policies,
key::kRemoteAccessHostTokenValidationUrl);
CopyDictionaryValue(*new_policies, *changed_policies,
key::kRemoteAccessHostTokenValidationCertificateIssuer);
}
// Save the new policies.
old_policies_.swap(new_policies);
return changed_policies.Pass();
}
void PolicyWatcher::OnPolicyUpdated(const policy::PolicyNamespace& ns,
const policy::PolicyMap& previous,
const policy::PolicyMap& current) {
scoped_ptr<base::DictionaryValue> new_policies =
CopyChromotingPoliciesIntoDictionary(current);
// Check for mistyped values and get rid of unknown policies.
if (!NormalizePolicies(new_policies.get())) {
SignalPolicyError();
return;
}
// Use default values for any missing policies.
scoped_ptr<base::DictionaryValue> filled_policies =
CopyValuesAndAddDefaults(*new_policies, *default_values_);
// Limit reporting to only the policies that were changed.
scoped_ptr<base::DictionaryValue> changed_policies =
StoreNewAndReturnChangedPolicies(filled_policies.Pass());
if (changed_policies->empty()) {
return;
}
// Verify that we are calling the callback with valid policies.
if (!VerifyWellformedness(*changed_policies)) {
SignalPolicyError(); SignalPolicyError();
return;
} }
// Notify our client of the changed policies.
policy_updated_callback_.Run(changed_policies.Pass());
} }
void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) { void PolicyWatcher::OnPolicyServiceInitialized(policy::PolicyDomain domain) {
......
...@@ -80,13 +80,20 @@ class PolicyWatcher : public policy::PolicyService::Observer, ...@@ -80,13 +80,20 @@ class PolicyWatcher : public policy::PolicyService::Observer,
private: private:
friend class PolicyWatcherTest; friend class PolicyWatcherTest;
// Takes the policy dictionary from the OS specific store and extracts the
// relevant policies.
void UpdatePolicies(const base::DictionaryValue* new_policy);
// Gets Chromoting schema stored inside |owned_schema_registry_|. // Gets Chromoting schema stored inside |owned_schema_registry_|.
const policy::Schema* GetPolicySchema() const; const policy::Schema* GetPolicySchema() const;
// Simplifying wrapper around Schema::Normalize.
// - Returns false if |dict| is invalid (i.e. contains mistyped policy
// values).
// - Returns true if |dict| was valid or got normalized.
bool NormalizePolicies(base::DictionaryValue* dict);
// Stores |new_policies| into |old_policies_|. Returns dictionary with items
// from |new_policies| that are different from the old |old_policies_|.
scoped_ptr<base::DictionaryValue> StoreNewAndReturnChangedPolicies(
scoped_ptr<base::DictionaryValue> new_policies);
// Signals policy error to the registered |PolicyErrorCallback|. // Signals policy error to the registered |PolicyErrorCallback|.
void SignalPolicyError(); void SignalPolicyError();
......
This diff is collapsed.
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#include "remoting/host/shutdown_watchdog.h" #include "remoting/host/shutdown_watchdog.h"
#include "remoting/host/signaling_connector.h" #include "remoting/host/signaling_connector.h"
#include "remoting/host/single_window_desktop_environment.h" #include "remoting/host/single_window_desktop_environment.h"
#include "remoting/host/third_party_auth_config.h"
#include "remoting/host/token_validator_factory_impl.h" #include "remoting/host/token_validator_factory_impl.h"
#include "remoting/host/usage_stats_consent.h" #include "remoting/host/usage_stats_consent.h"
#include "remoting/host/username.h" #include "remoting/host/username.h"
...@@ -71,6 +72,7 @@ ...@@ -71,6 +72,7 @@
#include "remoting/protocol/me2me_host_authenticator_factory.h" #include "remoting/protocol/me2me_host_authenticator_factory.h"
#include "remoting/protocol/network_settings.h" #include "remoting/protocol/network_settings.h"
#include "remoting/protocol/pairing_registry.h" #include "remoting/protocol/pairing_registry.h"
#include "remoting/protocol/port_range.h"
#include "remoting/protocol/token_validator.h" #include "remoting/protocol/token_validator.h"
#include "remoting/signaling/xmpp_signal_strategy.h" #include "remoting/signaling/xmpp_signal_strategy.h"
...@@ -339,8 +341,7 @@ class HostProcess : public ConfigWatcher::Delegate, ...@@ -339,8 +341,7 @@ class HostProcess : public ConfigWatcher::Delegate,
bool host_username_match_required_; bool host_username_match_required_;
bool allow_nat_traversal_; bool allow_nat_traversal_;
bool allow_relay_; bool allow_relay_;
uint16 min_udp_port_; PortRange udp_port_range_;
uint16 max_udp_port_;
std::string talkgadget_prefix_; std::string talkgadget_prefix_;
bool allow_pairing_; bool allow_pairing_;
...@@ -394,8 +395,6 @@ HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context, ...@@ -394,8 +395,6 @@ HostProcess::HostProcess(scoped_ptr<ChromotingHostContext> context,
host_username_match_required_(false), host_username_match_required_(false),
allow_nat_traversal_(true), allow_nat_traversal_(true),
allow_relay_(true), allow_relay_(true),
min_udp_port_(0),
max_udp_port_(0),
allow_pairing_(true), allow_pairing_(true),
curtain_required_(false), curtain_required_(false),
enable_gnubby_auth_(false), enable_gnubby_auth_(false),
...@@ -672,7 +671,7 @@ void HostProcess::CreateAuthenticatorFactory() { ...@@ -672,7 +671,7 @@ void HostProcess::CreateAuthenticatorFactory() {
scoped_ptr<protocol::AuthenticatorFactory> factory; scoped_ptr<protocol::AuthenticatorFactory> factory;
if (third_party_auth_config_.is_empty()) { if (third_party_auth_config_.is_null()) {
scoped_refptr<PairingRegistry> pairing_registry; scoped_refptr<PairingRegistry> pairing_registry;
if (allow_pairing_) { if (allow_pairing_) {
// On Windows |pairing_registry_| is initialized in // On Windows |pairing_registry_| is initialized in
...@@ -696,7 +695,10 @@ void HostProcess::CreateAuthenticatorFactory() { ...@@ -696,7 +695,10 @@ void HostProcess::CreateAuthenticatorFactory() {
host_secret_hash_, pairing_registry); host_secret_hash_, pairing_registry);
host_->set_pairing_registry(pairing_registry); host_->set_pairing_registry(pairing_registry);
} else if (third_party_auth_config_.is_valid()) { } else {
DCHECK(third_party_auth_config_.token_url.is_valid());
DCHECK(third_party_auth_config_.token_validation_url.is_valid());
scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory( scoped_ptr<protocol::TokenValidatorFactory> token_validator_factory(
new TokenValidatorFactoryImpl( new TokenValidatorFactoryImpl(
third_party_auth_config_, third_party_auth_config_,
...@@ -704,17 +706,6 @@ void HostProcess::CreateAuthenticatorFactory() { ...@@ -704,17 +706,6 @@ void HostProcess::CreateAuthenticatorFactory() {
factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth( factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
use_service_account_, host_owner_, local_certificate, key_pair_, use_service_account_, host_owner_, local_certificate, key_pair_,
token_validator_factory.Pass()); token_validator_factory.Pass());
} else {
// TODO(rmsousa): If the policy is bad the host should not go online. It
// should keep running, but not connected, until the policies are fixed.
// Having it show up as online and then reject all clients is misleading.
LOG(ERROR) << "One of the third-party token URLs is empty or invalid. "
<< "Host will reject all clients until policies are corrected. "
<< "TokenUrl: " << third_party_auth_config_.token_url << ", "
<< "TokenValidationUrl: "
<< third_party_auth_config_.token_validation_url;
factory = protocol::Me2MeHostAuthenticatorFactory::CreateRejecting();
} }
#if defined(OS_POSIX) #if defined(OS_POSIX)
...@@ -1189,34 +1180,15 @@ bool HostProcess::OnUdpPortPolicyUpdate(base::DictionaryValue* policies) { ...@@ -1189,34 +1180,15 @@ bool HostProcess::OnUdpPortPolicyUpdate(base::DictionaryValue* policies) {
// Returns true if the host has to be restarted after this policy update. // Returns true if the host has to be restarted after this policy update.
DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); DCHECK(context_->network_task_runner()->BelongsToCurrentThread());
std::string udp_port_range; std::string string_value;
if (!policies->GetString(policy::key::kRemoteAccessHostUdpPortRange, if (!policies->GetString(policy::key::kRemoteAccessHostUdpPortRange,
&udp_port_range)) { &string_value)) {
return false; return false;
} }
// Use default values if policy setting is empty or invalid. DCHECK(PortRange::Parse(string_value, &udp_port_range_));
uint16 min_udp_port = 0; HOST_LOG << "Policy restricts UDP port range to: " << udp_port_range_;
uint16 max_udp_port = 0; return true;
if (!udp_port_range.empty() &&
!NetworkSettings::ParsePortRange(udp_port_range, &min_udp_port,
&max_udp_port)) {
LOG(WARNING) << "Invalid port range policy: \"" << udp_port_range
<< "\". Using default values.";
}
if (min_udp_port_ != min_udp_port || max_udp_port_ != max_udp_port) {
if (min_udp_port != 0 && max_udp_port != 0) {
HOST_LOG << "Policy restricts UDP port range to [" << min_udp_port
<< ", " << max_udp_port << "]";
} else {
HOST_LOG << "Policy does not restrict UDP port range.";
}
min_udp_port_ = min_udp_port;
max_udp_port_ = max_udp_port;
return true;
}
return false;
} }
bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue* policies) { bool HostProcess::OnCurtainPolicyUpdate(base::DictionaryValue* policies) {
...@@ -1274,39 +1246,18 @@ bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate( ...@@ -1274,39 +1246,18 @@ bool HostProcess::OnHostTalkGadgetPrefixPolicyUpdate(
} }
bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies) { bool HostProcess::OnHostTokenUrlPolicyUpdate(base::DictionaryValue* policies) {
// Returns true if the host has to be restarted after this policy update. switch (ThirdPartyAuthConfig::Parse(*policies, &third_party_auth_config_)) {
DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); case ThirdPartyAuthConfig::NoPolicy:
return false;
bool token_policy_changed = false; case ThirdPartyAuthConfig::ParsingSuccess:
std::string token_url_string; HOST_LOG << "Policy sets third-party token URLs: "
if (policies->GetString(policy::key::kRemoteAccessHostTokenUrl, << third_party_auth_config_;
&token_url_string)) { return true;
token_policy_changed = true; case ThirdPartyAuthConfig::InvalidPolicy:
third_party_auth_config_.token_url = GURL(token_url_string); default:
} NOTREACHED();
std::string token_validation_url_string; return false;
if (policies->GetString(policy::key::kRemoteAccessHostTokenValidationUrl,
&token_validation_url_string)) {
token_policy_changed = true;
third_party_auth_config_.token_validation_url =
GURL(token_validation_url_string);
}
if (policies->GetString(
policy::key::kRemoteAccessHostTokenValidationCertificateIssuer,
&third_party_auth_config_.token_validation_cert_issuer)) {
token_policy_changed = true;
}
if (token_policy_changed) {
HOST_LOG << "Policy sets third-party token URLs: "
<< "TokenUrl: "
<< third_party_auth_config_.token_url << ", "
<< "TokenValidationUrl: "
<< third_party_auth_config_.token_validation_url << ", "
<< "TokenValidationCertificateIssuer: "
<< third_party_auth_config_.token_validation_cert_issuer;
} }
return token_policy_changed;
} }
bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue* policies) { bool HostProcess::OnPairingPolicyUpdate(base::DictionaryValue* policies) {
...@@ -1392,15 +1343,14 @@ void HostProcess::StartHost() { ...@@ -1392,15 +1343,14 @@ void HostProcess::StartHost() {
NetworkSettings network_settings(network_flags); NetworkSettings network_settings(network_flags);
if (min_udp_port_ && max_udp_port_) { if (!udp_port_range_.is_null()) {
network_settings.min_port = min_udp_port_; network_settings.port_range = udp_port_range_;
network_settings.max_port = max_udp_port_;
} else if (!allow_nat_traversal_) { } else if (!allow_nat_traversal_) {
// For legacy reasons we have to restrict the port range to a set of default // For legacy reasons we have to restrict the port range to a set of default
// values when nat traversal is disabled, even if the port range was not // values when nat traversal is disabled, even if the port range was not
// set in policy. // set in policy.
network_settings.min_port = NetworkSettings::kDefaultMinPort; network_settings.port_range.min_port = NetworkSettings::kDefaultMinPort;
network_settings.max_port = NetworkSettings::kDefaultMaxPort; network_settings.port_range.max_port = NetworkSettings::kDefaultMaxPort;
} }
host_.reset(new ChromotingHost( host_.reset(new ChromotingHost(
......
// Copyright 2015 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 "remoting/host/third_party_auth_config.h"
#include "base/logging.h"
#include "base/values.h"
#include "policy/policy_constants.h"
namespace remoting {
namespace {
bool ParseUrlPolicy(const std::string& str, GURL* out) {
if (str.empty()) {
*out = GURL();
return true;
}
GURL gurl(str);
if (!gurl.is_valid()) {
LOG(ERROR) << "Not a valid URL: " << str;
return false;
}
// We validate https-vs-http only on Release builds to help with manual testing.
#if defined(NDEBUG)
if (!gurl.SchemeIsSecure()) {
LOG(ERROR) << "Not a secure URL: " << str;
return false;
}
#endif
*out = gurl;
return true;
}
} // namespace
bool ThirdPartyAuthConfig::ParseStrings(
const std::string& token_url,
const std::string& token_validation_url,
const std::string& token_validation_cert_issuer,
ThirdPartyAuthConfig* result) {
ThirdPartyAuthConfig tmp;
// Extract raw values for the 3 individual fields.
bool urls_valid = true;
urls_valid &= ParseUrlPolicy(token_url, &tmp.token_url);
urls_valid &= ParseUrlPolicy(token_validation_url, &tmp.token_validation_url);
if (!urls_valid) {
return false;
}
tmp.token_validation_cert_issuer = token_validation_cert_issuer;
// Validate inter-dependencies between the 3 fields.
if (tmp.token_url.is_empty() ^ tmp.token_validation_url.is_empty()) {
LOG(ERROR) << "TokenUrl and TokenValidationUrl "
<< "have to be specified together.";
return false;
}
if (!tmp.token_validation_cert_issuer.empty() && tmp.token_url.is_empty()) {
LOG(ERROR) << "TokenValidationCertificateIssuer cannot be used "
<< "without TokenUrl and TokenValidationUrl.";
return false;
}
*result = tmp;
return true;
}
namespace {
void ExtractHelper(const base::DictionaryValue& policy_dict,
const std::string& policy_name,
bool* policy_present,
std::string* policy_value) {
if (policy_dict.GetString(policy_name, policy_value)) {
*policy_present = true;
} else {
policy_value->clear();
}
}
} // namespace
bool ThirdPartyAuthConfig::ExtractStrings(
const base::DictionaryValue& policy_dict,
std::string* token_url,
std::string* token_validation_url,
std::string* token_validation_cert_issuer) {
bool policies_present = false;
ExtractHelper(policy_dict, policy::key::kRemoteAccessHostTokenUrl,
&policies_present, token_url);
ExtractHelper(policy_dict, policy::key::kRemoteAccessHostTokenValidationUrl,
&policies_present, token_validation_url);
ExtractHelper(policy_dict,
policy::key::kRemoteAccessHostTokenValidationCertificateIssuer,
&policies_present, token_validation_cert_issuer);
return policies_present;
}
ThirdPartyAuthConfig::ParseStatus ThirdPartyAuthConfig::Parse(
const base::DictionaryValue& policy_dict,
ThirdPartyAuthConfig* result) {
// Extract 3 individial policy values.
std::string token_url;
std::string token_validation_url;
std::string token_validation_cert_issuer;
if (!ThirdPartyAuthConfig::ExtractStrings(policy_dict, &token_url,
&token_validation_url,
&token_validation_cert_issuer)) {
return NoPolicy;
}
// Parse the policy value.
if (!ThirdPartyAuthConfig::ParseStrings(token_url, token_validation_url,
token_validation_cert_issuer,
result)) {
return InvalidPolicy;
}
return ParsingSuccess;
}
std::ostream& operator<<(std::ostream& os, const ThirdPartyAuthConfig& cfg) {
if (cfg.is_null()) {
os << "<no 3rd party auth config specified>";
} else {
os << "TokenUrl = <" << cfg.token_url << ">, ";
os << "TokenValidationUrl = <" << cfg.token_validation_url << ">, ";
os << "TokenValidationCertificateIssuer = <"
<< cfg.token_validation_cert_issuer << ">";
}
return os;
}
} // namespace remoting
// Copyright 2015 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 REMOTING_HOST_THIRD_PARTY_AUTH_CONFIG_H_
#define REMOTING_HOST_THIRD_PARTY_AUTH_CONFIG_H_
#include <ostream>
#include <string>
#include "base/gtest_prod_util.h"
#include "url/gurl.h"
namespace base {
class DictionaryValue;
} // namespace base
namespace remoting {
struct ThirdPartyAuthConfig {
GURL token_url;
GURL token_validation_url;
std::string token_validation_cert_issuer;
inline bool is_null() const {
return token_url.is_empty() && token_validation_url.is_empty();
}
// Status of Parse method call.
enum ParseStatus {
// |policy_dict| contains invalid entries (i.e. malformed urls).
// |result| has not been modified.
InvalidPolicy,
// |policy_dict| doesn't contain any ThirdPartyAuthConfig-related entries.
// |result| has not been modified.
NoPolicy,
// |policy_dict| contains valid entries that have been stored into |result|.
ParsingSuccess,
};
static ParseStatus Parse(const base::DictionaryValue& policy_dict,
ThirdPartyAuthConfig* result);
private:
// Returns false and doesn't modify |result| if parsing fails (i.e. some input
// values are invalid).
static bool ParseStrings(const std::string& token_url,
const std::string& token_validation_url,
const std::string& token_validation_cert_issuer,
ThirdPartyAuthConfig* result);
FRIEND_TEST_ALL_PREFIXES(InvalidUrlTest, ParseInvalidUrl);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseEmpty);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseValidAll);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseValidNoCert);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseInvalidCombination);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ParseHttp);
// Extracts raw (raw = as strings) policy values from |policy_dict|.
// Missing policy values are set to an empty string.
// Returns false if no ThirdPartyAuthConfig-related policies were present.
static bool ExtractStrings(const base::DictionaryValue& policy_dict,
std::string* token_url,
std::string* token_validation_url,
std::string* token_validation_cert_issuer);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractEmpty);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractUnknown);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractAll);
FRIEND_TEST_ALL_PREFIXES(ThirdPartyAuthConfig, ExtractPartial);
};
std::ostream& operator<<(std::ostream& os, const ThirdPartyAuthConfig& cfg);
} // namespace remoting
#endif // REMOTING_HOST_THIRD_PARTY_AUTH_CONFIG_H_
// Copyright 2015 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 "remoting/host/third_party_auth_config.h"
#include <sstream>
#include "base/values.h"
#include "policy/policy_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
namespace key = ::policy::key;
TEST(ThirdPartyAuthConfig, ParseEmpty) {
ThirdPartyAuthConfig third_party_auth_config;
EXPECT_TRUE(
ThirdPartyAuthConfig::ParseStrings("", "", "", &third_party_auth_config));
EXPECT_TRUE(third_party_auth_config.is_null());
}
TEST(ThirdPartyAuthConfig, ParseValidAll) {
ThirdPartyAuthConfig third_party_auth_config;
EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings(
"https://token.com/", "https://validation.com/", "certificate subject",
&third_party_auth_config));
EXPECT_FALSE(third_party_auth_config.is_null());
EXPECT_EQ("https://token.com/", third_party_auth_config.token_url.spec());
EXPECT_EQ("https://validation.com/",
third_party_auth_config.token_validation_url.spec());
EXPECT_EQ("certificate subject",
third_party_auth_config.token_validation_cert_issuer);
}
TEST(ThirdPartyAuthConfig, ParseValidNoCert) {
ThirdPartyAuthConfig third_party_auth_config;
EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings("https://token.com/",
"https://validation.com/", "",
&third_party_auth_config));
EXPECT_FALSE(third_party_auth_config.is_null());
EXPECT_EQ("https://token.com/", third_party_auth_config.token_url.spec());
EXPECT_EQ("https://validation.com/",
third_party_auth_config.token_validation_url.spec());
EXPECT_EQ("", third_party_auth_config.token_validation_cert_issuer);
}
// We validate https-vs-http only on Release builds to help with manual testing.
#if !defined(NDEBUG)
TEST(ThirdPartyAuthConfig, ParseHttp) {
ThirdPartyAuthConfig third_party_auth_config;
EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings("http://token.com/",
"http://validation.com/", "",
&third_party_auth_config));
EXPECT_FALSE(third_party_auth_config.is_null());
EXPECT_EQ("http://token.com/", third_party_auth_config.token_url.spec());
EXPECT_EQ("http://validation.com/",
third_party_auth_config.token_validation_url.spec());
}
#endif
namespace {
const std::string valid_url("https://valid.com");
const std::string valid_cert("certificate subject");
} // namespace
class InvalidUrlTest : public ::testing::TestWithParam<const char*> {};
TEST_P(InvalidUrlTest, ParseInvalidUrl) {
const std::string& invalid_url(GetParam());
// Populate |config| with some known data - we will use this for validating
// that |config| doesn't get modified by ParseStrings during subsequent
// parsing
// failure tests.
ThirdPartyAuthConfig config;
EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings(
"https://token.com/", "https://validation.com/", "certificate subject",
&config));
// Test for parsing failure.
EXPECT_FALSE(ThirdPartyAuthConfig::ParseStrings(invalid_url, valid_url,
valid_cert, &config));
EXPECT_FALSE(ThirdPartyAuthConfig::ParseStrings(valid_url, invalid_url,
valid_cert, &config));
EXPECT_FALSE(
ThirdPartyAuthConfig::ParseStrings(invalid_url, "", "", &config));
EXPECT_FALSE(
ThirdPartyAuthConfig::ParseStrings("", invalid_url, "", &config));
// Validate that ParseStrings doesn't modify its output upon parsing failure.
EXPECT_EQ("https://token.com/", config.token_url.spec());
EXPECT_EQ("https://validation.com/", config.token_validation_url.spec());
EXPECT_EQ("certificate subject", config.token_validation_cert_issuer);
}
// We validate https-vs-http only on Release builds to help with manual testing.
#if defined(NDEBUG)
INSTANTIATE_TEST_CASE_P(ThirdPartyAuthConfig,
InvalidUrlTest,
::testing::Values("http://insecure.com",
"I am not a URL"));
#else
INSTANTIATE_TEST_CASE_P(ThirdPartyAuthConfig,
InvalidUrlTest,
::testing::Values("I am not a URL"));
#endif
TEST(ThirdPartyAuthConfig, ParseInvalidCombination) {
// Populate |config| with some known data - we will use this for validating
// that |config| doesn't get modified by ParseStrings during subsequent
// parsing
// failure tests.
ThirdPartyAuthConfig config;
EXPECT_TRUE(ThirdPartyAuthConfig::ParseStrings(
"https://token.com/", "https://validation.com/", "certificate subject",
&config));
// Only one of TokenUrl and TokenValidationUrl
EXPECT_FALSE(
ThirdPartyAuthConfig::ParseStrings("", valid_url, valid_cert, &config));
EXPECT_FALSE(
ThirdPartyAuthConfig::ParseStrings(valid_url, "", valid_cert, &config));
// CertSubject when no TokenUrl and TokenValidationUrl
EXPECT_FALSE(ThirdPartyAuthConfig::ParseStrings("", "", valid_cert, &config));
// Validate that ParseStrings doesn't modify its output upon parsing failure.
EXPECT_EQ("https://token.com/", config.token_url.spec());
EXPECT_EQ("https://validation.com/", config.token_validation_url.spec());
EXPECT_EQ("certificate subject", config.token_validation_cert_issuer);
}
TEST(ThirdPartyAuthConfig, ExtractEmpty) {
base::DictionaryValue dict;
std::string url1, url2, cert;
EXPECT_FALSE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert));
}
TEST(ThirdPartyAuthConfig, ExtractUnknown) {
base::DictionaryValue dict;
dict.SetString("unknownName", "someValue");
std::string url1, url2, cert;
EXPECT_FALSE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert));
}
TEST(ThirdPartyAuthConfig, ExtractAll) {
base::DictionaryValue dict;
dict.SetString(key::kRemoteAccessHostTokenUrl, "test1");
dict.SetString(key::kRemoteAccessHostTokenValidationUrl, "test2");
dict.SetString(key::kRemoteAccessHostTokenValidationCertificateIssuer, "t3");
std::string url1, url2, cert;
EXPECT_TRUE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert));
EXPECT_EQ("test1", url1);
EXPECT_EQ("test2", url2);
EXPECT_EQ("t3", cert);
}
TEST(ThirdPartyAuthConfig, ExtractPartial) {
base::DictionaryValue dict;
dict.SetString(key::kRemoteAccessHostTokenValidationUrl, "test2");
std::string url1, url2, cert;
EXPECT_TRUE(ThirdPartyAuthConfig::ExtractStrings(dict, &url1, &url2, &cert));
EXPECT_EQ("", url1);
EXPECT_EQ("test2", url2);
EXPECT_EQ("", cert);
}
TEST(ThirdPartyAuthConfig, Output) {
ThirdPartyAuthConfig third_party_auth_config;
third_party_auth_config.token_url = GURL("https://token.com");
third_party_auth_config.token_validation_url = GURL("https://validation.com");
third_party_auth_config.token_validation_cert_issuer = "certificate subject";
std::ostringstream str;
str << third_party_auth_config;
EXPECT_THAT(str.str(), testing::HasSubstr("token"));
EXPECT_THAT(str.str(), testing::HasSubstr("validation"));
EXPECT_THAT(str.str(), testing::HasSubstr("certificate subject"));
}
} // namespace remoting
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "net/url_request/url_request.h" #include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_context_getter.h"
#include "remoting/host/third_party_auth_config.h"
#include "remoting/protocol/token_validator.h" #include "remoting/protocol/token_validator.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -19,20 +20,6 @@ typedef std::vector<scoped_refptr<X509Certificate> > CertificateList; ...@@ -19,20 +20,6 @@ typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
namespace remoting { namespace remoting {
struct ThirdPartyAuthConfig {
inline bool is_empty() const {
return token_url.is_empty() && token_validation_url.is_empty();
}
inline bool is_valid() const {
return token_url.is_valid() && token_validation_url.is_valid();
}
GURL token_url;
GURL token_validation_url;
std::string token_validation_cert_issuer;
};
class TokenValidatorBase class TokenValidatorBase
: public net::URLRequest::Delegate, : public net::URLRequest::Delegate,
public protocol::TokenValidator { public protocol::TokenValidator {
......
...@@ -156,8 +156,8 @@ scoped_ptr<ChromiumPortAllocator> ChromiumPortAllocator::Create( ...@@ -156,8 +156,8 @@ scoped_ptr<ChromiumPortAllocator> ChromiumPortAllocator::Create(
flags |= cricket::PORTALLOCATOR_DISABLE_RELAY; flags |= cricket::PORTALLOCATOR_DISABLE_RELAY;
result->set_flags(flags); result->set_flags(flags);
result->SetPortRange(network_settings.min_port, result->SetPortRange(network_settings.port_range.min_port,
network_settings.max_port); network_settings.port_range.max_port);
return result.Pass(); return result.Pass();
} }
......
...@@ -97,12 +97,6 @@ Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth( ...@@ -97,12 +97,6 @@ Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
return result.Pass(); return result.Pass();
} }
// static
scoped_ptr<AuthenticatorFactory>
Me2MeHostAuthenticatorFactory::CreateRejecting() {
return make_scoped_ptr(new Me2MeHostAuthenticatorFactory());
}
Me2MeHostAuthenticatorFactory::Me2MeHostAuthenticatorFactory() { Me2MeHostAuthenticatorFactory::Me2MeHostAuthenticatorFactory() {
} }
......
...@@ -43,10 +43,6 @@ class Me2MeHostAuthenticatorFactory : public AuthenticatorFactory { ...@@ -43,10 +43,6 @@ class Me2MeHostAuthenticatorFactory : public AuthenticatorFactory {
scoped_refptr<RsaKeyPair> key_pair, scoped_refptr<RsaKeyPair> key_pair,
scoped_ptr<TokenValidatorFactory> token_validator_factory); scoped_ptr<TokenValidatorFactory> token_validator_factory);
// Create a factory that dispenses rejecting authenticators (used when the
// host config/policy is inconsistent)
static scoped_ptr<AuthenticatorFactory> CreateRejecting();
Me2MeHostAuthenticatorFactory(); Me2MeHostAuthenticatorFactory();
~Me2MeHostAuthenticatorFactory() override; ~Me2MeHostAuthenticatorFactory() override;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/logging.h" #include "base/logging.h"
#include "remoting/protocol/port_range.h"
namespace remoting { namespace remoting {
namespace protocol { namespace protocol {
...@@ -42,32 +43,17 @@ struct NetworkSettings { ...@@ -42,32 +43,17 @@ struct NetworkSettings {
NAT_TRAVERSAL_OUTGOING NAT_TRAVERSAL_OUTGOING
}; };
NetworkSettings() NetworkSettings() : flags(NAT_TRAVERSAL_DISABLED) {
: flags(NAT_TRAVERSAL_DISABLED),
min_port(0),
max_port(0) {
DCHECK(!(flags & (NAT_TRAVERSAL_STUN | NAT_TRAVERSAL_RELAY)) || DCHECK(!(flags & (NAT_TRAVERSAL_STUN | NAT_TRAVERSAL_RELAY)) ||
(flags & NAT_TRAVERSAL_OUTGOING)); (flags & NAT_TRAVERSAL_OUTGOING));
} }
explicit NetworkSettings(uint32 flags) explicit NetworkSettings(uint32 flags) : flags(flags) {}
: flags(flags),
min_port(0),
max_port(0) {
}
// Parse string in the form "<min_port>-<max_port>". E.g. "12400-12409".
// Returns true if string was parsed successfuly.
static bool ParsePortRange(const std::string& port_range,
uint16* out_min_port,
uint16* out_max_port);
uint32 flags; uint32 flags;
// |min_port| and |max_port| specify range (inclusive) of ports used by // Range of ports used by P2P sessions.
// P2P sessions. Any port can be used when both values are set to 0. PortRange port_range;
uint16 min_port;
uint16 max_port;
}; };
} // namespace protocol } // namespace protocol
......
// Copyright 2014 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 "remoting/protocol/network_settings.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
namespace protocol {
TEST(ParsePortRange, Basic) {
uint16 min, max;
// Valid range
EXPECT_TRUE(NetworkSettings::ParsePortRange("1-65535", &min, &max));
EXPECT_EQ(1u, min);
EXPECT_EQ(65535u, max);
EXPECT_TRUE(NetworkSettings::ParsePortRange(" 1 - 65535 ", &min, &max));
EXPECT_EQ(1u, min);
EXPECT_EQ(65535u, max);
EXPECT_TRUE(NetworkSettings::ParsePortRange("12400-12400", &min, &max));
EXPECT_EQ(12400u, min);
EXPECT_EQ(12400u, max);
// Invalid
EXPECT_FALSE(NetworkSettings::ParsePortRange("", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("-65535", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("1-", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("-", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("-1-65535", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("1--65535", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("1-65535-", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("0-65535", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("1-65536", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("1-4294967295", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("10-1", &min, &max));
EXPECT_FALSE(NetworkSettings::ParsePortRange("1foo-2bar", &min, &max));
}
} // namespace protocol
} // namespace remoting
// Copyright 2014 The Chromium Authors. All rights reserved. // Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "remoting/protocol/network_settings.h" #include "remoting/protocol/port_range.h"
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -11,23 +11,25 @@ ...@@ -11,23 +11,25 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
namespace remoting { namespace remoting {
namespace protocol {
// static bool PortRange::Parse(const std::string& port_range, PortRange* result) {
bool NetworkSettings::ParsePortRange(const std::string& port_range, DCHECK(result);
uint16* out_min_port,
uint16* out_max_port) { if (port_range.empty()) {
result->min_port = 0;
result->max_port = 0;
return true;
}
size_t separator_index = port_range.find('-'); size_t separator_index = port_range.find('-');
if (separator_index == std::string::npos) if (separator_index == std::string::npos)
return false; return false;
std::string min_port_string, max_port_string; std::string min_port_string, max_port_string;
base::TrimWhitespaceASCII(port_range.substr(0, separator_index), base::TrimWhitespaceASCII(port_range.substr(0, separator_index),
base::TRIM_ALL, base::TRIM_ALL, &min_port_string);
&min_port_string);
base::TrimWhitespaceASCII(port_range.substr(separator_index + 1), base::TrimWhitespaceASCII(port_range.substr(separator_index + 1),
base::TRIM_ALL, base::TRIM_ALL, &max_port_string);
&max_port_string);
unsigned min_port, max_port; unsigned min_port, max_port;
if (!base::StringToUint(min_port_string, &min_port) || if (!base::StringToUint(min_port_string, &min_port) ||
...@@ -38,10 +40,18 @@ namespace protocol { ...@@ -38,10 +40,18 @@ namespace protocol {
if (min_port == 0 || min_port > max_port || max_port > USHRT_MAX) if (min_port == 0 || min_port > max_port || max_port > USHRT_MAX)
return false; return false;
*out_min_port = static_cast<uint16>(min_port); result->min_port = static_cast<uint16>(min_port);
*out_max_port = static_cast<uint16>(max_port); result->max_port = static_cast<uint16>(max_port);
return true; return true;
} }
} // namespace protocol std::ostream& operator<<(std::ostream& os, const PortRange& port_range) {
if (port_range.is_null()) {
os << "<no port range specified>";
} else {
os << "[" << port_range.min_port << ", " << port_range.max_port << "]";
}
return os;
}
} // namespace remoting } // namespace remoting
// Copyright 2015 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 REMOTING_PROTOCOL_PORT_RANGE_H_
#define REMOTING_PROTOCOL_PORT_RANGE_H_
#include <ostream>
#include <string>
#include "base/basictypes.h"
namespace remoting {
// Wrapper for a value of UdpPortRange policy.
struct PortRange {
// Both |min_port| and |max_port| are inclusive.
uint16 min_port;
uint16 max_port;
// Returns true if |port_range| passed to Parse was an empty string
// (or if |this| has been initialized by the default constructor below).
inline bool is_null() const { return (min_port == 0) && (max_port == 0); }
// Parse string in the form "<min_port>-<max_port>". E.g. "12400-12409".
// Returns true if string was parsed successfuly.
//
// Returns false and doesn't modify |result| if parsing fails (i.e. when
// |port_range| doesn't represent a valid port range).
static bool Parse(const std::string& port_range, PortRange* result);
PortRange() : min_port(0), max_port(0) {}
};
std::ostream& operator<<(std::ostream& os, const PortRange& port_range);
} // namespace remoting
#endif // REMOTING_PROTOCOL_PORT_RANGE_H_
// Copyright 2015 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 "remoting/protocol/port_range.h"
#include <sstream>
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
TEST(PortRange, ParseEmpty) {
PortRange port_range;
EXPECT_TRUE(PortRange::Parse("", &port_range));
EXPECT_TRUE(port_range.is_null());
}
TEST(PortRange, ParseValid) {
PortRange port_range;
EXPECT_TRUE(PortRange::Parse("1-65535", &port_range));
EXPECT_FALSE(port_range.is_null());
EXPECT_EQ(1u, port_range.min_port);
EXPECT_EQ(65535u, port_range.max_port);
EXPECT_TRUE(PortRange::Parse(" 1 - 65535 ", &port_range));
EXPECT_FALSE(port_range.is_null());
EXPECT_EQ(1u, port_range.min_port);
EXPECT_EQ(65535u, port_range.max_port);
EXPECT_TRUE(PortRange::Parse("12400-12400", &port_range));
EXPECT_FALSE(port_range.is_null());
EXPECT_EQ(12400u, port_range.min_port);
EXPECT_EQ(12400u, port_range.max_port);
}
TEST(PortRange, ParseInvalid) {
PortRange port_range;
port_range.min_port = 123;
port_range.max_port = 456;
EXPECT_FALSE(PortRange::Parse("-65535", &port_range));
EXPECT_FALSE(PortRange::Parse("1-", &port_range));
EXPECT_FALSE(PortRange::Parse("-", &port_range));
EXPECT_FALSE(PortRange::Parse("-1-65535", &port_range));
EXPECT_FALSE(PortRange::Parse("1--65535", &port_range));
EXPECT_FALSE(PortRange::Parse("1-65535-", &port_range));
EXPECT_FALSE(PortRange::Parse("0-65535", &port_range));
EXPECT_FALSE(PortRange::Parse("1-65536", &port_range));
EXPECT_FALSE(PortRange::Parse("1-4294967295", &port_range));
EXPECT_FALSE(PortRange::Parse("10-1", &port_range));
EXPECT_FALSE(PortRange::Parse("1foo-2bar", &port_range));
// Unsuccessful parses should NOT modify their output.
EXPECT_EQ(123, port_range.min_port);
EXPECT_EQ(456, port_range.max_port);
}
TEST(PortRange, Output) {
PortRange port_range;
port_range.min_port = 123;
port_range.max_port = 456;
std::ostringstream str;
str << port_range;
EXPECT_THAT(str.str(), testing::MatchesRegex(".*123.*456.*"));
}
} // namespace remoting
...@@ -218,6 +218,8 @@ ...@@ -218,6 +218,8 @@
'host/single_window_input_injector_linux.cc', 'host/single_window_input_injector_linux.cc',
'host/single_window_input_injector_mac.cc', 'host/single_window_input_injector_mac.cc',
'host/single_window_input_injector_win.cc', 'host/single_window_input_injector_win.cc',
'host/third_party_auth_config.cc',
'host/third_party_auth_config.h',
'host/token_validator_base.cc', 'host/token_validator_base.cc',
'host/token_validator_base.h', 'host/token_validator_base.h',
'host/token_validator_factory_impl.cc', 'host/token_validator_factory_impl.cc',
......
...@@ -152,7 +152,6 @@ ...@@ -152,7 +152,6 @@
'protocol/negotiating_client_authenticator.h', 'protocol/negotiating_client_authenticator.h',
'protocol/negotiating_host_authenticator.cc', 'protocol/negotiating_host_authenticator.cc',
'protocol/negotiating_host_authenticator.h', 'protocol/negotiating_host_authenticator.h',
'protocol/network_settings.cc',
'protocol/network_settings.h', 'protocol/network_settings.h',
'protocol/pairing_authenticator_base.cc', 'protocol/pairing_authenticator_base.cc',
'protocol/pairing_authenticator_base.h', 'protocol/pairing_authenticator_base.h',
...@@ -162,6 +161,8 @@ ...@@ -162,6 +161,8 @@
'protocol/pairing_host_authenticator.h', 'protocol/pairing_host_authenticator.h',
'protocol/pairing_registry.cc', 'protocol/pairing_registry.cc',
'protocol/pairing_registry.h', 'protocol/pairing_registry.h',
'protocol/port_range.cc',
'protocol/port_range.h',
'protocol/pseudotcp_channel_factory.cc', 'protocol/pseudotcp_channel_factory.cc',
'protocol/pseudotcp_channel_factory.h', 'protocol/pseudotcp_channel_factory.h',
'protocol/secure_channel_factory.cc', 'protocol/secure_channel_factory.cc',
......
...@@ -187,6 +187,7 @@ ...@@ -187,6 +187,7 @@
'host/setup/oauth_helper_unittest.cc', 'host/setup/oauth_helper_unittest.cc',
'host/setup/pin_validator_unittest.cc', 'host/setup/pin_validator_unittest.cc',
'host/shaped_desktop_capturer_unittest.cc', 'host/shaped_desktop_capturer_unittest.cc',
'host/third_party_auth_config_unittest.cc',
'host/token_validator_factory_impl_unittest.cc', 'host/token_validator_factory_impl_unittest.cc',
'host/video_frame_pump_unittest.cc', 'host/video_frame_pump_unittest.cc',
'host/video_frame_recorder_unittest.cc', 'host/video_frame_recorder_unittest.cc',
...@@ -214,8 +215,8 @@ ...@@ -214,8 +215,8 @@
'protocol/monitored_video_stub_unittest.cc', 'protocol/monitored_video_stub_unittest.cc',
'protocol/mouse_input_filter_unittest.cc', 'protocol/mouse_input_filter_unittest.cc',
'protocol/negotiating_authenticator_unittest.cc', 'protocol/negotiating_authenticator_unittest.cc',
'protocol/network_settings_unittest.cc',
'protocol/pairing_registry_unittest.cc', 'protocol/pairing_registry_unittest.cc',
'protocol/port_range_unittest.cc',
'protocol/ppapi_module_stub.cc', 'protocol/ppapi_module_stub.cc',
'protocol/ssl_hmac_channel_authenticator_unittest.cc', 'protocol/ssl_hmac_channel_authenticator_unittest.cc',
'protocol/third_party_authenticator_unittest.cc', 'protocol/third_party_authenticator_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment