Skip to content

Commit

Permalink
refactor: split IAMCredentials GenerateAccessToken()
Browse files Browse the repository at this point in the history
We will need to parse the `GenerateAccessToken()` response in the
external account implementation. This splits the parsing to a standalone
function.
  • Loading branch information
coryan committed Dec 6, 2022
1 parent d0baafb commit 3156bc9
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 150 deletions.
56 changes: 40 additions & 16 deletions google/cloud/internal/oauth2_minimal_iam_credentials_rest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "google/cloud/internal/absl_str_join_quiet.h"
#include "google/cloud/internal/api_client_header.h"
#include "google/cloud/internal/format_time_point.h"
#include "google/cloud/internal/json_parsing.h"
#include "google/cloud/internal/make_status.h"
#include "google/cloud/internal/oauth2_credentials.h"
#include "google/cloud/internal/parse_rfc3339.h"
#include "google/cloud/internal/rest_client.h"
Expand All @@ -31,9 +33,12 @@ namespace cloud {
namespace oauth2_internal {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace {

using ::google::cloud::internal::InvalidArgumentError;

auto constexpr kIamCredentialsEndpoint =
"https://iamcredentials.googleapis.com/v1/";
}
} // namespace

MinimalIamCredentialsRestStub::MinimalIamCredentialsRestStub(
std::shared_ptr<oauth2_internal::Credentials> credentials, Options options,
Expand Down Expand Up @@ -65,21 +70,12 @@ MinimalIamCredentialsRestStub::GenerateAccessToken(

auto response = rest_client_->Post(rest_request, {payload.dump()});
if (!response) return std::move(response).status();
if (IsHttpError(**response)) return AsStatus(std::move(**response));
auto response_payload =
rest_internal::ReadAll(std::move(**response).ExtractPayload());
if (!response_payload.ok()) return response_payload.status();
auto parsed = nlohmann::json::parse(*response_payload, nullptr);
if (parsed.is_null() || parsed.count("accessToken") == 0 ||
parsed.count("expireTime") == 0) {
return Status(StatusCode::kUnknown,
"invalid response from service <" + parsed.dump() + ">");
}
auto expire_time = google::cloud::internal::ParseRfc3339(
parsed["expireTime"].get<std::string>());
if (!expire_time) return std::move(expire_time).status();
return google::cloud::internal::AccessToken{
parsed["accessToken"].get<std::string>(), *expire_time};
return ParseGenerateAccessTokenResponse(
**response,
internal::ErrorContext(
{{"gcloud-cpp.root.class", "MinimalIamCredentialsRestStub"},
{"gcloud-cpp.root.function", __func__},
{"serviceAccount", request.service_account}}));
}

std::string MinimalIamCredentialsRestStub::MakeRequestPath(
Expand Down Expand Up @@ -113,6 +109,34 @@ MinimalIamCredentialsRestLogging::GenerateAccessToken(
return response;
}

StatusOr<internal::AccessToken> ParseGenerateAccessTokenResponse(
rest_internal::RestResponse& response,
google::cloud::internal::ErrorContext const& ec) {
if (IsHttpError(response)) return AsStatus(std::move(response));
auto response_payload =
rest_internal::ReadAll(std::move(response).ExtractPayload());
if (!response_payload.ok()) return response_payload.status();
auto parsed = nlohmann::json::parse(*response_payload, nullptr, false);
if (!parsed.is_object()) {
return InvalidArgumentError("cannot parse response as a JSON object",
GCP_ERROR_INFO().WithContext(ec));
}
auto token = ValidateStringField(parsed, "accessToken",
"GenerateAccessToken() response", ec);
if (!token) return std::move(token).status();
auto expire_time_field = ValidateStringField(
parsed, "expireTime", "GenerateAccessToken() response", ec);
if (!expire_time_field) return std::move(expire_time_field).status();
auto expire_time = google::cloud::internal::ParseRfc3339(*expire_time_field);
if (!expire_time) {
return InvalidArgumentError(
"invalid format for `expireTime` field in `GenerateAccessToken() "
"response`",
GCP_ERROR_INFO().WithContext(ec));
}
return google::cloud::internal::AccessToken{*std::move(token), *expire_time};
}

std::shared_ptr<MinimalIamCredentialsRest> MakeMinimalIamCredentialsRestStub(
std::shared_ptr<oauth2_internal::Credentials> credentials,
Options options) {
Expand Down
6 changes: 6 additions & 0 deletions google/cloud/internal/oauth2_minimal_iam_credentials_rest.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "google/cloud//version.h"
#include "google/cloud/internal/credentials_impl.h"
#include "google/cloud/internal/error_context.h"
#include "google/cloud/internal/oauth2_credentials.h"
#include "google/cloud/internal/rest_client.h"
#include "google/cloud/options.h"
Expand All @@ -37,6 +38,11 @@ struct GenerateAccessTokenRequest {
std::vector<std::string> delegates;
};

/// Parse the HTTP response from a `GenerateAccessToken()` call.
StatusOr<google::cloud::internal::AccessToken> ParseGenerateAccessTokenResponse(
rest_internal::RestResponse& response,
google::cloud::internal::ErrorContext const& ec);

/**
* Wrapper for IAM Credentials intended for use with
* `ImpersonateServiceAccountCredentials`.
Expand Down
Loading

0 comments on commit 3156bc9

Please sign in to comment.