Skip to content

Commit

Permalink
test: adds integration tests for workload identity federation (#581)
Browse files Browse the repository at this point in the history
A setup script workloadidentityfederation-setup.sh is added to make the workload identity pool configuration changes on the current project, if needed. The setup script only needs to be run once on a project (already ran).
  • Loading branch information
lsirac authored Mar 17, 2021
1 parent 5c7deec commit 31ebe6e
Show file tree
Hide file tree
Showing 14 changed files with 663 additions and 102 deletions.
5 changes: 5 additions & 0 deletions .kokoro/nightly/integration.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ env_vars: {
key: "SECRET_MANAGER_KEYS"
value: "java-it-service-account"
}

env_vars: {
key: "GCS_BUCKET"
value: "byoid-it-bucket"
}
5 changes: 5 additions & 0 deletions .kokoro/presubmit/integration.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ env_vars: {
key: "SECRET_MANAGER_KEYS"
value: "java-it-service-account"
}

env_vars: {
key: "GCS_BUCKET"
value: "byoid-it-bucket"
}
23 changes: 14 additions & 9 deletions oauth2_http/java/com/google/auth/oauth2/AwsCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ static class AwsCredentialSource extends CredentialSource {
/**
* Internal constructor. See {@link
* ExternalAccountCredentials#ExternalAccountCredentials(HttpTransportFactory, String, String,
* String, CredentialSource, String, String, String, String, String, Collection)}
* String, CredentialSource, String, String, String, String, String, Collection,
* EnvironmentProvider)}
*/
AwsCredentials(
HttpTransportFactory transportFactory,
Expand All @@ -130,7 +131,8 @@ static class AwsCredentialSource extends CredentialSource {
@Nullable String quotaProjectId,
@Nullable String clientId,
@Nullable String clientSecret,
@Nullable Collection<String> scopes) {
@Nullable Collection<String> scopes,
@Nullable EnvironmentProvider environmentProvider) {
super(
transportFactory,
audience,
Expand All @@ -142,7 +144,8 @@ static class AwsCredentialSource extends CredentialSource {
quotaProjectId,
clientId,
clientSecret,
scopes);
scopes,
environmentProvider);
this.awsCredentialSource = credentialSource;
}

Expand Down Expand Up @@ -200,7 +203,8 @@ public GoogleCredentials createScoped(Collection<String> newScopes) {
getQuotaProjectId(),
getClientId(),
getClientSecret(),
newScopes);
newScopes,
getEnvironmentProvider());
}

private String retrieveResource(String url, String resourceName) throws IOException {
Expand Down Expand Up @@ -241,7 +245,7 @@ private String buildSubjectToken(AwsRequestSignature signature)

private String getAwsRegion() throws IOException {
// For AWS Lambda, the region is retrieved through the AWS_REGION environment variable.
String region = getEnv("AWS_REGION");
String region = getEnvironmentProvider().getEnv("AWS_REGION");
if (region != null) {
return region;
}
Expand All @@ -261,9 +265,9 @@ private String getAwsRegion() throws IOException {
@VisibleForTesting
AwsSecurityCredentials getAwsSecurityCredentials() throws IOException {
// Check environment variables for credentials first.
String accessKeyId = getEnv("AWS_ACCESS_KEY_ID");
String secretAccessKey = getEnv("AWS_SECRET_ACCESS_KEY");
String token = getEnv("Token");
String accessKeyId = getEnvironmentProvider().getEnv("AWS_ACCESS_KEY_ID");
String secretAccessKey = getEnvironmentProvider().getEnv("AWS_SECRET_ACCESS_KEY");
String token = getEnvironmentProvider().getEnv("Token");
if (accessKeyId != null && secretAccessKey != null) {
return new AwsSecurityCredentials(accessKeyId, secretAccessKey, token);
}
Expand Down Expand Up @@ -343,7 +347,8 @@ public AwsCredentials build() {
quotaProjectId,
clientId,
clientSecret,
scopes);
scopes,
environmentProvider);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.google.auth.oauth2;

/** Interface for an environment provider. */
interface EnvironmentProvider {
String getEnv(String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ abstract static class CredentialSource {

@Nullable protected final ImpersonatedCredentials impersonatedCredentials;

private EnvironmentProvider environmentProvider;

/**
* Constructor with minimum identifying information and custom HTTP transport.
*
Expand Down Expand Up @@ -121,6 +123,41 @@ protected ExternalAccountCredentials(
@Nullable String clientId,
@Nullable String clientSecret,
@Nullable Collection<String> scopes) {
this(
transportFactory,
audience,
subjectTokenType,
tokenUrl,
credentialSource,
tokenInfoUrl,
serviceAccountImpersonationUrl,
quotaProjectId,
clientId,
clientSecret,
scopes,
/* environmentProvider= */ null);
}

/**
* See {@link ExternalAccountCredentials#ExternalAccountCredentials(HttpTransportFactory, String,
* String, String, CredentialSource, String, String, String, String, String, Collection)}
*
* @param environmentProvider the environment provider. May be null. Defaults to {@link
* SystemEnvironmentProvider}.
*/
protected ExternalAccountCredentials(
HttpTransportFactory transportFactory,
String audience,
String subjectTokenType,
String tokenUrl,
CredentialSource credentialSource,
@Nullable String tokenInfoUrl,
@Nullable String serviceAccountImpersonationUrl,
@Nullable String quotaProjectId,
@Nullable String clientId,
@Nullable String clientSecret,
@Nullable Collection<String> scopes,
@Nullable EnvironmentProvider environmentProvider) {
this.transportFactory =
MoreObjects.firstNonNull(
transportFactory,
Expand All @@ -137,6 +174,9 @@ protected ExternalAccountCredentials(
this.clientSecret = clientSecret;
this.scopes =
(scopes == null || scopes.isEmpty()) ? Arrays.asList(CLOUD_PLATFORM_SCOPE) : scopes;
this.environmentProvider =
environmentProvider == null ? SystemEnvironmentProvider.getInstance() : environmentProvider;

this.impersonatedCredentials = initializeImpersonatedCredentials();
}

Expand Down Expand Up @@ -251,7 +291,8 @@ static ExternalAccountCredentials fromJson(
quotaProjectId,
clientId,
clientSecret,
/* scopes= */ null);
/* scopes= */ null,
/* environmentProvider= */ null);
}
return new IdentityPoolCredentials(
transportFactory,
Expand All @@ -264,7 +305,8 @@ static ExternalAccountCredentials fromJson(
quotaProjectId,
clientId,
clientSecret,
/* scopes= */ null);
/* scopes= */ null,
/* environmentProvider= */ null);
}

private static boolean isAwsCredential(Map<String, Object> credentialSource) {
Expand Down Expand Up @@ -296,7 +338,7 @@ protected AccessToken exchangeExternalCredentialForAccessToken(
}

private static String extractTargetPrincipal(String serviceAccountImpersonationUrl) {
// Extract the target principal
// Extract the target principal.
int startIndex = serviceAccountImpersonationUrl.lastIndexOf('/');
int endIndex = serviceAccountImpersonationUrl.indexOf(":generateAccessToken");

Expand Down Expand Up @@ -364,6 +406,10 @@ public Collection<String> getScopes() {
return scopes;
}

EnvironmentProvider getEnvironmentProvider() {
return environmentProvider;
}

/** Base builder for external account credentials. */
public abstract static class Builder extends GoogleCredentials.Builder {

Expand All @@ -372,6 +418,7 @@ public abstract static class Builder extends GoogleCredentials.Builder {
protected String tokenUrl;
protected String tokenInfoUrl;
protected CredentialSource credentialSource;
protected EnvironmentProvider environmentProvider;
protected HttpTransportFactory transportFactory;

@Nullable protected String serviceAccountImpersonationUrl;
Expand All @@ -394,6 +441,7 @@ protected Builder(ExternalAccountCredentials credentials) {
this.clientId = credentials.clientId;
this.clientSecret = credentials.clientSecret;
this.scopes = credentials.scopes;
this.environmentProvider = credentials.environmentProvider;
}

public Builder setAudience(String audience) {
Expand Down Expand Up @@ -451,6 +499,11 @@ public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) {
return this;
}

Builder setEnvironmentProvider(EnvironmentProvider environmentProvider) {
this.environmentProvider = environmentProvider;
return this;
}

public abstract ExternalAccountCredentials build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ private boolean hasHeaders() {
/**
* Internal constructor. See {@link
* ExternalAccountCredentials#ExternalAccountCredentials(HttpTransportFactory, String, String,
* String, CredentialSource, String, String, String, String, String, Collection)}
* String, CredentialSource, String, String, String, String, String, Collection,
* EnvironmentProvider)}
*/
IdentityPoolCredentials(
HttpTransportFactory transportFactory,
Expand All @@ -171,7 +172,8 @@ private boolean hasHeaders() {
@Nullable String quotaProjectId,
@Nullable String clientId,
@Nullable String clientSecret,
@Nullable Collection<String> scopes) {
@Nullable Collection<String> scopes,
@Nullable EnvironmentProvider environmentProvider) {
super(
transportFactory,
audience,
Expand All @@ -183,7 +185,8 @@ private boolean hasHeaders() {
quotaProjectId,
clientId,
clientSecret,
scopes);
scopes,
environmentProvider);
this.identityPoolCredentialSource = credentialSource;
}

Expand Down Expand Up @@ -280,7 +283,8 @@ public IdentityPoolCredentials createScoped(Collection<String> newScopes) {
getQuotaProjectId(),
getClientId(),
getClientSecret(),
newScopes);
newScopes,
getEnvironmentProvider());
}

public static Builder newBuilder() {
Expand Down Expand Up @@ -312,7 +316,8 @@ public IdentityPoolCredentials build() {
quotaProjectId,
clientId,
clientSecret,
scopes);
scopes,
environmentProvider);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.google.auth.oauth2;

/** Represents the default system environment provider. */
class SystemEnvironmentProvider implements EnvironmentProvider {
static final SystemEnvironmentProvider INSTANCE = new SystemEnvironmentProvider();

private SystemEnvironmentProvider() {}

@Override
public String getEnv(String name) {
return System.getenv(name);
}

public static SystemEnvironmentProvider getInstance() {
return INSTANCE;
}
}
Loading

0 comments on commit 31ebe6e

Please sign in to comment.