|
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/base64_transforms.h" |
17 | 18 | #include "google/cloud/internal/oauth2_credential_constants.h" |
18 | 19 | #include "google/cloud/internal/oauth2_universe_domain.h" |
@@ -896,6 +897,61 @@ TEST(ServiceAccountCredentialsTest, ParseServiceAccountRefreshResponse) { |
896 | 897 | EXPECT_EQ(token.token, "access-token-r1"); |
897 | 898 | } |
898 | 899 |
|
| 900 | +TEST(ServiceAccountCredentialsTest, |
| 901 | + ApplyServiceAccountCredentialsInfoOverrides) { |
| 902 | + auto info = ParseServiceAccountCredentials(MakeTestContents(), "test"); |
| 903 | + ASSERT_STATUS_OK(info); |
| 904 | + |
| 905 | + auto options = Options{} |
| 906 | + .set<google::cloud::ScopesOption>(std::vector<std::string>( |
| 907 | + {"https://www.googleapis.com/auth/userinfo.email", |
| 908 | + "https://www.googleapis.com/auth/cloud-platform"})) |
| 909 | + .set<google::cloud::SubjectOption>("my-subject"); |
| 910 | + |
| 911 | + ApplyServiceAccountCredentialsInfoOverrides(options, *info); |
| 912 | + |
| 913 | + auto const tp = std::chrono::system_clock::from_time_t(kFixedJwtTimestamp); |
| 914 | + auto components = AssertionComponentsFromInfo(*info, tp); |
| 915 | + auto assertion = |
| 916 | + MakeJWTAssertion(components.first, components.second, info->private_key); |
| 917 | + |
| 918 | + std::vector<std::string> actual_tokens = absl::StrSplit(assertion, '.'); |
| 919 | + ASSERT_EQ(actual_tokens.size(), 3); |
| 920 | + std::vector<std::vector<std::uint8_t>> decoded(actual_tokens.size()); |
| 921 | + std::transform( |
| 922 | + actual_tokens.begin(), actual_tokens.end(), decoded.begin(), |
| 923 | + [](std::string const& e) { return UrlsafeBase64Decode(e).value(); }); |
| 924 | + |
| 925 | + // Verify this is a valid key. |
| 926 | + auto const signature = |
| 927 | + SignUsingSha256(actual_tokens[0] + '.' + actual_tokens[1], kPrivateKey); |
| 928 | + ASSERT_STATUS_OK(signature); |
| 929 | + EXPECT_EQ(*signature, decoded[2]); |
| 930 | + |
| 931 | + // Verify the header and payloads are valid. |
| 932 | + auto const header = |
| 933 | + nlohmann::json::parse(decoded[0].begin(), decoded[0].end()); |
| 934 | + auto const expected_header = |
| 935 | + nlohmann::json{{"alg", "RS256"}, {"typ", "JWT"}, {"kid", kPrivateKeyId}}; |
| 936 | + EXPECT_EQ(header, expected_header); |
| 937 | + |
| 938 | + auto const payload = nlohmann::json::parse(decoded[1]); |
| 939 | + auto const iat = static_cast<std::intmax_t>(kFixedJwtTimestamp); |
| 940 | + auto const exp = iat + 3600; |
| 941 | + auto const expected_payload = nlohmann::json{ |
| 942 | + {"iss", kClientEmail}, |
| 943 | + {"scope", |
| 944 | + "https://www.googleapis.com/auth/cloud-platform " |
| 945 | + "https://www.googleapis.com/auth/userinfo.email"}, |
| 946 | + {"aud", kTokenUri}, |
| 947 | + {"iat", iat}, |
| 948 | + {"exp", exp}, |
| 949 | + {"sub", "my-subject"}, |
| 950 | + }; |
| 951 | + |
| 952 | + EXPECT_EQ(payload, expected_payload); |
| 953 | +} |
| 954 | + |
899 | 955 | } // namespace |
900 | 956 | GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END |
901 | 957 | } // namespace oauth2_internal |
|
0 commit comments