Skip to content
7 changes: 7 additions & 0 deletions google-cloud-bigtable/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
<!-- Use client defined default endpoints -->
<!-- Can be overriden on the commandline via `-Dbigtable.cfe-data-endpoint=bigtableadmin.googleapis.com:443` -->
<bigtable.cfe-data-endpoint/>
<bigtable.cfe-jwt-audience/>
<bigtable.cfe-admin-endpoint/>
<bigtable.directpath-data-endpoint/>
<bigtable.directpath-jwt-audience/>
<bigtable.directpath-admin-endpoint/>

<!-- This is used by bigtable-prod-batch-it profile to ensure that tests work on the batch endpoint.
Expand Down Expand Up @@ -425,6 +427,7 @@
<bigtable.env>cloud</bigtable.env>
<bigtable.data-endpoint>${bigtable.cfe-data-endpoint}</bigtable.data-endpoint>
<bigtable.admin-endpoint>${bigtable.cfe-admin-endpoint}</bigtable.admin-endpoint>
<bigtable.data-jwt-audience>${bigtable.cfe-jwt-audience}</bigtable.data-jwt-audience>
<bigtable.enable-grpc-logs>${bigtable.enable-grpc-logs}</bigtable.enable-grpc-logs>
<bigtable.grpc-log-dir>${project.build.directory}/test-grpc-logs/prod-it</bigtable.grpc-log-dir>
</systemPropertyVariables>
Expand Down Expand Up @@ -475,6 +478,7 @@
<bigtable.env>cloud</bigtable.env>
<bigtable.data-endpoint>${bigtable.cfe-data-batch-endpoint}</bigtable.data-endpoint>
<bigtable.admin-endpoint>${bigtable.cfe-admin-endpoint}</bigtable.admin-endpoint>
<bigtable.data-jwt-audience>${bigtable.cfe-jwt-audience}</bigtable.data-jwt-audience>
<bigtable.enable-grpc-logs>${bigtable.enable-grpc-logs}</bigtable.enable-grpc-logs>
<bigtable.grpc-log-dir>${project.build.directory}/test-grpc-logs/prod-batch-it</bigtable.grpc-log-dir>
</systemPropertyVariables>
Expand Down Expand Up @@ -510,6 +514,7 @@
<bigtable.env>cloud</bigtable.env>
<bigtable.data-endpoint>${bigtable.directpath-data-endpoint}</bigtable.data-endpoint>
<bigtable.admin-endpoint>${bigtable.directpath-admin-endpoint}</bigtable.admin-endpoint>
<bigtable.data-jwt-audience>${bigtable.directpath-jwt-audience}</bigtable.data-jwt-audience>
<bigtable.enable-grpc-logs>${bigtable.enable-grpc-logs}</bigtable.enable-grpc-logs>
<bigtable.grpc-log-dir>${project.build.directory}/test-grpc-logs/directpath-it</bigtable.grpc-log-dir>
<bigtable.connection-mode>REQUIRE_DIRECT_PATH</bigtable.connection-mode>
Expand Down Expand Up @@ -551,6 +556,7 @@
<bigtable.env>cloud</bigtable.env>
<bigtable.data-endpoint>${bigtable.cfe-data-endpoint}</bigtable.data-endpoint>
<bigtable.admin-endpoint>${bigtable.cfe-admin-endpoint}</bigtable.admin-endpoint>
<bigtable.data-jwt-audience>${bigtable.cfe-jwt-audience}</bigtable.data-jwt-audience>
<bigtable.enable-grpc-logs>${bigtable.enable-grpc-logs}</bigtable.enable-grpc-logs>
<bigtable.grpc-log-dir>${project.build.directory}/test-grpc-logs/cfe-it</bigtable.grpc-log-dir>
<bigtable.connection-mode>REQUIRE_CFE</bigtable.connection-mode>
Expand Down Expand Up @@ -589,6 +595,7 @@
<bigtable.env>cloud</bigtable.env>
<bigtable.data-endpoint>${bigtable.directpath-data-endpoint}</bigtable.data-endpoint>
<bigtable.admin-endpoint>${bigtable.directpath-admin-endpoint}</bigtable.admin-endpoint>
<bigtable.data-jwt-audience>${bigtable.directpath-jwt-audience}</bigtable.data-jwt-audience>
<bigtable.enable-grpc-logs>${bigtable.enable-grpc-logs}</bigtable.enable-grpc-logs>
<bigtable.grpc-log-dir>${project.build.directory}/test-grpc-logs/directpath-ipv4only-it</bigtable.grpc-log-dir>
<bigtable.connection-mode>REQUIRE_DIRECT_PATH_IPV4</bigtable.connection-mode>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,18 +228,13 @@ private static OpenTelemetry getOpenTelemetryFromMetricsProvider(

private static void patchCredentials(EnhancedBigtableStubSettings.Builder settings)
throws IOException {
int i = settings.getEndpoint().lastIndexOf(":");
String host = settings.getEndpoint().substring(0, i);
String audience = settings.getJwtAudienceMapping().get(host);
String audience = settings.getJwtAudience();

if (audience == null) {
return;
}
URI audienceUri = null;
try {
audienceUri = new URI(audience);
} catch (URISyntaxException e) {
throw new IllegalStateException("invalid JWT audience override", e);
throw new IllegalStateException("invalid JWT audience", e);
}

CredentialsProvider credentialsProvider = settings.getCredentialsProvider();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,18 +250,16 @@ public class EnhancedBigtableStubSettings extends StubSettings<EnhancedBigtableS
.build();

/**
* In most cases, jwt audience == service name. However in some cases, this is not the case. The
* following mapping is used to patch the audience in a JWT token.
* Default jwt audience is always the service name unless it's override to test / staging for
* testing.
*/
private static final Map<String, String> DEFAULT_JWT_AUDIENCE_MAPPING =
ImmutableMap.of("batch-bigtable.googleapis.com", "https://bigtable.googleapis.com/");
private static final String DEFAULT_DATA_JWT_AUDIENCE = "https://bigtable.googleapis.com/";

private final String projectId;
private final String instanceId;
private final String appProfileId;
private final boolean isRefreshingChannel;
private ImmutableList<String> primedTableIds;
private final Map<String, String> jwtAudienceMapping;
private final boolean enableRoutingCookie;
private final boolean enableRetryInfo;
private final boolean enableSkipTrailers;
Expand All @@ -287,6 +285,7 @@ public class EnhancedBigtableStubSettings extends StubSettings<EnhancedBigtableS
private final MetricsProvider metricsProvider;
@Nullable private final String metricsEndpoint;
@Nonnull private final InternalMetricsProvider internalMetricsProvider;
private final String jwtAudience;

private EnhancedBigtableStubSettings(Builder builder) {
super(builder);
Expand All @@ -311,13 +310,13 @@ private EnhancedBigtableStubSettings(Builder builder) {
appProfileId = builder.appProfileId;
isRefreshingChannel = builder.isRefreshingChannel;
primedTableIds = builder.primedTableIds;
jwtAudienceMapping = builder.jwtAudienceMapping;
enableRoutingCookie = builder.enableRoutingCookie;
enableRetryInfo = builder.enableRetryInfo;
enableSkipTrailers = builder.enableSkipTrailers;
metricsProvider = builder.metricsProvider;
metricsEndpoint = builder.metricsEndpoint;
internalMetricsProvider = builder.internalMetricsProvider;
jwtAudience = builder.jwtAudience;

// Per method settings.
readRowsSettings = builder.readRowsSettings.build();
Expand Down Expand Up @@ -376,9 +375,14 @@ public List<String> getPrimedTableIds() {
return primedTableIds;
}

/**
* @deprecated This is a no op and will always return an empty map. Audience is always set to
* bigtable service name.
*/
@InternalApi("Used for internal testing")
@Deprecated
public Map<String, String> getJwtAudienceMapping() {
return jwtAudienceMapping;
return ImmutableMap.of();
}

public MetricsProvider getMetricsProvider() {
Expand Down Expand Up @@ -748,7 +752,7 @@ public static class Builder extends StubSettings.Builder<EnhancedBigtableStubSet
private String appProfileId;
private boolean isRefreshingChannel;
private ImmutableList<String> primedTableIds;
private Map<String, String> jwtAudienceMapping;
private String jwtAudience;
private boolean enableRoutingCookie;
private boolean enableRetryInfo;
private boolean enableSkipTrailers;
Expand Down Expand Up @@ -789,13 +793,13 @@ private Builder() {
this.appProfileId = SERVER_DEFAULT_APP_PROFILE_ID;
this.isRefreshingChannel = true;
primedTableIds = ImmutableList.of();
jwtAudienceMapping = DEFAULT_JWT_AUDIENCE_MAPPING;
setCredentialsProvider(defaultCredentialsProviderBuilder().build());
this.enableRoutingCookie = true;
this.enableRetryInfo = true;
this.enableSkipTrailers = SKIP_TRAILERS;
metricsProvider = DefaultMetricsProvider.INSTANCE;
this.internalMetricsProvider = DEFAULT_INTERNAL_OTEL_PROVIDER;
this.jwtAudience = DEFAULT_DATA_JWT_AUDIENCE;

// Defaults provider
BigtableStubSettings.Builder baseDefaults = BigtableStubSettings.newBuilder();
Expand Down Expand Up @@ -928,12 +932,12 @@ private Builder(EnhancedBigtableStubSettings settings) {
appProfileId = settings.appProfileId;
isRefreshingChannel = settings.isRefreshingChannel;
primedTableIds = settings.primedTableIds;
jwtAudienceMapping = settings.jwtAudienceMapping;
enableRoutingCookie = settings.enableRoutingCookie;
enableRetryInfo = settings.enableRetryInfo;
metricsProvider = settings.metricsProvider;
metricsEndpoint = settings.getMetricsEndpoint();
internalMetricsProvider = settings.internalMetricsProvider;
jwtAudience = settings.jwtAudience;

// Per method settings.
readRowsSettings = settings.readRowsSettings.toBuilder();
Expand Down Expand Up @@ -1075,9 +1079,20 @@ public List<String> getPrimedTableIds() {
return primedTableIds;
}

/**
* @deprecated This is a no op. Audience is always set to bigtable service name.
* @see #setJwtAudience(String) to override the audience.
*/
@InternalApi("Used for internal testing")
@Deprecated
public Builder setJwtAudienceMapping(Map<String, String> jwtAudienceMapping) {
this.jwtAudienceMapping = Preconditions.checkNotNull(jwtAudienceMapping);
return this;
}

/** Set the jwt audience override. */
@InternalApi("Used for internal testing")
public Builder setJwtAudience(String audience) {
this.jwtAudience = audience;
return this;
}

Expand Down Expand Up @@ -1140,9 +1155,20 @@ public boolean areInternalMetricsEnabled() {
return internalMetricsProvider == DISABLED_INTERNAL_OTEL_PROVIDER;
}

/**
* @deprecated This is a no op and will always return an empty map. Audience is always set to
* bigtable service name.
* @see #getJwtAudience() to get the audience.
*/
@InternalApi("Used for internal testing")
@Deprecated
public Map<String, String> getJwtAudienceMapping() {
return jwtAudienceMapping;
return ImmutableMap.of();
}

/** Return the jwt audience override. */
String getJwtAudience() {
return this.jwtAudience;
}

/**
Expand Down Expand Up @@ -1318,7 +1344,6 @@ public String toString() {
.add("appProfileId", appProfileId)
.add("isRefreshingChannel", isRefreshingChannel)
.add("primedTableIds", primedTableIds)
.add("jwtAudienceMapping", jwtAudienceMapping)
.add("enableRoutingCookie", enableRoutingCookie)
.add("enableRetryInfo", enableRetryInfo)
.add("enableSkipTrailers", enableSkipTrailers)
Expand All @@ -1340,6 +1365,7 @@ public String toString() {
.add("metricsProvider", metricsProvider)
.add("metricsEndpoint", metricsEndpoint)
.add("areInternalMetricsEnabled", internalMetricsProvider == DEFAULT_INTERNAL_OTEL_PROVIDER)
.add("jwtAudience", jwtAudience)
.add("parent", super.toString())
.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ public void testNewClientsShareTransportChannel() throws Exception {

// Make sure that only 1 instance is created by each provider
Mockito.verify(transportChannelProvider, Mockito.times(1)).getTransportChannel();
Mockito.verify(credentialsProvider, Mockito.times(1)).getCredentials();
// getCredentials was called twice, in patchCredentials and when creating the fixed
// credentials in BigtableClientContext
Mockito.verify(credentialsProvider, Mockito.times(2)).getCredentials();
Mockito.verify(executorProvider, Mockito.times(1)).getExecutor();
Mockito.verify(watchdogProvider, Mockito.times(1)).getWatchdog();
}
Expand Down Expand Up @@ -270,7 +272,9 @@ public void testCreateWithRefreshingChannel() throws Exception {
factory.createForInstance("other-project", "other-instance");

// Make sure that only 1 instance is created by each provider
Mockito.verify(credentialsProvider, Mockito.times(1)).getCredentials();
// getCredentials was called twice, in patchCredentials and when creating the fixed credentials
// in BigtableClientContext
Mockito.verify(credentialsProvider, Mockito.times(2)).getCredentials();
Mockito.verify(executorProvider, Mockito.times(1)).getExecutor();
Mockito.verify(watchdogProvider, Mockito.times(1)).getWatchdog();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,6 @@ public void enableRetryInfoFalseValueTest() throws IOException {
"appProfileId",
"isRefreshingChannel",
"primedTableIds",
"jwtAudienceMapping",
"enableRoutingCookie",
"enableRetryInfo",
"enableSkipTrailers",
Expand All @@ -1013,6 +1012,7 @@ public void enableRetryInfoFalseValueTest() throws IOException {
"metricsProvider",
"metricsEndpoint",
"areInternalMetricsEnabled",
"jwtAudience",
};

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@
import com.google.cloud.bigtable.data.v2.stub.sql.SqlProtoFactory;
import com.google.cloud.bigtable.data.v2.stub.sql.SqlServerStream;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Queues;
import com.google.common.io.BaseEncoding;
import com.google.protobuf.ByteString;
Expand Down Expand Up @@ -224,8 +223,8 @@ public void testJwtAudience()
String expectedAudience = "http://localaudience";
EnhancedBigtableStubSettings settings =
defaultSettings.toBuilder()
.setJwtAudienceMapping(ImmutableMap.of("localhost", expectedAudience))
.setCredentialsProvider(FixedCredentialsProvider.create(jwtCreds))
.setJwtAudience(expectedAudience)
.build();
try (EnhancedBigtableStub stub = EnhancedBigtableStub.create(settings)) {
stub.readRowCallable().futureCall(Query.create("fake-table")).get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public boolean apply(InetSocketAddress input) {

private static final String DATA_ENDPOINT_PROPERTY_NAME = "bigtable.data-endpoint";
private static final String ADMIN_ENDPOINT_PROPERTY_NAME = "bigtable.admin-endpoint";
private static final String DATA_JWT_OVERRIDE_PROPERTY_NAME = "bigtable.data-jwt-audience";

private static final String PROJECT_PROPERTY_NAME = "bigtable.project";
private static final String INSTANCE_PROPERTY_NAME = "bigtable.instance";
Expand Down Expand Up @@ -106,6 +107,7 @@ static CloudEnv fromSystemProperties() {
return new CloudEnv(
getOptionalProperty(DATA_ENDPOINT_PROPERTY_NAME, ""),
getOptionalProperty(ADMIN_ENDPOINT_PROPERTY_NAME, ""),
getOptionalProperty(DATA_JWT_OVERRIDE_PROPERTY_NAME, ""),
getOptionalProperty(CMEK_KMS_KEY_PROPERTY_NAME, ""),
getRequiredProperty(PROJECT_PROPERTY_NAME),
getRequiredProperty(INSTANCE_PROPERTY_NAME),
Expand All @@ -117,6 +119,7 @@ static CloudEnv fromSystemProperties() {
private CloudEnv(
@Nullable String dataEndpoint,
@Nullable String adminEndpoint,
@Nullable String jwtAudienceOverride,
@Nullable String kmsKeyName,
String projectId,
String instanceId,
Expand All @@ -137,6 +140,9 @@ private CloudEnv(
if (!Strings.isNullOrEmpty(appProfileId)) {
dataSettings.setAppProfileId(appProfileId);
}
if (!Strings.isNullOrEmpty(jwtAudienceOverride)) {
dataSettings.stubSettings().setJwtAudience(jwtAudienceOverride);
}

configureConnection(dataSettings.stubSettings());
configureUserAgent(dataSettings.stubSettings());
Expand Down
Loading