Google Cloud Storage C++ Client  1.42.0
A C++ Client Library for Google Cloud Storage
service_account_credentials.h
Go to the documentation of this file.
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_OAUTH2_SERVICE_ACCOUNT_CREDENTIALS_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_OAUTH2_SERVICE_ACCOUNT_CREDENTIALS_H
17 
18 #include "google/cloud/storage/internal/curl_request_builder.h"
19 #include "google/cloud/storage/internal/openssl_util.h"
20 #include "google/cloud/storage/oauth2/credential_constants.h"
21 #include "google/cloud/storage/oauth2/credentials.h"
22 #include "google/cloud/storage/oauth2/refreshing_credentials_wrapper.h"
23 #include "google/cloud/storage/version.h"
24 #include "google/cloud/internal/sha256_hash.h"
25 #include "google/cloud/optional.h"
26 #include "google/cloud/status_or.h"
27 #include "absl/types/optional.h"
28 #include <chrono>
29 #include <condition_variable>
30 #include <ctime>
31 #include <iostream>
32 #include <mutex>
33 #include <set>
34 #include <string>
35 #include <vector>
36 
37 namespace google {
38 namespace cloud {
39 namespace storage {
41 
42 namespace oauth2 {
43 /// Object to hold information used to instantiate an ServiceAccountCredentials.
45  std::string client_email;
46  std::string private_key_id;
47  std::string private_key;
48  std::string token_uri;
49  // If no set is supplied, a default set of scopes will be used.
50  absl::optional<std::set<std::string>> scopes;
51  // See https://developers.google.com/identity/protocols/OAuth2ServiceAccount.
52  absl::optional<std::string> subject;
53 };
54 
55 /// Parses the contents of a JSON keyfile into a ServiceAccountCredentialsInfo.
57  std::string const& content, std::string const& source,
58  std::string const& default_token_uri = GoogleOAuthRefreshEndpoint());
59 
60 /**
61  * Parses the contents of a P12 keyfile into a ServiceAccountCredentialsInfo.
62  *
63  * @warning We strongly recommend that applications use JSON keyfiles instead.
64  *
65  * @note Note that P12 keyfiles do not contain the `client_email` for the
66  * service account, the application must obtain this through some other means
67  * and provide them to the function.
68  */
70  std::string const& source,
71  std::string const& default_token_uri = GoogleOAuthRefreshEndpoint());
72 
73 /// Parses a refresh response JSON string and uses the current time to create a
74 /// TemporaryToken.
77  storage::internal::HttpResponse const& response,
78  std::chrono::system_clock::time_point now);
79 
80 /**
81  * Splits a ServiceAccountCredentialsInfo into header and payload components
82  * and uses the current time to make a JWT assertion.
83  *
84  * @see
85  * https://cloud.google.com/endpoints/docs/frameworks/java/troubleshoot-jwt
86  *
87  * @see https://tools.ietf.org/html/rfc7523
88  */
89 std::pair<std::string, std::string> AssertionComponentsFromInfo(
91  std::chrono::system_clock::time_point now);
92 
93 /**
94  * Given a key and a JSON header and payload, creates a JWT assertion string.
95  *
96  * @see https://tools.ietf.org/html/rfc7519
97  */
98 std::string MakeJWTAssertion(std::string const& header,
99  std::string const& payload,
100  std::string const& pem_contents);
101 
102 /// Uses a ServiceAccountCredentialsInfo and the current time to construct a
103 /// JWT assertion. The assertion combined with the grant type is used to create
104 /// the refresh payload.
106  ServiceAccountCredentialsInfo const& info, std::string const& grant_type,
107  std::chrono::system_clock::time_point now);
108 
109 /**
110  * Wrapper class for Google OAuth 2.0 service account credentials.
111  *
112  * Takes a ServiceAccountCredentialsInfo and obtains access tokens from the
113  * Google Authorization Service as needed. Instances of this class should
114  * usually be created via the convenience methods declared in
115  * google_credentials.h.
116  *
117  * An HTTP Authorization header, with an access token as its value,
118  * can be obtained by calling the AuthorizationHeader() method; if the current
119  * access token is invalid or nearing expiration, this will class will first
120  * obtain a new access token before returning the Authorization header string.
121  *
122  * @see https://developers.google.com/identity/protocols/OAuth2ServiceAccount
123  * for an overview of using service accounts with Google's OAuth 2.0 system.
124  *
125  * @see https://cloud.google.com/storage/docs/reference/libraries for details on
126  * how to obtain and get started with service account credentials.
127  *
128  * @tparam HttpRequestBuilderType a dependency injection point. It makes it
129  * possible to mock internal libcurl wrappers. This should generally not be
130  * overridden except for testing.
131  * @tparam ClockType a dependency injection point to fetch the current time.
132  * This should generally not be overridden except for testing.
133  */
134 template <typename HttpRequestBuilderType =
135  storage::internal::CurlRequestBuilder,
136  typename ClockType = std::chrono::system_clock>
138  public:
140  : ServiceAccountCredentials(std::move(info), {}) {}
142  ChannelOptions const& options)
143  : info_(std::move(info)),
145  clock_() {}
146 
147  StatusOr<std::string> AuthorizationHeader() override {
148  std::unique_lock<std::mutex> lock(mu_);
149  return refreshing_creds_.AuthorizationHeader(clock_.now(),
150  [this] { return Refresh(); });
151  }
152 
153  /**
154  * Create a RSA SHA256 signature of the blob using the Credential object.
155  *
156  * @param signing_account the desired service account which should sign
157  * @p blob. If not set, uses this object's account. If set, it must match
158  * this object's service account.
159  * @param blob the string to sign. Note that sometimes the application must
160  * Base64-encode the data before signing.
161  * @return the signed blob as raw bytes. An error if the @p signing_account
162  * does not match the email for the credential's account.
163  */
164  StatusOr<std::vector<std::uint8_t>> SignBlob(
165  SigningAccount const& signing_account,
166  std::string const& blob) const override {
167  if (signing_account.has_value() &&
168  signing_account.value() != info_.client_email) {
170  "The current_credentials cannot sign blobs for " +
171  signing_account.value());
172  }
173  return internal::SignStringWithPem(blob, info_.private_key,
175  }
176 
177  std::string AccountEmail() const override { return info_.client_email; }
178  std::string KeyId() const override { return info_.private_key_id; }
179 
180  private:
181  StatusOr<RefreshingCredentialsWrapper::TemporaryToken> Refresh() {
182  HttpRequestBuilderType builder(
183  info_.token_uri,
184  storage::internal::GetDefaultCurlHandleFactory(options_));
185  builder.AddHeader("Content-Type: application/x-www-form-urlencoded");
186  // This is the value of grant_type for JSON-formatted service account
187  // keyfiles downloaded from Cloud Console.
188  std::string grant_type("grant_type=");
189  grant_type +=
190  builder.MakeEscapedString("urn:ietf:params:oauth:grant-type:jwt-bearer")
191  .get();
192 
193  auto payload =
194  CreateServiceAccountRefreshPayload(info_, grant_type, clock_.now());
195  auto response = std::move(builder).BuildRequest().MakeRequest(payload);
196  if (!response) return std::move(response).status();
197  if (response->status_code >= 300) return AsStatus(*response);
198  return ParseServiceAccountRefreshResponse(*response, clock_.now());
199  }
200 
202  Options options_;
203  mutable std::mutex mu_;
204  RefreshingCredentialsWrapper refreshing_creds_;
205  ClockType clock_;
206 };
207 
208 } // namespace oauth2
210 } // namespace storage
211 } // namespace cloud
212 } // namespace google
213 
214 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_OAUTH2_SERVICE_ACCOUNT_CREDENTIALS_H