Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: integration tests for pluggable auth #939

Merged
merged 10 commits into from Jul 29, 2022
5 changes: 5 additions & 0 deletions .kokoro/nightly/integration.cfg
Expand Up @@ -40,3 +40,8 @@ env_vars: {
key: "GCS_BUCKET"
value: "byoid-it-bucket"
}

env_vars: {
key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES"
value: "1"
}
ScruffyProdigy marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions .kokoro/presubmit/integration.cfg
Expand Up @@ -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"
ScruffyProdigy marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
ScruffyProdigy marked this conversation as resolved.
Show resolved Hide resolved
*/
@Test
void identityPoolCredentials() throws IOException {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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();
ScruffyProdigy marked this conversation as resolved.
Show resolved Hide resolved
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");
Expand Down