|
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | 15 | #include "google/cloud/internal/oauth2_service_account_credentials.h" |
| 16 | +#include "google/cloud/credentials.h" |
16 | 17 | #include "google/cloud/internal/absl_str_join_quiet.h" |
17 | 18 | #include "google/cloud/internal/getenv.h" |
18 | 19 | #include "google/cloud/internal/make_jwt_assertion.h" |
19 | 20 | #include "google/cloud/internal/make_status.h" |
20 | 21 | #include "google/cloud/internal/oauth2_google_credentials.h" |
21 | 22 | #include "google/cloud/internal/oauth2_universe_domain.h" |
| 23 | +#include "google/cloud/internal/parse_service_account_p12_file.h" |
22 | 24 | #include "google/cloud/internal/rest_response.h" |
23 | 25 | #include "google/cloud/internal/sign_using_sha256.h" |
24 | 26 | #include <nlohmann/json.hpp> |
| 27 | +#include <fstream> |
25 | 28 | #include <functional> |
26 | 29 |
|
27 | 30 | namespace google { |
@@ -240,6 +243,83 @@ StatusOr<std::string> MakeSelfSignedJWT( |
240 | 243 | info.private_key); |
241 | 244 | } |
242 | 245 |
|
| 246 | +StatusOr<std::shared_ptr<Credentials>> |
| 247 | +CreateServiceAccountCredentialsFromJsonContents( |
| 248 | + std::string const& contents, Options const& options, |
| 249 | + HttpClientFactory client_factory) { |
| 250 | + auto info = ParseServiceAccountCredentials(contents, "memory"); |
| 251 | + if (!info) return info.status(); |
| 252 | + |
| 253 | + if (options.has<ScopesOption>()) { |
| 254 | + auto const& s = options.get<ScopesOption>(); |
| 255 | + std::set<std::string> scopes{s.begin(), s.end()}; |
| 256 | + info->scopes = std::move(scopes); |
| 257 | + } |
| 258 | + |
| 259 | + if (options.has<SubjectOption>()) { |
| 260 | + info->subject = options.get<SubjectOption>(); |
| 261 | + } |
| 262 | + |
| 263 | + // Verify this is usable before returning it. |
| 264 | + auto const tp = std::chrono::system_clock::time_point{}; |
| 265 | + auto const components = AssertionComponentsFromInfo(*info, tp); |
| 266 | + auto jwt = MakeJWTAssertionNoThrow(components.first, components.second, |
| 267 | + info->private_key); |
| 268 | + if (!jwt) return jwt.status(); |
| 269 | + return StatusOr<std::shared_ptr<Credentials>>( |
| 270 | + std::make_shared<ServiceAccountCredentials>(*info, options, |
| 271 | + std::move(client_factory))); |
| 272 | +} |
| 273 | + |
| 274 | +StatusOr<std::shared_ptr<Credentials>> |
| 275 | +CreateServiceAccountCredentialsFromJsonFilePath( |
| 276 | + std::string const& path, Options const& options, |
| 277 | + HttpClientFactory client_factory) { |
| 278 | + std::ifstream is(path); |
| 279 | + if (!is.is_open()) { |
| 280 | + // We use kUnknown here because we don't know if the file does not exist, or |
| 281 | + // if we were unable to open it for some other reason. |
| 282 | + return internal::UnknownError("Cannot open credentials file " + path, |
| 283 | + GCP_ERROR_INFO()); |
| 284 | + } |
| 285 | + std::string contents(std::istreambuf_iterator<char>{is}, {}); |
| 286 | + return CreateServiceAccountCredentialsFromJsonContents( |
| 287 | + std::move(contents), options, std::move(client_factory)); |
| 288 | +} |
| 289 | + |
| 290 | +StatusOr<std::shared_ptr<Credentials>> |
| 291 | +CreateServiceAccountCredentialsFromP12FilePath( |
| 292 | + std::string const& path, Options const& options, |
| 293 | + HttpClientFactory client_factory) { |
| 294 | + auto info = ParseServiceAccountP12File(path); |
| 295 | + if (!info) return std::move(info).status(); |
| 296 | + |
| 297 | + if (options.has<ScopesOption>()) { |
| 298 | + auto const& s = options.get<ScopesOption>(); |
| 299 | + std::set<std::string> scopes{s.begin(), s.end()}; |
| 300 | + info->scopes = std::move(scopes); |
| 301 | + } |
| 302 | + |
| 303 | + if (options.has<SubjectOption>()) { |
| 304 | + info->subject = options.get<SubjectOption>(); |
| 305 | + } |
| 306 | + |
| 307 | + return StatusOr<std::shared_ptr<Credentials>>( |
| 308 | + std::make_shared<ServiceAccountCredentials>(*info, options, |
| 309 | + std::move(client_factory))); |
| 310 | +} |
| 311 | + |
| 312 | +StatusOr<std::shared_ptr<Credentials>> |
| 313 | +CreateServiceAccountCredentialsFromFilePath(std::string const& path, |
| 314 | + Options const& options, |
| 315 | + HttpClientFactory client_factory) { |
| 316 | + auto credentials = CreateServiceAccountCredentialsFromJsonFilePath( |
| 317 | + path, options, client_factory); |
| 318 | + if (credentials) return *credentials; |
| 319 | + return CreateServiceAccountCredentialsFromP12FilePath( |
| 320 | + path, options, std::move(client_factory)); |
| 321 | +} |
| 322 | + |
243 | 323 | ServiceAccountCredentials::ServiceAccountCredentials( |
244 | 324 | ServiceAccountCredentialsInfo info, Options options, |
245 | 325 | HttpClientFactory client_factory) |
@@ -313,7 +393,8 @@ bool ServiceAccountUseOAuth(ServiceAccountCredentialsInfo const& info) { |
313 | 393 | } |
314 | 394 |
|
315 | 395 | bool ServiceAccountCredentials::UseOAuth() { |
316 | | - return ServiceAccountUseOAuth(info_); |
| 396 | + return options_.has<DisableSelfSignedJWTOption>() || |
| 397 | + ServiceAccountUseOAuth(info_); |
317 | 398 | } |
318 | 399 |
|
319 | 400 | StatusOr<AccessToken> ServiceAccountCredentials::GetTokenOAuth( |
|
0 commit comments