From 6e23491fdd79a568fa3648b99423f8fe303cf0e5 Mon Sep 17 00:00:00 2001 From: Ryan Kohler Date: Thu, 30 Jun 2022 10:57:31 -0700 Subject: [PATCH 1/5] feat: integration tests for pluggable auth --- .kokoro/nightly/integration.cfg | 5 ++ .kokoro/presubmit/integration.cfg | 5 ++ .../ITWorkloadIdentityFederationTest.java | 72 ++++++++++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/.kokoro/nightly/integration.cfg b/.kokoro/nightly/integration.cfg index 832fcf7cb..fd4740ab1 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" +} \ No newline at end of file diff --git a/.kokoro/presubmit/integration.cfg b/.kokoro/presubmit/integration.cfg index 5f42e9c1b..0f79002a6 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" +} + +env_vars: { + key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES" + value: "1" } \ No newline at end of file diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java index 5ce78fcd2..ab6afa88c 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java @@ -50,7 +50,9 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.StringWriter; import java.nio.charset.StandardCharsets; +import java.time.Instant; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -86,7 +88,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 an output file. */ @Test void identityPoolCredentials() throws IOException { @@ -150,6 +152,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 +197,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); + + StringWriter fileContents = new StringWriter(); + fileContents.append("#!/bin/bash\n"); + fileContents.append("echo \""); + fileContents.append(executableJson.toPrettyString().replace("\"", "\\\"")); + fileContents.append("\"\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.toString().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"); From 4a0fa3ca65d9be4e880bdcac897e4a883bd41669 Mon Sep 17 00:00:00 2001 From: Ryan Kohler Date: Wed, 27 Jul 2022 14:12:18 -0700 Subject: [PATCH 2/5] feat: integration tests for pluggable auth --- .kokoro/nightly/integration.cfg | 2 +- .kokoro/presubmit/integration.cfg | 2 +- .../auth/oauth2/ITWorkloadIdentityFederationTest.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.kokoro/nightly/integration.cfg b/.kokoro/nightly/integration.cfg index fd4740ab1..84e14b4bb 100644 --- a/.kokoro/nightly/integration.cfg +++ b/.kokoro/nightly/integration.cfg @@ -44,4 +44,4 @@ env_vars: { env_vars: { key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES" value: "1" -} \ No newline at end of file +} diff --git a/.kokoro/presubmit/integration.cfg b/.kokoro/presubmit/integration.cfg index 0f79002a6..920bc8274 100644 --- a/.kokoro/presubmit/integration.cfg +++ b/.kokoro/presubmit/integration.cfg @@ -40,4 +40,4 @@ env_vars: { env_vars: { key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES" value: "1" -} \ No newline at end of file +} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java index ab6afa88c..da35932f2 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java @@ -50,7 +50,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.StringWriter; +import java.lang.StringBuilder; import java.nio.charset.StandardCharsets; import java.time.Instant; import org.junit.jupiter.api.BeforeEach; @@ -88,7 +88,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. Retrieves the OIDC token from an output file. + * service account key. Retrieves the OIDC token from a file. */ @Test void identityPoolCredentials() throws IOException { @@ -210,7 +210,7 @@ private GenericJson buildPluggableCredentialConfig() throws IOException { executableJson.put("token_type", "urn:ietf:params:oauth:token-type:jwt"); executableJson.put("id_token", idToken); - StringWriter fileContents = new StringWriter(); + StringBuilder fileContents = new StringBuilder(); fileContents.append("#!/bin/bash\n"); fileContents.append("echo \""); fileContents.append(executableJson.toPrettyString().replace("\"", "\\\"")); From e82373ed001098abddbe4141ec9b9d11139d7509 Mon Sep 17 00:00:00 2001 From: Ryan Kohler Date: Thu, 28 Jul 2022 13:06:24 -0700 Subject: [PATCH 3/5] feat: integration tests for pluggable auth --- .../auth/oauth2/ITWorkloadIdentityFederationTest.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java index da35932f2..3d2a230bf 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java @@ -210,11 +210,10 @@ private GenericJson buildPluggableCredentialConfig() throws IOException { executableJson.put("token_type", "urn:ietf:params:oauth:token-type:jwt"); executableJson.put("id_token", idToken); - StringBuilder fileContents = new StringBuilder(); - fileContents.append("#!/bin/bash\n"); - fileContents.append("echo \""); - fileContents.append(executableJson.toPrettyString().replace("\"", "\\\"")); - fileContents.append("\"\n"); + String fileContents = "#!/bin/bash\n" + + "echo \"" + + executableJson.toPrettyString().replace("\"", "\\\"") + + "\"\n"; File file = File.createTempFile( @@ -224,7 +223,7 @@ private GenericJson buildPluggableCredentialConfig() throws IOException { throw new IOException("Unable to make script executable"); } OAuth2Utils.writeInputStreamToFile( - new ByteArrayInputStream(fileContents.toString().getBytes(StandardCharsets.UTF_8)), + new ByteArrayInputStream(fileContents.getBytes(StandardCharsets.UTF_8)), file.getAbsolutePath()); GenericJson config = new GenericJson(); From 28c56e12d757ab1584d68e92f657dd2fb8094dc7 Mon Sep 17 00:00:00 2001 From: Ryan Kohler Date: Thu, 28 Jul 2022 17:14:12 -0700 Subject: [PATCH 4/5] feat: integration tests for pluggable auth --- .../com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java index 3d2a230bf..7ddfa09e5 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java @@ -50,7 +50,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.lang.StringBuilder; import java.nio.charset.StandardCharsets; import java.time.Instant; import org.junit.jupiter.api.BeforeEach; From f70b336cec828169c699e18f70c9086868b83c77 Mon Sep 17 00:00:00 2001 From: lsirac Date: Fri, 29 Jul 2022 13:55:56 -0700 Subject: [PATCH 5/5] fix: format --- .../auth/oauth2/ITWorkloadIdentityFederationTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java index 7ddfa09e5..8ece218a4 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ITWorkloadIdentityFederationTest.java @@ -209,10 +209,11 @@ private GenericJson buildPluggableCredentialConfig() throws IOException { 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"; + String fileContents = + "#!/bin/bash\n" + + "echo \"" + + executableJson.toPrettyString().replace("\"", "\\\"") + + "\"\n"; File file = File.createTempFile(