Skip to content

Commit f5e1f8b

Browse files
committed
feat: Support scopes field in impersonated json
1 parent d8c6aae commit f5e1f8b

File tree

4 files changed

+50
-0
lines changed

4 files changed

+50
-0
lines changed

google/cloud/internal/oauth2_google_credentials.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ StatusOr<std::unique_ptr<Credentials>> LoadCredsFromString(
8080
delegates.push_back(std::move(delegate));
8181
}
8282

83+
auto& scopes = opts.lookup<ScopesOption>();
84+
if (scopes.empty()) {
85+
for (auto& scope : info->scopes) {
86+
scopes.push_back(std::move(scope));
87+
}
88+
}
89+
8390
internal::ImpersonateServiceAccountConfig config(
8491
// The base credentials (GUAC) are used to create the IAM REST Stub. We
8592
// are going to override them by supplying our own IAM REST Stub,

google/cloud/internal/oauth2_impersonate_service_account_credentials.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ ParseImpersonatedServiceAccountCredentials(std::string const& content,
9595
}
9696
}
9797

98+
it = credentials.find("scopes");
99+
if (it != credentials.end()) {
100+
if (!it->is_array()) {
101+
return internal::InvalidArgumentError(
102+
"Malformed `scopes` field is not an array on data from " + source,
103+
GCP_ERROR_INFO());
104+
}
105+
for (auto const& scope : it->items()) {
106+
info.scopes.push_back(scope.value().get<std::string>());
107+
}
108+
}
109+
98110
it = credentials.find("quota_project_id");
99111
if (it != credentials.end()) {
100112
if (!it->is_string()) {

google/cloud/internal/oauth2_impersonate_service_account_credentials.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2929
struct ImpersonatedServiceAccountCredentialsInfo {
3030
std::string service_account;
3131
std::vector<std::string> delegates;
32+
std::vector<std::string> scopes;
3233
absl::optional<std::string> quota_project_id;
3334
std::string source_credentials;
3435
};

google/cloud/internal/oauth2_impersonate_service_account_credentials_test.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,36 @@ auto constexpr kFullValidConfigNoAction = R"""({
6363
"type": "impersonated_service_account"
6464
})""";
6565

66+
auto constexpr kWithScopes = R"""({
67+
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa3@developer.gserviceaccount.com:generateAccessToken",
68+
"scopes": [
69+
"https://www.googleapis.com/auth/cloud-platform",
70+
"https://www.googleapis.com/auth/trace.append"
71+
],
72+
"source_credentials": {
73+
"type": "authorized_user"
74+
},
75+
"type": "impersonated_service_account"
76+
})""";
77+
78+
TEST(ParseImpersonatedServiceAccountCredentials, WithScopes) {
79+
auto actual =
80+
ParseImpersonatedServiceAccountCredentials(kWithScopes, "test-data");
81+
ASSERT_STATUS_OK(actual);
82+
EXPECT_THAT(actual->scopes,
83+
ElementsAre("https://www.googleapis.com/auth/cloud-platform",
84+
"https://www.googleapis.com/auth/trace.append"));
85+
}
86+
87+
TEST(ParseImpersonatedServiceAccountCredentials, MalformedScopes) {
88+
auto json = nlohmann::json::parse(kFullValidConfig);
89+
json["scopes"] = "not-an-array";
90+
auto actual = ParseImpersonatedServiceAccountCredentials(json.dump(), "");
91+
EXPECT_THAT(actual, StatusIs(StatusCode::kInvalidArgument,
92+
AllOf(HasSubstr("Malformed"),
93+
HasSubstr("scopes"))));
94+
}
95+
6696
TEST(ParseImpersonatedServiceAccountCredentials, Success) {
6797
auto actual =
6898
ParseImpersonatedServiceAccountCredentials(kFullValidConfig, "test-data");

0 commit comments

Comments
 (0)