Skip to content

Commit bb5800b

Browse files
authored
feat(rest): support generateIdToken in impersonation url (#14853)
1 parent a89788f commit bb5800b

File tree

2 files changed

+34
-19
lines changed

2 files changed

+34
-19
lines changed

google/cloud/internal/oauth2_impersonate_service_account_credentials.cc

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,32 +67,21 @@ ParseImpersonatedServiceAccountCredentials(std::string const& content,
6767
}
6868
// We strip the service account from the path URL.
6969
auto url = it->get<std::string>();
70-
auto colon = url.rfind(':');
71-
if (colon == std::string::npos) {
72-
return internal::InvalidArgumentError(
73-
"Malformed `service_account_impersonation_url` field contents on data "
74-
"from " +
75-
source,
76-
GCP_ERROR_INFO());
77-
}
78-
if (url.substr(colon) != ":generateAccessToken") {
79-
// While `generateIdToken` is a valid RPC, we do not currently support ID
80-
// token flow. So we might as well error when parsing the credentials.
81-
return internal::InvalidArgumentError(
82-
"Only access token authentication is supported for impersonated "
83-
"service accounts from " +
84-
source,
85-
GCP_ERROR_INFO());
86-
}
87-
auto slash = url.rfind('/', colon);
70+
auto slash = url.rfind('/');
8871
if (slash == std::string::npos) {
8972
return internal::InvalidArgumentError(
9073
"Malformed `service_account_impersonation_url` field contents on data "
9174
"from " +
9275
source,
9376
GCP_ERROR_INFO());
9477
}
95-
info.service_account = std::string{url.substr(slash + 1, colon - slash - 1)};
78+
79+
// In the url, after the last slash, it is in the format of
80+
// `service_account[:action]`
81+
auto service_account_action = url.substr(slash + 1);
82+
auto colon = service_account_action.rfind(':');
83+
auto end = colon == std::string::npos ? service_account_action.size() : colon;
84+
info.service_account = service_account_action.substr(0, end);
9685

9786
it = credentials.find("delegates");
9887
if (it != credentials.end()) {

google/cloud/internal/oauth2_impersonate_service_account_credentials_test.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@ auto constexpr kFullValidConfig = R"""({
5050
"type": "impersonated_service_account"
5151
})""";
5252

53+
auto constexpr kFullValidConfigNoAction = R"""({
54+
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/[email protected]",
55+
"delegates": [
56+
57+
58+
],
59+
"quota_project_id": "my-project",
60+
"source_credentials": {
61+
"type": "authorized_user"
62+
},
63+
"type": "impersonated_service_account"
64+
})""";
65+
5366
TEST(ParseImpersonatedServiceAccountCredentials, Success) {
5467
auto actual =
5568
ParseImpersonatedServiceAccountCredentials(kFullValidConfig, "test-data");
@@ -146,6 +159,19 @@ TEST(ImpersonateServiceAccountCredentialsTest, Basic) {
146159
ASSERT_THAT(token, StatusIs(StatusCode::kPermissionDenied));
147160
}
148161

162+
TEST(ParseImpersonatedServiceAccountCredentialsWithoutAction, Success) {
163+
auto actual = ParseImpersonatedServiceAccountCredentials(
164+
kFullValidConfigNoAction, "test-data");
165+
ASSERT_STATUS_OK(actual);
166+
EXPECT_EQ(actual->service_account, "[email protected]");
167+
EXPECT_THAT(actual->delegates,
168+
ElementsAre("[email protected]",
169+
170+
EXPECT_THAT(actual->quota_project_id, Optional<std::string>("my-project"));
171+
EXPECT_THAT(actual->source_credentials,
172+
AllOf(HasSubstr("type"), HasSubstr("authorized_user")));
173+
}
174+
149175
} // namespace
150176
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
151177
} // namespace oauth2_internal

0 commit comments

Comments
 (0)