blob: 6c99b435469ee675f24e54c95b2c5b8bb1aad8c3 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// 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"
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
#pragma allow_unsafe_libc_calls
#endif
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.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/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "build/build_config.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/oauth_token_getter.h"
#include "remoting/base/oauth_token_getter_proxy.h"
#include "remoting/base/passthrough_oauth_token_getter.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/it2me/it2me_constants.h"
#include "remoting/host/policy_watcher.h"
#include "remoting/host/register_support_host_request.h"
#include "remoting/protocol/errors.h"
#include "remoting/protocol/transport_context.h"
#include "remoting/signaling/fake_signal_strategy.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 // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
namespace remoting {
using protocol::ErrorCode;
namespace {
// Shortening some type names for readability.
typedef protocol::ValidatingAuthenticator::Result ValidationResult;
typedef It2MeConfirmationDialog::Result DialogResult;
constexpr char kTestSupportId[] = "1234567";
constexpr char kTestHostUsername[] = "helpee@gmail.com";
const char kTestClientUsername[] = "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";
class HostEventReporterStub : public HostEventReporter {
public:
HostEventReporterStub() = default;
HostEventReporterStub(const HostEventReporterStub&) = delete;
HostEventReporterStub& operator=(const HostEventReporterStub&) = delete;
~HostEventReporterStub() override = default;
};
class FakeRegisterSupportHostRequest : public RegisterSupportHostRequest {
public:
void StartRequest(SignalStrategy* signal_strategy,
std::unique_ptr<net::ClientCertStore> client_cert_store,
scoped_refptr<RsaKeyPair> key_pair,
const std::string& authorized_helper,
std::optional<ChromeOsEnterpriseParams> params,
RegisterCallback callback) override {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), kTestSupportId,
base::TimeDelta(), ErrorCode::OK));
}
};
#if BUILDFLAG(IS_CHROMEOS)
std::unique_ptr<HostEventReporter> CreateHostEventReporterStub(
scoped_refptr<HostStatusMonitor>) {
return std::make_unique<HostEventReporterStub>();
}
ChromeOsEnterpriseParams GetDefaultEnterpriseParamsForEnterpriseAdmin() {
ChromeOsEnterpriseParams params;
params.request_origin = ChromeOsEnterpriseRequestOrigin::kEnterpriseAdmin;
return params;
}
ChromeOsEnterpriseParams GetDefaultEnterpriseParamsForClassManagement() {
ChromeOsEnterpriseParams params;
params.request_origin = ChromeOsEnterpriseRequestOrigin::kClassManagement;
return params;
}
#endif // BUILDFLAG(IS_CHROMEOS)
} // namespace
// This is invoked automatically by the gtest framework, and improves the error
// messages when a test fails (by properly formatting the host state instead
// of printing their byte value).
void PrintTo(It2MeHostState state, std::ostream* os) {
#define CASE(_state) \
case It2MeHostState::_state: \
*os << #_state; \
return;
switch (state) {
CASE(kDisconnected);
CASE(kStarting);
CASE(kRequestedAccessCode);
CASE(kReceivedAccessCode);
CASE(kConnecting);
CASE(kConnected);
CASE(kError);
CASE(kInvalidDomainError);
}
NOTREACHED();
}
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::SingleThreadTaskRunner::GetCurrentDefault()->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_(kTestClientUsername) {}
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<std::string_view, const base::Value&>>
policies);
void RunUntilStateChanged(It2MeHostState expected_state);
// Posts a task to the network thread, which posts a task back to the current
// thread to unblock. Useful when waiting for a side effect in the network
// thread to take place.
void RunNetworkThreadPendingTasks();
void RunValidationCallback(const std::string& remote_jid);
void StartHost();
void StartHost(std::optional<ChromeOsEnterpriseParams> enterprise_params);
void ShutdownHost();
void SimulateEffectiveSessionPoliciesReceived();
static base::Value MakeList(std::initializer_list<std::string_view> values);
ChromotingHost* GetHost() { return it2me_host_->host_.get(); }
const SessionPolicies& get_local_session_policies() const {
return it2me_host_->local_session_policies_provider_->get_local_policies();
}
bool is_using_corp_session_authz() const {
return it2me_host_->use_corp_session_authz_;
}
bool has_corp_host_status_logger() const {
return it2me_host_->corp_host_status_logger_.get() != nullptr;
}
// Configuration values used by StartHost();
std::optional<ChromeOsEnterpriseParams> enterprise_params_;
std::optional<std::string> authorized_helper_;
// 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, AcrossTasksDanglingUntriaged>
dialog_factory_ = nullptr;
std::optional<base::Value::Dict> policies_;
scoped_refptr<It2MeHost> it2me_host_;
PassthroughOAuthTokenGetter token_getter_;
bool is_corp_user_ = false;
std::string stored_access_code_;
private:
void StartupHostStateHelper(const base::RepeatingClosure& quit_closure);
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::RunLoop> run_loop_;
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_;
scoped_refptr<network::TestSharedURLLoaderFactory> test_url_loader_factory_;
base::WeakPtrFactory<It2MeHostTest> weak_factory_{this};
};
It2MeHostTest::It2MeHostTest() = default;
It2MeHostTest::~It2MeHostTest() = default;
void It2MeHostTest::SetUp() {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_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
#if BUILDFLAG(IS_CHROMEOS)
test_url_loader_factory_ = new network::TestSharedURLLoaderFactory();
#endif
run_loop_ = std::make_unique<base::RunLoop>();
network_change_notifier_ = net::NetworkChangeNotifier::CreateIfNeeded();
host_context_ = ChromotingHostContext::CreateForTesting(
new AutoThreadTaskRunner(
base::SingleThreadTaskRunner::GetCurrentDefault(),
run_loop_->QuitClosure()),
test_url_loader_factory_);
network_task_runner_ = host_context_->network_task_runner();
ui_task_runner_ = host_context_->ui_task_runner();
}
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<std::string_view, const base::Value&>>
policies) {
policies_.emplace();
for (const auto& policy : policies) {
policies_->Set(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::kStarting &&
last_host_state_ != It2MeHostState::kRequestedAccessCode) {
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(
webrtc::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"));
it2me_host_ = new It2MeHost();
if (enterprise_params_.has_value()) {
// Only ChromeOS supports this method, so tests setting enterprise params
// should only be run on ChromeOS.
it2me_host_->set_chrome_os_enterprise_params(*enterprise_params_);
}
if (authorized_helper_.has_value()) {
it2me_host_->set_authorized_helper(*authorized_helper_);
}
#if BUILDFLAG(IS_CHROMEOS)
it2me_host_->SetHostEventReporterFactoryForTesting(
base::BindRepeating(CreateHostEventReporterStub));
#endif // BUILDFLAG(IS_CHROMEOS)
auto create_connection_context = base::BindOnce(
[](std::unique_ptr<SignalStrategy> signal_strategy,
base::WeakPtr<OAuthTokenGetter> token_getter, bool is_corp_user,
ChromotingHostContext* host_context) {
auto context = std::make_unique<It2MeHost::DeferredConnectContext>();
context->is_corp_user = is_corp_user;
context->register_request =
std::make_unique<FakeRegisterSupportHostRequest>();
context->signaling_token_getter =
std::make_unique<OAuthTokenGetterProxy>(token_getter);
context->api_token_getter =
std::make_unique<OAuthTokenGetterProxy>(token_getter);
context->signal_strategy = std::move(signal_strategy);
return context;
},
std::move(fake_signal_strategy), token_getter_.GetWeakPtr(),
is_corp_user_);
it2me_host_->Connect(host_context_->Copy(), policies_->Clone(),
std::move(dialog_factory), weak_factory_.GetWeakPtr(),
std::move(create_connection_context), kTestHostUsername,
ice_config);
base::RunLoop run_loop;
state_change_callback_ =
base::BindOnce(&It2MeHostTest::StartupHostStateHelper,
base::Unretained(this), run_loop.QuitClosure());
run_loop.Run();
}
void It2MeHostTest::StartHost(
std::optional<ChromeOsEnterpriseParams> enterprise_params) {
enterprise_params_ = enterprise_params;
StartHost();
}
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::RunNetworkThreadPendingTasks() {
base::RunLoop run_loop;
network_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
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) {
stored_access_code_ = access_code;
}
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::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, std::move(state_change_callback_));
}
}
void It2MeHostTest::ShutdownHost() {
if (it2me_host_) {
it2me_host_->Disconnect();
RunUntilStateChanged(It2MeHostState::kDisconnected);
}
}
void It2MeHostTest::SimulateEffectiveSessionPoliciesReceived() {
base::RunLoop run_loop;
network_task_runner_->PostTaskAndReply(
FROM_HERE,
base::BindOnce(
base::IgnoreResult(&It2MeHost::OnEffectiveSessionPoliciesReceived),
it2me_host_, SessionPolicies{}),
run_loop.QuitClosure());
run_loop.Run();
}
base::Value It2MeHostTest::MakeList(
std::initializer_list<std::string_view> values) {
base::Value::List result;
for (const auto& value : values) {
result.Append(value);
}
return base::Value(std::move(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_);
// The first 7 digits of the access code are the support ID.
ASSERT_TRUE(stored_access_code_.starts_with(kTestSupportId));
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, LocalNatTraversalPolicyEnabled) {
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, LocalNatTraversalPolicyDisabled) {
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_);
}
TEST_F(It2MeHostTest, LocalRelayPolicyEnabled) {
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, LocalRelayPolicyDisabled) {
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_);
}
TEST_F(
It2MeHostTest,
LocalNatPoliciesChangedBeforeEffectivePoliciesAreReceived_ReportedToObserver) {
SetPolicies({
{policy::key::kRemoteAccessHostFirewallTraversal, base::Value(true)},
{policy::key::kRemoteAccessHostAllowRelayedConnection, base::Value(true)},
});
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(false)},
});
RunNetworkThreadPendingTasks();
EXPECT_FALSE(last_nat_traversal_enabled_value_);
EXPECT_FALSE(last_relay_connections_allowed_value_);
ShutdownHost();
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
TEST_F(
It2MeHostTest,
LocalNatPoliciesChangedAfterEffectivePoliciesAreReceived_NotReportedToObserver) {
SetPolicies({
{policy::key::kRemoteAccessHostFirewallTraversal, base::Value(true)},
{policy::key::kRemoteAccessHostAllowRelayedConnection, base::Value(true)},
});
StartHost();
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
EXPECT_TRUE(last_nat_traversal_enabled_value_);
EXPECT_TRUE(last_relay_connections_allowed_value_);
SimulateEffectiveSessionPoliciesReceived();
SetPolicies({
{policy::key::kRemoteAccessHostFirewallTraversal, base::Value(false)},
{policy::key::kRemoteAccessHostAllowRelayedConnection,
base::Value(false)},
});
RunNetworkThreadPendingTasks();
EXPECT_TRUE(last_nat_traversal_enabled_value_);
EXPECT_TRUE(last_relay_connections_allowed_value_);
ShutdownHost();
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, AuthorizedHelperCanConnect) {
authorized_helper_ = kTestClientUsername;
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, UnauthorizedHelperIsRejected) {
authorized_helper_ = kTestClientUsername;
StartHost();
RunValidationCallback(kTestClientJid2);
ASSERT_EQ(ValidationResult::ERROR_UNAUTHORIZED_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 = get_local_session_policies().host_udp_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 = get_local_session_policies().host_udp_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_);
}
TEST_F(It2MeHostTest, FileTransferDisallowedByDefault) {
StartHost();
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest, UriForwardingDisallowedByDefault) {
StartHost();
EXPECT_FALSE(*get_local_session_policies().allow_uri_forwarding);
}
TEST_F(It2MeHostTest, StartHost_CorpUser_UseCorpSessionAuthz) {
is_corp_user_ = true;
StartHost();
ASSERT_EQ(last_host_state_, It2MeHostState::kReceivedAccessCode);
// No shared secret after the support ID.
ASSERT_EQ(stored_access_code_, kTestSupportId);
ASSERT_TRUE(is_using_corp_session_authz());
ASSERT_TRUE(has_corp_host_status_logger());
}
TEST_F(It2MeHostTest, StartHost_NonCorpUser_DoesNotUseCorpSessionAuthz) {
is_corp_user_ = false;
StartHost();
ASSERT_EQ(last_host_state_, It2MeHostState::kReceivedAccessCode);
// The access code includes the shared secret so it is longer than the support
// ID.
ASSERT_GT(stored_access_code_.length(), strlen(kTestSupportId));
ASSERT_FALSE(is_using_corp_session_authz());
ASSERT_FALSE(has_corp_host_status_logger());
}
TEST_F(It2MeHostTest, AllowRemoteInputSessionPolicyEnabledByDefault) {
StartHost();
EXPECT_TRUE(*get_local_session_policies().allow_remote_input);
}
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(It2MeHostTest, ConnectRespectsSuppressDialogsParameter) {
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.suppress_user_dialogs = true;
StartHost(std::move(params));
EXPECT_FALSE(dialog_factory_->dialog_created());
EXPECT_FALSE(
GetHost()->desktop_environment_options().enable_user_interface());
}
TEST_F(It2MeHostTest, ConnectRespectsSuppressNotificationsParameter) {
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.suppress_notifications = true;
StartHost(std::move(params));
EXPECT_FALSE(dialog_factory_->dialog_created());
EXPECT_FALSE(GetHost()->desktop_environment_options().enable_notifications());
}
TEST_F(It2MeHostTest, ConnectRespectsTerminateUponInputParameter) {
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.terminate_upon_input = true;
StartHost(std::move(params));
EXPECT_TRUE(GetHost()->desktop_environment_options().terminate_upon_input());
}
TEST_F(It2MeHostTest, TerminateUponInputDefaultsToFalse) {
StartHost(/*enterprise_params=*/std::nullopt);
EXPECT_FALSE(GetHost()->desktop_environment_options().terminate_upon_input());
}
TEST_F(It2MeHostTest, ConnectRespectsMaximumSessionDurationParameter) {
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.maximum_session_duration = base::Hours(8);
StartHost(std::move(params));
EXPECT_EQ(GetHost()->desktop_environment_options().maximum_session_duration(),
base::Hours(8));
}
TEST_F(It2MeHostTest, ConnectRespectsEnableCurtainingParameter) {
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.curtain_local_user_session = true;
StartHost(std::move(params));
EXPECT_TRUE(*get_local_session_policies().curtain_required);
}
TEST_F(It2MeHostTest, ConnectRespectsAllowRemoteInputParameter) {
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.allow_remote_input = false;
StartHost(std::move(params));
EXPECT_FALSE(*get_local_session_policies().allow_remote_input);
}
TEST_F(It2MeHostTest, ConnectRespectsAllowClipboardSyncParameter) {
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.allow_clipboard_sync = false;
StartHost(std::move(params));
EXPECT_EQ(*get_local_session_policies().clipboard_size_bytes, 0U);
}
TEST_F(It2MeHostTest, EnableCurtainingDefaultsToFalse) {
StartHost(/*enterprise_params=*/std::nullopt);
EXPECT_FALSE(get_local_session_policies().curtain_required.has_value());
}
TEST_F(It2MeHostTest, AllowEnterpriseFileTransferWithPolicyEnabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
base::Value(true)}});
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.allow_file_transfer = true;
StartHost(std::move(params));
EXPECT_TRUE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest, AllowEnterpriseFileTransferWithPolicyDisabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
base::Value(false)}});
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.allow_file_transfer = true;
StartHost(std::move(params));
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest,
AllowEnterpriseFileTransferWithPolicyEnabledForNonEnterpriseSession) {
SetPolicies({{policy::key::kRemoteAccessHostAllowEnterpriseFileTransfer,
base::Value(true)}});
StartHost(/*enterprise_params=*/std::nullopt);
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest, AllowEnterpriseFileTransferWithPolicyNotSet) {
SetPolicies({});
ChromeOsEnterpriseParams params(
GetDefaultEnterpriseParamsForEnterpriseAdmin());
params.allow_file_transfer = true;
StartHost(std::move(params));
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest, EnableFileTransferDefaultsToFalse) {
StartHost(/*enterprise_params=*/std::nullopt);
EXPECT_FALSE(*get_local_session_policies().allow_file_transfer);
}
TEST_F(It2MeHostTest,
EnterpriseSessionsSucceedWhenRemoteSupportConnectionsPolicyDisabled) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
base::Value(false)}});
StartHost(GetDefaultEnterpriseParamsForEnterpriseAdmin());
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(GetDefaultEnterpriseParamsForEnterpriseAdmin());
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(GetDefaultEnterpriseParamsForEnterpriseAdmin());
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(/*enterprise_params=*/std::nullopt);
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
}
TEST_F(It2MeHostTest, EnterpriseSessionsShouldNotDisconnectOnPolicyChange) {
StartHost(GetDefaultEnterpriseParamsForEnterpriseAdmin());
const It2MeHostState initial_state = last_host_state_;
ASSERT_EQ(initial_state, It2MeHostState::kReceivedAccessCode);
SetPolicies({{policy::key::kRemoteAccessHostFirewallTraversal,
base::Value(!last_nat_traversal_enabled_value_)}});
// Using RunUntilIdle is frowned upon, but there is no other way to check a
// change does *not* happen.
base::RunLoop().RunUntilIdle();
ASSERT_EQ(last_host_state_, initial_state);
}
TEST_F(It2MeHostTest, EnterpriseClassManagementSessionsSucceedAsAStudent) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
base::Value(false)},
{policy::key::kClassManagementEnabled, base::Value("student")}});
StartHost(GetDefaultEnterpriseParamsForClassManagement());
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
}
TEST_F(It2MeHostTest, EnterpriseClassManagementSessionsSucceedAsATeacher) {
SetPolicies({{policy::key::kRemoteAccessHostAllowRemoteSupportConnections,
base::Value(false)},
{policy::key::kClassManagementEnabled, base::Value("teacher")}});
StartHost(GetDefaultEnterpriseParamsForClassManagement());
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
}
TEST_F(
It2MeHostTest,
EnterpriseClassManagementSessionsFailsWhenClassManagementPolicyDisabled) {
SetPolicies(
{{policy::key::kClassManagementEnabled, base::Value("disabled")}});
StartHost(GetDefaultEnterpriseParamsForClassManagement());
ASSERT_EQ(It2MeHostState::kError, last_host_state_);
ASSERT_EQ(ErrorCode::DISALLOWED_BY_POLICY, last_error_code_);
}
TEST_F(It2MeHostTest,
EnterpriseClassManagementSessionsFailsWhenClassManagementPolicyUnset) {
StartHost(GetDefaultEnterpriseParamsForClassManagement());
ASSERT_EQ(It2MeHostState::kError, last_host_state_);
ASSERT_EQ(ErrorCode::DISALLOWED_BY_POLICY, last_error_code_);
}
TEST_F(It2MeHostTest,
EnterpriseClassManagementSessionsShouldNotCheckHostDomain) {
SetPolicies({{policy::key::kRemoteAccessHostDomainList,
MakeList({"other-domain.com"})},
{policy::key::kClassManagementEnabled, base::Value("student")}});
StartHost(GetDefaultEnterpriseParamsForClassManagement());
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,
EnterpriseClassManagementSessionsShouldNotCheckClientDomain) {
SetPolicies({{policy::key::kRemoteAccessHostClientDomainList,
MakeList({"other-domain.com"})},
{policy::key::kClassManagementEnabled, base::Value("student")}});
authorized_helper_ = kTestClientUsername;
StartHost(GetDefaultEnterpriseParamsForClassManagement());
ASSERT_EQ(It2MeHostState::kReceivedAccessCode, last_host_state_);
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,
EnterpriseClassManagementSessionsFailWithoutAuthorizedUser) {
SetPolicies({{policy::key::kClassManagementEnabled, base::Value("student")}});
StartHost(GetDefaultEnterpriseParamsForClassManagement());
RunValidationCallback(kTestClientJid);
ASSERT_EQ(ValidationResult::ERROR_UNAUTHORIZED_ACCOUNT, validation_result_);
RunUntilStateChanged(It2MeHostState::kDisconnected);
ASSERT_EQ(It2MeHostState::kDisconnected, last_host_state_);
}
#endif
} // namespace remoting