Commit bdc4a979 authored by Yuwei Huang's avatar Yuwei Huang Committed by Commit Bot

[Remoting] Integrate with OAuthTokenGetter for FtlClient

This CL makes FtlClient use OAuthTokenGetter to retrieve access token
and attach it to the gRPC request. It also has some other changes in the
FTL playground:
* Move FtlSignalingPlayground into a separate class to make it cleaner.
* Make FtlSignalingPlayground prompt and read access code from the user
  and use it to start up an OAuthTokenGetter.

Bug: 927962
Change-Id: I43d2f19b53b41e2fa3652e6c6e4c09eb54ae889e
Reviewed-on: https://chromium-review.googlesource.com/c/1496317Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Commit-Queue: Joe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636861}
parent 0daaef05
...@@ -23,7 +23,9 @@ constexpr char kFtlServerEndpoint[] = "instantmessaging-pa.googleapis.com"; ...@@ -23,7 +23,9 @@ constexpr char kFtlServerEndpoint[] = "instantmessaging-pa.googleapis.com";
namespace remoting { namespace remoting {
FtlClient::FtlClient() { FtlClient::FtlClient(OAuthTokenGetter* token_getter) : weak_factory_(this) {
DCHECK(token_getter);
token_getter_ = token_getter;
auto channel_creds = grpc::SslCredentials(grpc::SslCredentialsOptions()); auto channel_creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
auto channel = grpc::CreateChannel(kFtlServerEndpoint, channel_creds); auto channel = grpc::CreateChannel(kFtlServerEndpoint, channel_creds);
peer_to_peer_stub_ = PeerToPeer::NewStub(channel); peer_to_peer_stub_ = PeerToPeer::NewStub(channel);
...@@ -35,10 +37,42 @@ void FtlClient::GetIceServer(RpcCallback<ftl::GetICEServerResponse> callback) { ...@@ -35,10 +37,42 @@ void FtlClient::GetIceServer(RpcCallback<ftl::GetICEServerResponse> callback) {
ftl::GetICEServerRequest request; ftl::GetICEServerRequest request;
request.set_allocated_header(BuildRequestHeader().release()); request.set_allocated_header(BuildRequestHeader().release());
dispatcher_.ExecuteAsyncRpc( GetOAuthTokenAndExecuteRpc(
base::BindOnce(&PeerToPeer::Stub::AsyncGetICEServer, base::BindOnce(&PeerToPeer::Stub::AsyncGetICEServer,
base::Unretained(peer_to_peer_stub_.get())), base::Unretained(peer_to_peer_stub_.get())),
CreateClientContext(), request, std::move(callback)); request, std::move(callback));
}
template <typename RequestType, typename ResponseType>
void FtlClient::GetOAuthTokenAndExecuteRpc(
GrpcAsyncDispatcher::AsyncRpcFunction<RequestType, ResponseType> rpc,
const RequestType& request,
RpcCallback<ResponseType> callback) {
token_getter_->CallWithToken(base::BindOnce(
&FtlClient::ExecuteRpcWithFetchedOAuthToken<RequestType, ResponseType>,
weak_factory_.GetWeakPtr(), std::move(rpc), request,
std::move(callback)));
}
template <typename RequestType, typename ResponseType>
void FtlClient::ExecuteRpcWithFetchedOAuthToken(
GrpcAsyncDispatcher::AsyncRpcFunction<RequestType, ResponseType> rpc,
const RequestType& request,
RpcCallback<ResponseType> callback,
OAuthTokenGetter::Status status,
const std::string& user_email,
const std::string& access_token) {
std::unique_ptr<grpc::ClientContext> context = CreateClientContext();
if (status != OAuthTokenGetter::Status::SUCCESS) {
LOG(ERROR) << "Failed to fetch access token. Status: " << status;
}
if (status == OAuthTokenGetter::Status::SUCCESS && !access_token.empty()) {
context->set_credentials(grpc::AccessTokenCredentials(access_token));
} else {
LOG(WARNING) << "Attempting to execute RPC without access token.";
}
dispatcher_.ExecuteAsyncRpc(std::move(rpc), std::move(context), request,
std::move(callback));
} }
// static // static
......
...@@ -6,8 +6,11 @@ ...@@ -6,8 +6,11 @@
#define REMOTING_SIGNALING_FTL_CLIENT_H_ #define REMOTING_SIGNALING_FTL_CLIENT_H_
#include <memory> #include <memory>
#include <string>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "remoting/base/oauth_token_getter.h"
#include "remoting/signaling/ftl_services.grpc.pb.h" #include "remoting/signaling/ftl_services.grpc.pb.h"
#include "remoting/signaling/grpc_async_dispatcher.h" #include "remoting/signaling/grpc_async_dispatcher.h"
#include "third_party/grpc/src/include/grpcpp/support/status.h" #include "third_party/grpc/src/include/grpcpp/support/status.h"
...@@ -21,7 +24,7 @@ class FtlClient { ...@@ -21,7 +24,7 @@ class FtlClient {
using RpcCallback = using RpcCallback =
base::OnceCallback<void(grpc::Status, const ResponseType&)>; base::OnceCallback<void(grpc::Status, const ResponseType&)>;
FtlClient(); explicit FtlClient(OAuthTokenGetter* token_getter);
~FtlClient(); ~FtlClient();
// Retrieves the ice server configs. // Retrieves the ice server configs.
...@@ -31,12 +34,29 @@ class FtlClient { ...@@ -31,12 +34,29 @@ class FtlClient {
using PeerToPeer = using PeerToPeer =
google::internal::communications::instantmessaging::v1::PeerToPeer; google::internal::communications::instantmessaging::v1::PeerToPeer;
template <typename RequestType, typename ResponseType>
void GetOAuthTokenAndExecuteRpc(
GrpcAsyncDispatcher::AsyncRpcFunction<RequestType, ResponseType> rpc,
const RequestType& request,
RpcCallback<ResponseType> callback);
template <typename RequestType, typename ResponseType>
void ExecuteRpcWithFetchedOAuthToken(
GrpcAsyncDispatcher::AsyncRpcFunction<RequestType, ResponseType> rpc,
const RequestType& request,
RpcCallback<ResponseType> callback,
OAuthTokenGetter::Status status,
const std::string& user_email,
const std::string& access_token);
static std::unique_ptr<grpc::ClientContext> CreateClientContext(); static std::unique_ptr<grpc::ClientContext> CreateClientContext();
static std::unique_ptr<ftl::RequestHeader> BuildRequestHeader(); static std::unique_ptr<ftl::RequestHeader> BuildRequestHeader();
OAuthTokenGetter* token_getter_;
std::unique_ptr<PeerToPeer::Stub> peer_to_peer_stub_; std::unique_ptr<PeerToPeer::Stub> peer_to_peer_stub_;
GrpcAsyncDispatcher dispatcher_; GrpcAsyncDispatcher dispatcher_;
base::WeakPtrFactory<FtlClient> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FtlClient); DISALLOW_COPY_AND_ASSIGN(FtlClient);
}; };
......
...@@ -180,9 +180,19 @@ if (enable_remoting_host && !is_android && !is_chromeos) { ...@@ -180,9 +180,19 @@ if (enable_remoting_host && !is_android && !is_chromeos) {
executable("ftl_signaling_playground") { executable("ftl_signaling_playground") {
sources = [ sources = [
"ftl_signaling_playground.cc", "ftl_signaling_playground.cc",
"ftl_signaling_playground.h",
"ftl_signaling_playground_main.cc",
"test_oauth_token_factory.cc",
"test_oauth_token_factory.h",
] ]
deps = [ deps = [
"//google_apis",
"//mojo/core/embedder",
"//remoting/base",
"//remoting/base:authorization",
"//remoting/signaling", "//remoting/signaling",
"//services/network:network_service",
"//services/network/public/mojom",
] ]
} }
......
...@@ -2,39 +2,100 @@ ...@@ -2,39 +2,100 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/at_exit.h" #include "remoting/test/ftl_signaling_playground.h"
#include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/path_service.h"
#include "base/message_loop/message_loop.h" #include "base/strings/stringprintf.h"
#include "base/run_loop.h" #include "remoting/base/oauth_token_getter_impl.h"
#include "remoting/signaling/ftl_client.h" #include "remoting/signaling/ftl_client.h"
#include "remoting/test/test_oauth_token_factory.h"
namespace remoting { namespace {
class FtlSignalingPlayground { constexpr char kSwitchNameHelp[] = "help";
public: constexpr char kSwitchNameAuthCode[] = "code";
FtlSignalingPlayground();
~FtlSignalingPlayground();
void GetIceServer(base::OnceClosure on_done); // Reads a newline-terminated string from stdin.
std::string ReadString() {
const int kMaxLen = 1024;
std::string str(kMaxLen, 0);
char* result = fgets(&str[0], kMaxLen, stdin);
if (!result)
return std::string();
size_t newline_index = str.find('\n');
if (newline_index != std::string::npos)
str[newline_index] = '\0';
str.resize(strlen(&str[0]));
return str;
}
private: // Read the value of |switch_name| from command line if it exists, otherwise
static void OnGetIceServerResponse(base::OnceClosure on_done, // read from stdin.
grpc::Status status, std::string ReadStringFromCommandLineOrStdin(const std::string& switch_name,
const ftl::GetICEServerResponse& response); const std::string& read_prompt) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switch_name)) {
return command_line->GetSwitchValueASCII(switch_name);
}
printf("%s", read_prompt.c_str());
return ReadString();
}
FtlClient client_; } // namespace
DISALLOW_COPY_AND_ASSIGN(FtlSignalingPlayground);
}; namespace remoting {
FtlSignalingPlayground::FtlSignalingPlayground() = default; FtlSignalingPlayground::FtlSignalingPlayground() = default;
FtlSignalingPlayground::~FtlSignalingPlayground() = default; FtlSignalingPlayground::~FtlSignalingPlayground() = default;
bool FtlSignalingPlayground::ShouldPrintHelp() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchNameHelp);
}
void FtlSignalingPlayground::PrintHelp() {
printf("Usage: %s [--code=<auth-code>]\n",
base::CommandLine::ForCurrentProcess()
->GetProgram()
.MaybeAsASCII()
.c_str());
}
void FtlSignalingPlayground::StartAndAuthenticate() {
DCHECK(!token_getter_factory_);
DCHECK(!token_getter_);
DCHECK(!client_);
static const std::string read_auth_code_prompt = base::StringPrintf(
"Please authenticate at:\n\n"
" %s\n\n"
"Enter the auth code: ",
TestOAuthTokenGetterFactory::GetAuthorizationCodeUri().c_str());
std::string auth_code = ReadStringFromCommandLineOrStdin(
kSwitchNameAuthCode, read_auth_code_prompt);
token_getter_factory_ = std::make_unique<TestOAuthTokenGetterFactory>();
// We can't get back the refresh token since we have first-party scope, so
// we are not trying to store it.
// TODO(yuweih): Consider storing the access token and reuse it until it is
// expired.
token_getter_ = token_getter_factory_->CreateFromIntermediateCredentials(
auth_code,
base::DoNothing::Repeatedly<const std::string&, const std::string&>());
client_ = std::make_unique<FtlClient>(token_getter_.get());
}
void FtlSignalingPlayground::GetIceServer(base::OnceClosure on_done) { void FtlSignalingPlayground::GetIceServer(base::OnceClosure on_done) {
client_.GetIceServer(base::BindOnce( DCHECK(client_);
client_->GetIceServer(base::BindOnce(
&FtlSignalingPlayground::OnGetIceServerResponse, std::move(on_done))); &FtlSignalingPlayground::OnGetIceServerResponse, std::move(on_done)));
VLOG(0) << "Running GetIceServer..."; VLOG(0) << "Running GetIceServer...";
} }
...@@ -72,17 +133,3 @@ void FtlSignalingPlayground::OnGetIceServerResponse( ...@@ -72,17 +133,3 @@ void FtlSignalingPlayground::OnGetIceServerResponse(
} }
} // namespace remoting } // namespace remoting
int main(int argc, char const* argv[]) {
base::AtExitManager exitManager;
base::CommandLine::Init(argc, argv);
base::MessageLoopForIO message_loop;
remoting::FtlSignalingPlayground playground;
base::RunLoop run_loop;
playground.GetIceServer(run_loop.QuitClosure());
run_loop.Run();
return 0;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_TEST_FTL_SIGNALING_PLAYGROUND_H_
#define REMOTING_TEST_FTL_SIGNALING_PLAYGROUND_H_
#include <memory>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "remoting/base/oauth_token_getter.h"
#include "remoting/signaling/ftl_client.h"
namespace remoting {
class TestOAuthTokenGetterFactory;
class FtlSignalingPlayground {
public:
FtlSignalingPlayground();
~FtlSignalingPlayground();
bool ShouldPrintHelp();
void PrintHelp();
void StartAndAuthenticate();
void GetIceServer(base::OnceClosure on_done);
private:
static void OnGetIceServerResponse(base::OnceClosure on_done,
grpc::Status status,
const ftl::GetICEServerResponse& response);
std::unique_ptr<TestOAuthTokenGetterFactory> token_getter_factory_;
std::unique_ptr<OAuthTokenGetter> token_getter_;
std::unique_ptr<FtlClient> client_;
DISALLOW_COPY_AND_ASSIGN(FtlSignalingPlayground);
};
} // namespace remoting
#endif // REMOTING_TEST_FTL_SIGNALING_PLAYGROUND_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/task/task_scheduler/task_scheduler.h"
#include "mojo/core/embedder/embedder.h"
#include "remoting/test/ftl_signaling_playground.h"
int main(int argc, char const* argv[]) {
base::AtExitManager exitManager;
base::CommandLine::Init(argc, argv);
base::MessageLoopForIO message_loop;
remoting::FtlSignalingPlayground playground;
if (playground.ShouldPrintHelp()) {
playground.PrintHelp();
return 0;
}
base::TaskScheduler::CreateAndStartWithDefaultParams(
"FtlSignalingPlayground");
mojo::core::Init();
playground.StartAndAuthenticate();
base::RunLoop run_loop;
playground.GetIceServer(run_loop.QuitClosure());
run_loop.Run();
return 0;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/test/test_oauth_token_factory.h"
#include <utility>
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "google_apis/google_api_keys.h"
#include "net/base/escape.h"
#include "remoting/base/oauth_token_getter_impl.h"
#include "remoting/base/url_request_context_getter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/transitional_url_loader_factory_owner.h"
namespace remoting {
namespace {
constexpr char kChromotingAuthScopeValues[] =
"https://www.googleapis.com/auth/chromoting "
"https://www.googleapis.com/auth/googletalk "
"https://www.googleapis.com/auth/userinfo.email "
"https://www.googleapis.com/auth/tachyon";
constexpr char kOauthRedirectUrl[] =
"https://chromoting-oauth.talkgadget."
"google.com/talkgadget/oauth/chrome-remote-desktop/dev";
} // namespace
TestOAuthTokenGetterFactory::TestOAuthTokenGetterFactory() {
auto url_request_context_getter =
base::MakeRefCounted<URLRequestContextGetter>(
base::ThreadTaskRunnerHandle::Get());
url_loader_factory_owner_ =
std::make_unique<network::TransitionalURLLoaderFactoryOwner>(
url_request_context_getter);
}
TestOAuthTokenGetterFactory::~TestOAuthTokenGetterFactory() = default;
// static
std::string TestOAuthTokenGetterFactory::GetAuthorizationCodeUri() {
// Replace space characters with a '+' sign when formatting.
bool use_plus = true;
return base::StringPrintf(
"https://accounts.google.com/o/oauth2/auth"
"?scope=%s"
"&redirect_uri=https://chromoting-oauth.talkgadget.google.com/"
"talkgadget/oauth/chrome-remote-desktop/dev"
"&response_type=code"
"&client_id=%s"
"&access_type=offline",
net::EscapeUrlEncodedData(kChromotingAuthScopeValues, use_plus).c_str(),
net::EscapeUrlEncodedData(
google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING),
use_plus)
.c_str());
}
std::unique_ptr<OAuthTokenGetter>
TestOAuthTokenGetterFactory::CreateFromIntermediateCredentials(
const std::string& auth_code,
const OAuthTokenGetter::CredentialsUpdatedCallback& on_credentials_update) {
auto oauth_credentials =
std::make_unique<OAuthTokenGetter::OAuthIntermediateCredentials>(
auth_code, /* is_service_account */ false);
oauth_credentials->oauth_redirect_uri = kOauthRedirectUrl;
return std::make_unique<OAuthTokenGetterImpl>(
std::move(oauth_credentials), on_credentials_update,
url_loader_factory_owner_->GetURLLoaderFactory(),
/* auto_refresh */ true);
}
} // namespace remoting
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_TEST_TEST_OAUTH_TOKEN_FACTORY_H_
#define REMOTING_TEST_TEST_OAUTH_TOKEN_FACTORY_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "remoting/base/oauth_token_getter.h"
namespace network {
class TransitionalURLLoaderFactoryOwner;
} // namespace network
namespace remoting {
// The factory object must outlive all OAuthTokenGetters it creates.
class TestOAuthTokenGetterFactory {
public:
TestOAuthTokenGetterFactory();
~TestOAuthTokenGetterFactory();
static std::string GetAuthorizationCodeUri();
std::unique_ptr<OAuthTokenGetter> CreateFromIntermediateCredentials(
const std::string& auth_code,
const OAuthTokenGetter::CredentialsUpdatedCallback&
on_credentials_update);
private:
std::unique_ptr<network::TransitionalURLLoaderFactoryOwner>
url_loader_factory_owner_;
DISALLOW_COPY_AND_ASSIGN(TestOAuthTokenGetterFactory);
};
} // namespace remoting
#endif // REMOTING_TEST_TEST_OAUTH_TOKEN_FACTORY_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment