From bdbaab12c1d972264fb60217a207975d51a437d6 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 20 Dec 2023 15:56:07 -0500 Subject: [PATCH 1/7] feat: Full endpoint resolution --- .../InstantiatingGrpcChannelProvider.java | 13 +- .../InstantiatingGrpcChannelProviderTest.java | 19 ++ gax-java/gax/clirr-ignored-differences.xml | 10 + .../com/google/api/gax/rpc/ClientContext.java | 36 ++-- .../google/api/gax/rpc/EndpointContext.java | 98 ++++++++- .../com/google/api/gax/rpc/StubSettings.java | 17 ++ .../google/api/gax/rpc/ClientContextTest.java | 81 ++++++- .../api/gax/rpc/EndpointContextTest.java | 197 ++++++++++++++++-- .../api/gax/rpc/testing/FakeStubSettings.java | 5 + 9 files changed, 435 insertions(+), 41 deletions(-) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index b92f9ca7a4..2703d13486 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -295,6 +295,10 @@ private void logDirectPathMisconfig() { Level.WARNING, "DirectPath is misconfigured. DirectPath is only available in a GCE environment."); } + if (!canUseDirectPathWithUniverseDomain()) { + LOG.log( + Level.WARNING, "DirectPath will only work in the the googleapis.com Universe Domain"); + } } } } @@ -325,6 +329,10 @@ static boolean isOnComputeEngine() { return false; } + private boolean canUseDirectPathWithUniverseDomain() { + return endpoint.contains("googleapis.com"); + } + @VisibleForTesting ChannelCredentials createMtlsChannelCredentials() throws IOException, GeneralSecurityException { if (mtlsProvider.useMtlsClientCertificate()) { @@ -356,7 +364,10 @@ private ManagedChannel createSingleChannel() throws IOException { // Check DirectPath traffic. boolean useDirectPathXds = false; - if (isDirectPathEnabled() && isNonDefaultServiceAccountAllowed() && isOnComputeEngine()) { + if (isDirectPathEnabled() + && isNonDefaultServiceAccountAllowed() + && isOnComputeEngine() + && canUseDirectPathWithUniverseDomain()) { CallCredentials callCreds = MoreCallCredentials.from(credentials); ChannelCredentials channelCreds = GoogleDefaultChannelCredentials.newBuilder().callCredentials(callCreds).build(); diff --git a/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java b/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java index edd7a73768..9fdea5e398 100644 --- a/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java +++ b/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java @@ -290,6 +290,7 @@ public void testDirectPathXdsEnabled() throws IOException { InstantiatingGrpcChannelProvider.newBuilder() .setAttemptDirectPath(true) .setAttemptDirectPathXds() + .setEndpoint("test.googleapis.com:443") .build(); assertThat(provider.isDirectPathXdsEnabled()).isTrue(); @@ -528,6 +529,7 @@ public void testLogDirectPathMisconfigWrongCredential() { InstantiatingGrpcChannelProvider.newBuilder() .setAttemptDirectPathXds() .setAttemptDirectPath(true) + .setEndpoint("test.googleapis.com:443") .build(); assertThat(logHandler.getAllMessages()) .contains( @@ -545,6 +547,7 @@ public void testLogDirectPathMisconfigNotOnGCE() { .setAttemptDirectPathXds() .setAttemptDirectPath(true) .setAllowNonDefaultServiceAccount(true) + .setEndpoint("test.googleapis.com:443") .build(); if (!InstantiatingGrpcChannelProvider.isOnComputeEngine()) { assertThat(logHandler.getAllMessages()) @@ -554,6 +557,22 @@ public void testLogDirectPathMisconfigNotOnGCE() { InstantiatingGrpcChannelProvider.LOG.removeHandler(logHandler); } + @Test + public void testLogDirectPathMisconfigNotInGDU() { + FakeLogHandler logHandler = new FakeLogHandler(); + InstantiatingGrpcChannelProvider.LOG.addHandler(logHandler); + InstantiatingGrpcChannelProvider provider = + InstantiatingGrpcChannelProvider.newBuilder() + .setAttemptDirectPathXds() + .setAttemptDirectPath(true) + .setAllowNonDefaultServiceAccount(true) + .setEndpoint("test.random.endpoint.com:443") + .build(); + assertThat(logHandler.getAllMessages()) + .contains("DirectPath will only work in the the googleapis.com Universe Domain"); + InstantiatingGrpcChannelProvider.LOG.removeHandler(logHandler); + } + private static class FakeLogHandler extends Handler { List records = new ArrayList<>(); diff --git a/gax-java/gax/clirr-ignored-differences.xml b/gax-java/gax/clirr-ignored-differences.xml index 690b74ee71..dd54f7b6c2 100644 --- a/gax-java/gax/clirr-ignored-differences.xml +++ b/gax-java/gax/clirr-ignored-differences.xml @@ -25,4 +25,14 @@ com/google/api/gax/rpc/TransportChannelProvider * getEndpoint() + + 7012 + com/google/api/gax/rpc/TransportChannelProvider + * needsResolvedEndpoint() + + + 7013 + com/google/api/gax/rpc/ClientContext* + * *UniverseDomain*(*) + diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 49c43c4060..10dea2fdfd 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -104,6 +104,9 @@ public abstract class ClientContext { @Nullable abstract String getServiceName(); + @Nullable + public abstract String getUniverseDomain(); + @Nullable public abstract String getEndpoint(); @@ -157,15 +160,29 @@ public static ClientContext create(StubSettings settings) throws IOException { final ScheduledExecutorService backgroundExecutor = backgroundExecutorProvider.getExecutor(); Credentials credentials = settings.getCredentialsProvider().getCredentials(); + boolean usingGDCH = credentials instanceof GdchCredentials; + EndpointContext endpointContext = + EndpointContext.newBuilder() + .setServiceName(settings.getServiceName()) + .setUniverseDomain(settings.getUniverseDomain()) + .setClientSettingsEndpoint(settings.getEndpoint()) + .setTransportChannelProviderEndpoint( + settings.getTransportChannelProvider().getEndpoint()) + .setMtlsEndpoint(settings.getMtlsEndpoint()) + .setSwitchToMtlsEndpointAllowed(settings.getSwitchToMtlsEndpointAllowed()) + .setUsingGDCH(usingGDCH) + .build(); + String endpoint = endpointContext.getResolvedEndpoint(); + String universeDomain = endpointContext.getResolvedUniverseDomain(); String settingsGdchApiAudience = settings.getGdchApiAudience(); - if (credentials instanceof GdchCredentials) { + if (usingGDCH) { // We recompute the GdchCredentials with the audience String audienceString; if (!Strings.isNullOrEmpty(settingsGdchApiAudience)) { audienceString = settingsGdchApiAudience; - } else if (!Strings.isNullOrEmpty(settings.getEndpoint())) { - audienceString = settings.getEndpoint(); + } else if (!Strings.isNullOrEmpty(endpoint)) { + audienceString = endpoint; } else { throw new IllegalArgumentException("Could not infer GDCH api audience from settings"); } @@ -204,16 +221,6 @@ public static ClientContext create(StubSettings settings) throws IOException { if (transportChannelProvider.needsCredentials() && credentials != null) { transportChannelProvider = transportChannelProvider.withCredentials(credentials); } - EndpointContext endpointContext = - EndpointContext.newBuilder() - .setServiceName(settings.getServiceName()) - .setClientSettingsEndpoint(settings.getEndpoint()) - .setTransportChannelProviderEndpoint( - settings.getTransportChannelProvider().getEndpoint()) - .setMtlsEndpoint(settings.getMtlsEndpoint()) - .setSwitchToMtlsEndpointAllowed(settings.getSwitchToMtlsEndpointAllowed()) - .build(); - String endpoint = endpointContext.getResolvedEndpoint(); if (transportChannelProvider.needsEndpoint()) { transportChannelProvider = transportChannelProvider.withEndpoint(endpoint); } @@ -264,6 +271,7 @@ public static ClientContext create(StubSettings settings) throws IOException { .setClock(clock) .setDefaultCallContext(defaultCallContext) .setServiceName(settings.getServiceName()) + .setUniverseDomain(universeDomain) .setEndpoint(settings.getEndpoint()) .setQuotaProjectId(settings.getQuotaProjectId()) .setStreamWatchdog(watchdog) @@ -332,6 +340,8 @@ public abstract static class Builder { // Package-Private scope for internal use only. Shared between StubSettings and ClientContext abstract Builder setServiceName(String serviceName); + public abstract Builder setUniverseDomain(String universeDomain); + public abstract Builder setEndpoint(String endpoint); public abstract Builder setQuotaProjectId(String QuotaProjectId); diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index 8f7a6eecaf..c3c7de3fb7 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -33,13 +33,30 @@ import com.google.api.gax.rpc.mtls.MtlsProvider; import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; import java.io.IOException; import javax.annotation.Nullable; -/** Contains the fields required to resolve the endpoint */ +/** Contains the fields required to resolve the endpoint and Universe Domain */ @InternalApi @AutoValue public abstract class EndpointContext { + // Default to port 443 for HTTPS. Using HTTP requires explicitly setting the endpoint + private static final String ENDPOINT_TEMPLATE = "SERVICE_NAME.UNIVERSE_DOMAIN:443"; + static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; + + /** + * ServiceName is host URI for Google Cloud Services. It follows the format of + * `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName of + * speech and cloudasset.googleapis.com would have a ServiceName of cloudasset. + */ + // TODO: Remove @Nullable after first release 2024 (Builder will default to ""). + @Nullable + public abstract String serviceName(); + + @Nullable + public abstract String universeDomain(); + /** * ServiceName is host URI for Google Cloud Services. It follows the format of * `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName of @@ -69,28 +86,76 @@ public abstract class EndpointContext { @Nullable public abstract MtlsProvider mtlsProvider(); + public abstract boolean usingGDCH(); + public abstract Builder toBuilder(); private String resolvedEndpoint; + private String resolvedUniverseDomain; public static Builder newBuilder() { - return new AutoValue_EndpointContext.Builder().setSwitchToMtlsEndpointAllowed(false); + return new AutoValue_EndpointContext.Builder() + .setSwitchToMtlsEndpointAllowed(false) + .setUsingGDCH(false); } + /** Determines the fully resolved endpoint and universe domain values */ @VisibleForTesting void determineEndpoint() throws IOException { MtlsProvider mtlsProvider = mtlsProvider() == null ? new MtlsProvider() : mtlsProvider(); + // TransportChannelProvider's endpoint will override the ClientSettings' endpoint String customEndpoint = transportChannelProviderEndpoint() == null ? clientSettingsEndpoint() : transportChannelProviderEndpoint(); - resolvedEndpoint = - mtlsEndpointResolver( - customEndpoint, mtlsEndpoint(), switchToMtlsEndpointAllowed(), mtlsProvider); + + // GDC-H has a separate flow + if (usingGDCH()) { + determineGDCHEndpoint(customEndpoint); + return; + } + // Check for "" (empty string) + if (universeDomain() != null && universeDomain().isEmpty()) { + throw new IllegalArgumentException("The universe domain value cannot be empty."); + } + // Universe Domain defaults to the GDU if it's not provided by the user. + resolvedUniverseDomain = universeDomain() != null ? universeDomain() : GOOGLE_DEFAULT_UNIVERSE; + + if (Strings.isNullOrEmpty(customEndpoint)) { + customEndpoint = buildEndpointTemplate(serviceName(), resolvedUniverseDomain); + resolvedEndpoint = + mtlsEndpointResolver( + customEndpoint, mtlsEndpoint(), switchToMtlsEndpointAllowed(), mtlsProvider); + // Check if mTLS is configured with non-GDU + if (resolvedEndpoint.equals(mtlsEndpoint()) + && !resolvedUniverseDomain.equals(GOOGLE_DEFAULT_UNIVERSE)) { + throw new IllegalArgumentException( + "mTLS is not supported in any universe other than googleapis.com"); + } + } else { + resolvedEndpoint = customEndpoint; + } + } + + // GDC-H has no concept of Universe Domain. Do not set the resolvedUniverseDomain value + private void determineGDCHEndpoint(String customEndpoint) { + if (universeDomain() != null) { + throw new IllegalArgumentException( + "Universe domain configuration is incompatible with GDC-H"); + } else if (customEndpoint == null) { + resolvedEndpoint = buildEndpointTemplate(serviceName(), GOOGLE_DEFAULT_UNIVERSE); + } else { + resolvedEndpoint = customEndpoint; + } + } + + // Construct the endpoint with the template + private String buildEndpointTemplate(String serviceName, String resolvedUniverseDomain) { + return ENDPOINT_TEMPLATE + .replace("SERVICE_NAME", serviceName) + .replace("UNIVERSE_DOMAIN", resolvedUniverseDomain); } - // This takes in parameters because determineEndpoint()'s logic will be updated - // to pass custom values in. // Follows https://google.aip.dev/auth/4114 for resolving the endpoint @VisibleForTesting String mtlsEndpointResolver( @@ -123,6 +188,14 @@ public String getResolvedEndpoint() { return resolvedEndpoint; } + /** + * The resolved Universe Domain is the computed Universe Domain after accounting for the custom + * Universe Domain + */ + public String getResolvedUniverseDomain() { + return resolvedUniverseDomain; + } + @AutoValue.Builder public abstract static class Builder { /** @@ -132,6 +205,15 @@ public abstract static class Builder { */ public abstract Builder setServiceName(String serviceName); + public abstract Builder setUniverseDomain(String universeDomain); + + /** + * ServiceName is host URI for Google Cloud Services. It follows the format of + * `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName + * of speech and cloudasset.googleapis.com would have a ServiceName of cloudasset. + */ + public abstract Builder setServiceName(String serviceName); + /** * ClientSettingsEndpoint is the endpoint value set via the ClientSettings/StubSettings classes. */ @@ -149,6 +231,8 @@ public abstract static class Builder { public abstract Builder setMtlsProvider(MtlsProvider mtlsProvider); + public abstract Builder setUsingGDCH(boolean usingGDCH); + abstract EndpointContext autoBuild(); public EndpointContext build() throws IOException { diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java index f534dc07e1..f446fd3d11 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java @@ -81,6 +81,7 @@ public abstract class StubSettings> { @Nonnull private final ApiTracerFactory tracerFactory; // Track if deprecated setExecutorProvider is called private boolean deprecatedExecutorProviderSet; + private final String universeDomain; /** * Indicate when creating transport whether it is allowed to use mTLS endpoint instead of the @@ -108,6 +109,7 @@ protected StubSettings(Builder builder) { this.tracerFactory = builder.tracerFactory; this.deprecatedExecutorProviderSet = builder.deprecatedExecutorProviderSet; this.gdchApiAudience = builder.gdchApiAudience; + this.universeDomain = builder.universeDomain; } /** @deprecated Please use {@link #getBackgroundExecutorProvider()}. */ @@ -147,6 +149,10 @@ public String getServiceName() { return ""; } + public final String getUniverseDomain() { + return universeDomain; + } + public final String getEndpoint() { return endpoint; } @@ -199,6 +205,7 @@ public String toString() { .add("headerProvider", headerProvider) .add("internalHeaderProvider", internalHeaderProvider) .add("clock", clock) + .add("universeDomain", universeDomain) .add("endpoint", endpoint) .add("mtlsEndpoint", mtlsEndpoint) .add("switchToMtlsEndpointAllowed", switchToMtlsEndpointAllowed) @@ -230,6 +237,7 @@ public abstract static class Builder< @Nonnull private Duration streamWatchdogCheckInterval; @Nonnull private ApiTracerFactory tracerFactory; private boolean deprecatedExecutorProviderSet; + private String universeDomain; /** * Indicate when creating transport whether it is allowed to use mTLS endpoint instead of the @@ -257,6 +265,7 @@ protected Builder(StubSettings settings) { this.tracerFactory = settings.tracerFactory; this.deprecatedExecutorProviderSet = settings.deprecatedExecutorProviderSet; this.gdchApiAudience = settings.gdchApiAudience; + this.universeDomain = settings.universeDomain; } /** Get Quota Project ID from Client Context * */ @@ -293,6 +302,7 @@ protected Builder(ClientContext clientContext) { this.tracerFactory = BaseApiTracerFactory.getInstance(); this.deprecatedExecutorProviderSet = false; this.gdchApiAudience = null; + this.universeDomain = null; } else { ExecutorProvider fixedExecutorProvider = FixedExecutorProvider.create(clientContext.getExecutor()); @@ -316,6 +326,7 @@ protected Builder(ClientContext clientContext) { this.tracerFactory = clientContext.getTracerFactory(); this.quotaProjectId = getQuotaProjectIdFromClientContext(clientContext); this.gdchApiAudience = clientContext.getGdchApiAudience(); + this.universeDomain = clientContext.getUniverseDomain(); } } @@ -428,6 +439,11 @@ public B setClock(ApiClock clock) { return self(); } + public B setUniverseDomain(String universeDomain) { + this.universeDomain = universeDomain; + return self(); + } + public B setEndpoint(String endpoint) { this.endpoint = endpoint; this.switchToMtlsEndpointAllowed = false; @@ -577,6 +593,7 @@ public String toString() { .add("headerProvider", headerProvider) .add("internalHeaderProvider", internalHeaderProvider) .add("clock", clock) + .add("universeDomain", universeDomain) .add("endpoint", endpoint) .add("mtlsEndpoint", mtlsEndpoint) .add("switchToMtlsEndpointAllowed", switchToMtlsEndpointAllowed) diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java index 096349971c..bffa6165da 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java @@ -73,6 +73,7 @@ @RunWith(JUnit4.class) public class ClientContextTest { private static final String DEFAULT_ENDPOINT = "test.googleapis.com"; + private static final String DEFAULT_UNIVERSE_DOMAIN = "googleapis.com"; private static class InterceptingExecutor extends ScheduledThreadPoolExecutor { boolean shutdownCalled = false; @@ -182,6 +183,11 @@ public String getEndpoint() { return endpoint; } + @Override + public boolean needsResolvedEndpoint() { + return true; + } + @Override public TransportChannelProvider withEndpoint(String endpoint) { return new FakeTransportProvider( @@ -788,10 +794,12 @@ private TransportChannelProvider getFakeTransportChannelProvider() { FakeTransportChannel.create(new FakeChannel()), null, true, null, null, DEFAULT_ENDPOINT); } + // EndpointContext will construct a valid endpoint if nothing is provided @Test - public void testCreateClientContext_withGdchCredentialNoAudienceNoEndpoint_throws() - throws IOException { - TransportChannelProvider transportChannelProvider = getFakeTransportChannelProvider(); + public void testCreateClientContext_withGdchCredentialNoAudienceNoEndpoint() throws IOException { + TransportChannelProvider transportChannelProvider = + new FakeTransportProvider( + FakeTransportChannel.create(new FakeChannel()), null, true, null, null, null); Credentials creds = getMockGdchCredentials(); CredentialsProvider provider = FixedCredentialsProvider.create(creds); @@ -800,6 +808,34 @@ public void testCreateClientContext_withGdchCredentialNoAudienceNoEndpoint_throw clientSettingsBuilder.setCredentialsProvider(provider); clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); + ClientContext context = ClientContext.create(clientSettingsBuilder.build()); + + Credentials fromContext = context.getCredentials(); + Credentials fromProvider = provider.getCredentials(); + assertNotNull(fromProvider); + assertNotNull(fromContext); + assertThat(fromContext).isInstanceOf(GdchCredentials.class); + assertThat(fromProvider).isInstanceOf(GdchCredentials.class); + assertNotSame(fromContext, fromProvider); + verify((GdchCredentials) fromProvider, times(1)) + .createWithGdchAudience(URI.create("test.googleapis.com:443")); + } + + @Test + public void testCreateClientContext_withGdchCredentialNoAudienceEmptyEndpoint_throws() + throws IOException { + TransportChannelProvider transportChannelProvider = + new FakeTransportProvider( + FakeTransportChannel.create(new FakeChannel()), null, true, null, null, null); + Credentials creds = getMockGdchCredentials(); + + CredentialsProvider provider = FixedCredentialsProvider.create(creds); + StubSettings settings = + new FakeStubSettings.Builder().setGdchApiAudience(null).setEndpoint("").build(); + FakeClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings); + clientSettingsBuilder.setCredentialsProvider(provider); + clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); + // should throw IllegalArgumentException ex = assertThrows( @@ -811,7 +847,9 @@ public void testCreateClientContext_withGdchCredentialNoAudienceNoEndpoint_throw @Test public void testCreateClientContext_withGdchCredentialWithoutAudienceWithEndpoint_correct() throws IOException { - TransportChannelProvider transportChannelProvider = getFakeTransportChannelProvider(); + TransportChannelProvider transportChannelProvider = + new FakeTransportProvider( + FakeTransportChannel.create(new FakeChannel()), null, true, null, null, null); Credentials creds = getMockGdchCredentials(); // it should correctly create a client context with gdch creds and null audience @@ -934,6 +972,7 @@ public void testCreateClientContext_SetEndpointViaClientSettings() throws IOExce ClientSettings clientSettings = clientSettingsBuilder.build(); ClientContext clientContext = ClientContext.create(clientSettings); assertThat(clientContext.getEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + assertThat(clientContext.getUniverseDomain()).isEqualTo(DEFAULT_UNIVERSE_DOMAIN); } @Test @@ -955,6 +994,7 @@ public void testCreateClientContext_SetEndpointViaTransportChannelProvider() thr ClientContext clientContext = ClientContext.create(clientSettings); // ClientContext.getEndpoint() currently always refers to the ClientSettingsEndpoint value assertThat(clientContext.getEndpoint()).isEqualTo(null); + assertThat(clientContext.getUniverseDomain()).isEqualTo(DEFAULT_UNIVERSE_DOMAIN); } @Test @@ -980,5 +1020,38 @@ public void testCreateClientContext_SetEndpointViaClientSettingsAndTransportChan ClientContext clientContext = ClientContext.create(clientSettings); // ClientContext.getEndpoint() currently always refers to the ClientSettingsEndpoint value assertThat(clientContext.getEndpoint()).isEqualTo(clientSettingsEndpoint); + assertThat(clientContext.getUniverseDomain()).isEqualTo(DEFAULT_UNIVERSE_DOMAIN); + } + + @Test + public void testCreateClientContext_doNotSetUniverseDomain() throws IOException { + TransportChannelProvider transportChannelProvider = + new FakeTransportProvider( + FakeTransportChannel.create(new FakeChannel()), null, true, null, null, null); + StubSettings settings = new FakeStubSettings.Builder().setEndpoint(null).build(); + ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings); + clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); + clientSettingsBuilder.setCredentialsProvider( + FixedCredentialsProvider.create(Mockito.mock(Credentials.class))); + ClientSettings clientSettings = clientSettingsBuilder.build(); + ClientContext clientContext = ClientContext.create(clientSettings); + assertThat(clientContext.getUniverseDomain()).isEqualTo(DEFAULT_UNIVERSE_DOMAIN); + } + + @Test + public void testCreateClientContext_setUniverseDomain() throws IOException { + TransportChannelProvider transportChannelProvider = + new FakeTransportProvider( + FakeTransportChannel.create(new FakeChannel()), null, true, null, null, null); + String universeDomain = "testdomain.com"; + StubSettings settings = + new FakeStubSettings.Builder().setEndpoint(null).setUniverseDomain(universeDomain).build(); + ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings); + clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); + clientSettingsBuilder.setCredentialsProvider( + FixedCredentialsProvider.create(Mockito.mock(Credentials.class))); + ClientSettings clientSettings = clientSettingsBuilder.build(); + ClientContext clientContext = ClientContext.create(clientSettings); + assertThat(clientContext.getUniverseDomain()).isEqualTo(universeDomain); } } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java index bb403d0971..7fc56ab322 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java @@ -35,24 +35,25 @@ import com.google.api.gax.rpc.testing.FakeMtlsProvider; import com.google.common.truth.Truth; import java.io.IOException; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class EndpointContextTest { - private static final String DEFAULT_ENDPOINT = "test.googleapis.com"; - private static final String DEFAULT_MTLS_ENDPOINT = "test.mtls.googleapis.com"; - private static EndpointContext defaultEndpointContext; + private static final String DEFAULT_ENDPOINT = "test.googleapis.com:443"; + private static final String DEFAULT_MTLS_ENDPOINT = "test.mtls.googleapis.com:443"; + private EndpointContext.Builder defaultEndpointContextBuilder; - @BeforeClass - public static void setUp() throws IOException { - defaultEndpointContext = + @Before + public void setUp() throws IOException { + defaultEndpointContextBuilder = EndpointContext.newBuilder() + .setServiceName("test") + .setUniverseDomain(EndpointContext.GOOGLE_DEFAULT_UNIVERSE) .setClientSettingsEndpoint(DEFAULT_ENDPOINT) - .setMtlsEndpoint(DEFAULT_MTLS_ENDPOINT) - .build(); + .setMtlsEndpoint(DEFAULT_MTLS_ENDPOINT); } @Test @@ -67,8 +68,9 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsFalse() throws IOException "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = false; + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - defaultEndpointContext.mtlsEndpointResolver( + endpointContext.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_ENDPOINT); } @@ -85,8 +87,9 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageAuto() throw "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - defaultEndpointContext.mtlsEndpointResolver( + endpointContext.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_MTLS_ENDPOINT); } @@ -103,8 +106,9 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageAlways() thr "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - defaultEndpointContext.mtlsEndpointResolver( + endpointContext.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_MTLS_ENDPOINT); } @@ -121,8 +125,9 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageNever() thro "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - defaultEndpointContext.mtlsEndpointResolver( + endpointContext.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_ENDPOINT); } @@ -141,14 +146,15 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageNever() thro "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - defaultEndpointContext.mtlsEndpointResolver( + endpointContext.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_ENDPOINT); } @Test - public void mtlsEndpointResolver_getKeyStore_throwsIOException() { + public void mtlsEndpointResolver_getKeyStore_throwsIOException() throws IOException { boolean useClientCertificate = true; boolean throwExceptionForGetKeyStore = true; MtlsProvider mtlsProvider = @@ -159,13 +165,172 @@ public void mtlsEndpointResolver_getKeyStore_throwsIOException() { "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); assertThrows( IOException.class, () -> - defaultEndpointContext.mtlsEndpointResolver( + endpointContext.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)); } + + @Test + public void determineEndpoint_noUniverseDomain_usesClientSettingsEndpoint() throws IOException { + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + } + + @Test + public void determineEndpoint_noUniverseDomain_usesTransportChannelProviderEndpoint() + throws IOException { + String transportChannelProviderEndpoint = "random.endpoint.com:443"; + EndpointContext endpointContext = + defaultEndpointContextBuilder + .setClientSettingsEndpoint(null) + .setTransportChannelProviderEndpoint(transportChannelProviderEndpoint) + .build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()) + .isEqualTo(transportChannelProviderEndpoint); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + } + + @Test + public void determineEndpoint_noUniverseDomain_overrideUsesTransportChannelProviderEndpoint() + throws IOException { + String transportChannelProviderEndpoint = "random.endpoint.com"; + EndpointContext endpointContext = + defaultEndpointContextBuilder + .setClientSettingsEndpoint(DEFAULT_ENDPOINT) + .setTransportChannelProviderEndpoint(transportChannelProviderEndpoint) + .build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()) + .isEqualTo(transportChannelProviderEndpoint); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + } + + @Test + public void determineEndpoint_emptyUniverseDomain_throwsIllegalArgumentException() { + EndpointContext.Builder endpointContextBuilder = + defaultEndpointContextBuilder.setUniverseDomain(""); + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, endpointContextBuilder::build); + Truth.assertThat(exception.getMessage()) + .isEqualTo("The universe domain value cannot be empty."); + } + + @Test + public void determineEndpoint_GDUUniverseDomain() throws IOException { + EndpointContext endpointContext = defaultEndpointContextBuilder.build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + } + + @Test + public void determineEndpoint_nonGDUUniverseDomain() throws IOException { + String universeDomain = "random.com"; + EndpointContext endpointContext = + defaultEndpointContextBuilder.setUniverseDomain(universeDomain).build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isEqualTo(universeDomain); + } + + @Test + public void determineEndpoint_noUniverseDomain_noEndpoints() throws IOException { + String expectedEndpoint = "random.googleapis.com:443"; + EndpointContext endpointContext = + defaultEndpointContextBuilder + .setServiceName("random") + .setClientSettingsEndpoint(null) + .setTransportChannelProviderEndpoint(null) + .build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(expectedEndpoint); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + } + + @Test + public void determineEndpoint_mtlsConfigured_GDU() throws IOException { + MtlsProvider mtlsProvider = + new FakeMtlsProvider( + true, + MtlsProvider.MtlsEndpointUsagePolicy.ALWAYS, + FakeMtlsProvider.createTestMtlsKeyStore(), + "", + false); + EndpointContext endpointContext = + defaultEndpointContextBuilder + .setClientSettingsEndpoint(null) + .setTransportChannelProviderEndpoint(null) + .setSwitchToMtlsEndpointAllowed(true) + .setMtlsProvider(mtlsProvider) + .build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_MTLS_ENDPOINT); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + } + + @Test + public void determineEndpoint_mtlsConfigured_nonGDU_throwsIllegalArgumentException() + throws IOException { + MtlsProvider mtlsProvider = + new FakeMtlsProvider( + true, + MtlsProvider.MtlsEndpointUsagePolicy.ALWAYS, + FakeMtlsProvider.createTestMtlsKeyStore(), + "", + false); + EndpointContext.Builder endpointContextBuilder = + defaultEndpointContextBuilder + .setUniverseDomain("random.com") + .setClientSettingsEndpoint(null) + .setTransportChannelProviderEndpoint(null) + .setSwitchToMtlsEndpointAllowed(true) + .setMtlsProvider(mtlsProvider); + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, endpointContextBuilder::build); + Truth.assertThat(exception.getMessage()) + .isEqualTo("mTLS is not supported in any universe other than googleapis.com"); + } + + @Test + public void determineEndpoint_gdchFlow_setUniverseDomain() throws IOException { + EndpointContext.Builder endpointContextBuilder = + defaultEndpointContextBuilder.setUsingGDCH(true); + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, endpointContextBuilder::build); + Truth.assertThat(exception.getMessage()) + .isEqualTo("Universe domain configuration is incompatible with GDC-H"); + } + + @Test + public void determineEndpoint_gdchFlow_noUniverseDomain_noCustomEndpoint() throws IOException { + EndpointContext endpointContext = + defaultEndpointContextBuilder + .setUniverseDomain(null) + .setUsingGDCH(true) + .setClientSettingsEndpoint(null) + .build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); + } + + @Test + public void determineEndpoint_gdchFlow_noUniverseDomain_customEndpoint() throws IOException { + String clientSettingsEndpoint = "random.endpoint.com:443"; + EndpointContext endpointContext = + defaultEndpointContextBuilder + .setUniverseDomain(null) + .setUsingGDCH(true) + .setClientSettingsEndpoint(clientSettingsEndpoint) + .build(); + Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(clientSettingsEndpoint); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); + } } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeStubSettings.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeStubSettings.java index 2c41d75a47..c5f0cc81f4 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeStubSettings.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeStubSettings.java @@ -41,6 +41,11 @@ private FakeStubSettings(Builder builder) throws IOException { super(builder); } + @Override + public String getServiceName() { + return "test"; + } + @Override public StubSettings.Builder toBuilder() { return new Builder(this); From bf878b91bcd9b6f9937eea15b3c43c10c39d1ebc Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 20 Dec 2023 16:15:15 -0500 Subject: [PATCH 2/7] chore: Fix lint issues --- gax-java/gax/clirr-ignored-differences.xml | 4 ---- .../com/google/api/gax/rpc/EndpointContext.java | 16 ---------------- .../google/api/gax/rpc/ClientContextTest.java | 5 ----- 3 files changed, 25 deletions(-) diff --git a/gax-java/gax/clirr-ignored-differences.xml b/gax-java/gax/clirr-ignored-differences.xml index dd54f7b6c2..1c4dd28a3c 100644 --- a/gax-java/gax/clirr-ignored-differences.xml +++ b/gax-java/gax/clirr-ignored-differences.xml @@ -25,10 +25,6 @@ com/google/api/gax/rpc/TransportChannelProvider * getEndpoint() - - 7012 - com/google/api/gax/rpc/TransportChannelProvider - * needsResolvedEndpoint() 7013 diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index c3c7de3fb7..161ae64181 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -50,21 +50,12 @@ public abstract class EndpointContext { * `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName of * speech and cloudasset.googleapis.com would have a ServiceName of cloudasset. */ - // TODO: Remove @Nullable after first release 2024 (Builder will default to ""). @Nullable public abstract String serviceName(); @Nullable public abstract String universeDomain(); - /** - * ServiceName is host URI for Google Cloud Services. It follows the format of - * `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName of - * speech and cloudasset.googleapis.com would have a ServiceName of cloudasset. - */ - @Nullable - public abstract String serviceName(); - /** * ClientSettingsEndpoint is the endpoint value set via the ClientSettings/StubSettings classes. */ @@ -207,13 +198,6 @@ public abstract static class Builder { public abstract Builder setUniverseDomain(String universeDomain); - /** - * ServiceName is host URI for Google Cloud Services. It follows the format of - * `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName - * of speech and cloudasset.googleapis.com would have a ServiceName of cloudasset. - */ - public abstract Builder setServiceName(String serviceName); - /** * ClientSettingsEndpoint is the endpoint value set via the ClientSettings/StubSettings classes. */ diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java index bffa6165da..5e23206ee9 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java @@ -183,11 +183,6 @@ public String getEndpoint() { return endpoint; } - @Override - public boolean needsResolvedEndpoint() { - return true; - } - @Override public TransportChannelProvider withEndpoint(String endpoint) { return new FakeTransportProvider( From 13aa12ee08399134cafea0185592a55c7a8962d0 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 27 Dec 2023 21:51:08 -0500 Subject: [PATCH 3/7] chore: Address PR comments --- .../google/api/gax/rpc/EndpointContext.java | 65 ++++++++++--------- .../api/gax/rpc/EndpointContextTest.java | 34 +++++----- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index 161ae64181..757777e28d 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -41,8 +41,6 @@ @InternalApi @AutoValue public abstract class EndpointContext { - // Default to port 443 for HTTPS. Using HTTP requires explicitly setting the endpoint - private static final String ENDPOINT_TEMPLATE = "SERVICE_NAME.UNIVERSE_DOMAIN:443"; static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; /** @@ -82,7 +80,8 @@ public abstract class EndpointContext { public abstract Builder toBuilder(); private String resolvedEndpoint; - private String resolvedUniverseDomain; + // Default to the GDU + private String resolvedUniverseDomain = GOOGLE_DEFAULT_UNIVERSE; public static Builder newBuilder() { return new AutoValue_EndpointContext.Builder() @@ -90,9 +89,19 @@ public static Builder newBuilder() { .setUsingGDCH(false); } + private void determineUniverseDomain() { + // Check for "" (empty string) + if (universeDomain() != null && universeDomain().isEmpty()) { + throw new IllegalArgumentException("The universe domain value cannot be empty."); + } + // Override with user set universe domain if provided + if (universeDomain() != null) { + resolvedUniverseDomain = universeDomain(); + } + } + /** Determines the fully resolved endpoint and universe domain values */ - @VisibleForTesting - void determineEndpoint() throws IOException { + private void determineEndpoint() throws IOException { MtlsProvider mtlsProvider = mtlsProvider() == null ? new MtlsProvider() : mtlsProvider(); // TransportChannelProvider's endpoint will override the ClientSettings' endpoint String customEndpoint = @@ -102,49 +111,44 @@ void determineEndpoint() throws IOException { // GDC-H has a separate flow if (usingGDCH()) { - determineGDCHEndpoint(customEndpoint); + resolvedEndpoint = determineGDCHEndpoint(customEndpoint); return; } - // Check for "" (empty string) - if (universeDomain() != null && universeDomain().isEmpty()) { - throw new IllegalArgumentException("The universe domain value cannot be empty."); - } - // Universe Domain defaults to the GDU if it's not provided by the user. - resolvedUniverseDomain = universeDomain() != null ? universeDomain() : GOOGLE_DEFAULT_UNIVERSE; + // If user does not provide a custom endpoint, build one with the universe domain if (Strings.isNullOrEmpty(customEndpoint)) { customEndpoint = buildEndpointTemplate(serviceName(), resolvedUniverseDomain); - resolvedEndpoint = - mtlsEndpointResolver( - customEndpoint, mtlsEndpoint(), switchToMtlsEndpointAllowed(), mtlsProvider); - // Check if mTLS is configured with non-GDU - if (resolvedEndpoint.equals(mtlsEndpoint()) - && !resolvedUniverseDomain.equals(GOOGLE_DEFAULT_UNIVERSE)) { - throw new IllegalArgumentException( - "mTLS is not supported in any universe other than googleapis.com"); - } - } else { - resolvedEndpoint = customEndpoint; } + + String endpoint = + mtlsEndpointResolver( + customEndpoint, mtlsEndpoint(), switchToMtlsEndpointAllowed(), mtlsProvider); + + // Check if mTLS is configured with non-GDU + if (endpoint.equals(mtlsEndpoint()) + && !resolvedUniverseDomain.equals(GOOGLE_DEFAULT_UNIVERSE)) { + throw new IllegalArgumentException( + "mTLS is not supported in any universe other than googleapis.com"); + } + + resolvedEndpoint = endpoint; } // GDC-H has no concept of Universe Domain. Do not set the resolvedUniverseDomain value - private void determineGDCHEndpoint(String customEndpoint) { + private String determineGDCHEndpoint(String customEndpoint) { if (universeDomain() != null) { throw new IllegalArgumentException( "Universe domain configuration is incompatible with GDC-H"); } else if (customEndpoint == null) { - resolvedEndpoint = buildEndpointTemplate(serviceName(), GOOGLE_DEFAULT_UNIVERSE); + return buildEndpointTemplate(serviceName(), GOOGLE_DEFAULT_UNIVERSE); } else { - resolvedEndpoint = customEndpoint; + return customEndpoint; } } - // Construct the endpoint with the template + // Default to port 443 for HTTPS. Using HTTP requires explicitly setting the endpoint private String buildEndpointTemplate(String serviceName, String resolvedUniverseDomain) { - return ENDPOINT_TEMPLATE - .replace("SERVICE_NAME", serviceName) - .replace("UNIVERSE_DOMAIN", resolvedUniverseDomain); + return serviceName + "." + resolvedUniverseDomain + ":443"; } // Follows https://google.aip.dev/auth/4114 for resolving the endpoint @@ -221,6 +225,7 @@ public abstract static class Builder { public EndpointContext build() throws IOException { EndpointContext endpointContext = autoBuild(); + endpointContext.determineUniverseDomain(); endpointContext.determineEndpoint(); return endpointContext; } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java index 7fc56ab322..058e7c9926 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java @@ -177,15 +177,17 @@ public void mtlsEndpointResolver_getKeyStore_throwsIOException() throws IOExcept } @Test - public void determineEndpoint_noUniverseDomain_usesClientSettingsEndpoint() throws IOException { - EndpointContext endpointContext = defaultEndpointContextBuilder.build(); + public void endpointContextBuild_noUniverseDomain_usesClientSettingsEndpoint() + throws IOException { + EndpointContext endpointContext = + defaultEndpointContextBuilder.setClientSettingsEndpoint(DEFAULT_ENDPOINT).build(); Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); Truth.assertThat(endpointContext.getResolvedUniverseDomain()) .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @Test - public void determineEndpoint_noUniverseDomain_usesTransportChannelProviderEndpoint() + public void endpointContextBuild_noUniverseDomain_usesTransportChannelProviderEndpoint() throws IOException { String transportChannelProviderEndpoint = "random.endpoint.com:443"; EndpointContext endpointContext = @@ -200,7 +202,7 @@ public void determineEndpoint_noUniverseDomain_usesTransportChannelProviderEndpo } @Test - public void determineEndpoint_noUniverseDomain_overrideUsesTransportChannelProviderEndpoint() + public void endpointContextBuild_noUniverseDomain_overrideUsesTransportChannelProviderEndpoint() throws IOException { String transportChannelProviderEndpoint = "random.endpoint.com"; EndpointContext endpointContext = @@ -215,7 +217,7 @@ public void determineEndpoint_noUniverseDomain_overrideUsesTransportChannelProvi } @Test - public void determineEndpoint_emptyUniverseDomain_throwsIllegalArgumentException() { + public void endpointContextBuild_emptyStringUniverseDomain_throwsIllegalArgumentException() { EndpointContext.Builder endpointContextBuilder = defaultEndpointContextBuilder.setUniverseDomain(""); IllegalArgumentException exception = @@ -225,7 +227,7 @@ public void determineEndpoint_emptyUniverseDomain_throwsIllegalArgumentException } @Test - public void determineEndpoint_GDUUniverseDomain() throws IOException { + public void endpointContextBuild_GDUUniverseDomain() throws IOException { EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); Truth.assertThat(endpointContext.getResolvedUniverseDomain()) @@ -233,7 +235,7 @@ public void determineEndpoint_GDUUniverseDomain() throws IOException { } @Test - public void determineEndpoint_nonGDUUniverseDomain() throws IOException { + public void endpointContextBuild_nonGDUUniverseDomain() throws IOException { String universeDomain = "random.com"; EndpointContext endpointContext = defaultEndpointContextBuilder.setUniverseDomain(universeDomain).build(); @@ -242,7 +244,7 @@ public void determineEndpoint_nonGDUUniverseDomain() throws IOException { } @Test - public void determineEndpoint_noUniverseDomain_noEndpoints() throws IOException { + public void endpointContextBuild_noUniverseDomain_noEndpoints() throws IOException { String expectedEndpoint = "random.googleapis.com:443"; EndpointContext endpointContext = defaultEndpointContextBuilder @@ -256,7 +258,7 @@ public void determineEndpoint_noUniverseDomain_noEndpoints() throws IOException } @Test - public void determineEndpoint_mtlsConfigured_GDU() throws IOException { + public void endpointContextBuild_mtlsConfigured_GDU() throws IOException { MtlsProvider mtlsProvider = new FakeMtlsProvider( true, @@ -277,7 +279,7 @@ public void determineEndpoint_mtlsConfigured_GDU() throws IOException { } @Test - public void determineEndpoint_mtlsConfigured_nonGDU_throwsIllegalArgumentException() + public void endpointContextBuild_mtlsConfigured_nonGDU_throwsIllegalArgumentException() throws IOException { MtlsProvider mtlsProvider = new FakeMtlsProvider( @@ -300,7 +302,7 @@ public void determineEndpoint_mtlsConfigured_nonGDU_throwsIllegalArgumentExcepti } @Test - public void determineEndpoint_gdchFlow_setUniverseDomain() throws IOException { + public void endpointContextBuild_gdchFlow_setUniverseDomain() throws IOException { EndpointContext.Builder endpointContextBuilder = defaultEndpointContextBuilder.setUsingGDCH(true); IllegalArgumentException exception = @@ -310,7 +312,7 @@ public void determineEndpoint_gdchFlow_setUniverseDomain() throws IOException { } @Test - public void determineEndpoint_gdchFlow_noUniverseDomain_noCustomEndpoint() throws IOException { + public void endpointContextBuild_gdchFlow_noUniverseDomain_noCustomEndpoint() throws IOException { EndpointContext endpointContext = defaultEndpointContextBuilder .setUniverseDomain(null) @@ -318,11 +320,12 @@ public void determineEndpoint_gdchFlow_noUniverseDomain_noCustomEndpoint() throw .setClientSettingsEndpoint(null) .build(); Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @Test - public void determineEndpoint_gdchFlow_noUniverseDomain_customEndpoint() throws IOException { + public void endpointContextBuild_gdchFlow_noUniverseDomain_customEndpoint() throws IOException { String clientSettingsEndpoint = "random.endpoint.com:443"; EndpointContext endpointContext = defaultEndpointContextBuilder @@ -331,6 +334,7 @@ public void determineEndpoint_gdchFlow_noUniverseDomain_customEndpoint() throws .setClientSettingsEndpoint(clientSettingsEndpoint) .build(); Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(clientSettingsEndpoint); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } } From 18578827379d997246f91663bf6bda9a5eb9e84b Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 27 Dec 2023 22:58:47 -0500 Subject: [PATCH 4/7] chore: Do not set resolved universe domain for gdch --- .../java/com/google/api/gax/rpc/EndpointContext.java | 10 ++++++---- .../com/google/api/gax/rpc/EndpointContextTest.java | 6 ++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index 757777e28d..f790ac825d 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -81,7 +81,7 @@ public abstract class EndpointContext { private String resolvedEndpoint; // Default to the GDU - private String resolvedUniverseDomain = GOOGLE_DEFAULT_UNIVERSE; + private String resolvedUniverseDomain; public static Builder newBuilder() { return new AutoValue_EndpointContext.Builder() @@ -90,14 +90,16 @@ public static Builder newBuilder() { } private void determineUniverseDomain() { + // Do not set the universe domain for GDC-H + if (usingGDCH()) { + return; + } // Check for "" (empty string) if (universeDomain() != null && universeDomain().isEmpty()) { throw new IllegalArgumentException("The universe domain value cannot be empty."); } // Override with user set universe domain if provided - if (universeDomain() != null) { - resolvedUniverseDomain = universeDomain(); - } + resolvedUniverseDomain = universeDomain() != null ? universeDomain() : GOOGLE_DEFAULT_UNIVERSE; } /** Determines the fully resolved endpoint and universe domain values */ diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java index 058e7c9926..24bc578b32 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java @@ -320,8 +320,7 @@ public void endpointContextBuild_gdchFlow_noUniverseDomain_noCustomEndpoint() th .setClientSettingsEndpoint(null) .build(); Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) - .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); } @Test @@ -334,7 +333,6 @@ public void endpointContextBuild_gdchFlow_noUniverseDomain_customEndpoint() thro .setClientSettingsEndpoint(clientSettingsEndpoint) .build(); Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(clientSettingsEndpoint); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) - .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); + Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); } } From 15d510ea2c7a0879e2bd13cc7b7848ddbf2f781d Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Thu, 28 Dec 2023 12:04:09 -0500 Subject: [PATCH 5/7] chore: Move helper methods to the Builder class --- .../com/google/api/gax/rpc/ClientContext.java | 4 +- .../google/api/gax/rpc/EndpointContext.java | 230 +++++++++--------- .../api/gax/rpc/EndpointContextTest.java | 54 ++-- 3 files changed, 144 insertions(+), 144 deletions(-) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 10dea2fdfd..b122da3d45 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -172,8 +172,8 @@ public static ClientContext create(StubSettings settings) throws IOException { .setSwitchToMtlsEndpointAllowed(settings.getSwitchToMtlsEndpointAllowed()) .setUsingGDCH(usingGDCH) .build(); - String endpoint = endpointContext.getResolvedEndpoint(); - String universeDomain = endpointContext.getResolvedUniverseDomain(); + String endpoint = endpointContext.resolvedEndpoint(); + String universeDomain = endpointContext.resolvedUniverseDomain(); String settingsGdchApiAudience = settings.getGdchApiAudience(); if (usingGDCH) { diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index f790ac825d..f8d866332c 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -77,11 +77,12 @@ public abstract class EndpointContext { public abstract boolean usingGDCH(); - public abstract Builder toBuilder(); + @Nullable + public abstract String resolvedUniverseDomain(); - private String resolvedEndpoint; - // Default to the GDU - private String resolvedUniverseDomain; + public abstract String resolvedEndpoint(); + + public abstract Builder toBuilder(); public static Builder newBuilder() { return new AutoValue_EndpointContext.Builder() @@ -89,110 +90,6 @@ public static Builder newBuilder() { .setUsingGDCH(false); } - private void determineUniverseDomain() { - // Do not set the universe domain for GDC-H - if (usingGDCH()) { - return; - } - // Check for "" (empty string) - if (universeDomain() != null && universeDomain().isEmpty()) { - throw new IllegalArgumentException("The universe domain value cannot be empty."); - } - // Override with user set universe domain if provided - resolvedUniverseDomain = universeDomain() != null ? universeDomain() : GOOGLE_DEFAULT_UNIVERSE; - } - - /** Determines the fully resolved endpoint and universe domain values */ - private void determineEndpoint() throws IOException { - MtlsProvider mtlsProvider = mtlsProvider() == null ? new MtlsProvider() : mtlsProvider(); - // TransportChannelProvider's endpoint will override the ClientSettings' endpoint - String customEndpoint = - transportChannelProviderEndpoint() == null - ? clientSettingsEndpoint() - : transportChannelProviderEndpoint(); - - // GDC-H has a separate flow - if (usingGDCH()) { - resolvedEndpoint = determineGDCHEndpoint(customEndpoint); - return; - } - - // If user does not provide a custom endpoint, build one with the universe domain - if (Strings.isNullOrEmpty(customEndpoint)) { - customEndpoint = buildEndpointTemplate(serviceName(), resolvedUniverseDomain); - } - - String endpoint = - mtlsEndpointResolver( - customEndpoint, mtlsEndpoint(), switchToMtlsEndpointAllowed(), mtlsProvider); - - // Check if mTLS is configured with non-GDU - if (endpoint.equals(mtlsEndpoint()) - && !resolvedUniverseDomain.equals(GOOGLE_DEFAULT_UNIVERSE)) { - throw new IllegalArgumentException( - "mTLS is not supported in any universe other than googleapis.com"); - } - - resolvedEndpoint = endpoint; - } - - // GDC-H has no concept of Universe Domain. Do not set the resolvedUniverseDomain value - private String determineGDCHEndpoint(String customEndpoint) { - if (universeDomain() != null) { - throw new IllegalArgumentException( - "Universe domain configuration is incompatible with GDC-H"); - } else if (customEndpoint == null) { - return buildEndpointTemplate(serviceName(), GOOGLE_DEFAULT_UNIVERSE); - } else { - return customEndpoint; - } - } - - // Default to port 443 for HTTPS. Using HTTP requires explicitly setting the endpoint - private String buildEndpointTemplate(String serviceName, String resolvedUniverseDomain) { - return serviceName + "." + resolvedUniverseDomain + ":443"; - } - - // Follows https://google.aip.dev/auth/4114 for resolving the endpoint - @VisibleForTesting - String mtlsEndpointResolver( - String endpoint, - String mtlsEndpoint, - boolean switchToMtlsEndpointAllowed, - MtlsProvider mtlsProvider) - throws IOException { - if (switchToMtlsEndpointAllowed && mtlsProvider != null) { - switch (mtlsProvider.getMtlsEndpointUsagePolicy()) { - case ALWAYS: - return mtlsEndpoint; - case NEVER: - return endpoint; - default: - if (mtlsProvider.useMtlsClientCertificate() && mtlsProvider.getKeyStore() != null) { - return mtlsEndpoint; - } - return endpoint; - } - } - return endpoint; - } - - /** - * The resolved endpoint is the computed endpoint after accounting for the custom endpoints and - * mTLS configurations. - */ - public String getResolvedEndpoint() { - return resolvedEndpoint; - } - - /** - * The resolved Universe Domain is the computed Universe Domain after accounting for the custom - * Universe Domain - */ - public String getResolvedUniverseDomain() { - return resolvedUniverseDomain; - } - @AutoValue.Builder public abstract static class Builder { /** @@ -223,13 +120,122 @@ public abstract static class Builder { public abstract Builder setUsingGDCH(boolean usingGDCH); + public abstract Builder setResolvedEndpoint(String resolvedEndpoint); + + public abstract Builder setResolvedUniverseDomain(String resolvedUniverseDomain); + + abstract String serviceName(); + + abstract String universeDomain(); + + abstract String clientSettingsEndpoint(); + + abstract String transportChannelProviderEndpoint(); + + abstract String mtlsEndpoint(); + + abstract boolean switchToMtlsEndpointAllowed(); + + abstract MtlsProvider mtlsProvider(); + + abstract boolean usingGDCH(); + + abstract String resolvedUniverseDomain(); + abstract EndpointContext autoBuild(); + private String determineUniverseDomain() { + // Do not set the universe domain for GDC-H + if (usingGDCH()) { + return null; + } + // Check for "" (empty string) + if (universeDomain() != null && universeDomain().isEmpty()) { + throw new IllegalArgumentException("The universe domain value cannot be empty."); + } + // Override with user set universe domain if provided + return universeDomain() != null ? universeDomain() : GOOGLE_DEFAULT_UNIVERSE; + } + + /** Determines the fully resolved endpoint and universe domain values */ + private String determineEndpoint() throws IOException { + MtlsProvider mtlsProvider = mtlsProvider() == null ? new MtlsProvider() : mtlsProvider(); + // TransportChannelProvider's endpoint will override the ClientSettings' endpoint + String customEndpoint = + transportChannelProviderEndpoint() == null + ? clientSettingsEndpoint() + : transportChannelProviderEndpoint(); + + // GDC-H has a separate flow + if (usingGDCH()) { + return determineGDCHEndpoint(customEndpoint); + } + + // If user does not provide a custom endpoint, build one with the universe domain + if (Strings.isNullOrEmpty(customEndpoint)) { + customEndpoint = buildEndpointTemplate(serviceName(), resolvedUniverseDomain()); + } + + String endpoint = + mtlsEndpointResolver( + customEndpoint, mtlsEndpoint(), switchToMtlsEndpointAllowed(), mtlsProvider); + + // Check if mTLS is configured with non-GDU + if (endpoint.equals(mtlsEndpoint()) + && !resolvedUniverseDomain().equals(GOOGLE_DEFAULT_UNIVERSE)) { + throw new IllegalArgumentException( + "mTLS is not supported in any universe other than googleapis.com"); + } + + return endpoint; + } + + // GDC-H has no concept of Universe Domain. Do not set the resolvedUniverseDomain value + private String determineGDCHEndpoint(String customEndpoint) { + if (universeDomain() != null) { + throw new IllegalArgumentException( + "Universe domain configuration is incompatible with GDC-H"); + } else if (customEndpoint == null) { + return buildEndpointTemplate(serviceName(), GOOGLE_DEFAULT_UNIVERSE); + } else { + return customEndpoint; + } + } + + // Default to port 443 for HTTPS. Using HTTP requires explicitly setting the endpoint + private String buildEndpointTemplate(String serviceName, String resolvedUniverseDomain) { + return serviceName + "." + resolvedUniverseDomain + ":443"; + } + + // Follows https://google.aip.dev/auth/4114 for resolving the endpoint + @VisibleForTesting + String mtlsEndpointResolver( + String endpoint, + String mtlsEndpoint, + boolean switchToMtlsEndpointAllowed, + MtlsProvider mtlsProvider) + throws IOException { + if (switchToMtlsEndpointAllowed && mtlsProvider != null) { + switch (mtlsProvider.getMtlsEndpointUsagePolicy()) { + case ALWAYS: + return mtlsEndpoint; + case NEVER: + return endpoint; + default: + if (mtlsProvider.useMtlsClientCertificate() && mtlsProvider.getKeyStore() != null) { + return mtlsEndpoint; + } + return endpoint; + } + } + return endpoint; + } + public EndpointContext build() throws IOException { - EndpointContext endpointContext = autoBuild(); - endpointContext.determineUniverseDomain(); - endpointContext.determineEndpoint(); - return endpointContext; + // The Universe Domain is used to resolve the Endpoint. It should be resolved first + setResolvedUniverseDomain(determineUniverseDomain()); + setResolvedEndpoint(determineEndpoint()); + return autoBuild(); } } } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java index 24bc578b32..0886c628c1 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java @@ -68,9 +68,8 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsFalse() throws IOException "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = false; - EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - endpointContext.mtlsEndpointResolver( + defaultEndpointContextBuilder.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_ENDPOINT); } @@ -87,9 +86,8 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageAuto() throw "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; - EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - endpointContext.mtlsEndpointResolver( + defaultEndpointContextBuilder.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_MTLS_ENDPOINT); } @@ -106,9 +104,8 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageAlways() thr "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; - EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - endpointContext.mtlsEndpointResolver( + defaultEndpointContextBuilder.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_MTLS_ENDPOINT); } @@ -125,9 +122,8 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageNever() thro "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; - EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - endpointContext.mtlsEndpointResolver( + defaultEndpointContextBuilder.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_ENDPOINT); } @@ -146,9 +142,8 @@ public void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageNever() thro "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; - EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat( - endpointContext.mtlsEndpointResolver( + defaultEndpointContextBuilder.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) .isEqualTo(DEFAULT_ENDPOINT); } @@ -165,11 +160,10 @@ public void mtlsEndpointResolver_getKeyStore_throwsIOException() throws IOExcept "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; - EndpointContext endpointContext = defaultEndpointContextBuilder.build(); assertThrows( IOException.class, () -> - endpointContext.mtlsEndpointResolver( + defaultEndpointContextBuilder.mtlsEndpointResolver( DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, @@ -181,8 +175,8 @@ public void endpointContextBuild_noUniverseDomain_usesClientSettingsEndpoint() throws IOException { EndpointContext endpointContext = defaultEndpointContextBuilder.setClientSettingsEndpoint(DEFAULT_ENDPOINT).build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.resolvedUniverseDomain()) .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @@ -195,9 +189,9 @@ public void endpointContextBuild_noUniverseDomain_usesTransportChannelProviderEn .setClientSettingsEndpoint(null) .setTransportChannelProviderEndpoint(transportChannelProviderEndpoint) .build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()) + Truth.assertThat(endpointContext.resolvedEndpoint()) .isEqualTo(transportChannelProviderEndpoint); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + Truth.assertThat(endpointContext.resolvedUniverseDomain()) .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @@ -210,9 +204,9 @@ public void endpointContextBuild_noUniverseDomain_overrideUsesTransportChannelPr .setClientSettingsEndpoint(DEFAULT_ENDPOINT) .setTransportChannelProviderEndpoint(transportChannelProviderEndpoint) .build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()) + Truth.assertThat(endpointContext.resolvedEndpoint()) .isEqualTo(transportChannelProviderEndpoint); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + Truth.assertThat(endpointContext.resolvedUniverseDomain()) .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @@ -229,8 +223,8 @@ public void endpointContextBuild_emptyStringUniverseDomain_throwsIllegalArgument @Test public void endpointContextBuild_GDUUniverseDomain() throws IOException { EndpointContext endpointContext = defaultEndpointContextBuilder.build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.resolvedUniverseDomain()) .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @@ -239,8 +233,8 @@ public void endpointContextBuild_nonGDUUniverseDomain() throws IOException { String universeDomain = "random.com"; EndpointContext endpointContext = defaultEndpointContextBuilder.setUniverseDomain(universeDomain).build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isEqualTo(universeDomain); + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.resolvedUniverseDomain()).isEqualTo(universeDomain); } @Test @@ -252,8 +246,8 @@ public void endpointContextBuild_noUniverseDomain_noEndpoints() throws IOExcepti .setClientSettingsEndpoint(null) .setTransportChannelProviderEndpoint(null) .build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(expectedEndpoint); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(expectedEndpoint); + Truth.assertThat(endpointContext.resolvedUniverseDomain()) .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @@ -273,8 +267,8 @@ public void endpointContextBuild_mtlsConfigured_GDU() throws IOException { .setSwitchToMtlsEndpointAllowed(true) .setMtlsProvider(mtlsProvider) .build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_MTLS_ENDPOINT); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()) + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_MTLS_ENDPOINT); + Truth.assertThat(endpointContext.resolvedUniverseDomain()) .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @@ -319,8 +313,8 @@ public void endpointContextBuild_gdchFlow_noUniverseDomain_noCustomEndpoint() th .setUsingGDCH(true) .setClientSettingsEndpoint(null) .build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); + Truth.assertThat(endpointContext.resolvedUniverseDomain()).isNull(); } @Test @@ -332,7 +326,7 @@ public void endpointContextBuild_gdchFlow_noUniverseDomain_customEndpoint() thro .setUsingGDCH(true) .setClientSettingsEndpoint(clientSettingsEndpoint) .build(); - Truth.assertThat(endpointContext.getResolvedEndpoint()).isEqualTo(clientSettingsEndpoint); - Truth.assertThat(endpointContext.getResolvedUniverseDomain()).isNull(); + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(clientSettingsEndpoint); + Truth.assertThat(endpointContext.resolvedUniverseDomain()).isNull(); } } From 653db8e49056bed9a860944731f9e03f1b92e1f6 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Thu, 28 Dec 2023 22:27:29 -0500 Subject: [PATCH 6/7] chore: Address PR comments --- .../com/google/api/gax/rpc/ClientContext.java | 3 +- .../google/api/gax/rpc/EndpointContext.java | 28 ++++++++----------- .../google/api/gax/rpc/ClientContextTest.java | 23 ++++++++++++--- .../api/gax/rpc/EndpointContextTest.java | 6 ++-- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index b122da3d45..e7fac9d0c6 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -173,7 +173,6 @@ public static ClientContext create(StubSettings settings) throws IOException { .setUsingGDCH(usingGDCH) .build(); String endpoint = endpointContext.resolvedEndpoint(); - String universeDomain = endpointContext.resolvedUniverseDomain(); String settingsGdchApiAudience = settings.getGdchApiAudience(); if (usingGDCH) { @@ -271,7 +270,7 @@ public static ClientContext create(StubSettings settings) throws IOException { .setClock(clock) .setDefaultCallContext(defaultCallContext) .setServiceName(settings.getServiceName()) - .setUniverseDomain(universeDomain) + .setUniverseDomain(settings.getUniverseDomain()) .setEndpoint(settings.getEndpoint()) .setQuotaProjectId(settings.getQuotaProjectId()) .setStreamWatchdog(watchdog) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index f8d866332c..4771398005 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -77,8 +77,7 @@ public abstract class EndpointContext { public abstract boolean usingGDCH(); - @Nullable - public abstract String resolvedUniverseDomain(); + abstract String resolvedUniverseDomain(); public abstract String resolvedEndpoint(); @@ -145,9 +144,13 @@ public abstract static class Builder { abstract EndpointContext autoBuild(); private String determineUniverseDomain() { - // Do not set the universe domain for GDC-H if (usingGDCH()) { - return null; + // GDC-H has no concept of Universe Domain. User should not set a custom value + if (universeDomain() != null) { + throw new IllegalArgumentException( + "Universe domain configuration is incompatible with GDC-H"); + } + return GOOGLE_DEFAULT_UNIVERSE; } // Check for "" (empty string) if (universeDomain() != null && universeDomain().isEmpty()) { @@ -168,7 +171,10 @@ private String determineEndpoint() throws IOException { // GDC-H has a separate flow if (usingGDCH()) { - return determineGDCHEndpoint(customEndpoint); + if (customEndpoint == null) { + return buildEndpointTemplate(serviceName(), resolvedUniverseDomain()); + } + return customEndpoint; } // If user does not provide a custom endpoint, build one with the universe domain @@ -190,18 +196,6 @@ private String determineEndpoint() throws IOException { return endpoint; } - // GDC-H has no concept of Universe Domain. Do not set the resolvedUniverseDomain value - private String determineGDCHEndpoint(String customEndpoint) { - if (universeDomain() != null) { - throw new IllegalArgumentException( - "Universe domain configuration is incompatible with GDC-H"); - } else if (customEndpoint == null) { - return buildEndpointTemplate(serviceName(), GOOGLE_DEFAULT_UNIVERSE); - } else { - return customEndpoint; - } - } - // Default to port 443 for HTTPS. Using HTTP requires explicitly setting the endpoint private String buildEndpointTemplate(String serviceName, String resolvedUniverseDomain) { return serviceName + "." + resolvedUniverseDomain + ":443"; diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java index 5e23206ee9..cad4a7869a 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/ClientContextTest.java @@ -959,7 +959,11 @@ public void testCreateClientContext_SetEndpointViaClientSettings() throws IOExce TransportChannelProvider transportChannelProvider = new FakeTransportProvider( FakeTransportChannel.create(new FakeChannel()), null, true, null, null, null); - StubSettings settings = new FakeStubSettings.Builder().setEndpoint(DEFAULT_ENDPOINT).build(); + StubSettings settings = + new FakeStubSettings.Builder() + .setEndpoint(DEFAULT_ENDPOINT) + .setUniverseDomain(DEFAULT_UNIVERSE_DOMAIN) + .build(); ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings); clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); clientSettingsBuilder.setCredentialsProvider( @@ -980,7 +984,11 @@ public void testCreateClientContext_SetEndpointViaTransportChannelProvider() thr null, null, DEFAULT_ENDPOINT); - StubSettings settings = new FakeStubSettings.Builder().setEndpoint(null).build(); + StubSettings settings = + new FakeStubSettings.Builder() + .setEndpoint(null) + .setUniverseDomain(DEFAULT_UNIVERSE_DOMAIN) + .build(); ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings); clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); clientSettingsBuilder.setCredentialsProvider( @@ -1006,7 +1014,10 @@ public void testCreateClientContext_SetEndpointViaClientSettingsAndTransportChan null, transportChannelProviderEndpoint); StubSettings settings = - new FakeStubSettings.Builder().setEndpoint(clientSettingsEndpoint).build(); + new FakeStubSettings.Builder() + .setEndpoint(clientSettingsEndpoint) + .setUniverseDomain(DEFAULT_UNIVERSE_DOMAIN) + .build(); ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings); clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); clientSettingsBuilder.setCredentialsProvider( @@ -1023,7 +1034,11 @@ public void testCreateClientContext_doNotSetUniverseDomain() throws IOException TransportChannelProvider transportChannelProvider = new FakeTransportProvider( FakeTransportChannel.create(new FakeChannel()), null, true, null, null, null); - StubSettings settings = new FakeStubSettings.Builder().setEndpoint(null).build(); + StubSettings settings = + new FakeStubSettings.Builder() + .setEndpoint(null) + .setUniverseDomain(DEFAULT_UNIVERSE_DOMAIN) + .build(); ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings); clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider); clientSettingsBuilder.setCredentialsProvider( diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java index 0886c628c1..d040450786 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java @@ -314,7 +314,8 @@ public void endpointContextBuild_gdchFlow_noUniverseDomain_noCustomEndpoint() th .setClientSettingsEndpoint(null) .build(); Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); - Truth.assertThat(endpointContext.resolvedUniverseDomain()).isNull(); + Truth.assertThat(endpointContext.resolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } @Test @@ -327,6 +328,7 @@ public void endpointContextBuild_gdchFlow_noUniverseDomain_customEndpoint() thro .setClientSettingsEndpoint(clientSettingsEndpoint) .build(); Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(clientSettingsEndpoint); - Truth.assertThat(endpointContext.resolvedUniverseDomain()).isNull(); + Truth.assertThat(endpointContext.resolvedUniverseDomain()) + .isEqualTo(EndpointContext.GOOGLE_DEFAULT_UNIVERSE); } } From 3d3d7a581d706065ef7866e6746f2be9bb95d25d Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Tue, 2 Jan 2024 11:46:23 -0500 Subject: [PATCH 7/7] chore: Add javadocs for universe domain --- .../java/com/google/api/gax/rpc/EndpointContext.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index 4771398005..89100a06df 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -51,6 +51,12 @@ public abstract class EndpointContext { @Nullable public abstract String serviceName(); + /** + * Universe Domain is the domain for Google Cloud Services. It follows the format of + * `{ServiceName}.{UniverseDomain}`. For example, speech.googleapis.com would have a Universe + * Domain value of `googleapis.com` and cloudasset.test.com would have a Universe Domain of + * `test.com`. If this value is not set, this will default to `googleapis.com`. + */ @Nullable public abstract String universeDomain(); @@ -98,6 +104,12 @@ public abstract static class Builder { */ public abstract Builder setServiceName(String serviceName); + /** + * Universe Domain is the domain for Google Cloud Services. It follows the format of + * `{ServiceName}.{UniverseDomain}`. For example, speech.googleapis.com would have a Universe + * Domain value of `googleapis.com` and cloudasset.test.com would have a Universe Domain of + * `test.com`. If this value is not set, this will default to `googleapis.com`. + */ public abstract Builder setUniverseDomain(String universeDomain); /**