0

Authenticate runtime with CastCoreService.

This change integrates the runtime authentication flow with
Cast Web Runtime that would allow using TCP/IP sockets on
devices.

Bug: b:389181125
Change-Id: I86877b3d0a1b0a1b7716b7663beb7451b5d379b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6219899
Commit-Queue: Vigen Issahhanjan <vigeni@google.com>
Reviewed-by: Simeon Anfinrud <sanfin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1418294}
This commit is contained in:
Vigen Issahhanjan
2025-02-10 12:20:40 -08:00
committed by Chromium LUCI CQ
parent 48b2ab99b1
commit ee43a5ecbf
8 changed files with 127 additions and 29 deletions

2
DEPS

@ -1881,7 +1881,7 @@ deps = {
Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '0dfd77492fdb0dcd06027c5842095e2e908adc90',
'src/third_party/cast_core/public/src':
Var('chromium_git') + '/cast_core/public' + '@' + 'fbc5e98031e1271a0a566fcd4d9092b2d3275d05',
Var('chromium_git') + '/cast_core/public' + '@' + 'dcb3d2e87cebe20b6dda06d8b29abb9af27ca422',
'src/third_party/catapult':
Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'),

@ -39,10 +39,10 @@ void CastBrowserTest::SetUp() {
void CastBrowserTest::SetUpCommandLine(base::CommandLine* command_line) {
command_line->AppendSwitchASCII(switches::kTestType, "browser");
command_line->AppendSwitchASCII(
cast::core::kCastCoreRuntimeIdSwitch,
cast::core::switches::kCastCoreRuntimeId,
base::Uuid::GenerateRandomV4().AsLowercaseString());
command_line->AppendSwitchASCII(
cast::core::kRuntimeServicePathSwitch,
cast::core::switches::kRuntimeServicePath,
"unix:/tmp/runtime-service.sock." +
base::Uuid::GenerateRandomV4().AsLowercaseString());
}

@ -5,17 +5,25 @@
#ifndef CHROMECAST_CAST_CORE_CAST_CORE_SWITCHES_H_
#define CHROMECAST_CAST_CORE_CAST_CORE_SWITCHES_H_
namespace cast {
namespace core {
namespace cast::core::switches {
// Specifies the Cast Core runtime ID, --cast-core-runtime-id=<runtime_id>.
constexpr char kCastCoreRuntimeIdSwitch[] = "cast-core-runtime-id";
inline constexpr char kCastCoreRuntimeId[] = "cast-core-runtime-id";
// Specifies the Cast Core runtime gRPC endpoint,
// --runtime-service-path=<endpoint>.
constexpr char kRuntimeServicePathSwitch[] = "runtime-service-path";
inline constexpr char kRuntimeServicePath[] = "runtime-service-path";
} // namespace core
} // namespace cast
// Specifies the Cast Core service gRPC endpoint.
inline constexpr char kCastCoreServiceEndpoint[] = "cast-core-service-endpoint";
// Specifies that TCP/IP should be used as the gRPC transport typeby Cast Core;
// otherwise UDS is used.
inline constexpr char kEnableGrpcOverTcpIp[] = "enable-grpc-over-tcpip";
// Authentication token securely sent to the runtime.
inline constexpr char kRuntimeAuthToken[] = "runtime-auth-token";
} // namespace cast::core::switches
#endif // CHROMECAST_CAST_CORE_CAST_CORE_SWITCHES_H_

@ -214,8 +214,12 @@ void RuntimeApplicationServiceImpl::Load(
return;
}
LOG(INFO) << "Runtime application server started: endpoint="
<< request.runtime_application_service_info().grpc_endpoint();
LOG(INFO) << "Runtime application service started: app_id="
<< request.application_config().app_id()
#if DCHECK_IS_ON()
<< ", endpoint=" << grpc_server_->endpoint()
#endif // DCHECK_IS_ON()
;
// TODO(vigeni): Consider extacting this into RuntimeApplicationBase as a
// mojo.

@ -60,7 +60,14 @@ class RuntimeApplicationServiceImpl : public cast_receiver::EmbedderApplication,
void Stop(const cast::runtime::StopApplicationRequest& request,
StatusCallback callback);
const std::string& app_id() { return runtime_application_->GetAppId(); }
// Returns current application ID.
const std::string& app_id() const { return runtime_application_->GetAppId(); }
// Returns RuntimeApplicationService gRPC server endpoint.
const std::string& endpoint() const {
CHECK(grpc_server_);
return grpc_server_->endpoint();
}
// EmbedderApplication implementation:
void NotifyApplicationStarted() override;

@ -6,6 +6,7 @@
#include "base/check.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/task/bind_post_task.h"
@ -53,30 +54,45 @@ RuntimeServiceImpl::~RuntimeServiceImpl() {
cast_receiver::Status RuntimeServiceImpl::Start() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto* command_line = base::CommandLine::ForCurrentProcess();
std::string runtime_id =
command_line->GetSwitchValueASCII(cast::core::kCastCoreRuntimeIdSwitch);
std::string runtime_id = command_line->GetSwitchValueASCII(
cast::core::switches::kCastCoreRuntimeId);
if (runtime_id.empty()) {
// This may happen during unfreeze of the browser process. Usually the cast
// service process is dead, too, but a certain condition how this happens on
// Android is not known. Most probable cause is OS reboot/update etc.
LOG(ERROR) << "Runtime id must be specified in command line with: --"
<< cast::core::kCastCoreRuntimeIdSwitch;
<< cast::core::switches::kCastCoreRuntimeId;
return cast_receiver::Status(
cast_receiver::StatusCode::kFailedPrecondition);
}
std::string runtime_service_path =
command_line->GetSwitchValueASCII(cast::core::kRuntimeServicePathSwitch);
std::string runtime_service_path = command_line->GetSwitchValueASCII(
cast::core::switches::kRuntimeServicePath);
if (runtime_service_path.empty()) {
// This may happen during unfreeze of the browser process with cast service
// process dead.
LOG(ERROR)
<< "Runtime service endpoint must be specified in command line with: --"
<< cast::core::kRuntimeServicePathSwitch;
<< cast::core::switches::kRuntimeServicePath;
return cast_receiver::Status(
cast_receiver::StatusCode::kFailedPrecondition);
}
return Start(runtime_id, runtime_service_path);
auto status = Start(runtime_id, runtime_service_path);
if (!status.ok()) {
return status;
}
bool enable_grpc_over_tcpip =
command_line->HasSwitch(cast::core::switches::kEnableGrpcOverTcpIp);
std::string cast_core_service_endpoint = command_line->GetSwitchValueASCII(
cast::core::switches::kCastCoreServiceEndpoint);
std::string authentication_token = command_line->GetSwitchValueASCII(
cast::core::switches::kRuntimeAuthToken);
MaybeAuthenticateRuntime(enable_grpc_over_tcpip, runtime_id,
cast_core_service_endpoint, authentication_token);
return status;
}
cast_receiver::Status RuntimeServiceImpl::Start(
@ -86,9 +102,6 @@ cast_receiver::Status RuntimeServiceImpl::Start(
CHECK(!runtime_id.empty());
CHECK(!runtime_service_endpoint.empty());
LOG(INFO) << "Starting runtime service: runtime_id=" << runtime_id
<< ", endpoint=" << runtime_service_endpoint;
grpc_server_.emplace();
grpc_server_
->SetHandler<cast::runtime::RuntimeServiceHandler::LoadApplication>(
@ -126,15 +139,21 @@ cast_receiver::Status RuntimeServiceImpl::Start(
weak_factory_.GetWeakPtr())));
auto status = grpc_server_->Start(std::string(runtime_service_endpoint));
// Browser runtime must crash if the runtime service failed to start to avoid
// the process to dangle without any proper connection to the Cast Core.
// Browser runtime must crash if the runtime service failed to start to
// avoid the process to dangle without any proper connection to the Cast
// Core.
if (!status.ok()) {
LOG(ERROR) << "Failed to start runtime service: status="
<< status.error_message();
return cast_receiver::Status(cast_receiver::StatusCode::kInvalidArgument);
}
LOG(INFO) << "Runtime service started";
LOG(INFO) << "Runtime service started: runtime_id=" << runtime_id
#if DCHECK_IS_ON()
<< ", endpoint=" << grpc_server_->endpoint()
#endif // DCHECK_IS_ON()
;
return cast_receiver::OkStatus();
}
@ -143,8 +162,8 @@ void RuntimeServiceImpl::ResetGrpcServices() {
if (heartbeat_reactor_) {
heartbeat_timer_.Stop();
// Reset the writes callback as we're not expecting any more responses from
// gRPC framework.
// Reset the writes callback as we're not expecting any more responses
// from gRPC framework.
heartbeat_reactor_->SetWritesAvailableCallback(base::DoNothing());
heartbeat_reactor_->Write(grpc::Status::OK);
heartbeat_reactor_ = nullptr;
@ -358,7 +377,8 @@ void RuntimeServiceImpl::HandleStartMetricsRecorder(
return;
}
LOG(INFO) << "Started recording metrics";
DLOG(INFO) << "Started recording metrics: endpoint="
<< request.metrics_recorder_service_info().grpc_endpoint();
metrics_recorder_stub_.emplace(
request.metrics_recorder_service_info().grpc_endpoint());
reactor->Write(cast::runtime::StartMetricsRecorderResponse());
@ -414,6 +434,12 @@ void RuntimeServiceImpl::OnApplicationLoaded(
cast::runtime::LoadApplicationResponse response;
response.mutable_message_port_info();
response.mutable_runtime_application_service_info()->set_grpc_endpoint(
platform_app->endpoint());
DLOG(INFO) << "Runtime application service loaded: endpoint="
<< platform_app->endpoint();
reactor->Write(std::move(response));
}
@ -502,6 +528,50 @@ void RuntimeServiceImpl::OnHeartbeatSent(
weak_factory_.GetWeakPtr())));
}
void RuntimeServiceImpl::MaybeAuthenticateRuntime(
bool enable_grpc_over_tcpip,
const std::string& runtime_id,
const std::string& cast_core_service_endpoint,
const std::string& authentication_token) {
if (!enable_grpc_over_tcpip) {
LOG(INFO) << "Skipping runtime authentication as not requested";
return;
}
CHECK(!cast_core_service_endpoint.empty())
<< "Cast Core service endpoint must be specified for authentication";
CHECK(!authentication_token.empty())
<< "Auth token must be present for TCP/IP endpoints";
cast_core_service_stub_.emplace(cast_core_service_endpoint);
auto call =
cast_core_service_stub_
->CreateCall<cast::core::CastCoreServiceStub::AuthenticateRuntime>();
call.request().set_runtime_id(runtime_id);
call.request().set_authentication_token(authentication_token);
call.request().mutable_runtime_service_info()->set_grpc_endpoint(
grpc_server_->endpoint());
call.request().set_challenge("my challenge");
std::move(call).InvokeAsync(base::BindPostTask(
task_runner_, base::BindOnce(&RuntimeServiceImpl::OnRuntimeAuthenticated,
weak_factory_.GetWeakPtr())));
}
void RuntimeServiceImpl::OnRuntimeAuthenticated(
cast::utils::GrpcStatusOr<cast::core::AuthenticateRuntimeResponse>
response_or) {
if (!response_or.ok()) {
LOG(ERROR) << "Failed to authenticate runtime";
return;
}
LOG(INFO) << "Runtime is authenticated: sig="
<< response_or->challenge_signature()
<< ", chain=" << response_or->certificate_chain_size();
// TODO(vigeni): Add signature verification.
}
void RuntimeServiceImpl::RecordMetrics(
cast::metrics::RecordRequest request,
CastRuntimeMetricsRecorderService::RecordCompleteCallback

@ -20,6 +20,7 @@
#include "chromecast/cast_core/runtime/browser/runtime_application_service_impl.h"
#include "components/cast_receiver/browser/public/runtime_application_dispatcher.h"
#include "components/cast_receiver/common/public/status.h"
#include "third_party/cast_core/public/src/proto/core/cast_core_service.castcore.pb.h"
#include "third_party/cast_core/public/src/proto/metrics/metrics_recorder.castcore.pb.h"
#include "third_party/cast_core/public/src/proto/runtime/runtime_service.castcore.pb.h"
@ -101,6 +102,13 @@ class RuntimeServiceImpl final
void OnMetricsRecorderServiceStopped(
cast::runtime::RuntimeServiceHandler::StopMetricsRecorder::Reactor*
reactor);
void MaybeAuthenticateRuntime(bool enable_grpc_over_tcpip,
const std::string& runtime_id,
const std::string& cast_core_service_endpoint,
const std::string& runtime_auth_token);
void OnRuntimeAuthenticated(
cast::utils::GrpcStatusOr<cast::core::AuthenticateRuntimeResponse>
response_or);
void ResetGrpcServices();
@ -120,6 +128,7 @@ class RuntimeServiceImpl final
CastRuntimeMetricsRecorder metrics_recorder_;
std::optional<cast::utils::GrpcServer> grpc_server_;
std::optional<cast::core::CastCoreServiceStub> cast_core_service_stub_;
std::optional<cast::metrics::MetricsRecorderServiceStub>
metrics_recorder_stub_;
std::optional<CastRuntimeMetricsRecorderService> metrics_recorder_service_;