Commit 6815cff2 authored by Lambros Lambrou's avatar Lambros Lambrou Committed by Commit Bot

Class to exchange OAuth refresh token from host config.

This class accepts a refresh token read from the host config. It
returns either a new refresh token with updated scopes, or a status code
to indicate no upgrade is needed.

Bug: 954427
Change-Id: I806abe0b1ebe2a979640cde07b3eb15a14cbe3e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1627693
Commit-Queue: Joe Downing <joedow@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662856}
parent 8702a01f
......@@ -99,6 +99,8 @@ source_set("authorization") {
"oauth_token_getter_impl.h",
"oauth_token_getter_proxy.cc",
"oauth_token_getter_proxy.h",
"offline_token_exchanger.cc",
"offline_token_exchanger.h",
]
configs += [
......
// 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/base/offline_token_exchanger.h"
#include <utility>
#include "base/logging.h"
#include "google_apis/google_api_keys.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace remoting {
namespace {
// Maximum number of retries on network/500 errors.
const int kMaxRetries = 3;
} // namespace
OfflineTokenExchanger::OfflineTokenExchanger(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: gaia_oauth_client_(
std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory)),
token_exchanger_(url_loader_factory) {
token_exchanger_.set_offline_mode(true);
}
OfflineTokenExchanger::~OfflineTokenExchanger() = default;
void OfflineTokenExchanger::ExchangeRefreshToken(
const std::string& refresh_token,
TokenCallback callback) {
DCHECK(callback_.is_null());
callback_ = std::move(callback);
// Get access token from refresh token, needed by OAuthTokenExchanger.
gaia::OAuthClientInfo client_info = {
google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
// Redirect URL is only used when getting tokens from auth code. It
// is not required when getting access tokens from refresh tokens.
""};
std::vector<std::string> empty_scope_list; // Use scope from refresh token.
gaia_oauth_client_->RefreshToken(client_info, refresh_token, empty_scope_list,
kMaxRetries, this);
}
void OfflineTokenExchanger::OnRefreshTokenResponse(
const std::string& access_token,
int expires_in_seconds) {
access_token_ = access_token;
token_exchanger_.ExchangeToken(
access_token,
base::BindOnce(&OfflineTokenExchanger::OnExchangeTokenResponse,
base::Unretained(this)));
}
void OfflineTokenExchanger::OnOAuthError() {
LOG(ERROR) << "OAuth error.";
std::move(callback_).Run(FAILURE, std::string());
}
void OfflineTokenExchanger::OnNetworkError(int response_code) {
LOG(ERROR) << "Network error: " << response_code;
std::move(callback_).Run(FAILURE, std::string());
}
void OfflineTokenExchanger::OnExchangeTokenResponse(
OAuthTokenGetter::Status status,
const std::string& refresh_token,
const std::string& access_token) {
if (status == OAuthTokenGetter::SUCCESS) {
if (access_token_ == access_token) {
std::move(callback_).Run(NO_EXCHANGE, std::string());
} else {
std::move(callback_).Run(SUCCESS, refresh_token);
}
} else {
LOG(ERROR) << "Error exchanging token.";
std::move(callback_).Run(FAILURE, std::string());
}
}
} // 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_BASE_OFFLINE_TOKEN_EXCHANGER_H_
#define REMOTING_BASE_OFFLINE_TOKEN_EXCHANGER_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "google_apis/gaia/gaia_oauth_client.h"
#include "remoting/base/oauth_token_exchanger.h"
namespace remoting {
// This class exchanges an OAuth refresh token (read from the host
// config) for a new refresh token with required scopes. This can be
// used to upgrade and write a new host config if needed. This is a
// simple wrapper around OAuthTokenExchanger - it uses the input refresh
// token to get an access token, then passes it to OAuthTokenExchanger (with
// offline mode) to maybe get a new refresh/access token pair.
class OfflineTokenExchanger : public gaia::GaiaOAuthClient::Delegate {
public:
enum Status {
// New refresh token provided.
SUCCESS,
// No token exchange needed.
NO_EXCHANGE,
// Failed to test the token's scopes, or to get a new token.
FAILURE,
};
typedef base::OnceCallback<void(Status status,
const std::string& refresh_token)>
TokenCallback;
explicit OfflineTokenExchanger(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
~OfflineTokenExchanger() override;
// |refresh_token| is the OAuth token from the host config.
// |callback| will be notified with the new refresh token if exchange took
// place, or NO_EXCHANGE if current token is good, or FAILURE.
void ExchangeRefreshToken(const std::string& refresh_token,
TokenCallback callback);
private:
// gaia::GaiaOAuthClient::Delegate interface.
void OnRefreshTokenResponse(const std::string& access_token,
int expires_in_seconds) override;
void OnOAuthError() override;
void OnNetworkError(int response_code) override;
void OnExchangeTokenResponse(OAuthTokenGetter::Status status,
const std::string& refresh_token,
const std::string& access_token);
std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
OAuthTokenExchanger token_exchanger_;
TokenCallback callback_;
// Store the access token, in order to determine whether token-exchange
// actually occurred.
std::string access_token_;
DISALLOW_COPY_AND_ASSIGN(OfflineTokenExchanger);
};
} // namespace remoting
#endif // REMOTING_BASE_OFFLINE_TOKEN_EXCHANGER_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