From 22f37aa687b7ffb4209a131860ccdd02f6fc4d42 Mon Sep 17 00:00:00 2001 From: Ryan Kohler Date: Fri, 29 Jul 2022 16:59:42 -0400 Subject: [PATCH] feat: integration tests for pluggable auth (#939) * feat: integration tests for pluggable auth * feat: integration tests for pluggable auth * feat: integration tests for pluggable auth * feat: integration tests for pluggable auth * fix: format Co-authored-by: Leo <39062083+lsirac@users.noreply.github.com> Co-authored-by: lsirac --- .kokoro/nightly/integration.cfg | 5 ++ .kokoro/presubmit/integration.cfg | 7 +- .../ITWorkloadIdentityFederationTest.java | 71 ++++++++++++++++++- 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/.kokoro/nightly/integration.cfg b/.kokoro/nightly/integration.cfg index 832fcf7cb..84e14b4bb 100644 --- a/.kokoro/nightly/integration.cfg +++ b/.kokoro/nightly/integration.cfg @@ -40,3 +40,8 @@ env_vars: { key: "GCS_BUCKET" value: "byoid-it-bucket" } + +env_vars: { + key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES" + value: "1" +} diff --git a/.kokoro/presubmit/integration.cfg b/.kokoro/presubmit/integration.cfg index 5f42e9c1b..920bc8274 100644 --- a/.kokoro/presubmit/integration.cfg +++ b/.kokoro/presubmit/integration.cfg @@ -35,4 +35,9 @@ env_vars: { env_vars: { key: "GCS_BUCKET" value: "byoid-it-bucket" -} \ No newline at end of file +} + +env_vars: { + key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES" + value: "1" +} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java index 5ce78fcd2..8ece218a4 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java @@ -51,6 +51,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.Instant; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -86,7 +87,7 @@ void setup() throws IOException { * using the iamcredentials generateIdToken API. This will use the service account client ID as * the sub field of the token. This OIDC token will be used as the external subject token to be * exchanged for a GCP access token via GCP STS endpoint and then to impersonate the original - * service account key. + * service account key. Retrieves the OIDC token from a file. */ @Test void identityPoolCredentials() throws IOException { @@ -150,6 +151,23 @@ void awsCredentials() throws Exception { callGcs(awsCredential); } + /** + * PluggableCredential (OIDC provider): Uses the service account to generate a Google ID token + * using the iamcredentials generateIdToken API. This will use the service account client ID as + * the sub field of the token. This OIDC token will be used as the external subject token to be + * exchanged for a GCP access token via GCP STS endpoint and then to impersonate the original + * service account key. Runs an executable to get the OIDC token. + */ + @Test + void pluggableAuthCredentials() throws IOException { + PluggableAuthCredentials pluggableAuthCredentials = + (PluggableAuthCredentials) + ExternalAccountCredentials.fromJson( + buildPluggableCredentialConfig(), OAuth2Utils.HTTP_TRANSPORT_FACTORY); + + callGcs(pluggableAuthCredentials); + } + private GenericJson buildIdentityPoolCredentialConfig() throws IOException { String idToken = generateGoogleIdToken(OIDC_AUDIENCE); @@ -178,6 +196,57 @@ private GenericJson buildIdentityPoolCredentialConfig() throws IOException { return config; } + private GenericJson buildPluggableCredentialConfig() throws IOException { + String idToken = generateGoogleIdToken(OIDC_AUDIENCE); + + Instant expiration_time = Instant.now().plusSeconds(60 * 60); + + GenericJson executableJson = new GenericJson(); + executableJson.setFactory(OAuth2Utils.JSON_FACTORY); + executableJson.put("success", true); + executableJson.put("version", 1); + executableJson.put("expiration_time", expiration_time.toEpochMilli()); + executableJson.put("token_type", "urn:ietf:params:oauth:token-type:jwt"); + executableJson.put("id_token", idToken); + + String fileContents = + "#!/bin/bash\n" + + "echo \"" + + executableJson.toPrettyString().replace("\"", "\\\"") + + "\"\n"; + + File file = + File.createTempFile( + "ITWorkloadIdentityFederation", /* suffix= */ null, /* directory= */ null); + file.deleteOnExit(); + if (!file.setExecutable(true, true)) { + throw new IOException("Unable to make script executable"); + } + OAuth2Utils.writeInputStreamToFile( + new ByteArrayInputStream(fileContents.getBytes(StandardCharsets.UTF_8)), + file.getAbsolutePath()); + + GenericJson config = new GenericJson(); + config.put("type", "external_account"); + config.put("audience", OIDC_AUDIENCE); + config.put("subject_token_type", "urn:ietf:params:oauth:token-type:jwt"); + config.put("token_url", "https://sts.googleapis.com/v1/token"); + config.put( + "service_account_impersonation_url", + String.format( + "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/%s:generateAccessToken", + clientEmail)); + + GenericJson credentialSource = new GenericJson(); + config.put("credential_source", credentialSource); + + GenericJson executableConfig = new GenericJson(); + credentialSource.put("executable", executableConfig); + executableConfig.put("command", file.getAbsolutePath()); + + return config; + } + private GenericJson buildAwsCredentialConfig() { GenericJson config = new GenericJson(); config.put("type", "external_account");