blob: 20c9dcc1f17be12c7abaed023f3b25e31855cca6 [file] [log] [blame]
// 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/setup/host_starter_oauth_helper.h"
#include <memory>
#include <string>
#include <utility>
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/stringprintf.h"
#include "google_apis/gaia/gaia_oauth_client.h"
#include "remoting/host/setup/host_starter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace remoting {
namespace {
using Result = HostStarter::Result;
constexpr int kMaxGetTokensRetries = 3;
} // namespace
HostStarterOAuthHelper::HostStarterOAuthHelper(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: oauth_client_(
std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory)) {}
HostStarterOAuthHelper::~HostStarterOAuthHelper() = default;
void HostStarterOAuthHelper::FetchTokens(
const std::string& user_email,
const std::string& authorization_code,
gaia::OAuthClientInfo oauth_client_info,
OnDoneCallback done_callback,
OnErrorCallback error_callback) {
// An instance of this class should only be used once.
CHECK(expected_user_email_.empty());
CHECK(!done_callback_);
CHECK(!error_callback_);
expected_user_email_ = user_email;
done_callback_ = std::move(done_callback);
error_callback_ = std::move(error_callback);
oauth_client_->GetTokensFromAuthCode(std::move(oauth_client_info),
authorization_code, kMaxGetTokensRetries,
this);
}
void HostStarterOAuthHelper::OnGetTokensResponse(
const std::string& refresh_token,
const std::string& access_token,
int expires_in_seconds) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Ignore |expires_in_seconds| since the setup process will complete well
// before the tokens expire.
access_token_ = access_token;
refresh_token_ = refresh_token;
// Get the email corresponding to the access token.
oauth_client_->GetUserEmail(access_token, 1, this);
}
void HostStarterOAuthHelper::OnRefreshTokenResponse(
const std::string& access_token,
int expires_in_seconds) {
// We never request a new access token using a refresh token.
NOTREACHED_IN_MIGRATION();
}
void HostStarterOAuthHelper::OnGetUserEmailResponse(
const std::string& user_email) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!expected_user_email_.empty() &&
!base::EqualsCaseInsensitiveASCII(expected_user_email_, user_email)) {
// Verify that the token retrieved matches the expected user email.
std::move(error_callback_)
.Run(base::StringPrintf(
"authorization_code was created for `%s` which does not "
"match the expected account: `%s`",
user_email.c_str(), expected_user_email_.c_str()),
Result::PERMISSION_DENIED);
return;
}
std::move(done_callback_).Run(user_email, access_token_, refresh_token_);
}
void HostStarterOAuthHelper::OnOAuthError() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::move(error_callback_)
.Run("Failed to exchange the authorization_code due to an OAuth error.",
Result::OAUTH_ERROR);
}
void HostStarterOAuthHelper::OnNetworkError(int response_code) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::move(error_callback_)
.Run(base::StringPrintf("Failed to exchange the authorization_code due "
"to a network error: %d.",
response_code),
Result::NETWORK_ERROR);
}
} // namespace remoting