0

[remoting corp logging] Implement CorpHostStatusLogger

This CL implements the CorpHostStatusLogger and hooks it up with the
JingleSessionManager, so that it reports the disconnect event to the
corp logging service with both the error code and the SessionAuthz
reauth token attached.

The tricky part of this CL is to pass the reauth token from the
SessionAuthzReauthorizer to the CorpHostStatusLogger. There is
`HostStatusObserver`, but it implements a mojo interface, meaning it
will be rather difficult to pass pointers around (without being rejected
by the mojo reviewer). Just passing the reauth token around in callbacks
would also work, but that would be very messy.

To get that working, this CL introduces a `SessionObserver`, which
allows implementations to observer state changes on multiple sessions
and know which session has changed. `authentication_type()` and
`implementing_authenticator()` are added to `Authenticator` to allow
`CorpHostStatusLogger` to extract the reauth token from the generalized
`Authenticator` reference.

Bug: b/328138087
Change-Id: Ic7b9ea297d28488ef65d4071860836b47e9c3b5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5359454
Auto-Submit: Yuwei Huang <yuweih@chromium.org>
Reviewed-by: Joe Downing <joedow@chromium.org>
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1271835}
This commit is contained in:
Yuwei Huang
2024-03-12 21:39:57 +00:00
committed by Chromium LUCI CQ
parent 1e8168a564
commit 73563374d5
46 changed files with 738 additions and 24 deletions

@ -43,6 +43,8 @@ source_set("base") {
"compound_buffer.h",
"constants.cc",
"constants.h",
"corp_auth_util.cc",
"corp_auth_util.h",
"corp_logging_service_client.cc",
"corp_logging_service_client.h",
"corp_service_client.cc",

@ -0,0 +1,35 @@
// Copyright 2024 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/base/corp_auth_util.h"
#include "base/check.h"
#include "remoting/base/oauth_token_getter_impl.h"
namespace remoting {
namespace {
constexpr char kOAuthScope[] =
"https://www.googleapis.com/auth/chromoting.me2me.host";
} // namespace
std::unique_ptr<OAuthTokenGetterImpl> CreateCorpTokenGetter(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& service_account_email,
const std::string& refresh_token) {
DCHECK(url_loader_factory);
DCHECK(!service_account_email.empty());
DCHECK(!refresh_token.empty());
return std::make_unique<OAuthTokenGetterImpl>(
std::make_unique<OAuthTokenGetter::OAuthAuthorizationCredentials>(
service_account_email, refresh_token,
/* is_service_account= */ true,
std::vector<std::string>{kOAuthScope}),
url_loader_factory,
/* auto_refresh= */ false);
}
} // namespace remoting

@ -0,0 +1,28 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_BASE_CORP_AUTH_UTIL_H_
#define REMOTING_BASE_CORP_AUTH_UTIL_H_
#include <memory>
#include <string>
#include "base/memory/scoped_refptr.h"
#include "remoting/base/oauth_token_getter_impl.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace remoting {
// Creates an OAuthTokenGetterImpl that is suitable for making requests to corp
// APIs. Corp APIs' authentication config is different from that of the regular
// APIs, so you can't make authenticated corp API requests with the regular
// OAuthTokenGetter.
std::unique_ptr<OAuthTokenGetterImpl> CreateCorpTokenGetter(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& service_account_email,
const std::string& refresh_token);
} // namespace remoting
#endif // REMOTING_BASE_CORP_AUTH_UTIL_H_

@ -9,34 +9,22 @@
#include "base/check.h"
#include "base/task/sequenced_task_runner.h"
#include "remoting/base/corp_auth_util.h"
#include "remoting/base/corp_session_authz_service_client.h"
#include "remoting/base/oauth_token_getter_impl.h"
#include "remoting/base/oauth_token_getter_proxy.h"
namespace remoting {
namespace {
constexpr char kOAuthScope[] =
"https://www.googleapis.com/auth/chromoting.me2me.host";
} // namespace
CorpSessionAuthzServiceClientFactory::CorpSessionAuthzServiceClientFactory(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& service_account_email,
const std::string& refresh_token) {
DCHECK(url_loader_factory);
DCHECK(!service_account_email.empty());
DCHECK(!refresh_token.empty());
url_loader_factory_ = url_loader_factory;
oauth_token_getter_ = std::make_unique<OAuthTokenGetterImpl>(
std::make_unique<OAuthTokenGetter::OAuthAuthorizationCredentials>(
service_account_email, refresh_token,
/* is_service_account= */ true,
std::vector<std::string>{kOAuthScope}),
url_loader_factory_,
/* auto_refresh= */ false);
oauth_token_getter_ = CreateCorpTokenGetter(
url_loader_factory, service_account_email, refresh_token);
oauth_token_getter_task_runner_ =
base::SequencedTaskRunner::GetCurrentDefault();
}

@ -275,6 +275,8 @@ static_library("common") {
"config_watcher.h",
"continue_window.cc",
"continue_window.h",
"corp_host_status_logger.cc",
"corp_host_status_logger.h",
"crash_process.cc",
"crash_process.h",
"curtain_mode.h",
@ -795,6 +797,7 @@ source_set("unit_tests") {
"chromoting_host_unittest.cc",
"client_session_unittest.cc",
"config_file_watcher_unittest.cc",
"corp_host_status_logger_unittest.cc",
"daemon_process_unittest.cc",
"desktop_display_info_unittest.cc",
"desktop_display_layout_util_unittest.cc",
@ -867,6 +870,7 @@ source_set("unit_tests") {
"//remoting/host/setup:common",
"//remoting/host/webauthn:unit_tests",
"//remoting/proto",
"//remoting/proto:internal_structs",
"//remoting/proto/remoting/v1:chrome_os_enterprise_options",
"//remoting/proto/remoting/v1:remote_support_host_messages",
"//remoting/protocol:test_support",

@ -0,0 +1,86 @@
// Copyright 2024 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/corp_host_status_logger.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "remoting/base/corp_auth_util.h"
#include "remoting/base/corp_logging_service_client.h"
#include "remoting/base/logging.h"
#include "remoting/base/protobuf_http_status.h"
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/credentials_type.h"
#include "remoting/protocol/session.h"
#include "remoting/protocol/session_authz_authenticator.h"
#include "remoting/protocol/session_authz_reauthorizer.h"
#include "remoting/protocol/session_manager.h"
namespace remoting {
CorpHostStatusLogger::CorpHostStatusLogger(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& service_account_email,
const std::string& refresh_token)
: CorpHostStatusLogger(std::make_unique<CorpLoggingServiceClient>(
url_loader_factory,
CreateCorpTokenGetter(url_loader_factory,
service_account_email,
refresh_token))) {}
CorpHostStatusLogger::CorpHostStatusLogger(
std::unique_ptr<LoggingServiceClient> service_client)
: service_client_(std::move(service_client)) {}
CorpHostStatusLogger::~CorpHostStatusLogger() = default;
void CorpHostStatusLogger::StartObserving(
protocol::SessionManager& session_manager) {
observer_subscription_ = session_manager.AddSessionObserver(this);
}
void CorpHostStatusLogger::OnSessionStateChange(
const protocol::Session& session,
protocol::Session::State state) {
if (state != protocol::Session::State::CLOSED &&
state != protocol::Session::State::FAILED) {
return;
}
if (session.authenticator().credentials_type() !=
protocol::CredentialsType::CORP_SESSION_AUTHZ) {
VLOG(1) << "Current session is not authenticated with SessionAuthz. "
<< "Disconnect event not logged.";
return;
}
const protocol::SessionAuthzReauthorizer* reauthorizer =
static_cast<const protocol::SessionAuthzAuthenticator&>(
session.authenticator().implementing_authenticator())
.reauthorizer();
if (!reauthorizer) {
// TODO: b/328138087 - add |session_authz_id| to the request so that we can
// still log the disconnect event explicitly, in case SessionAuthz has
// failed.
LOG(WARNING) << "Current session does not have a reauthorizer. "
<< "Disconnect event not logged.";
return;
}
internal::ReportSessionDisconnectedRequestStruct request{
.session_authz_reauth_token = reauthorizer->session_reauth_token(),
.error_code = session.error(),
};
service_client_->ReportSessionDisconnected(
request, base::BindOnce([](const ProtobufHttpStatus& status) {
if (status.ok()) {
HOST_LOG << "Disconnect event logged.";
} else {
LOG(ERROR) << "Failed to log disconnect event: "
<< status.error_message() << '('
<< static_cast<int>(status.error_code()) << ')';
}
}));
}
} // namespace remoting

@ -0,0 +1,51 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_CORP_HOST_STATUS_LOGGER_H_
#define REMOTING_HOST_CORP_HOST_STATUS_LOGGER_H_
#include <memory>
#include <string>
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "remoting/protocol/session.h"
#include "remoting/protocol/session_observer.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace remoting {
namespace protocol {
class SessionManager;
} // namespace protocol
class LoggingServiceClient;
// A class that reports host status changes to the corp logging service. This is
// not used for external users. For internal details, see go/crd-corp-logging.
class CorpHostStatusLogger final : public protocol::SessionObserver {
public:
CorpHostStatusLogger(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const std::string& service_account_email,
const std::string& refresh_token);
explicit CorpHostStatusLogger(
std::unique_ptr<LoggingServiceClient> service_client);
~CorpHostStatusLogger() override;
CorpHostStatusLogger(const CorpHostStatusLogger&) = delete;
CorpHostStatusLogger& operator=(const CorpHostStatusLogger&) = delete;
void StartObserving(protocol::SessionManager& session_manager);
private:
// protocol::SessionObserver
void OnSessionStateChange(const protocol::Session& session,
protocol::Session::State state) override;
std::unique_ptr<LoggingServiceClient> service_client_;
Subscription observer_subscription_;
};
} // namespace remoting
#endif // REMOTING_HOST_CORP_HOST_STATUS_LOGGER_H_

@ -0,0 +1,158 @@
// Copyright 2024 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/corp_host_status_logger.h"
#include <memory>
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/test/mock_callback.h"
#include "base/time/time.h"
#include "remoting/base/logging_service_client.h"
#include "remoting/proto/logging_service.h"
#include "remoting/protocol/credentials_type.h"
#include "remoting/protocol/protocol_mock_objects.h"
#include "remoting/protocol/session_authz_authenticator.h"
#include "remoting/protocol/session_authz_reauthorizer.h"
#include "remoting/protocol/session_observer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace remoting {
namespace {
using testing::_;
using testing::Return;
using testing::ReturnRef;
constexpr char kFakeReauthToken[] = "fake_reauth_token";
class MockLoggingServiceClient final : public LoggingServiceClient {
public:
MockLoggingServiceClient() = default;
~MockLoggingServiceClient() override = default;
MockLoggingServiceClient(const MockLoggingServiceClient&) = delete;
MockLoggingServiceClient& operator=(const MockLoggingServiceClient&) = delete;
MOCK_METHOD(void,
ReportSessionDisconnected,
(const internal::ReportSessionDisconnectedRequestStruct&,
StatusCallback));
};
} // namespace
class CorpHostStatusLoggerTest : public testing::Test {
public:
CorpHostStatusLoggerTest();
~CorpHostStatusLoggerTest() override;
protected:
void SetUpSessionAuthzAuthenticator(bool has_reauthorizer);
raw_ptr<MockLoggingServiceClient> service_client_;
std::unique_ptr<CorpHostStatusLogger> logger_;
raw_ptr<protocol::SessionObserver> logger_as_observer_;
base::MockOnceClosure unsubscribe_closure_;
protocol::MockSession session_;
protocol::MockSessionManager session_manager_;
protocol::MockAuthenticator authenticator_;
protocol::SessionAuthzAuthenticator session_authz_authenticator_{
protocol::CredentialsType::CORP_SESSION_AUTHZ, nullptr,
base::NullCallback()};
};
CorpHostStatusLoggerTest::CorpHostStatusLoggerTest() {
auto service_client = std::make_unique<MockLoggingServiceClient>();
service_client_ = service_client.get();
logger_ = std::make_unique<CorpHostStatusLogger>(std::move(service_client));
logger_as_observer_ = logger_.get();
EXPECT_CALL(session_, authenticator())
.WillRepeatedly(ReturnRef(authenticator_));
EXPECT_CALL(session_manager_, AddSessionObserver(logger_.get()))
.WillOnce(Return(
protocol::SessionObserver::Subscription(unsubscribe_closure_.Get())));
logger_->StartObserving(session_manager_);
}
CorpHostStatusLoggerTest::~CorpHostStatusLoggerTest() {
EXPECT_CALL(unsubscribe_closure_, Run());
service_client_ = nullptr;
logger_as_observer_ = nullptr;
logger_.reset();
}
void CorpHostStatusLoggerTest::SetUpSessionAuthzAuthenticator(
bool has_reauthorizer) {
EXPECT_CALL(authenticator_, credentials_type())
.WillOnce(Return(session_authz_authenticator_.credentials_type()));
EXPECT_CALL(authenticator_, implementing_authenticator())
.WillOnce(
ReturnRef(session_authz_authenticator_.implementing_authenticator()));
if (has_reauthorizer) {
session_authz_authenticator_.SetReauthorizerForTesting(
std::make_unique<protocol::SessionAuthzReauthorizer>(
nullptr, "fake_session_id", kFakeReauthToken, base::Minutes(5),
base::DoNothing()));
}
}
TEST_F(CorpHostStatusLoggerTest, UnsubscribeOnceDestroyed) {
// Test done in the destructor.
}
TEST_F(CorpHostStatusLoggerTest, IgnoreUninterestingState) {
EXPECT_CALL(*service_client_, ReportSessionDisconnected(_, _)).Times(0);
logger_as_observer_->OnSessionStateChange(
session_, protocol::Session::State::AUTHENTICATING);
}
TEST_F(CorpHostStatusLoggerTest, IgnoreNonSessionAuthzSession) {
EXPECT_CALL(*service_client_, ReportSessionDisconnected(_, _)).Times(0);
EXPECT_CALL(authenticator_, credentials_type())
.WillOnce(Return(protocol::CredentialsType::SHARED_SECRET));
logger_as_observer_->OnSessionStateChange(session_,
protocol::Session::State::CLOSED);
}
TEST_F(CorpHostStatusLoggerTest, IgnoreSessionWithoutReauthorizer) {
EXPECT_CALL(*service_client_, ReportSessionDisconnected(_, _)).Times(0);
SetUpSessionAuthzAuthenticator(/* has_reauthorizer= */ false);
logger_as_observer_->OnSessionStateChange(session_,
protocol::Session::State::CLOSED);
}
TEST_F(CorpHostStatusLoggerTest, ReportsSessionDisconnectedForClosed) {
EXPECT_CALL(session_, error()).WillOnce(Return(ErrorCode::OK));
internal::ReportSessionDisconnectedRequestStruct expected_request{
.session_authz_reauth_token = kFakeReauthToken,
.error_code = ErrorCode::OK,
};
EXPECT_CALL(*service_client_, ReportSessionDisconnected(expected_request, _));
SetUpSessionAuthzAuthenticator(/* has_reauthorizer= */ true);
logger_as_observer_->OnSessionStateChange(session_,
protocol::Session::State::CLOSED);
}
TEST_F(CorpHostStatusLoggerTest, ReportsSessionDisconnectedForFailed) {
EXPECT_CALL(session_, error()).WillOnce(Return(ErrorCode::PEER_IS_OFFLINE));
internal::ReportSessionDisconnectedRequestStruct expected_request{
.session_authz_reauth_token = kFakeReauthToken,
.error_code = ErrorCode::PEER_IS_OFFLINE,
};
EXPECT_CALL(*service_client_, ReportSessionDisconnected(expected_request, _));
SetUpSessionAuthzAuthenticator(/* has_reauthorizer= */ true);
logger_as_observer_->OnSessionStateChange(session_,
protocol::Session::State::FAILED);
}
} // namespace remoting

@ -25,6 +25,8 @@ class PamAuthorizer : public protocol::Authenticator {
~PamAuthorizer() override;
// protocol::Authenticator:
protocol::CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;
@ -59,6 +61,15 @@ PamAuthorizer::PamAuthorizer(
PamAuthorizer::~PamAuthorizer() {}
protocol::CredentialsType PamAuthorizer::credentials_type() const {
return underlying_->credentials_type();
}
const protocol::Authenticator& PamAuthorizer::implementing_authenticator()
const {
return underlying_->implementing_authenticator();
}
protocol::Authenticator::State PamAuthorizer::state() const {
if (local_login_status_ == DISALLOWED) {
return REJECTED;

@ -70,6 +70,7 @@
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/config_file_watcher.h"
#include "remoting/host/config_watcher.h"
#include "remoting/host/corp_host_status_logger.h"
#include "remoting/host/crash_process.h"
#include "remoting/host/desktop_environment.h"
#include "remoting/host/desktop_session_connector.h"
@ -475,6 +476,9 @@ class HostProcess : public ConfigWatcher::Delegate,
#endif
std::unique_ptr<HostPowerSaveBlocker> power_save_blocker_;
// Only set if |is_googler_| is true.
std::unique_ptr<CorpHostStatusLogger> corp_host_status_logger_;
std::unique_ptr<ChromotingHost> host_;
// Used to keep this HostProcess alive until it is shutdown.
@ -1872,6 +1876,10 @@ void HostProcess::StartHost() {
// externally, we don't want to apply this policy for non-Googlers.
desktop_environment_options_.set_enable_user_interface(
enable_user_interface_);
corp_host_status_logger_ = std::make_unique<CorpHostStatusLogger>(
context_->url_loader_factory(), service_account_email_,
oauth_refresh_token_);
corp_host_status_logger_->StartObserving(*session_manager);
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
@ -2002,6 +2010,7 @@ void HostProcess::GoOffline(const std::string& host_offline_reason) {
host_event_logger_.reset();
host_status_logger_.reset();
power_save_blocker_.reset();
corp_host_status_logger_.reset();
ftl_host_change_notification_listener_.reset();
// Before shutting down HostSignalingManager, send the |host_offline_reason|

@ -12,6 +12,9 @@
namespace remoting::internal {
struct ReportSessionDisconnectedRequestStruct {
bool operator==(const ReportSessionDisconnectedRequestStruct&) const =
default;
std::string session_authz_reauth_token;
ErrorCode error_code;
};

@ -70,6 +70,7 @@ static_library("protocol") {
"connection_to_host.h",
"content_description.cc",
"content_description.h",
"credentials_type.h",
"data_channel_manager.cc",
"data_channel_manager.h",
"datagram_channel_factory.h",
@ -180,6 +181,7 @@ static_library("protocol") {
"session_authz_reauthorizer.cc",
"session_authz_reauthorizer.h",
"session_manager.h",
"session_observer.h",
"session_options_provider.h",
"session_plugin.h",
"socket_util.cc",

@ -9,6 +9,7 @@
#include <string>
#include "base/functional/callback.h"
#include "remoting/protocol/credentials_type.h"
namespace jingle_xmpp {
class XmlElement;
@ -118,6 +119,17 @@ class Authenticator {
Authenticator();
virtual ~Authenticator();
// Returns the credentials type of the authenticator.
virtual CredentialsType credentials_type() const = 0;
// Returns the authenticator that implements `credentials_type()`. The
// returned value is usually `*this`, but may be an underlying authenticator
// if this authenticator is a wrapper (e.g. negotiating) authenticator. Note
// that some authenticators may use other authenticators internally, but they
// will still return `*this` as long as it implements an credentials type
// that is not implemented by the authenticators it use.
virtual const Authenticator& implementing_authenticator() const = 0;
// Returns current state of the authenticator.
virtual State state() const = 0;

@ -0,0 +1,34 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_PROTOCOL_CREDENTIALS_TYPE_H_
#define REMOTING_PROTOCOL_CREDENTIALS_TYPE_H_
namespace remoting::protocol {
// The type of the credentials used for authentication.
enum class CredentialsType {
// The credentials type is unknown. This is usually reported by a wrapper
// (e.g. negotiating) authenticator when the underlying authenticator is not
// determined yet.
UNKNOWN,
// Key exchange based on a shared secret, e.g. a PIN or an IT2ME access code.
SHARED_SECRET,
// Key exchange based on a shared pairing secret.
PAIRED,
// Authentication using the third-party authentication server, which generates
// a shared secret for key exchange.
THIRD_PARTY,
// Authentication using the corp-internal SessionAuthz service, which
// generates a shared secret for key exchange.
CORP_SESSION_AUTHZ,
};
} // namespace remoting::protocol
#endif // REMOTING_PROTOCOL_CREDENTIALS_TYPE_H_

@ -122,6 +122,14 @@ void FakeAuthenticator::Resume() {
std::move(resume_closure_).Run();
}
CredentialsType FakeAuthenticator::credentials_type() const {
return config_.credentials_type;
}
const Authenticator& FakeAuthenticator::implementing_authenticator() const {
return *this;
}
Authenticator::State FakeAuthenticator::state() const {
EXPECT_LE(messages_, config_.round_trips * 2);

@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/credentials_type.h"
namespace remoting::protocol {
@ -63,6 +64,7 @@ class FakeAuthenticator : public Authenticator {
Action action = Action::ACCEPT;
bool async = true;
raw_ptr<base::RepeatingClosureList> reject_after_accepted;
CredentialsType credentials_type = CredentialsType::SHARED_SECRET;
};
FakeAuthenticator(Type type,
@ -96,6 +98,8 @@ class FakeAuthenticator : public Authenticator {
void Resume();
// Authenticator interface.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;

@ -10,6 +10,7 @@
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/task/single_thread_task_runner.h"
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/fake_authenticator.h"
#include "remoting/protocol/session_plugin.h"
#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
@ -58,7 +59,7 @@ void FakeSession::SetEventHandler(EventHandler* event_handler) {
event_handler_ = event_handler;
}
ErrorCode FakeSession::error() {
ErrorCode FakeSession::error() const {
return error_;
}
@ -70,6 +71,10 @@ const SessionConfig& FakeSession::config() {
return *config_;
}
const Authenticator& FakeSession::authenticator() const {
return *authenticator_;
}
void FakeSession::SetTransport(Transport* transport) {
transport_ = transport;
}

@ -51,9 +51,10 @@ class FakeSession : public Session {
// Session interface.
void SetEventHandler(EventHandler* event_handler) override;
ErrorCode error() override;
ErrorCode error() const override;
const std::string& jid() override;
const SessionConfig& config() override;
const Authenticator& authenticator() const override;
void SetTransport(Transport* transport) override;
void Close(ErrorCode error) override;
void AddPlugin(SessionPlugin* plugin) override;

@ -24,6 +24,7 @@
#include "remoting/protocol/jingle_messages.h"
#include "remoting/protocol/jingle_session_manager.h"
#include "remoting/protocol/session_config.h"
#include "remoting/protocol/session_observer.h"
#include "remoting/protocol/session_plugin.h"
#include "remoting/protocol/transport.h"
#include "remoting/signaling/iq_sender.h"
@ -214,7 +215,7 @@ void JingleSession::SetEventHandler(Session::EventHandler* event_handler) {
event_handler_ = event_handler;
}
ErrorCode JingleSession::error() {
ErrorCode JingleSession::error() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return error_;
}
@ -343,6 +344,11 @@ const SessionConfig& JingleSession::config() {
return *config_;
}
const Authenticator& JingleSession::authenticator() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return *authenticator_;
}
void JingleSession::SetTransport(Transport* transport) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!transport_);
@ -800,6 +806,11 @@ void JingleSession::SetState(State new_state) {
DCHECK_NE(state_, FAILED);
state_ = new_state;
// Observers must be called before the event handler, since the event
// handler may destroy the session.
for (SessionObserver& observer : session_manager_->observers_) {
observer.OnSessionStateChange(*this, new_state);
}
if (event_handler_) {
event_handler_->OnSessionStateChange(new_state);
}

@ -38,9 +38,10 @@ class JingleSession : public Session {
// Session interface.
void SetEventHandler(Session::EventHandler* event_handler) override;
ErrorCode error() override;
ErrorCode error() const override;
const std::string& jid() override;
const SessionConfig& config() override;
const Authenticator& authenticator() const override;
void SetTransport(Transport* transport) override;
void Close(protocol::ErrorCode error) override;
void AddPlugin(SessionPlugin* plugin) override;

@ -11,6 +11,7 @@
#include "remoting/protocol/content_description.h"
#include "remoting/protocol/jingle_messages.h"
#include "remoting/protocol/jingle_session.h"
#include "remoting/protocol/session_observer.h"
#include "remoting/protocol/transport.h"
#include "remoting/signaling/iq_sender.h"
#include "remoting/signaling/signal_strategy.h"
@ -59,6 +60,17 @@ void JingleSessionManager::set_authenticator_factory(
authenticator_factory_ = std::move(authenticator_factory);
}
SessionObserver::Subscription JingleSessionManager::AddSessionObserver(
SessionObserver* observer) {
observers_.AddObserver(observer);
return SessionObserver::Subscription(
base::BindOnce(&JingleSessionManager::RemoveSessionObserver,
weak_factory_.GetWeakPtr(), observer));
}
void JingleSessionManager::RemoveSessionObserver(SessionObserver* observer) {
observers_.RemoveObserver(observer);
}
void JingleSessionManager::OnSignalStrategyStateChange(
SignalStrategy::State state) {}

@ -9,9 +9,12 @@
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "remoting/protocol/jingle_messages.h"
#include "remoting/protocol/session_manager.h"
#include "remoting/protocol/session_observer.h"
#include "remoting/signaling/signal_strategy.h"
namespace jingle_xmpp {
@ -50,10 +53,14 @@ class JingleSessionManager : public SessionManager,
std::unique_ptr<Authenticator> authenticator) override;
void set_authenticator_factory(
std::unique_ptr<AuthenticatorFactory> authenticator_factory) override;
[[nodiscard]] SessionObserver::Subscription AddSessionObserver(
SessionObserver* observer) override;
private:
friend class JingleSession;
void RemoveSessionObserver(SessionObserver* observer);
// SignalStrategy::Listener interface.
void OnSignalStrategyStateChange(SignalStrategy::State state) override;
bool OnSignalStrategyIncomingStanza(
@ -76,8 +83,11 @@ class JingleSessionManager : public SessionManager,
std::unique_ptr<IqSender> iq_sender_;
SessionsMap sessions_;
base::ObserverList<SessionObserver> observers_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<JingleSessionManager> weak_factory_{this};
};
} // namespace protocol

@ -29,6 +29,8 @@
#include "remoting/protocol/fake_authenticator.h"
#include "remoting/protocol/jingle_session_manager.h"
#include "remoting/protocol/network_settings.h"
#include "remoting/protocol/protocol_mock_objects.h"
#include "remoting/protocol/session_observer.h"
#include "remoting/protocol/session_plugin.h"
#include "remoting/protocol/transport.h"
#include "remoting/protocol/transport_context.h"
@ -663,4 +665,34 @@ TEST_F(JingleSessionTest, AuthenticatorRejectedAfterAccepted) {
ASSERT_NE(client_session_->error(), ErrorCode::OK);
}
TEST_F(JingleSessionTest, ObserverIsNotified) {
MockSessionObserver observer;
const Session* accepted_session = nullptr;
EXPECT_CALL(observer, OnSessionStateChange(_, _))
.WillRepeatedly([&](const Session& session, Session::State state) {
if (state == Session::State::ACCEPTED) {
accepted_session = &session;
}
});
FakeAuthenticator::Config auth_config(FakeAuthenticator::ACCEPT);
CreateSessionManagers(auth_config);
auto subscription = host_server_->AddSessionObserver(&observer);
InitiateConnection(auth_config, false);
ASSERT_EQ(accepted_session, host_session_.get());
}
TEST_F(JingleSessionTest, ObserverIsNotNotifiedAfterSubscriptionIsDestroyed) {
MockSessionObserver observer;
EXPECT_CALL(observer, OnSessionStateChange(_, _)).Times(0);
FakeAuthenticator::Config auth_config(FakeAuthenticator::ACCEPT);
CreateSessionManagers(auth_config);
auto subscription = std::make_unique<SessionObserver::Subscription>(
host_server_->AddSessionObserver(&observer));
subscription.reset();
InitiateConnection(auth_config, false);
}
} // namespace remoting::protocol

@ -16,6 +16,7 @@
#include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/credentials_type.h"
#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
namespace remoting::protocol {
@ -38,6 +39,20 @@ NegotiatingAuthenticatorBase::NegotiatingAuthenticatorBase(
NegotiatingAuthenticatorBase::~NegotiatingAuthenticatorBase() = default;
CredentialsType NegotiatingAuthenticatorBase::credentials_type() const {
if (!current_authenticator_) {
return CredentialsType::UNKNOWN;
}
return current_authenticator_->credentials_type();
}
const Authenticator& NegotiatingAuthenticatorBase::implementing_authenticator()
const {
return current_authenticator_
? current_authenticator_->implementing_authenticator()
: *this;
}
Authenticator::State NegotiatingAuthenticatorBase::state() const {
return state_;
}

@ -68,6 +68,8 @@ class NegotiatingAuthenticatorBase : public Authenticator {
~NegotiatingAuthenticatorBase() override;
// Authenticator interface.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;

@ -16,6 +16,7 @@
#include "remoting/protocol/authenticator_test_base.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/connection_tester.h"
#include "remoting/protocol/credentials_type.h"
#include "remoting/protocol/host_authentication_config.h"
#include "remoting/protocol/negotiating_authenticator_base.h"
#include "remoting/protocol/negotiating_client_authenticator.h"
@ -325,4 +326,15 @@ TEST_F(NegotiatingAuthenticatorTest, NotifyStateChangeAfterAccepted) {
Authenticator::RejectionReason::REAUTHZ_POLICY_CHECK_FAILED);
}
TEST_F(NegotiatingAuthenticatorTest,
ReturnCorrectCredentialsTypeAndImplementingAuthenticator) {
InitAuthenticators(kNoClientId, kNoPairedSecret, kTestPin, kTestPin);
ASSERT_EQ(host_->credentials_type(), CredentialsType::UNKNOWN);
ASSERT_EQ(&host_->implementing_authenticator(), host_.get());
VerifyAccepted();
ASSERT_EQ(host_->credentials_type(), CredentialsType::SHARED_SECRET);
ASSERT_NE(&host_->implementing_authenticator(), host_.get());
}
} // namespace remoting::protocol

@ -17,6 +17,7 @@
#include "base/strings/string_split.h"
#include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/credentials_type.h"
#include "remoting/protocol/host_authentication_config.h"
#include "remoting/protocol/pairing_host_authenticator.h"
#include "remoting/protocol/pairing_registry.h"
@ -149,6 +150,7 @@ void NegotiatingHostAuthenticator::CreateAuthenticator(
case Method::CORP_SESSION_AUTHZ_SPAKE2_CURVE25519: {
DCHECK(config_->session_authz_client_factory);
auto authenticator = std::make_unique<SessionAuthzAuthenticator>(
CredentialsType::CORP_SESSION_AUTHZ,
config_->session_authz_client_factory->Create(),
base::BindRepeating(&Spake2Authenticator::CreateForHost, local_id_,
remote_id_, config_->local_cert,

@ -11,6 +11,7 @@
#include "base/logging.h"
#include "remoting/base/constants.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/credentials_type.h"
namespace remoting::protocol {
@ -23,6 +24,15 @@ const jingle_xmpp::StaticQName kPairingErrorAttribute = {"", "error"};
PairingAuthenticatorBase::PairingAuthenticatorBase() {}
PairingAuthenticatorBase::~PairingAuthenticatorBase() = default;
CredentialsType PairingAuthenticatorBase::credentials_type() const {
return CredentialsType::PAIRED;
}
const Authenticator& PairingAuthenticatorBase::implementing_authenticator()
const {
return *this;
}
Authenticator::State PairingAuthenticatorBase::state() const {
DCHECK(spake2_authenticator_);
return spake2_authenticator_->state();

@ -45,6 +45,8 @@ class PairingAuthenticatorBase : public Authenticator {
~PairingAuthenticatorBase() override;
// Authenticator interface.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;

@ -47,6 +47,9 @@ MockSession::~MockSession() = default;
MockSessionManager::MockSessionManager() = default;
MockSessionManager::~MockSessionManager() = default;
MockSessionObserver::MockSessionObserver() = default;
MockSessionObserver::~MockSessionObserver() = default;
MockPairingRegistryDelegate::MockPairingRegistryDelegate() = default;
MockPairingRegistryDelegate::~MockPairingRegistryDelegate() = default;

@ -28,6 +28,7 @@
#include "remoting/protocol/pairing_registry.h"
#include "remoting/protocol/session.h"
#include "remoting/protocol/session_manager.h"
#include "remoting/protocol/session_observer.h"
#include "remoting/protocol/transport.h"
#include "remoting/protocol/video_stub.h"
#include "remoting/signaling/signaling_address.h"
@ -45,6 +46,11 @@ class MockAuthenticator : public Authenticator {
~MockAuthenticator() override;
MOCK_METHOD(CredentialsType, credentials_type, (), (const, override));
MOCK_METHOD(const Authenticator&,
implementing_authenticator,
(),
(const, override));
MOCK_CONST_METHOD0(state, Authenticator::State());
MOCK_CONST_METHOD0(started, bool());
MOCK_CONST_METHOD0(rejection_reason, Authenticator::RejectionReason());
@ -217,10 +223,11 @@ class MockSession : public Session {
~MockSession() override;
MOCK_METHOD1(SetEventHandler, void(Session::EventHandler* event_handler));
MOCK_METHOD0(error, ErrorCode());
MOCK_METHOD(ErrorCode, error, (), (const, override));
MOCK_METHOD1(SetTransport, void(Transport*));
MOCK_METHOD0(jid, const std::string&());
MOCK_METHOD0(config, const SessionConfig&());
MOCK_METHOD(const Authenticator&, authenticator, (), (const, override));
MOCK_METHOD1(Close, void(ErrorCode error));
MOCK_METHOD1(AddPlugin, void(SessionPlugin* plugin));
};
@ -243,6 +250,9 @@ class MockSessionManager : public SessionManager {
MOCK_METHOD0(Close, void());
MOCK_METHOD1(set_authenticator_factory_ptr,
void(AuthenticatorFactory* factory));
MOCK_METHOD(SessionObserver::Subscription,
AddSessionObserver,
(SessionObserver * observer));
std::unique_ptr<Session> Connect(
const SignalingAddress& peer_address,
std::unique_ptr<Authenticator> authenticator) override {
@ -254,6 +264,17 @@ class MockSessionManager : public SessionManager {
}
};
class MockSessionObserver : public SessionObserver {
public:
MockSessionObserver();
~MockSessionObserver() override;
MockSessionObserver(const MockSessionObserver&) = delete;
MockSessionObserver& operator=(const MockSessionObserver&) = delete;
MOCK_METHOD(void, OnSessionStateChange, (const Session&, Session::State));
};
// Simple delegate that caches information on paired clients in memory.
class MockPairingRegistryDelegate : public PairingRegistry::Delegate {
public:

@ -17,6 +17,15 @@ RejectingAuthenticator::RejectingAuthenticator(RejectionReason rejection_reason)
RejectingAuthenticator::~RejectingAuthenticator() = default;
CredentialsType RejectingAuthenticator::credentials_type() const {
return CredentialsType::UNKNOWN;
}
const Authenticator& RejectingAuthenticator::implementing_authenticator()
const {
return *this;
}
Authenticator::State RejectingAuthenticator::state() const {
return state_;
}

@ -22,6 +22,8 @@ class RejectingAuthenticator : public Authenticator {
~RejectingAuthenticator() override;
// Authenticator interface
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;

@ -14,6 +14,7 @@
namespace remoting::protocol {
class Authenticator;
class SessionPlugin;
class Transport;
@ -71,7 +72,7 @@ class Session {
virtual void SetEventHandler(EventHandler* event_handler) = 0;
// Returns error code for a failed session.
virtual ErrorCode error() = 0;
virtual ErrorCode error() const = 0;
// JID of the other side.
virtual const std::string& jid() = 0;
@ -80,6 +81,8 @@ class Session {
// Returned pointer is valid until connection is closed.
virtual const SessionConfig& config() = 0;
virtual const Authenticator& authenticator() const = 0;
// Sets Transport to be used by the session. Must be called before the
// session becomes AUTHENTICATED. The transport must outlive the session.
virtual void SetTransport(Transport* transport) = 0;

@ -15,15 +15,21 @@
#include "remoting/base/protobuf_http_status.h"
#include "remoting/proto/session_authz_service.h"
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/credentials_type.h"
#include "remoting/protocol/session_authz_reauthorizer.h"
namespace remoting::protocol {
SessionAuthzAuthenticator::SessionAuthzAuthenticator(
CredentialsType credentials_type,
std::unique_ptr<SessionAuthzServiceClient> service_client,
const CreateBaseAuthenticatorCallback& create_base_authenticator_callback)
: service_client_(std::move(service_client)),
create_base_authenticator_callback_(create_base_authenticator_callback) {}
: credentials_type_(credentials_type),
service_client_(std::move(service_client)),
create_base_authenticator_callback_(create_base_authenticator_callback) {
// CORP_SESSION_AUTHZ is currently the only supported type.
DCHECK_EQ(credentials_type, CredentialsType::CORP_SESSION_AUTHZ);
}
SessionAuthzAuthenticator::~SessionAuthzAuthenticator() = default;
@ -31,6 +37,15 @@ void SessionAuthzAuthenticator::Start(base::OnceClosure resume_callback) {
GenerateHostToken(std::move(resume_callback));
}
CredentialsType SessionAuthzAuthenticator::credentials_type() const {
return credentials_type_;
}
const Authenticator& SessionAuthzAuthenticator::implementing_authenticator()
const {
return *this;
}
Authenticator::State SessionAuthzAuthenticator::state() const {
switch (session_authz_state_) {
case SessionAuthzState::NOT_STARTED:
@ -114,6 +129,11 @@ SessionAuthzAuthenticator::CreateChannelAuthenticator() const {
return underlying_->CreateChannelAuthenticator();
}
void SessionAuthzAuthenticator::SetReauthorizerForTesting(
std::unique_ptr<SessionAuthzReauthorizer> reauthorizer) {
reauthorizer_ = std::move(reauthorizer);
}
void SessionAuthzAuthenticator::GenerateHostToken(
base::OnceClosure resume_callback) {
session_authz_state_ = SessionAuthzState::GENERATING_HOST_TOKEN;

@ -16,6 +16,7 @@
#include "remoting/proto/session_authz_service.h"
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/credentials_type.h"
#include "remoting/protocol/session_authz_reauthorizer.h"
#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
@ -33,6 +34,7 @@ class SessionAuthzAuthenticator : public Authenticator {
remoting::kChromotingXmlNamespace, "session-token"};
SessionAuthzAuthenticator(
CredentialsType credentials_type,
std::unique_ptr<SessionAuthzServiceClient> service_client,
const CreateBaseAuthenticatorCallback&
create_base_authenticator_callback);
@ -46,7 +48,13 @@ class SessionAuthzAuthenticator : public Authenticator {
// state until |resume_callback| is called.
void Start(base::OnceClosure resume_callback);
const SessionAuthzReauthorizer* reauthorizer() const {
return reauthorizer_.get();
}
// Authenticator implementation.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;
@ -57,6 +65,9 @@ class SessionAuthzAuthenticator : public Authenticator {
std::unique_ptr<ChannelAuthenticator> CreateChannelAuthenticator()
const override;
void SetReauthorizerForTesting(
std::unique_ptr<SessionAuthzReauthorizer> reauthorizer);
private:
enum class SessionAuthzState {
NOT_STARTED,
@ -106,6 +117,7 @@ class SessionAuthzAuthenticator : public Authenticator {
void StartReauthorizerIfNecessary();
void OnReauthorizationFailed();
CredentialsType credentials_type_;
std::unique_ptr<SessionAuthzServiceClient> service_client_;
CreateBaseAuthenticatorCallback create_base_authenticator_callback_;
std::unique_ptr<Authenticator> underlying_;

@ -26,6 +26,7 @@
#include "remoting/protocol/authenticator.h"
#include "remoting/protocol/authenticator_test_base.h"
#include "remoting/protocol/connection_tester.h"
#include "remoting/protocol/credentials_type.h"
#include "remoting/protocol/spake2_authenticator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -74,6 +75,8 @@ class FakeClientAuthenticator : public Authenticator {
~FakeClientAuthenticator() override;
// Authenticator implementation.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;
@ -110,6 +113,15 @@ class FakeClientAuthenticator : public Authenticator {
bool underlying_authenticator_message_suppressed_ = false;
};
CredentialsType FakeClientAuthenticator::credentials_type() const {
return CredentialsType::CORP_SESSION_AUTHZ;
}
const Authenticator& FakeClientAuthenticator::implementing_authenticator()
const {
return *this;
}
Authenticator::State FakeClientAuthenticator::state() const {
switch (session_authz_state_) {
case SessionAuthzState::READY_TO_SEND_SESSION_TOKEN:
@ -225,7 +237,7 @@ void SessionAuthzAuthenticatorTest::SetUp() {
auto mock_service_client = std::make_unique<MockSessionAuthzServiceClient>();
mock_service_client_ = mock_service_client.get();
auto host_authenticator = std::make_unique<SessionAuthzAuthenticator>(
std::move(mock_service_client),
CredentialsType::CORP_SESSION_AUTHZ, std::move(mock_service_client),
base::BindRepeating(&Spake2Authenticator::CreateForHost, kHostId,
kClientId, host_cert_, key_pair_));
host_authenticator_ = host_authenticator.get();

@ -43,6 +43,10 @@ class SessionAuthzReauthorizer {
const net::BackoffEntry* GetBackoffEntryForTest() const;
const std::string& session_reauth_token() const {
return session_reauth_token_;
}
private:
void ScheduleNextReauth();
void Reauthorize();

@ -57,6 +57,7 @@
#include "base/functional/callback.h"
#include "remoting/protocol/session.h"
#include "remoting/protocol/session_observer.h"
namespace remoting {
@ -126,6 +127,11 @@ class SessionManager {
// factory before all authenticators it created are deleted.
virtual void set_authenticator_factory(
std::unique_ptr<AuthenticatorFactory> authenticator_factory) = 0;
// Adds a session observer. Discarding the returned subscription will result
// in the removal of the observer.
[[nodiscard]] virtual SessionObserver::Subscription AddSessionObserver(
SessionObserver* observer) = 0;
};
} // namespace protocol

@ -0,0 +1,40 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_PROTOCOL_SESSION_OBSERVER_H_
#define REMOTING_PROTOCOL_SESSION_OBSERVER_H_
#include "base/functional/callback_helpers.h"
#include "base/observer_list_types.h"
#include "remoting/protocol/session.h"
namespace remoting::protocol {
// An interface for observing session state changes. It is similar to
// Session::EventHandler. The differences are:
//
// 1. The observer is registered on SessionManager, rather than the Session.
// 2. Implementations will observe state changes from multiple sessions. The
// |session| parameter will tell you which session's state has changed.
// 3. Unlike Session::EventHandler, the SessionObserver is not supposed to
// modify the Session. It is only supposed to observe the changes.
//
// An example of the observer is a logger that needs to know the error code and
// the authentication type when the session state has changed.
class SessionObserver : public base::CheckedObserver {
public:
using Subscription = base::ScopedClosureRunner;
// Called after session state has changed. The observer must not destroy the
// session from within the method.
virtual void OnSessionStateChange(const Session& session,
Session::State state) = 0;
protected:
SessionObserver() = default;
};
} // namespace remoting::protocol
#endif // REMOTING_PROTOCOL_SESSION_OBSERVER_H_

@ -135,6 +135,14 @@ Spake2Authenticator::~Spake2Authenticator() {
SPAKE2_CTX_free(spake2_context_);
}
CredentialsType Spake2Authenticator::credentials_type() const {
return CredentialsType::SHARED_SECRET;
}
const Authenticator& Spake2Authenticator::implementing_authenticator() const {
return *this;
}
Authenticator::State Spake2Authenticator::state() const {
if (state_ == ACCEPTED && !outgoing_verification_hash_.empty()) {
return MESSAGE_READY;

@ -46,6 +46,8 @@ class Spake2Authenticator : public Authenticator {
~Spake2Authenticator() override;
// Authenticator interface.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;

@ -31,6 +31,15 @@ ThirdPartyAuthenticatorBase::ThirdPartyAuthenticatorBase(
ThirdPartyAuthenticatorBase::~ThirdPartyAuthenticatorBase() = default;
CredentialsType ThirdPartyAuthenticatorBase::credentials_type() const {
return CredentialsType::THIRD_PARTY;
}
const Authenticator& ThirdPartyAuthenticatorBase::implementing_authenticator()
const {
return *this;
}
bool ThirdPartyAuthenticatorBase::started() const {
return started_;
}

@ -38,6 +38,8 @@ class ThirdPartyAuthenticatorBase : public Authenticator {
~ThirdPartyAuthenticatorBase() override;
// Authenticator interface.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;

@ -34,6 +34,15 @@ ValidatingAuthenticator::ValidatingAuthenticator(
ValidatingAuthenticator::~ValidatingAuthenticator() = default;
CredentialsType ValidatingAuthenticator::credentials_type() const {
return current_authenticator_->credentials_type();
}
const Authenticator& ValidatingAuthenticator::implementing_authenticator()
const {
return current_authenticator_->implementing_authenticator();
}
Authenticator::State ValidatingAuthenticator::state() const {
return pending_auth_message_ ? MESSAGE_READY : state_;
}

@ -45,6 +45,8 @@ class ValidatingAuthenticator : public Authenticator {
~ValidatingAuthenticator() override;
// Authenticator interface.
CredentialsType credentials_type() const override;
const Authenticator& implementing_authenticator() const override;
State state() const override;
bool started() const override;
RejectionReason rejection_reason() const override;