Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ extend-exclude = [
"ci/etc/invalidated-keyfile.json",
"google/cloud/internal/curl_rest_client_integration_test.cc",
"google/cloud/internal/grpc_service_account_authentication_test.cc",
"google/cloud/internal/oauth2_gdch_service_account_credentials_test.cc",
"google/cloud/internal/oauth2_google_credentials_test.cc",
"google/cloud/internal/oauth2_service_account_credentials_test.cc",
"google/cloud/internal/rest_client_integration_test.cc",
Expand Down
6 changes: 6 additions & 0 deletions ci/cloudbuild/dockerfiles/ubuntu-20.04-install.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
# limitations under the License.

FROM ubuntu:20.04
ARG NCPU=4
ARG ARCH=amd64

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
Expand Down Expand Up @@ -199,5 +201,9 @@ RUN curl -fsSL https://github.com/mozilla/sccache/releases/download/v0.10.0/scca
mv sccache /usr/local/bin/sccache && \
chmod +x /usr/local/bin/sccache

RUN curl -o /usr/bin/bazelisk -sSL "https://github.com/bazelbuild/bazelisk/releases/download/v1.28.1/bazelisk-linux-${ARCH}" && \
chmod +x /usr/bin/bazelisk && \
ln -s /usr/bin/bazelisk /usr/bin/bazel

# Update the ld.conf cache in case any libraries were installed in /usr/local/lib*
RUN ldconfig /usr/local/lib*
6 changes: 6 additions & 0 deletions google/cloud/credentials.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ std::shared_ptr<Credentials> MakeComputeEngineCredentials(Options opts) {
std::move(opts));
}

std::shared_ptr<Credentials> MakeGDCHServiceAccountCredentials(
std::string json_object, std::string audience, Options opts) {
return std::make_shared<internal::GDCHServiceAccountConfig>(
std::move(json_object), std::move(audience), std::move(opts));
}
Comment on lines +77 to +81
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The second overload of MakeGDCHServiceAccountCredentials (which takes only audience and opts) is declared in google/cloud/credentials.h but is missing its implementation in google/cloud/credentials.cc. This will lead to linker errors when users attempt to call it.

std::shared_ptr<Credentials> MakeGDCHServiceAccountCredentials(
    std::string json_object, std::string audience, Options opts) {
  return std::make_shared<internal::GDCHServiceAccountConfig>(
      std::move(json_object), std::move(audience), std::move(opts));
}

std::shared_ptr<Credentials> MakeGDCHServiceAccountCredentials(
    std::string audience, Options opts) {
  return std::make_shared<internal::GDCHServiceAccountConfig>(
      std::move(audience), std::move(opts));
}


GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace cloud
} // namespace google
44 changes: 44 additions & 0 deletions google/cloud/credentials.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,40 @@ std::shared_ptr<Credentials> MakeApiKeyCredentials(std::string api_key,
*/
std::shared_ptr<Credentials> MakeComputeEngineCredentials(Options opts = {});

/**
* Creates credentials for a Google Distributed Cloud Hosting (GDCH) Service
* Account.
*
* @see https://docs.cloud.google.com/distributed-cloud/hosted/docs/latest/gdcag
* for more information on GDCH air-gapped environments.
*
*
* @see https://cloud.google.com/docs/authentication for more information on
* authentication in GCP.
*
* @see https://cloud.google.com/docs/authentication/client-libraries for more
* information on authentication for client libraries.
*
* [aip/4115]: https://google.aip.dev/auth/4115
*
* @ingroup guac
*
* @param json_object service account configuration as a JSON string. If
* omitted, the contents of the file at GOOGLE_APPLICATION_CREDENTIALS is
* used.
*
* @param audience authentication endpoint for the service identity used if
* AudienceOption not present in opts.
*
* @param opts optional configuration values. Note that the effect of these
* parameters depends on the underlying transport. For example,
* `LoggingComponentsOption` is ignored by gRPC-based services.
*/
std::shared_ptr<Credentials> MakeGDCHServiceAccountCredentials(
std::string json_object, std::string audience, Options opts = {});
std::shared_ptr<Credentials> MakeGDCHServiceAccountCredentials(
std::string audience, Options opts = {});

/**
* Configure the delegates for `MakeImpersonateServiceAccountCredentials()`
*
Expand All @@ -475,6 +509,16 @@ struct ScopesOption {
using Type = std::vector<std::string>;
};

/**
* Configure the audience for `MakeGDCHServiceAccountCredentials`.
*
* @ingroup options
* @ingroup guac
*/
struct AudienceOption {
using Type = std::string;
};

/**
* Overrides the subject for `MakeServiceAccountCredentials` and
* `MakeServiceAccountCredentialsFromFile()`.
Expand Down
2 changes: 2 additions & 0 deletions google/cloud/google_cloud_cpp_rest_internal.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ google_cloud_cpp_rest_internal_hdrs = [
"internal/oauth2_error_credentials.h",
"internal/oauth2_external_account_credentials.h",
"internal/oauth2_external_account_token_source.h",
"internal/oauth2_gdch_service_account_credentials.h",
"internal/oauth2_google_application_default_credentials_file.h",
"internal/oauth2_google_credentials.h",
"internal/oauth2_http_client_factory.h",
Expand Down Expand Up @@ -108,6 +109,7 @@ google_cloud_cpp_rest_internal_srcs = [
"internal/oauth2_decorate_credentials.cc",
"internal/oauth2_error_credentials.cc",
"internal/oauth2_external_account_credentials.cc",
"internal/oauth2_gdch_service_account_credentials.cc",
"internal/oauth2_google_application_default_credentials_file.cc",
"internal/oauth2_google_credentials.cc",
"internal/oauth2_impersonate_service_account_credentials.cc",
Expand Down
3 changes: 3 additions & 0 deletions google/cloud/google_cloud_cpp_rest_internal.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ add_library(
internal/oauth2_external_account_credentials.cc
internal/oauth2_external_account_credentials.h
internal/oauth2_external_account_token_source.h
internal/oauth2_gdch_service_account_credentials.cc
internal/oauth2_gdch_service_account_credentials.h
internal/oauth2_google_application_default_credentials_file.cc
internal/oauth2_google_application_default_credentials_file.h
internal/oauth2_google_credentials.cc
Expand Down Expand Up @@ -280,6 +282,7 @@ if (BUILD_TESTING)
internal/oauth2_compute_engine_credentials_test.cc
internal/oauth2_credentials_test.cc
internal/oauth2_external_account_credentials_test.cc
internal/oauth2_gdch_service_account_credentials_test.cc
internal/oauth2_google_application_default_credentials_file_test.cc
internal/oauth2_google_credentials_test.cc
internal/oauth2_impersonate_service_account_credentials_test.cc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ google_cloud_cpp_rest_internal_unit_tests = [
"internal/oauth2_compute_engine_credentials_test.cc",
"internal/oauth2_credentials_test.cc",
"internal/oauth2_external_account_credentials_test.cc",
"internal/oauth2_gdch_service_account_credentials_test.cc",
"internal/oauth2_google_application_default_credentials_file_test.cc",
"internal/oauth2_google_credentials_test.cc",
"internal/oauth2_impersonate_service_account_credentials_test.cc",
Expand Down
14 changes: 14 additions & 0 deletions google/cloud/internal/credentials_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "google/cloud/internal/credentials_impl.h"
#include "google/cloud/common_options.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/internal/populate_common_options.h"
#include <chrono>

Expand Down Expand Up @@ -106,6 +107,19 @@ ApiKeyConfig::ApiKeyConfig(std::string api_key, Options opts)
ComputeEngineCredentialsConfig::ComputeEngineCredentialsConfig(Options opts)
: options_(PopulateAuthOptions(std::move(opts))) {}

GDCHServiceAccountConfig::GDCHServiceAccountConfig(std::string json_object,
std::string audience,
Options opts)
: json_object_(std::move(json_object)),
audience_(std::move(audience)),
options_(PopulateAuthOptions(std::move(opts))) {}

GDCHServiceAccountConfig::GDCHServiceAccountConfig(std::string audience,
Options opts)
: file_path_(GetEnv("GOOGLE_APPLICATION_CREDENTIALS").value_or("")),
audience_(std::move(audience)),
options_(PopulateAuthOptions(std::move(opts))) {}

} // namespace internal
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace cloud
Expand Down
40 changes: 31 additions & 9 deletions google/cloud/internal/credentials_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
#include "google/cloud/options.h"
#include "google/cloud/status_or.h"
#include "google/cloud/version.h"
#include "absl/types/optional.h"
#include <chrono>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <vector>

Expand All @@ -41,6 +41,7 @@ class ServiceAccountConfig;
class ExternalAccountConfig;
class ApiKeyConfig;
class ComputeEngineCredentialsConfig;
class GDCHServiceAccountConfig;

std::shared_ptr<Credentials> MakeErrorCredentials(Status error_status);

Expand All @@ -56,6 +57,7 @@ class CredentialsVisitor {
virtual void visit(ExternalAccountConfig const&) = 0;
virtual void visit(ApiKeyConfig const&) = 0;
virtual void visit(ComputeEngineCredentialsConfig const&) = 0;
virtual void visit(GDCHServiceAccountConfig const&) = 0;

static void dispatch(Credentials const& credentials,
CredentialsVisitor& visitor);
Expand Down Expand Up @@ -147,20 +149,18 @@ class ServiceAccountConfig : public Credentials {
// Only one of json_object or file_path should have a value.
// TODO(#15886): Use the C++ type system to make better constructors that
// enforces this comment.
ServiceAccountConfig(absl::optional<std::string> json_object,
absl::optional<std::string> file_path, Options opts);
ServiceAccountConfig(std::optional<std::string> json_object,
std::optional<std::string> file_path, Options opts);

absl::optional<std::string> const& json_object() const {
return json_object_;
}
absl::optional<std::string> const& file_path() const { return file_path_; }
std::optional<std::string> const& json_object() const { return json_object_; }
std::optional<std::string> const& file_path() const { return file_path_; }
Options const& options() const { return options_; }

private:
void dispatch(CredentialsVisitor& v) const override { v.visit(*this); }

absl::optional<std::string> json_object_;
absl::optional<std::string> file_path_;
std::optional<std::string> json_object_;
std::optional<std::string> file_path_;
Options options_;
};

Expand Down Expand Up @@ -206,6 +206,28 @@ class ComputeEngineCredentialsConfig : public Credentials {
Options options_;
};

class GDCHServiceAccountConfig : public Credentials {
public:
GDCHServiceAccountConfig(std::string json_object, std::string audience,
Options opts);
GDCHServiceAccountConfig(std::string audience, Options opts);

~GDCHServiceAccountConfig() override = default;

std::optional<std::string> const& file_path() const { return file_path_; }
std::string const& json_object() const { return json_object_; }
std::string const& audience() const { return audience_; }
Options const& options() const { return options_; }

private:
void dispatch(CredentialsVisitor& v) const override { v.visit(*this); }

std::optional<std::string> file_path_ = std::nullopt;
std::string json_object_;
std::string audience_;
Options options_;
};

/// A helper function to initialize Auth options.
Options PopulateAuthOptions(Options options);

Expand Down
13 changes: 13 additions & 0 deletions google/cloud/internal/credentials_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ TEST(Credentials, ApiKeyCredentials) {
EXPECT_EQ("api-key", visitor.api_key);
}

TEST(Credentials, GDCHServiceAccountCredentials) {
TestCredentialsVisitor visitor;

auto credentials = MakeGDCHServiceAccountCredentials(
"test-json", "test-audience",
Options{}.set<AudienceOption>("test-audience-option"));
CredentialsVisitor::dispatch(*credentials, visitor);
EXPECT_EQ("GDCHServiceAccountConfig", visitor.name);
EXPECT_EQ("test-json", visitor.json_object);
EXPECT_EQ("test-audience", visitor.audience);
EXPECT_EQ("test-audience-option", visitor.options.get<AudienceOption>());
}

TEST(PopulateAuthOptions, EmptyOptions) {
auto result_options = PopulateAuthOptions(Options{});

Expand Down
8 changes: 6 additions & 2 deletions google/cloud/internal/curl_rest_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/strip.h"
#include <nlohmann/json.hpp>

namespace google {
namespace cloud {
Expand Down Expand Up @@ -214,8 +215,11 @@ StatusOr<std::unique_ptr<RestResponse>> CurlRestClient::Post(
out->append(
absl::StrCat(i.first, "=", (*impl)->MakeEscapedString(i.second)));
});
Status response = MakeRequestWithPayload(CurlImpl::HttpMethod::kPost, context,
request, **impl, {form_payload});
// TODO(sdhart): do we still need this conversion?
std::vector<absl::Span<char const>> span_payload{form_payload};
Status response =
MakeRequestWithPayload(CurlImpl::HttpMethod::kPost, context, request,
**impl, std::move(span_payload));
if (!response.ok()) return response;
return {std::unique_ptr<CurlRestResponse>(
new CurlRestResponse(std::move(options), std::move(*impl)))};
Expand Down
5 changes: 3 additions & 2 deletions google/cloud/internal/make_jwt_assertion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ namespace internal {

StatusOr<std::string> MakeJWTAssertionNoThrow(std::string const& header,
std::string const& payload,
std::string const& pem_contents) {
std::string const& pem_contents,
SignatureFormat format) {
auto const body =
UrlsafeBase64Encode(header) + '.' + UrlsafeBase64Encode(payload);
auto pem_signature = internal::SignUsingSha256(body, pem_contents);
auto pem_signature = internal::SignUsingSha256(body, pem_contents, format);
if (!pem_signature) return std::move(pem_signature).status();
return body + '.' + UrlsafeBase64Encode(*pem_signature);
}
Expand Down
15 changes: 12 additions & 3 deletions google/cloud/internal/make_jwt_assertion.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_MAKE_JWT_ASSERTION_H
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_MAKE_JWT_ASSERTION_H

#include "google/cloud/internal/sign_using_sha256.h"
#include "google/cloud/status_or.h"
#include "google/cloud/version.h"
#include <string>
Expand All @@ -23,9 +24,17 @@ namespace google {
namespace cloud {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace internal {
StatusOr<std::string> MakeJWTAssertionNoThrow(std::string const& header,
std::string const& payload,
std::string const& pem_contents);

/**
* Creates a JWT.
*
* @note SignatureFormat defaults to SignatureFormat::kDER for backwards
* compatibility.
*/
StatusOr<std::string> MakeJWTAssertionNoThrow(
std::string const& header, std::string const& payload,
std::string const& pem_contents,
SignatureFormat format = SignatureFormat::kDER);

} // namespace internal
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
Expand Down
Loading
Loading