#include "remoting/host/it2me/it2me_host.h"
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.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/base/session_policies.h"
#include "remoting/host/chromeos/chromeos_enterprise_params.h"
#include "remoting/host/chromeos/features.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/host_event_reporter.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 "services/network/test/test_shared_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "base/linux_util.h"
#endif
#if BUILDFLAG(IS_LINUX)
#include "remoting/host/linux/wayland_manager.h"
#include "remoting/host/linux/wayland_utils.h"
#endif
namespace remoting {
ErrorCode;
namespace {
ValidationResult;
DialogResult;
const char kTestUserName[] = …;
const char kTestClientJid[] = …;
const char kTestClientJid2[] = …;
const char kTestClientUsernameNoJid[] = …;
const char kTestClientJidWithSlash[] = …;
const char kResourceOnly[] = …;
const char kMatchingDomain[] = …;
const char kMismatchedDomain1[] = …;
const char kMismatchedDomain2[] = …;
const char kMismatchedDomain3[] = …;
const char kPortRange[] = …;
const char kTestStunServer[] = …;
class HostEventReporterStub : public HostEventReporter { … };
#if BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<HostEventReporter> CreateHostEventReporterStub(
scoped_refptr<HostStatusMonitor>) {
return std::make_unique<HostEventReporterStub>();
}
#endif
}
void PrintTo(It2MeHostState state, std::ostream* os) { … }
class FakeIt2MeConfirmationDialog : public It2MeConfirmationDialog { … };
FakeIt2MeConfirmationDialog::FakeIt2MeConfirmationDialog() = default;
FakeIt2MeConfirmationDialog::FakeIt2MeConfirmationDialog(
const std::string& remote_user_email,
DialogResult dialog_result)
: … { … }
FakeIt2MeConfirmationDialog::~FakeIt2MeConfirmationDialog() = default;
void FakeIt2MeConfirmationDialog::Show(const std::string& remote_user_email,
ResultCallback callback) { … }
class FakeIt2MeDialogFactory : public It2MeConfirmationDialogFactory { … };
FakeIt2MeDialogFactory::FakeIt2MeDialogFactory()
: … { … }
FakeIt2MeDialogFactory::~FakeIt2MeDialogFactory() = default;
std::unique_ptr<It2MeConfirmationDialog> FakeIt2MeDialogFactory::Create() { … }
class It2MeHostTest : public testing::Test, public It2MeHost::Observer { … };
It2MeHostTest::It2MeHostTest() = default;
It2MeHostTest::~It2MeHostTest() = default;
void It2MeHostTest::SetUp() { … }
void It2MeHostTest::TearDown() { … }
void It2MeHostTest::OnValidationComplete(base::OnceClosure resume_callback,
ValidationResult validation_result) { … }
void It2MeHostTest::SetPolicies(
std::initializer_list<std::pair<std::string_view, const base::Value&>>
policies) { … }
void It2MeHostTest::StartupHostStateHelper(
const base::RepeatingClosure& quit_closure) { … }
void It2MeHostTest::StartHost() { … }
void It2MeHostTest::StartHost(
std::optional<ChromeOsEnterpriseParams> enterprise_params) { … }
void It2MeHostTest::RunUntilStateChanged(It2MeHostState expected_state) { … }
void It2MeHostTest::RunValidationCallback(const std::string& remote_jid) { … }
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) { … }
void It2MeHostTest::OnStateChanged(It2MeHostState state, ErrorCode error_code) { … }
void It2MeHostTest::ShutdownHost() { … }
base::Value It2MeHostTest::MakeList(
std::initializer_list<std::string_view> values) { … }
void ReceiveIceConfig(protocol::IceConfig* ice_config,
const protocol::IceConfig& received_ice_config) { … }
TEST_F(It2MeHostTest, StartAndStop) { … }
TEST_F(It2MeHostTest, IceConfig) { … }
TEST_F(It2MeHostTest, NatTraversalPolicyEnabled) { … }
TEST_F(It2MeHostTest, NatTraversalPolicyDisabled) { … }
TEST_F(It2MeHostTest,
DISABLED_NatTraversalPolicyDisabledTransitionCausesDisconnect) { … }
TEST_F(It2MeHostTest, RelayPolicyEnabled) { … }
TEST_F(It2MeHostTest, RelayPolicyDisabled) { … }
TEST_F(It2MeHostTest, DISABLED_RelayPolicyDisabledTransitionCausesDisconnect) { … }
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchingDomain) { … }
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchStart) { … }
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchEnd) { … }
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchFirst) { … }
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyMatchSecond) { … }
TEST_F(It2MeHostTest, HostValidationHostDomainListPolicyNoMatch) { … }
TEST_F(It2MeHostTest, ConnectionValidationNoClientDomainListPolicyValidJid) { … }
TEST_F(It2MeHostTest, ConnectionValidationNoClientDomainListPolicyInvalidJid) { … }
TEST_F(It2MeHostTest,
ConnectionValidationNoClientDomainListPolicyInvalidUsername) { … }
TEST_F(It2MeHostTest,
ConnectionValidationNoClientDomainListPolicyResourceOnly) { … }
TEST_F(It2MeHostTest,
ConnectionValidationClientDomainListPolicyMatchingDomain) { … }
TEST_F(It2MeHostTest,
ConnectionValidationClientDomainListPolicyInvalidUserName) { … }
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyNoJid) { … }
TEST_F(It2MeHostTest, ConnectionValidationWrongClientDomainMatchStart) { … }
TEST_F(It2MeHostTest, ConnectionValidationWrongClientDomainMatchEnd) { … }
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyMatchFirst) { … }
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyMatchSecond) { … }
TEST_F(It2MeHostTest, ConnectionValidationClientDomainListPolicyNoMatch) { … }
TEST_F(It2MeHostTest, AuthorizedHelperCanConnect) { … }
TEST_F(It2MeHostTest, UnauthorizedHelperIsRejected) { … }
TEST_F(It2MeHostTest, HostUdpPortRangePolicyValidRange) { … }
TEST_F(It2MeHostTest, HostUdpPortRangePolicyNoRange) { … }
TEST_F(It2MeHostTest, ConnectionValidationConfirmationDialogAccept) { … }
TEST_F(It2MeHostTest, ConnectionValidationConfirmationDialogReject) { … }
TEST_F(It2MeHostTest, MultipleConnectionsTriggerDisconnect) { … }
TEST_F(It2MeHostTest, AllowSupportHostConnectionsPolicyEnabled) { … }
TEST_F(It2MeHostTest, AllowSupportHostConnectionsPolicyDisabled) { … }
TEST_F(It2MeHostTest, FileTransferDisallowedByDefault) { … }
TEST_F(It2MeHostTest, UriForwardingDisallowedByDefault) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(It2MeHostTest, ConnectRespectsSuppressDialogsParameter) {
StartHost(ChromeOsEnterpriseParams{.suppress_user_dialogs = true});
EXPECT_FALSE(dialog_factory_->dialog_created());
EXPECT_FALSE(
GetHost()->desktop_environment_options().enable_user_interface());
}
TEST_F(It2MeHostTest, ConnectRespectsSuppressNotificationsParameter) {
StartHost(ChromeOsEnterpriseParams{.suppress_notifications = true});
EXPECT_FALSE(dialog_factory_->dialog_created());
EXPECT_FALSE(GetHost()->desktop_environment_options().enable_notifications());
}
TEST_F(It2MeHostTest, ConnectRespectsTerminateUponInputParameter) {
StartHost(ChromeOsEnterpriseParams{.terminate_upon_input = true});
EXPECT_TRUE(GetHost()->desktop_environment_options().terminate_upon_input());
}
TEST_F(It2MeHostTest, TerminateUponInputDefaultsToFalse) {
StartHost(std::nullopt);
EXPECT_FALSE(GetHost()->desktop_environment_options().terminate_upon_input());
}
TEST_F(It2MeHostTest, ConnectRespectsEnableCurtainingParameter) {
StartHost(ChromeOsEnterpriseParams{.curtain_local_user_session = true});
EXPECT_TRUE(GetHost()->desktop_environment_options().enable_curtaining());
}
TEST_F(It2MeHostTest, EnableCurtainingDefaultsToFalse) {
StartHost(std::nullopt);
EXPECT_FALSE(GetHost()->desktop_environment_options().enable_curtaining());
}
TEST_F(It2MeHostTest, AllowEnterpriseFileTransferWithPolicyEnabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
base::Value(true)}});
StartHost(ChromeOsEnterpriseParams{.allow_file_transfer = true});
EXPECT_TRUE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest, AllowEnterpriseFileTransferWithPolicyDisabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
base::Value(false)}});
StartHost(ChromeOsEnterpriseParams{.allow_file_transfer = true});
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest,
AllowEnterpriseFileTransferWithPolicyEnabledForNonEnterpriseSession) {
SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
base::Value(true)}});
StartHost(std::nullopt);
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest, AllowEnterpriseFileTransferWithPolicyNotSet) {
SetPolicies({});
StartHost(ChromeOsEnterpriseParams{.allow_file_transfer = true});
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest, EnableFileTransferDefaultsToFalse) {
StartHost(std::nullopt);
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest,
EnterpriseSessionsSucceedWhenRemoteSupportConnectionsPolicyDisabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
base::Value(false)}});
StartHost(ChromeOsEnterpriseParams());
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
ASSERT_EQ(ErrorCode::OK, last_error_code_);
}
TEST_F(It2MeHostTest, EnterpriseSessionsShouldNotCheckHostDomain) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({"other-domain.com"})}});
StartHost(ChromeOsEnterpriseParams());
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
ASSERT_EQ(ErrorCode::OK, last_error_code_);
}
TEST_F(
It2MeHostTest,
EnterpriseSessionsFailWhenEnterpriseRemoteSupportConnectionsPolicyDisabled) {
SetPolicies(
{{policy::key::kRemoteAccessHostAllowEnterpriseRemoteSupportConnections,
base::Value(false)}});
StartHost(ChromeOsEnterpriseParams());
ASSERT_EQ(It2MeHostState::kError, last_host_state_);
ASSERT_EQ(ErrorCode::DISALLOWED_BY_POLICY, last_error_code_);
}
TEST_F(
It2MeHostTest,
RemoteSupportSessionsSucceedWhenEnterpriseRemoteSupportConnectionsPolicyDisabled) {
SetPolicies(
{{policy::key::kRemoteAccessHostAllowEnterpriseRemoteSupportConnections,
base::Value(false)}});
StartHost(std::nullopt);
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
}
#endif
}