blob: cf10a8e66a04d07faa98908d6423dc56e31ff152 [file] [log] [blame]
// Copyright 2016 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/it2me/it2me_host.h"
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/policy/policy_constants.h"
#include "net/base/network_change_notifier.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/it2me/it2me_confirmation_dialog.h"
#include "remoting/host/policy_watcher.h"
#include "remoting/host/xmpp_register_support_host_request.h"
#include "remoting/protocol/errors.h"
#include "remoting/protocol/transport_context.h"
#include "remoting/signaling/fake_signal_strategy.h"
#include "remoting/signaling/xmpp_log_to_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "base/linux_util.h"
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
namespace remoting {
using protocol::ErrorCode;
namespace {
// Shortening some type names for readability.
typedef protocol::ValidatingAuthenticator::Result ValidationResult;
typedef It2MeConfirmationDialog::Result DialogResult;
const char kTestUserName[] = "ficticious_user@gmail.com";
const char kTestClientJid[] = "ficticious_user@gmail.com/jid_resource";
const char kTestClientJid2[] = "ficticious_user_2@gmail.com/jid_resource";
const char kTestClientUsernameNoJid[] = "completely_ficticious_user@gmail.com";
const char kTestClientJidWithSlash[] = "fake/user@gmail.com/jid_resource";
const char kResourceOnly[] = "/jid_resource";
const char kMatchingDomain[] = "gmail.com";
const char kMismatchedDomain1[] = "similar_to_gmail.com";
const char kMismatchedDomain2[] = "gmail_at_the_beginning.com";
const char kMismatchedDomain3[] = "not_even_close.com";
// Note that this is intentionally different from the default port range.
const char kPortRange[] = "12401-12408";
const char kTestStunServer[] = "test_relay_server.com";
} // namespace
class FakeIt2MeConfirmationDialog : public It2MeConfirmationDialog {
public:
FakeIt2MeConfirmationDialog(const std::string& remote_user_email,
DialogResult dialog_result);
FakeIt2MeConfirmationDialog(const FakeIt2MeConfirmationDialog&) = delete;
FakeIt2MeConfirmationDialog& operator=(const FakeIt2MeConfirmationDialog&) =
delete;
~FakeIt2MeConfirmationDialog() override;
// It2MeConfirmationDialog implementation.
void Show(const std::string& remote_user_email,
ResultCallback callback) override;
private:
FakeIt2MeConfirmationDialog();
std::string remote_user_email_;
DialogResult dialog_result_ = DialogResult::OK;
};
FakeIt2MeConfirmationDialog::FakeIt2MeConfirmationDialog() = default;
FakeIt2MeConfirmationDialog::FakeIt2MeConfirmationDialog(
const std::string& remote_user_email,
DialogResult dialog_result)
: remote_user_email_(remote_user_email), dialog_result_(dialog_result) {}
FakeIt2MeConfirmationDialog::~FakeIt2MeConfirmationDialog() = default;
void FakeIt2MeConfirmationDialog::Show(const std::string& remote_user_email,
ResultCallback callback) {
EXPECT_STREQ(remote_user_email_.c_str(), remote_user_email.c_str());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), dialog_result_));
}
class FakeIt2MeDialogFactory : public It2MeConfirmationDialogFactory {
public:
FakeIt2MeDialogFactory();
FakeIt2MeDialogFactory(const FakeIt2MeDialogFactory&) = delete;
FakeIt2MeDialogFactory& operator=(const FakeIt2MeDialogFactory&) = delete;
~FakeIt2MeDialogFactory() override;
std::unique_ptr<It2MeConfirmationDialog> Create() override;
void set_dialog_result(DialogResult dialog_result) {
dialog_result_ = dialog_result;
}
void set_remote_user_email(const std::string& remote_user_email) {
remote_user_email_ = remote_user_email;
}
bool dialog_created() const { return dialog_created_; }
private:
std::string remote_user_email_;
DialogResult dialog_result_ = DialogResult::OK;
bool dialog_created_ = false;
};
FakeIt2MeDialogFactory::FakeIt2MeDialogFactory()
: It2MeConfirmationDialogFactory(
It2MeConfirmationDialog::DialogStyle::kConsumer),
remote_user_email_(kTestUserName) {}
FakeIt2MeDialogFactory::~FakeIt2MeDialogFactory() = default;
std::unique_ptr<It2MeConfirmationDialog> FakeIt2MeDialogFactory::Create() {
EXPECT_FALSE(remote_user_email_.empty());
dialog_created_ = true;
return std::make_unique<FakeIt2MeConfirmationDialog>(remote_user_email_,
dialog_result_);
}
class It2MeHostTest : public testing::Test, public It2MeHost::Observer {
public:
It2MeHostTest();
It2MeHostTest(const It2MeHostTest&) = delete;
It2MeHostTest& operator=(const It2MeHostTest&) = delete;
~It2MeHostTest() override;
// testing::Test interface.
void SetUp() override;
void TearDown() override;
void OnValidationComplete(base::OnceClosure resume_callback,
ValidationResult validation_result);
protected:
// It2MeHost::Observer interface.
void OnClientAuthenticated(const std::string& client_username) override;
void OnStoreAccessCode(const std::string& access_code,
base::TimeDelta access_code_lifetime) override;
void OnNatPoliciesChanged(bool nat_traversal_enabled,
bool relay_connections_allowed) override;
void OnStateChanged(It2MeHostState state, ErrorCode error_code) override;
void SetPolicies(
std::initializer_list<std::pair<base::StringPiece, const base::Value&>>
policies);
void RunUntilStateChanged(It2MeHostState expected_state);
void RunValidationCallback(const std::string& remote_jid);
void StartHost();
void ShutdownHost();
static base::ListValue MakeList(
std::initializer_list<base::StringPiece> values);
ChromotingHost* GetHost() { return it2me_host_->host_.get(); }
// Configuration values used by StartHost();
absl::optional<bool> enable_dialogs_;
absl::optional<bool> enable_notifications_;
absl::optional<bool> is_enterprise_session_;
// Stores the last nat traversal policy value received.
bool last_nat_traversal_enabled_value_ = false;
// Stores the last relay enabled policy value received.
bool last_relay_connections_allowed_value_ = false;
ValidationResult validation_result_ = ValidationResult::SUCCESS;
base::OnceClosure state_change_callback_;
It2MeHostState last_host_state_ = It2MeHostState::kDisconnected;
ErrorCode last_error_code_ = ErrorCode::OK;
// Used to set ConfirmationDialog behavior.
raw_ptr<FakeIt2MeDialogFactory> dialog_factory_ = nullptr;
std::unique_ptr<base::DictionaryValue> policies_;
scoped_refptr<It2MeHost> it2me_host_;
private:
void StartupHostStateHelper(const base::RepeatingClosure& quit_closure);
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::RunLoop> run_loop_;
std::unique_ptr<FakeSignalStrategy> fake_bot_signal_strategy_;
std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
std::unique_ptr<ChromotingHostContext> host_context_;
scoped_refptr<AutoThreadTaskRunner> network_task_runner_;
scoped_refptr<AutoThreadTaskRunner> ui_task_runner_;
base::WeakPtrFactory<It2MeHostTest> weak_factory_{this};
};
It2MeHostTest::It2MeHostTest() {}
It2MeHostTest::~It2MeHostTest() = default;
void It2MeHostTest::SetUp() {
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
// Need to prime the host OS version value for linux to prevent IO on the
// network thread. base::GetLinuxDistro() caches the result.
base::GetLinuxDistro();
#endif
run_loop_ = std::make_unique<base::RunLoop>();
network_change_notifier_ = net::NetworkChangeNotifier::CreateIfNeeded();
host_context_ = ChromotingHostContext::Create(new AutoThreadTaskRunner(
base::ThreadTaskRunnerHandle::Get(), run_loop_->QuitClosure()));
network_task_runner_ = host_context_->network_task_runner();
ui_task_runner_ = host_context_->ui_task_runner();
fake_bot_signal_strategy_ =
std::make_unique<FakeSignalStrategy>(SignalingAddress("fake_bot_jid"));
}
void It2MeHostTest::TearDown() {
// Shutdown the host if it hasn't been already. Without this, the call to
// run_loop_->Run() may never return.
it2me_host_->Disconnect();
network_task_runner_ = nullptr;
ui_task_runner_ = nullptr;
host_context_.reset();
it2me_host_ = nullptr;
run_loop_->Run();
}
void It2MeHostTest::OnValidationComplete(base::OnceClosure resume_callback,
ValidationResult validation_result) {
validation_result_ = validation_result;
ui_task_runner_->PostTask(FROM_HERE, std::move(resume_callback));
}
void It2MeHostTest::SetPolicies(
std::initializer_list<std::pair<base::StringPiece, const base::Value&>>
policies) {
policies_ = std::make_unique<base::DictionaryValue>();
for (const auto& policy : policies) {
policies_->SetKey(policy.first, policy.second.Clone());
}
if (it2me_host_) {
it2me_host_->OnPolicyUpdate(std::move(policies_));
}
}
void It2MeHostTest::StartupHostStateHelper(
const base::RepeatingClosure& quit_closure) {
if (last_host_state_ == It2MeHostState::kRequestedAccessCode) {
network_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&It2MeHost::SetStateForTesting, it2me_host_.get(),
It2MeHostState::kReceivedAccessCode, ErrorCode::OK));
} else if (last_host_state_ != It2MeHostState::kStarting) {
quit_closure.Run();
return;
}
state_change_callback_ =
base::BindOnce(&It2MeHostTest::StartupHostStateHelper,
base::Unretained(this), quit_closure);
}
void It2MeHostTest::StartHost() {
if (!policies_) {
policies_ = PolicyWatcher::GetDefaultPolicies();
}
std::unique_ptr<FakeIt2MeDialogFactory> dialog_factory(
new FakeIt2MeDialogFactory());
dialog_factory_ = dialog_factory.get();
protocol::IceConfig ice_config;
ice_config.stun_servers.push_back(rtc::SocketAddress(kTestStunServer, 100));
ice_config.expiration_time = base::Time::Now() + base::Hours(2);
auto fake_signal_strategy =
std::make_unique<FakeSignalStrategy>(SignalingAddress("fake_local_jid"));
fake_bot_signal_strategy_->ConnectTo(fake_signal_strategy.get());
it2me_host_ = new It2MeHost();
if (enable_dialogs_.has_value()) {
// Only ChromeOS supports this method, so tests setting enable_dialogs
// should only be run on ChromeOS.
it2me_host_->set_enable_dialogs(enable_dialogs_.value());
}
if (enable_notifications_.has_value()) {
// Only ChromeOS supports this method, so tests setting enable_notifications
// should only be run on ChromeOS.
it2me_host_->set_enable_notifications(enable_notifications_.value());
}
if (is_enterprise_session_.has_value()) {
// Only ChromeOS supports this method, so tests setting
// is_enterprise_session should only be run on ChromeOS.
it2me_host_->set_is_enterprise_session(is_enterprise_session_.value());
}
auto create_connection_context = base::BindOnce(
[](std::unique_ptr<SignalStrategy> signal_strategy,
ChromotingHostContext* host_context) {
auto context = std::make_unique<It2MeHost::DeferredConnectContext>();
context->register_request =
std::make_unique<XmppRegisterSupportHostRequest>("fake_bot_jid");
context->log_to_server = std::make_unique<XmppLogToServer>(
ServerLogEntry::IT2ME, signal_strategy.get(), "fake_bot_jid",
host_context->network_task_runner());
context->signal_strategy = std::move(signal_strategy);
return context;
},
std::move(fake_signal_strategy));
it2me_host_->Connect(host_context_->Copy(), policies_->CreateDeepCopy(),
std::move(dialog_factory), weak_factory_.GetWeakPtr(),
std::move(create_connection_context), kTestUserName,
ice_config);
base::RunLoop run_loop;
state_change_callback_ =
base::BindOnce(&It2MeHostTest::StartupHostStateHelper,
base::Unretained(this), run_loop.QuitClosure());
run_loop.Run();
}
void It2MeHostTest::RunUntilStateChanged(It2MeHostState expected_state) {
if (last_host_state_ == expected_state) {
// Bail out early if the state is already correct.
return;
}
base::RunLoop run_loop;
state_change_callback_ = run_loop.QuitClosure();
run_loop.Run();
}
void It2MeHostTest::RunValidationCallback(const std::string& remote_jid) {
base::RunLoop run_loop;
network_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
it2me_host_->GetValidationCallbackForTesting(), remote_jid,
base::BindOnce(&It2MeHostTest::OnValidationComplete,
base::Unretained(this), run_loop.QuitClosure())));
run_loop.Run();
}
void It2MeHostTest::OnClientAuthenticated(const std::string& client_username) {}
void It2MeHostTest::OnStoreAccessCode(const std::string& access_code,
base::TimeDelta access_code_lifetime) {}
void It2MeHostTest::OnNatPoliciesChanged(bool nat_traversal_enabled,
bool relay_connections_allowed) {
last_nat_traversal_enabled_value_ = nat_traversal_enabled;
last_relay_connections_allowed_value_ = relay_connections_allowed;
}
void It2MeHostTest::OnStateChanged(It2MeHostState state, ErrorCode error_code) {
last_host_state_ = state;
last_error_code_ = error_code;
if (state_change_callback_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, std::move(state_change_callback_));
}
}
void It2MeHostTest::ShutdownHost() {
if (it2me_host_) {
it2me_host_->Disconnect();
RunUntilStateChanged(It2MeHostState::kDisconnected);
}
}
base::ListValue It2MeHostTest::MakeList(
std::initializer_list<base::StringPiece> values) {
base::ListValue result;
for (const auto& value : values) {
result.Append(value);
}
return result;
}
// Callback to receive IceConfig from TransportContext
void ReceiveIceConfig(protocol::IceConfig* ice_config,
const protocol::IceConfig& received_ice_config) {
*ice_config = received_ice_config;
}
TEST_F(It2MeHostTest, StartAndStop) {
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
ASSERT_EQ(ErrorCode::OK, last_error_code_);
}
// Verify that IceConfig is passed to the TransportContext.
TEST_F(It2MeHostTest, IceConfig) {
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
protocol::IceConfig ice_config;
GetHost()->transport_context_for_tests()->GetIceConfig(
base::BindOnce(&ReceiveIceConfig, &ice_config));
EXPECT_EQ(ice_config.stun_servers[0].hostname(), kTestStunServer);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, NatTraversalPolicyEnabled) {
SetPolicies(
{{policy::key::kRemoteAccessHostFirewallTraversal, base::Value(true)}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
EXPECT_TRUE(last_nat_traversal_enabled_value_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, NatTraversalPolicyDisabled) {
SetPolicies(
{{policy::key::kRemoteAccessHostFirewallTraversal, base::Value(false)}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
EXPECT_FALSE(last_nat_traversal_enabled_value_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
// TODO(crbug/1122155): flaky test.
TEST_F(It2MeHostTest,
DISABLED_NatTraversalPolicyDisabledTransitionCausesDisconnect) {
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
EXPECT_TRUE(last_nat_traversal_enabled_value_);
EXPECT_TRUE(last_relay_connections_allowed_value_);
SetPolicies(
{{policy::key::kRemoteAccessHostFirewallTraversal, base::Value(false)},
{policy::key::kRemoteAccessHostAllowRelayedConnection,
base::Value(true)}});
RunUntilStateChanged(It2MeHostState::kDisconnected);
EXPECT_FALSE(last_nat_traversal_enabled_value_);
EXPECT_TRUE(last_relay_connections_allowed_value_);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, RelayPolicyEnabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRelayedConnection,
base::Value(true)}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
EXPECT_TRUE(last_relay_connections_allowed_value_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, RelayPolicyDisabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRelayedConnection,
base::Value(false)}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
EXPECT_FALSE(last_relay_connections_allowed_value_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
// TODO(crbug.com/1126973): Flaky test.
TEST_F(It2MeHostTest, DISABLED_RelayPolicyDisabledTransitionCausesDisconnect) {
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
EXPECT_TRUE(last_nat_traversal_enabled_value_);
EXPECT_TRUE(last_relay_connections_allowed_value_);
SetPolicies(
{{policy::key::kRemoteAccessHostFirewallTraversal, base::Value(true)},
{policy::key::kRemoteAccessHostAllowRelayedConnection,
base::Value(false)}});
RunUntilStateChanged(It2MeHostState::kDisconnected);
EXPECT_TRUE(last_nat_traversal_enabled_value_);
EXPECT_FALSE(last_relay_connections_allowed_value_);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchingDomain) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({kMatchingDomain})}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchStart) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({kMismatchedDomain2})}});
StartHost();
ASSERT_EQ(It2MeHostState::kInvalidDomainError, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchEnd) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({kMismatchedDomain1})}});
StartHost();
ASSERT_EQ(It2MeHostState::kInvalidDomainError, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchFirst) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({kMatchingDomain, kMismatchedDomain1})}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchSecond) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({kMismatchedDomain1, kMatchingDomain})}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyNoMatch) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({kMismatchedDomain1, kMismatchedDomain2,
kMismatchedDomain3})}});
StartHost();
ASSERT_EQ(It2MeHostState::kInvalidDomainError, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, ConnectionValidationNoClientDomainListPolicyValidJid) {
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::SUCCESS, validation_result_);
ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, ConnectionValidationNoClientDomainListPolicyInvalidJid) {
StartHost();
RunValidationCallback(kTestClientUsernameNoJid);
ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest,
ConnectionValidationNoClientDomainListPolicyInvalidUsername) {
StartHost();
dialog_factory_->set_remote_user_email("fake");
RunValidationCallback(kTestClientJidWithSlash);
ASSERT_EQ(ValidationResult::SUCCESS, validation_result_);
ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest,
ConnectionValidationNoClientDomainListPolicyResourceOnly) {
StartHost();
RunValidationCallback(kResourceOnly);
ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest,
ConnectionValidationClientDomainListPolicyMatchingDomain) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMatchingDomain})}});
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::SUCCESS, validation_result_);
ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest,
ConnectionValidationClientDomainListPolicyInvalidUserName) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMatchingDomain})}});
StartHost();
RunValidationCallback(kTestClientJidWithSlash);
ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyNoJid) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMatchingDomain})}});
StartHost();
RunValidationCallback(kTestClientUsernameNoJid);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_);
}
TEST_F(It2MeHostTest, ConnectionValidationWrongClientDomainMatchStart) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMismatchedDomain2})}});
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, ConnectionValidationWrongClientDomainMatchEnd) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMismatchedDomain1})}});
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyMatchFirst) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMatchingDomain, kMismatchedDomain1})}});
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::SUCCESS, validation_result_);
ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyMatchSecond) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMismatchedDomain1, kMatchingDomain})}});
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::SUCCESS, validation_result_);
ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyNoMatch) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({kMismatchedDomain1, kMismatchedDomain2,
kMismatchedDomain3})}});
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::ERROR_INVALID_ACCOUNT, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, HostUdpPortRangePolicyValidRange) {
PortRange port_range_actual;
ASSERT_TRUE(PortRange::Parse(kPortRange, &port_range_actual));
SetPolicies(
{{policy::key::kRemoteAccessHostUdpPortRange, base::Value(kPortRange)}});
StartHost();
PortRange port_range =
GetHost()->transport_context_for_tests()->network_settings().port_range;
ASSERT_EQ(port_range_actual.min_port, port_range.min_port);
ASSERT_EQ(port_range_actual.max_port, port_range.max_port);
}
TEST_F(It2MeHostTest, HostUdpPortRangePolicyNoRange) {
StartHost();
PortRange port_range =
GetHost()->transport_context_for_tests()->network_settings().port_range;
ASSERT_TRUE(port_range.is_null());
}
TEST_F(It2MeHostTest, ConnectionValidationConfirmationDialogAccept) {
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::SUCCESS, validation_result_);
ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
ASSERT_EQ(ErrorCode::OK, last_error_code_);
}
TEST_F(It2MeHostTest, ConnectionValidationConfirmationDialogReject) {
StartHost();
dialog_factory_->set_dialog_result(DialogResult::CANCEL);
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::ERROR_REJECTED_BY_USER, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
ASSERT_EQ(ErrorCode::SESSION_REJECTED, last_error_code_);
}
TEST_F(It2MeHostTest, MultipleConnectionsTriggerDisconnect) {
StartHost();
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::SUCCESS, validation_result_);
ASSERT_EQ(It2MeHostState::kConnecting, last_host_state_);
RunValidationCallback(kTestClientJid2);
ASSERT_EQ(ValidationResult::ERROR_TOO_MANY_CONNECTIONS, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, AllowSupportHostConnectionsPolicyEnabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
base::Value(true)}});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(It2MeHostTest, AllowSupportHostConnectionsPolicyDisabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
base::Value(false)}});
StartHost();
ASSERT_EQ(It2MeHostState::kError, last_host_state_);
ASSERT_EQ(ErrorCode::DISALLOWED_BY_POLICY, last_error_code_);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(It2MeHostTest, ConnectRespectsSuppressDialogsParameter) {
enable_dialogs_ = false;
StartHost();
EXPECT_FALSE(dialog_factory_->dialog_created());
EXPECT_FALSE(
GetHost()->desktop_environment_options().enable_user_interface());
}
TEST_F(It2MeHostTest, ConnectRespectsSuppressNotificationsParameter) {
enable_notifications_ = false;
StartHost();
EXPECT_FALSE(dialog_factory_->dialog_created());
EXPECT_FALSE(GetHost()->desktop_environment_options().enable_notifications());
}
TEST_F(It2MeHostTest,
EnterpriseSessionsSucceedWhenRemoteSupportConnectionsPolicyDisabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
base::Value(false)}});
is_enterprise_session_ = true;
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
ASSERT_EQ(ErrorCode::OK, last_error_code_);
}
#endif
} // namespace remoting