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 c62962f40c..c24c74af04 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 @@ -42,9 +42,12 @@ import com.google.api.gax.rpc.TransportChannel; import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.internal.EnvironmentProvider; -import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.rpc.mtls.CertificateBasedAccess; import com.google.auth.ApiKeyCredentials; import com.google.auth.Credentials; +import com.google.auth.mtls.CertificateSourceUnavailableException; +import com.google.auth.mtls.DefaultMtlsProviderFactory; +import com.google.auth.mtls.MtlsProvider; import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.auth.oauth2.SecureSessionAgent; import com.google.auth.oauth2.SecureSessionAgentConfig; @@ -150,6 +153,7 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP @Nullable private final Boolean allowNonDefaultServiceAccount; @VisibleForTesting final ImmutableMap directPathServiceConfig; @Nullable private final MtlsProvider mtlsProvider; + private final CertificateBasedAccess certificateBasedAccess; @Nullable private final SecureSessionAgent s2aConfigProvider; private final List allowedHardBoundTokenTypes; @VisibleForTesting final Map headersWithDuplicatesRemoved = new HashMap<>(); @@ -183,6 +187,7 @@ private InstantiatingGrpcChannelProvider(Builder builder) { this.mtlsEndpoint = builder.mtlsEndpoint; this.allowedHardBoundTokenTypes = builder.allowedHardBoundTokenTypes; this.mtlsProvider = builder.mtlsProvider; + this.certificateBasedAccess = builder.certificateBasedAccess; this.s2aConfigProvider = builder.s2aConfigProvider; this.envProvider = builder.envProvider; this.interceptorProvider = builder.interceptorProvider; @@ -484,7 +489,10 @@ boolean canUseDirectPathWithUniverseDomain() { @VisibleForTesting ChannelCredentials createMtlsChannelCredentials() throws IOException, GeneralSecurityException { - if (mtlsProvider.useMtlsClientCertificate()) { + if (mtlsProvider == null) { + return null; + } + if (certificateBasedAccess.useMtlsClientCertificate()) { KeyStore mtlsKeyStore = mtlsProvider.getKeyStore(); if (mtlsKeyStore != null) { KeyManagerFactory factory = @@ -853,7 +861,8 @@ public static final class Builder { private boolean useS2A; private EnvironmentProvider envProvider; private SecureSessionAgent s2aConfigProvider = SecureSessionAgent.create(); - private MtlsProvider mtlsProvider = new MtlsProvider(); + @Nullable private MtlsProvider mtlsProvider; + private CertificateBasedAccess certificateBasedAccess; @Nullable private GrpcInterceptorProvider interceptorProvider; @Nullable private Integer maxInboundMessageSize; @Nullable private Integer maxInboundMetadataSize; @@ -904,6 +913,7 @@ private Builder(InstantiatingGrpcChannelProvider provider) { this.allowedHardBoundTokenTypes = provider.allowedHardBoundTokenTypes; this.directPathServiceConfig = provider.directPathServiceConfig; this.mtlsProvider = provider.mtlsProvider; + this.certificateBasedAccess = provider.certificateBasedAccess; this.s2aConfigProvider = provider.s2aConfigProvider; } @@ -994,6 +1004,12 @@ Builder setMtlsProvider(MtlsProvider mtlsProvider) { return this; } + @VisibleForTesting + Builder setCertificateBasedAccess(CertificateBasedAccess certificateBasedAccess) { + this.certificateBasedAccess = certificateBasedAccess; + return this; + } + @VisibleForTesting Builder setS2AConfigProvider(SecureSessionAgent s2aConfigProvider) { this.s2aConfigProvider = s2aConfigProvider; @@ -1269,6 +1285,25 @@ CallCredentials createHardBoundTokensCallCredentials( } public InstantiatingGrpcChannelProvider build() { + if (certificateBasedAccess == null) { + certificateBasedAccess = CertificateBasedAccess.createWithSystemEnv(); + } + if (certificateBasedAccess.useMtlsClientCertificate()) { + if (mtlsProvider == null) { + // Attempt to create default MtlsProvider from environment. + try { + mtlsProvider = DefaultMtlsProviderFactory.create(); + } catch (CertificateSourceUnavailableException e) { + // This is okay. Leave mtlsProvider as null so that we will not auto-upgrade + // to mTLS endpoints. See https://google.aip.dev/auth/4114. + } catch (IOException e) { + LOG.log( + Level.WARNING, + "DefaultMtlsProviderFactory encountered unexpected IOException: " + e.getMessage()); + } + } + } + if (isMtlsS2AHardBoundTokensEnabled()) { // Set a {@code ComputeEngineCredentials} instance to be per-RPC call credentials, // which will be used to fetch MTLS_S2A hard bound tokens from the metdata server. 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 86203ce47d..5c4dfca8c4 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 @@ -46,10 +46,11 @@ import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.internal.EnvironmentProvider; import com.google.api.gax.rpc.mtls.AbstractMtlsTransportChannelTest; -import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.rpc.mtls.CertificateBasedAccess; import com.google.auth.ApiKeyCredentials; import com.google.auth.Credentials; import com.google.auth.http.AuthHttpConstants; +import com.google.auth.mtls.MtlsProvider; import com.google.auth.oauth2.CloudShellCredentials; import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.auth.oauth2.SecureSessionAgent; @@ -92,6 +93,7 @@ class InstantiatingGrpcChannelProviderTest extends AbstractMtlsTransportChannelT private static final String API_KEY_AUTH_HEADER_KEY = "x-goog-api-key"; private static String originalOSName; private ComputeEngineCredentials computeEngineCredentials; + private CertificateBasedAccess certificateBasedAccess; @BeforeAll public static void setupClass() { @@ -101,6 +103,9 @@ public static void setupClass() { @BeforeEach public void setup() throws IOException { computeEngineCredentials = Mockito.mock(ComputeEngineCredentials.class); + certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "never" : "false"); } @AfterEach @@ -208,6 +213,7 @@ void testWithPoolSize() throws IOException { TransportChannelProvider provider = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .build() .withExecutor((Executor) executor) .withHeaders(Collections.emptyMap()) @@ -277,6 +283,7 @@ private void testWithInterceptors(int numChannels) throws Exception { InstantiatingGrpcChannelProvider channelProvider = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setEndpoint("localhost:8080") .setPoolSize(numChannels) .setHeaderProvider(Mockito.mock(HeaderProvider.class)) @@ -310,6 +317,7 @@ void testChannelConfigurator() throws IOException { // Invoke the provider InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setEndpoint("localhost:8080") .setHeaderProvider(Mockito.mock(HeaderProvider.class)) .setExecutor(Mockito.mock(Executor.class)) @@ -331,6 +339,7 @@ void testWithGCECredentials() throws IOException { TransportChannelProvider provider = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .build() .withExecutor((Executor) executor) @@ -414,6 +423,7 @@ void testWithNonGCECredentials() throws IOException { InstantiatingGrpcChannelProvider.newBuilder() .setAttemptDirectPath(true) .setChannelConfigurator(channelConfigurator) + .setCertificateBasedAccess(certificateBasedAccess) .build() .withExecutor((Executor) executor) .withHeaders(Collections.emptyMap()) @@ -442,6 +452,7 @@ void testWithDirectPathDisabled() throws IOException { InstantiatingGrpcChannelProvider.newBuilder() .setAttemptDirectPath(false) .setChannelConfigurator(channelConfigurator) + .setCertificateBasedAccess(certificateBasedAccess) .build() .withExecutor((Executor) executor) .withHeaders(Collections.emptyMap()) @@ -469,6 +480,7 @@ void testWithNoDirectPathFlagSet() throws IOException { TransportChannelProvider provider = InstantiatingGrpcChannelProvider.newBuilder() .setChannelConfigurator(channelConfigurator) + .setCertificateBasedAccess(certificateBasedAccess) .build() .withExecutor((Executor) executor) .withHeaders(Collections.emptyMap()) @@ -488,6 +500,7 @@ void testWithIPv6Address() throws IOException { TransportChannelProvider provider = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .build() .withExecutor((Executor) executor) .withHeaders(Collections.emptyMap()) @@ -513,6 +526,7 @@ void testWithPrimeChannel() throws IOException { .setHeaderProvider(Mockito.mock(HeaderProvider.class)) .setExecutor(Mockito.mock(Executor.class)) .setChannelPrimer(mockChannelPrimer) + .setCertificateBasedAccess(certificateBasedAccess) .build(); provider.getTransportChannel().shutdownNow(); @@ -526,7 +540,9 @@ void testWithPrimeChannel() throws IOException { @Test void testWithDefaultDirectPathServiceConfig() { InstantiatingGrpcChannelProvider provider = - InstantiatingGrpcChannelProvider.newBuilder().build(); + InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) + .build(); ImmutableMap defaultServiceConfig = provider.directPathServiceConfig; @@ -591,6 +607,7 @@ void testWithCustomDirectPathServiceConfig() { InstantiatingGrpcChannelProvider provider = InstantiatingGrpcChannelProvider.newBuilder() .setDirectPathServiceConfig(passedServiceConfig) + .setCertificateBasedAccess(certificateBasedAccess) .build(); ImmutableMap defaultServiceConfig = provider.directPathServiceConfig; @@ -598,12 +615,14 @@ void testWithCustomDirectPathServiceConfig() { } @Override - protected Object getMtlsObjectFromTransportChannel(MtlsProvider provider) + protected Object getMtlsObjectFromTransportChannel( + MtlsProvider provider, CertificateBasedAccess certificateBasedAccess) throws IOException, GeneralSecurityException { InstantiatingGrpcChannelProvider channelProvider = InstantiatingGrpcChannelProvider.newBuilder() .setEndpoint("localhost:8080") .setMtlsProvider(provider) + .setCertificateBasedAccess(certificateBasedAccess) .setHeaderProvider(Mockito.mock(HeaderProvider.class)) .setExecutor(Mockito.mock(Executor.class)) .build(); @@ -632,7 +651,10 @@ private void createAndCloseTransportChannel(InstantiatingGrpcChannelProvider pro FakeLogHandler logHandler = new FakeLogHandler(); InstantiatingGrpcChannelProvider.LOG.addHandler(logHandler); InstantiatingGrpcChannelProvider provider = - createChannelProviderBuilderForDirectPathLogTests().setAttemptDirectPathXds().build(); + createChannelProviderBuilderForDirectPathLogTests() + .setAttemptDirectPathXds() + .setCertificateBasedAccess(certificateBasedAccess) + .build(); createAndCloseTransportChannel(provider); assertThat(logHandler.getAllMessages()) .contains( @@ -647,7 +669,9 @@ void testLogDirectPathMisconfig_AttemptDirectPathNotSetAndAttemptDirectPathXdsSe InstantiatingGrpcChannelProvider.LOG.addHandler(logHandler); InstantiatingGrpcChannelProvider provider = - createChannelProviderBuilderForDirectPathLogTests().build(); + createChannelProviderBuilderForDirectPathLogTests() + .setCertificateBasedAccess(certificateBasedAccess) + .build(); createAndCloseTransportChannel(provider); assertThat(logHandler.getAllMessages()) .contains( @@ -663,6 +687,7 @@ void testLogDirectPathMisconfig_shouldNotLogInTheBuilder() { InstantiatingGrpcChannelProvider.newBuilder() .setAttemptDirectPathXds() .setAttemptDirectPath(true) + .setCertificateBasedAccess(certificateBasedAccess) .build(); assertThat(logHandler.getAllMessages()).isEmpty(); @@ -680,6 +705,7 @@ void testLogDirectPathMisconfigWrongCredential() throws Exception { .setHeaderProvider(Mockito.mock(HeaderProvider.class)) .setExecutor(Mockito.mock(Executor.class)) .setEndpoint(DEFAULT_ENDPOINT) + .setCertificateBasedAccess(certificateBasedAccess) .build(); TransportChannel transportChannel = provider.getTransportChannel(); @@ -706,6 +732,7 @@ void testLogDirectPathMisconfigNotOnGCE() throws Exception { .setHeaderProvider(Mockito.mock(HeaderProvider.class)) .setExecutor(Mockito.mock(Executor.class)) .setEndpoint(DEFAULT_ENDPOINT) + .setCertificateBasedAccess(certificateBasedAccess) .build(); TransportChannel transportChannel = provider.getTransportChannel(); @@ -731,6 +758,7 @@ public void canUseDirectPath_happyPath() throws IOException { .thenReturn("false"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setEndpoint(DEFAULT_ENDPOINT) @@ -758,6 +786,7 @@ public void canUseDirectPath_boundTokenNotEnabledWithNonComputeCredentials() { .thenReturn("false"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setAllowHardBoundTokenTypes(Collections.singletonList(HardBoundTokenTypes.ALTS)) .setCredentials(credentials) @@ -782,6 +811,7 @@ public void canUseDirectPath_happyPathWithBoundToken() throws IOException { .thenReturn(ComputeEngineCredentials.newBuilder()); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setAllowHardBoundTokenTypes(Collections.singletonList(HardBoundTokenTypes.ALTS)) @@ -809,6 +839,7 @@ public void canUseDirectPath_directPathEnvVarDisabled() throws IOException { .thenReturn("true"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setEndpoint(DEFAULT_ENDPOINT) @@ -829,6 +860,7 @@ public void canUseDirectPath_directPathEnvVarNotSet_attemptDirectPathIsTrue() { System.setProperty("os.name", "Linux"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setEndpoint(DEFAULT_ENDPOINT); @@ -842,6 +874,7 @@ public void canUseDirectPath_directPathEnvVarNotSet_attemptDirectPathIsFalse() { System.setProperty("os.name", "Linux"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(false) .setCredentials(computeEngineCredentials) .setEndpoint(DEFAULT_ENDPOINT); @@ -861,6 +894,7 @@ public void canUseDirectPath_nonComputeCredentials() { .thenReturn("false"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(credentials) .setEndpoint(DEFAULT_ENDPOINT) @@ -880,6 +914,7 @@ public void canUseDirectPath_isNotOnComputeEngine_invalidOsNameSystemProperty() .thenReturn("false"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setEndpoint(DEFAULT_ENDPOINT) @@ -899,6 +934,7 @@ public void canUseDirectPath_isNotOnComputeEngine_invalidSystemProductName() { .thenReturn("false"); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setEndpoint(DEFAULT_ENDPOINT) @@ -921,6 +957,7 @@ public void canUseDirectPath_isNotOnComputeEngine_unableToGetSystemProductName() .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setEndpoint(DEFAULT_ENDPOINT) + .setCertificateBasedAccess(certificateBasedAccess) .setEnvProvider(envProvider); InstantiatingGrpcChannelProvider provider = new InstantiatingGrpcChannelProvider(builder, ""); Truth.assertThat(provider.canUseDirectPath()).isFalse(); @@ -937,6 +974,7 @@ public void canUseDirectPath_nonGDUUniverseDomain() { String nonGDUEndpoint = "test.random.com:443"; InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setAttemptDirectPath(true) .setCredentials(computeEngineCredentials) .setEndpoint(nonGDUEndpoint) @@ -966,6 +1004,7 @@ void providersInitializedWithConflictingApiKeyCredentialHeaders_removesDuplicate ApiKeyCredentials apiKeyCredentials = ApiKeyCredentials.create(correctApiKey); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setCredentials(apiKeyCredentials) .setHeaderProvider(getHeaderProviderWithApiKeyHeader()) .setEndpoint("test.random.com:443"); @@ -983,6 +1022,7 @@ void providersInitializedWithConflictingNonApiKeyCredentialHeaders_doesNotRemove header.put(AuthHttpConstants.AUTHORIZATION, authProvidedHeader); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setCredentials(computeEngineCredentials) .setHeaderProvider(FixedHeaderProvider.create(header)) .setEndpoint("test.random.com:443"); @@ -1011,6 +1051,7 @@ void buildProvider_handlesNullCredentialsMetadataRequest() throws IOException { Mockito.when(credentials.getRequestMetadata()).thenReturn(null); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setHeaderProvider(getHeaderProviderWithApiKeyHeader()) .setEndpoint("test.random.com:443"); @@ -1028,6 +1069,7 @@ void buildProvider_handlesErrorRetrievingCredentialsMetadataRequest() throws IOE .thenThrow(new IOException("Error getting request metadata")); InstantiatingGrpcChannelProvider.Builder builder = InstantiatingGrpcChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) .setHeaderProvider(getHeaderProviderWithApiKeyHeader()) .setEndpoint("test.random.com:443"); InstantiatingGrpcChannelProvider provider = builder.build(); diff --git a/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/SettingsTest.java b/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/SettingsTest.java index f08a3c3a89..a1ab8a8e8e 100644 --- a/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/SettingsTest.java +++ b/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/SettingsTest.java @@ -51,8 +51,8 @@ import com.google.api.gax.rpc.StubSettings; import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.UnaryCallSettings; -import com.google.api.gax.rpc.mtls.MtlsProvider; import com.google.auth.Credentials; +import com.google.auth.mtls.MtlsProvider; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -83,7 +83,7 @@ private static class FakeStubSettings extends StubSettings { public static final int DEFAULT_SERVICE_PORT = 443; public static final String DEFAULT_SERVICE_ENDPOINT = DEFAULT_SERVICE_ADDRESS + ':' + DEFAULT_SERVICE_PORT; - public static final MtlsProvider DEFAULT_MTLS_PROVIDER = new MtlsProvider(); + public static final MtlsProvider DEFAULT_MTLS_PROVIDER = null; public static final ImmutableList DEFAULT_SERVICE_SCOPES = ImmutableList.builder() .add("https://www.googleapis.com/auth/pubsub") diff --git a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java index 1171ef1b59..528018ec75 100644 --- a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java +++ b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProvider.java @@ -36,8 +36,11 @@ import com.google.api.gax.rpc.FixedHeaderProvider; import com.google.api.gax.rpc.HeaderProvider; import com.google.api.gax.rpc.TransportChannelProvider; -import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.rpc.mtls.CertificateBasedAccess; import com.google.auth.Credentials; +import com.google.auth.mtls.CertificateSourceUnavailableException; +import com.google.auth.mtls.DefaultMtlsProviderFactory; +import com.google.auth.mtls.MtlsProvider; import com.google.common.annotations.VisibleForTesting; import java.io.IOException; import java.security.GeneralSecurityException; @@ -45,6 +48,9 @@ import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.Nullable; /** * InstantiatingHttpJsonChannelProvider is a TransportChannelProvider which constructs a {@link @@ -61,12 +67,16 @@ @InternalExtensionOnly public final class InstantiatingHttpJsonChannelProvider implements TransportChannelProvider { + @VisibleForTesting + static final Logger LOG = Logger.getLogger(InstantiatingHttpJsonChannelProvider.class.getName()); + private final Executor executor; private final HeaderProvider headerProvider; private final HttpJsonInterceptorProvider interceptorProvider; private final String endpoint; private final HttpTransport httpTransport; - private final MtlsProvider mtlsProvider; + @Nullable private final MtlsProvider mtlsProvider; + private final CertificateBasedAccess certificateBasedAccess; private InstantiatingHttpJsonChannelProvider( Executor executor, @@ -74,13 +84,15 @@ private InstantiatingHttpJsonChannelProvider( HttpJsonInterceptorProvider interceptorProvider, String endpoint, HttpTransport httpTransport, - MtlsProvider mtlsProvider) { + MtlsProvider mtlsProvider, + CertificateBasedAccess certificateBasedAccess) { this.executor = executor; this.headerProvider = headerProvider; this.interceptorProvider = interceptorProvider; this.endpoint = endpoint; this.httpTransport = httpTransport; this.mtlsProvider = mtlsProvider; + this.certificateBasedAccess = certificateBasedAccess; } /** @@ -173,7 +185,10 @@ public TransportChannelProvider withCredentials(Credentials credentials) { } HttpTransport createHttpTransport() throws IOException, GeneralSecurityException { - if (mtlsProvider.useMtlsClientCertificate()) { + if (mtlsProvider == null) { + return null; + } + if (certificateBasedAccess.useMtlsClientCertificate()) { KeyStore mtlsKeyStore = mtlsProvider.getKeyStore(); if (mtlsKeyStore != null) { return new NetHttpTransport.Builder().trustCertificates(null, mtlsKeyStore, "").build(); @@ -237,7 +252,8 @@ public static final class Builder { private HttpJsonInterceptorProvider interceptorProvider; private String endpoint; private HttpTransport httpTransport; - private MtlsProvider mtlsProvider = new MtlsProvider(); + private MtlsProvider mtlsProvider; + private CertificateBasedAccess certificateBasedAccess; private Builder() {} @@ -247,6 +263,7 @@ private Builder(InstantiatingHttpJsonChannelProvider provider) { this.endpoint = provider.endpoint; this.httpTransport = provider.httpTransport; this.mtlsProvider = provider.mtlsProvider; + this.certificateBasedAccess = provider.certificateBasedAccess; this.interceptorProvider = provider.interceptorProvider; } @@ -317,9 +334,39 @@ Builder setMtlsProvider(MtlsProvider mtlsProvider) { return this; } + @VisibleForTesting + Builder setCertificateBasedAccess(CertificateBasedAccess certificateBasedAccess) { + this.certificateBasedAccess = certificateBasedAccess; + return this; + } + public InstantiatingHttpJsonChannelProvider build() { + if (certificateBasedAccess == null) { + certificateBasedAccess = CertificateBasedAccess.createWithSystemEnv(); + } + if (certificateBasedAccess.useMtlsClientCertificate()) { + if (mtlsProvider == null) { + // Attempt to create default MtlsProvider from environment. + try { + mtlsProvider = DefaultMtlsProviderFactory.create(); + } catch (CertificateSourceUnavailableException e) { + // This is okay. Leave mtlsProvider as null so that we will not auto-upgrade + // to mTLS endpoints. See https://google.aip.dev/auth/4114. + } catch (IOException e) { + LOG.log( + Level.WARNING, + "DefaultMtlsProviderFactory encountered unexpected IOException: " + e.getMessage()); + } + } + } return new InstantiatingHttpJsonChannelProvider( - executor, headerProvider, interceptorProvider, endpoint, httpTransport, mtlsProvider); + executor, + headerProvider, + interceptorProvider, + endpoint, + httpTransport, + mtlsProvider, + certificateBasedAccess); } } } diff --git a/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProviderTest.java b/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProviderTest.java index 3e6b2d56d1..17ad9f2cbf 100644 --- a/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProviderTest.java +++ b/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/InstantiatingHttpJsonChannelProviderTest.java @@ -35,7 +35,8 @@ import com.google.api.gax.rpc.HeaderProvider; import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.mtls.AbstractMtlsTransportChannelTest; -import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.rpc.mtls.CertificateBasedAccess; +import com.google.auth.mtls.MtlsProvider; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Collections; @@ -43,6 +44,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -50,13 +52,24 @@ class InstantiatingHttpJsonChannelProviderTest extends AbstractMtlsTransportChan private static final String DEFAULT_ENDPOINT = "localhost:8080"; private static final Map DEFAULT_HEADER_MAP = Collections.emptyMap(); + private CertificateBasedAccess certificateBasedAccess; + + @BeforeEach + public void setup() throws IOException { + certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "never" : "false"); + } @Test void basicTest() throws IOException { ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1); executor.shutdown(); - TransportChannelProvider provider = InstantiatingHttpJsonChannelProvider.newBuilder().build(); + TransportChannelProvider provider = + InstantiatingHttpJsonChannelProvider.newBuilder() + .setCertificateBasedAccess(certificateBasedAccess) + .build(); assertThat(provider.needsEndpoint()).isTrue(); provider = provider.withEndpoint(DEFAULT_ENDPOINT); @@ -108,7 +121,10 @@ void basicTest() throws IOException { @Test void managedChannelUsesDefaultChannelExecutor() throws IOException { InstantiatingHttpJsonChannelProvider instantiatingHttpJsonChannelProvider = - InstantiatingHttpJsonChannelProvider.newBuilder().setEndpoint(DEFAULT_ENDPOINT).build(); + InstantiatingHttpJsonChannelProvider.newBuilder() + .setEndpoint(DEFAULT_ENDPOINT) + .setCertificateBasedAccess(certificateBasedAccess) + .build(); instantiatingHttpJsonChannelProvider = (InstantiatingHttpJsonChannelProvider) instantiatingHttpJsonChannelProvider.withHeaders(DEFAULT_HEADER_MAP); @@ -140,6 +156,7 @@ void managedChannelUsesCustomExecutor() throws IOException { InstantiatingHttpJsonChannelProvider.newBuilder() .setEndpoint(DEFAULT_ENDPOINT) .setExecutor(executor) + .setCertificateBasedAccess(certificateBasedAccess) .build(); instantiatingHttpJsonChannelProvider = (InstantiatingHttpJsonChannelProvider) @@ -164,12 +181,14 @@ void managedChannelUsesCustomExecutor() throws IOException { } @Override - protected Object getMtlsObjectFromTransportChannel(MtlsProvider provider) + protected Object getMtlsObjectFromTransportChannel( + MtlsProvider provider, CertificateBasedAccess certificateBasedAccess) throws IOException, GeneralSecurityException { InstantiatingHttpJsonChannelProvider channelProvider = InstantiatingHttpJsonChannelProvider.newBuilder() .setEndpoint("localhost:8080") .setMtlsProvider(provider) + .setCertificateBasedAccess(certificateBasedAccess) .setHeaderProvider(Mockito.mock(HeaderProvider.class)) .setExecutor(Mockito.mock(Executor.class)) .build(); diff --git a/gax-java/gax/clirr-ignored-differences.xml b/gax-java/gax/clirr-ignored-differences.xml index 4e0a8816c1..3b0228f94e 100644 --- a/gax-java/gax/clirr-ignored-differences.xml +++ b/gax-java/gax/clirr-ignored-differences.xml @@ -128,4 +128,26 @@ com/google/api/gax/rpc/TransportChannelProvider * needsMtlsEndpoint() + + 7013 + com/google/api/gax/rpc/EndpointContext + com.google.api.gax.rpc.mtls.CertificateBasedAccess certificateBasedAccess() + + + 7006 + com/google/api/gax/rpc/EndpointContext + com.google.api.gax.rpc.mtls.MtlsProvider mtlsProvider()Add commentMore actions + com.google.auth.mtls.MtlsProvider + + + 7013 + com/google/api/gax/rpc/EndpointContext$Builder + com.google.api.gax.rpc.EndpointContext$Builder setCertificateBasedAccess(com.google.api.gax.rpc.mtls.CertificateBasedAccess) + + + 7005 + com/google/api/gax/rpc/EndpointContext$Builder + com.google.api.gax.rpc.EndpointContext$Builder setMtlsProvider(com.google.api.gax.rpc.mtls.MtlsProvider) + com.google.api.gax.rpc.EndpointContext$Builder setMtlsProvider(com.google.auth.mtls.MtlsProvider) + 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 2db7361e3a..bf2e98f882 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 @@ -31,13 +31,18 @@ import com.google.api.core.InternalApi; import com.google.api.gax.rpc.internal.EnvironmentProvider; -import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.rpc.mtls.CertificateBasedAccess; import com.google.auth.Credentials; +import com.google.auth.mtls.CertificateSourceUnavailableException; +import com.google.auth.mtls.DefaultMtlsProviderFactory; +import com.google.auth.mtls.MtlsProvider; import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nullable; /** @@ -50,6 +55,8 @@ @AutoValue public abstract class EndpointContext { + @VisibleForTesting static final Logger LOG = Logger.getLogger(EndpointContext.class.getName()); + private static final EndpointContext INSTANCE; // static block initialization for exception handling @@ -117,6 +124,9 @@ public static EndpointContext getDefaultInstance() { @Nullable public abstract MtlsProvider mtlsProvider(); + @Nullable + abstract CertificateBasedAccess certificateBasedAccess(); + public abstract boolean usingGDCH(); abstract String resolvedUniverseDomain(); @@ -212,6 +222,8 @@ public abstract static class Builder { public abstract Builder setMtlsProvider(MtlsProvider mtlsProvider); + abstract Builder setCertificateBasedAccess(CertificateBasedAccess certificateBasedAccess); + public abstract Builder setUsingGDCH(boolean usingGDCH); public abstract Builder setResolvedEndpoint(String resolvedEndpoint); @@ -238,8 +250,11 @@ public abstract static class Builder { abstract boolean switchToMtlsEndpointAllowed(); + @Nullable abstract MtlsProvider mtlsProvider(); + abstract CertificateBasedAccess certificateBasedAccess(); + abstract boolean usingGDCH(); abstract String resolvedUniverseDomain(); @@ -272,7 +287,22 @@ private String determineUniverseDomain() { /** Determines the fully resolved endpoint and universe domain values */ private String determineEndpoint() throws IOException { - MtlsProvider mtlsProvider = mtlsProvider() == null ? new MtlsProvider() : mtlsProvider(); + CertificateBasedAccess certificateBasedAccess = + certificateBasedAccess() == null + ? CertificateBasedAccess.createWithSystemEnv() + : certificateBasedAccess(); + MtlsProvider mtlsProvider = mtlsProvider(); + if (mtlsProvider == null) { + try { + mtlsProvider = DefaultMtlsProviderFactory.create(); + } catch (CertificateSourceUnavailableException e) { + // This is okay. Leave mtlsProvider as null; + } catch (IOException e) { + LOG.log( + Level.WARNING, + "DefaultMtlsProviderFactory encountered unexpected IOException: " + e.getMessage()); + } + } // TransportChannelProvider's endpoint will override the ClientSettings' endpoint String customEndpoint = transportChannelProviderEndpoint() == null @@ -294,7 +324,11 @@ private String determineEndpoint() throws IOException { String endpoint = mtlsEndpointResolver( - customEndpoint, mtlsEndpoint(), switchToMtlsEndpointAllowed(), mtlsProvider); + customEndpoint, + mtlsEndpoint(), + switchToMtlsEndpointAllowed(), + mtlsProvider, + certificateBasedAccess); // Check if mTLS is configured with non-GDU if (endpoint.equals(mtlsEndpoint()) @@ -351,16 +385,18 @@ String mtlsEndpointResolver( String endpoint, String mtlsEndpoint, boolean switchToMtlsEndpointAllowed, - MtlsProvider mtlsProvider) + MtlsProvider mtlsProvider, + CertificateBasedAccess certificateBasedAccess) throws IOException { - if (switchToMtlsEndpointAllowed && mtlsProvider != null) { - switch (mtlsProvider.getMtlsEndpointUsagePolicy()) { + if (switchToMtlsEndpointAllowed && certificateBasedAccess != null && mtlsProvider != null) { + switch (certificateBasedAccess.getMtlsEndpointUsagePolicy()) { case ALWAYS: return mtlsEndpoint; case NEVER: return endpoint; default: - if (mtlsProvider.useMtlsClientCertificate() && mtlsProvider.getKeyStore() != null) { + if (certificateBasedAccess.useMtlsClientCertificate() + && mtlsProvider.getKeyStore() != null) { return mtlsEndpoint; } return endpoint; diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/CertificateBasedAccess.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/CertificateBasedAccess.java new file mode 100644 index 0000000000..6f722bff60 --- /dev/null +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/CertificateBasedAccess.java @@ -0,0 +1,83 @@ +/* + * Copyright 2025 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.rpc.mtls; + +import com.google.api.core.InternalApi; +import com.google.api.gax.rpc.internal.EnvironmentProvider; + +/** + * Utility class for handling certificate-based access configurations. + * + *

This class handles the processing of GOOGLE_API_USE_CLIENT_CERTIFICATE and + * GOOGLE_API_USE_MTLS_ENDPOINT environment variables according to https://google.aip.dev/auth/4114 + */ +@InternalApi +public class CertificateBasedAccess { + + private final EnvironmentProvider envProvider; + + /** The EnvironmentProvider mechanism supports env var injection for unit tests. */ + public CertificateBasedAccess(EnvironmentProvider envProvider) { + this.envProvider = envProvider; + } + + public static CertificateBasedAccess createWithSystemEnv() { + return new CertificateBasedAccess(System::getenv); + } + + /** + * The policy for mutual TLS endpoint usage. NEVER means always use regular endpoint; ALWAYS means + * always use mTLS endpoint; AUTO means auto switch to mTLS endpoint if client certificate exists + * and should be used. + */ + public enum MtlsEndpointUsagePolicy { + NEVER, + AUTO, + ALWAYS; + } + + /** Returns if mutual TLS client certificate should be used. */ + public boolean useMtlsClientCertificate() { + String useClientCertificate = envProvider.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE"); + return "true".equals(useClientCertificate); + } + + /** Returns the current mutual TLS endpoint usage policy. */ + public MtlsEndpointUsagePolicy getMtlsEndpointUsagePolicy() { + String mtlsEndpointUsagePolicy = envProvider.getenv("GOOGLE_API_USE_MTLS_ENDPOINT"); + if ("never".equals(mtlsEndpointUsagePolicy)) { + return MtlsEndpointUsagePolicy.NEVER; + } else if ("always".equals(mtlsEndpointUsagePolicy)) { + return MtlsEndpointUsagePolicy.ALWAYS; + } + return MtlsEndpointUsagePolicy.AUTO; + } +} diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/ContextAwareMetadataJson.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/ContextAwareMetadataJson.java index 25d7d27de7..9e92ac5ce0 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/ContextAwareMetadataJson.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/ContextAwareMetadataJson.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Google LLC + * Copyright 2025 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,12 +32,18 @@ import com.google.api.client.json.GenericJson; import com.google.api.client.util.Key; -import com.google.api.core.BetaApi; import com.google.common.collect.ImmutableList; import java.util.List; -/** Data class representing context_aware_metadata.json file. */ -@BetaApi +/** + * Data class representing context_aware_metadata.json file. + * + *

This class is deprecated. It has been replaced by + * com.google.auth.mtls.ContextAwareMetadataJson from the Java auth library. + * + *

Note: This class is for Google cloud internal use only. + */ +@Deprecated public class ContextAwareMetadataJson extends GenericJson { /** Cert provider command */ @Key("cert_provider_command") diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/MtlsProvider.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/MtlsProvider.java index c24fc80d6f..88e423c47c 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/MtlsProvider.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/mtls/MtlsProvider.java @@ -48,8 +48,14 @@ /** * Provider class for mutual TLS. It is used to configure the mutual TLS in the transport with the * default client certificate on device. + * + *

This class is deprecated. It has been replaced by com.google.auth.mtls.SecureConnectProvider + * from the Java auth library. + * + *

Note: This class is for Google cloud internal use only. */ @BetaApi +@Deprecated public class MtlsProvider { interface ProcessProvider { public Process createProcess(InputStream metadata) throws IOException; 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 59342927ca..ef64ccd726 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 @@ -34,9 +34,10 @@ import com.google.api.gax.core.NoCredentialsProvider; import com.google.api.gax.rpc.internal.EnvironmentProvider; -import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.api.gax.rpc.mtls.CertificateBasedAccess; import com.google.api.gax.rpc.testing.FakeMtlsProvider; import com.google.auth.Credentials; +import com.google.auth.mtls.MtlsProvider; import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.common.truth.Truth; import io.grpc.Status; @@ -53,12 +54,15 @@ class EndpointContextTest { @BeforeEach void setUp() throws IOException { + MtlsProvider mtlsProvider = + new FakeMtlsProvider(FakeMtlsProvider.createTestMtlsKeyStore(), "", false); defaultEndpointContextBuilder = EndpointContext.newBuilder() .setServiceName("test") .setUniverseDomain(Credentials.GOOGLE_DEFAULT_UNIVERSE) .setClientSettingsEndpoint(DEFAULT_ENDPOINT) - .setMtlsEndpoint(DEFAULT_MTLS_ENDPOINT); + .setMtlsEndpoint(DEFAULT_MTLS_ENDPOINT) + .setMtlsProvider(mtlsProvider); statusCode = Mockito.mock(StatusCode.class); Mockito.when(statusCode.getCode()).thenReturn(StatusCode.Code.UNAUTHENTICATED); Mockito.when(statusCode.getTransportCode()).thenReturn(Status.Code.UNAUTHENTICATED); @@ -66,107 +70,111 @@ void setUp() throws IOException { @Test void mtlsEndpointResolver_switchToMtlsAllowedIsFalse() throws IOException { - boolean useClientCertificate = true; boolean throwExceptionForGetKeyStore = false; MtlsProvider mtlsProvider = new FakeMtlsProvider( - useClientCertificate, - MtlsProvider.MtlsEndpointUsagePolicy.AUTO, - FakeMtlsProvider.createTestMtlsKeyStore(), - "", - throwExceptionForGetKeyStore); + FakeMtlsProvider.createTestMtlsKeyStore(), "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = false; + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "true"); Truth.assertThat( defaultEndpointContextBuilder.mtlsEndpointResolver( - DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) + DEFAULT_ENDPOINT, + DEFAULT_MTLS_ENDPOINT, + switchToMtlsEndpointAllowed, + mtlsProvider, + certificateBasedAccess)) .isEqualTo(DEFAULT_ENDPOINT); } @Test void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageAuto() throws IOException { - boolean useClientCertificate = true; boolean throwExceptionForGetKeyStore = false; MtlsProvider mtlsProvider = new FakeMtlsProvider( - useClientCertificate, - MtlsProvider.MtlsEndpointUsagePolicy.AUTO, - FakeMtlsProvider.createTestMtlsKeyStore(), - "", - throwExceptionForGetKeyStore); + FakeMtlsProvider.createTestMtlsKeyStore(), "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "true"); Truth.assertThat( defaultEndpointContextBuilder.mtlsEndpointResolver( - DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) + DEFAULT_ENDPOINT, + DEFAULT_MTLS_ENDPOINT, + switchToMtlsEndpointAllowed, + mtlsProvider, + certificateBasedAccess)) .isEqualTo(DEFAULT_MTLS_ENDPOINT); } @Test void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageAlways() throws IOException { - boolean useClientCertificate = true; boolean throwExceptionForGetKeyStore = false; MtlsProvider mtlsProvider = new FakeMtlsProvider( - useClientCertificate, - MtlsProvider.MtlsEndpointUsagePolicy.ALWAYS, - FakeMtlsProvider.createTestMtlsKeyStore(), - "", - throwExceptionForGetKeyStore); + FakeMtlsProvider.createTestMtlsKeyStore(), "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "always" : "true"); Truth.assertThat( defaultEndpointContextBuilder.mtlsEndpointResolver( - DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) + DEFAULT_ENDPOINT, + DEFAULT_MTLS_ENDPOINT, + switchToMtlsEndpointAllowed, + mtlsProvider, + certificateBasedAccess)) .isEqualTo(DEFAULT_MTLS_ENDPOINT); } @Test void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_mtlsUsageNever() throws IOException { - boolean useClientCertificate = true; boolean throwExceptionForGetKeyStore = false; MtlsProvider mtlsProvider = new FakeMtlsProvider( - useClientCertificate, - MtlsProvider.MtlsEndpointUsagePolicy.NEVER, - FakeMtlsProvider.createTestMtlsKeyStore(), - "", - throwExceptionForGetKeyStore); + FakeMtlsProvider.createTestMtlsKeyStore(), "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "never" : "true"); Truth.assertThat( defaultEndpointContextBuilder.mtlsEndpointResolver( - DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) + DEFAULT_ENDPOINT, + DEFAULT_MTLS_ENDPOINT, + switchToMtlsEndpointAllowed, + mtlsProvider, + certificateBasedAccess)) .isEqualTo(DEFAULT_ENDPOINT); } @Test void mtlsEndpointResolver_switchToMtlsAllowedIsTrue_useCertificateIsFalse_nullMtlsKeystore() throws IOException { - boolean useClientCertificate = false; boolean throwExceptionForGetKeyStore = false; - MtlsProvider mtlsProvider = - new FakeMtlsProvider( - useClientCertificate, - MtlsProvider.MtlsEndpointUsagePolicy.AUTO, - null, - "", - throwExceptionForGetKeyStore); + MtlsProvider mtlsProvider = new FakeMtlsProvider(null, "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "false"); Truth.assertThat( defaultEndpointContextBuilder.mtlsEndpointResolver( - DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, mtlsProvider)) + DEFAULT_ENDPOINT, + DEFAULT_MTLS_ENDPOINT, + switchToMtlsEndpointAllowed, + mtlsProvider, + certificateBasedAccess)) .isEqualTo(DEFAULT_ENDPOINT); } @Test void mtlsEndpointResolver_getKeyStore_throwsIOException() throws IOException { - boolean useClientCertificate = true; boolean throwExceptionForGetKeyStore = true; - MtlsProvider mtlsProvider = - new FakeMtlsProvider( - useClientCertificate, - MtlsProvider.MtlsEndpointUsagePolicy.AUTO, - null, - "", - throwExceptionForGetKeyStore); + MtlsProvider mtlsProvider = new FakeMtlsProvider(null, "", throwExceptionForGetKeyStore); boolean switchToMtlsEndpointAllowed = true; + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "true"); assertThrows( IOException.class, () -> @@ -174,7 +182,8 @@ void mtlsEndpointResolver_getKeyStore_throwsIOException() throws IOException { DEFAULT_ENDPOINT, DEFAULT_MTLS_ENDPOINT, switchToMtlsEndpointAllowed, - mtlsProvider)); + mtlsProvider, + certificateBasedAccess)); } @Test @@ -260,18 +269,17 @@ void endpointContextBuild_noUniverseDomain_noEndpoints() throws IOException { @Test void endpointContextBuild_mtlsConfigured_GDU() throws IOException { MtlsProvider mtlsProvider = - new FakeMtlsProvider( - true, - MtlsProvider.MtlsEndpointUsagePolicy.ALWAYS, - FakeMtlsProvider.createTestMtlsKeyStore(), - "", - false); + new FakeMtlsProvider(FakeMtlsProvider.createTestMtlsKeyStore(), "", false); + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "always" : "true"); EndpointContext endpointContext = defaultEndpointContextBuilder .setClientSettingsEndpoint(null) .setTransportChannelProviderEndpoint(null) .setSwitchToMtlsEndpointAllowed(true) .setMtlsProvider(mtlsProvider) + .setCertificateBasedAccess(certificateBasedAccess) .build(); Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_MTLS_ENDPOINT); Truth.assertThat(endpointContext.resolvedUniverseDomain()) @@ -282,19 +290,18 @@ void endpointContextBuild_mtlsConfigured_GDU() throws IOException { void endpointContextBuild_mtlsConfigured_nonGDU_throwsIllegalArgumentException() throws IOException { MtlsProvider mtlsProvider = - new FakeMtlsProvider( - true, - MtlsProvider.MtlsEndpointUsagePolicy.ALWAYS, - FakeMtlsProvider.createTestMtlsKeyStore(), - "", - false); + new FakeMtlsProvider(FakeMtlsProvider.createTestMtlsKeyStore(), "", false); + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "always" : "true"); EndpointContext.Builder endpointContextBuilder = defaultEndpointContextBuilder .setUniverseDomain("random.com") .setClientSettingsEndpoint(null) .setTransportChannelProviderEndpoint(null) .setSwitchToMtlsEndpointAllowed(true) - .setMtlsProvider(mtlsProvider); + .setMtlsProvider(mtlsProvider) + .setCertificateBasedAccess(certificateBasedAccess); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, endpointContextBuilder::build); Truth.assertThat(exception.getMessage()) diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/AbstractMtlsTransportChannelTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/AbstractMtlsTransportChannelTest.java index 1251dc47d1..bea4674b76 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/AbstractMtlsTransportChannelTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/AbstractMtlsTransportChannelTest.java @@ -35,8 +35,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.google.api.gax.rpc.mtls.MtlsProvider.MtlsEndpointUsagePolicy; import com.google.api.gax.rpc.testing.FakeMtlsProvider; +import com.google.auth.mtls.MtlsProvider; import java.io.IOException; import java.security.GeneralSecurityException; import org.junit.jupiter.api.Test; @@ -48,42 +48,49 @@ public abstract class AbstractMtlsTransportChannelTest { * GrpcTransportChannel, the mTLS object is the ChannelCredentials. The transport channel is mTLS * if and only if the related mTLS object is not null. */ - protected abstract Object getMtlsObjectFromTransportChannel(MtlsProvider provider) + protected abstract Object getMtlsObjectFromTransportChannel( + MtlsProvider provider, CertificateBasedAccess certificateBasedAccess) throws IOException, GeneralSecurityException; @Test void testNotUseClientCertificate() throws IOException, GeneralSecurityException { - MtlsProvider provider = - new FakeMtlsProvider(false, MtlsEndpointUsagePolicy.AUTO, null, "", false); - assertNull(getMtlsObjectFromTransportChannel(provider)); + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "false"); + MtlsProvider provider = new FakeMtlsProvider(null, "", false); + assertNull(getMtlsObjectFromTransportChannel(provider, certificateBasedAccess)); } @Test void testUseClientCertificate() throws IOException, GeneralSecurityException { + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "true"); MtlsProvider provider = - new FakeMtlsProvider( - true, - MtlsEndpointUsagePolicy.AUTO, - FakeMtlsProvider.createTestMtlsKeyStore(), - "", - false); - assertNotNull(getMtlsObjectFromTransportChannel(provider)); + new FakeMtlsProvider(FakeMtlsProvider.createTestMtlsKeyStore(), "", false); + assertNotNull(getMtlsObjectFromTransportChannel(provider, certificateBasedAccess)); } @Test void testNoClientCertificate() throws IOException, GeneralSecurityException { - MtlsProvider provider = - new FakeMtlsProvider(true, MtlsEndpointUsagePolicy.AUTO, null, "", false); - assertNull(getMtlsObjectFromTransportChannel(provider)); + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "true"); + MtlsProvider provider = new FakeMtlsProvider(null, "", false); + assertNull(getMtlsObjectFromTransportChannel(provider, certificateBasedAccess)); } @Test void testGetKeyStoreThrows() throws GeneralSecurityException { // Test the case where provider.getKeyStore() throws. - MtlsProvider provider = - new FakeMtlsProvider(true, MtlsEndpointUsagePolicy.AUTO, null, "", true); + CertificateBasedAccess certificateBasedAccess = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "true"); + MtlsProvider provider = new FakeMtlsProvider(null, "", true); IOException actual = - assertThrows(IOException.class, () -> getMtlsObjectFromTransportChannel(provider)); + assertThrows( + IOException.class, + () -> getMtlsObjectFromTransportChannel(provider, certificateBasedAccess)); assertTrue(actual.getMessage().contains("getKeyStore throws exception")); } } diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/CertificateBasedAccessTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/CertificateBasedAccessTest.java new file mode 100644 index 0000000000..e328e0af47 --- /dev/null +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/CertificateBasedAccessTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2021 Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.api.gax.rpc.mtls; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class CertificateBasedAccessTest { + + @Test + void testUseMtlsEndpointAlways() { + CertificateBasedAccess cba = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "always" : "false"); + assertEquals( + CertificateBasedAccess.MtlsEndpointUsagePolicy.ALWAYS, cba.getMtlsEndpointUsagePolicy()); + } + + @Test + void testUseMtlsEndpointAuto() { + CertificateBasedAccess cba = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "false"); + assertEquals( + CertificateBasedAccess.MtlsEndpointUsagePolicy.AUTO, cba.getMtlsEndpointUsagePolicy()); + } + + @Test + void testUseMtlsEndpointNever() { + CertificateBasedAccess cba = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "never" : "false"); + assertEquals( + CertificateBasedAccess.MtlsEndpointUsagePolicy.NEVER, cba.getMtlsEndpointUsagePolicy()); + } + + @Test + void testUseMtlsClientCertificateTrue() { + CertificateBasedAccess cba = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_CLIENT_CERTIFICATE") ? "true" : "auto"); + assertTrue(cba.useMtlsClientCertificate()); + } + + @Test + void testUseMtlsClientCertificateFalse() { + CertificateBasedAccess cba = + new CertificateBasedAccess( + name -> name.equals("GOOGLE_API_USE_CLIENT_CERTIFICATE") ? "false" : "auto"); + assertFalse(cba.useMtlsClientCertificate()); + } +} diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/MtlsProviderTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/MtlsProviderTest.java deleted file mode 100644 index 9835b4c120..0000000000 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/mtls/MtlsProviderTest.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2021 Google LLC - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.google.api.gax.rpc.mtls; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.GeneralSecurityException; -import java.util.List; -import org.junit.jupiter.api.Test; - -class MtlsProviderTest { - - private static class TestCertProviderCommandProcess extends Process { - - private boolean runForever; - private int exitValue; - - public TestCertProviderCommandProcess(int exitValue, boolean runForever) { - this.runForever = runForever; - this.exitValue = exitValue; - } - - @Override - public OutputStream getOutputStream() { - return null; - } - - @Override - public InputStream getInputStream() { - return null; - } - - @Override - public InputStream getErrorStream() { - return null; - } - - @Override - public int waitFor() throws InterruptedException { - return 0; - } - - @Override - public int exitValue() { - if (runForever) { - throw new IllegalThreadStateException(); - } - return exitValue; - } - - @Override - public void destroy() {} - } - - static class TestProcessProvider implements MtlsProvider.ProcessProvider { - - private int exitCode; - - public TestProcessProvider(int exitCode) { - this.exitCode = exitCode; - } - - @Override - public Process createProcess(InputStream metadata) throws IOException { - return new TestCertProviderCommandProcess(exitCode, false); - } - } - - @Test - void testUseMtlsEndpointAlways() { - MtlsProvider mtlsProvider = - new MtlsProvider( - name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "always" : "false", - new TestProcessProvider(0), - "/path/to/missing/file"); - assertEquals( - MtlsProvider.MtlsEndpointUsagePolicy.ALWAYS, mtlsProvider.getMtlsEndpointUsagePolicy()); - } - - @Test - void testUseMtlsEndpointAuto() { - MtlsProvider mtlsProvider = - new MtlsProvider( - name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "false", - new TestProcessProvider(0), - "/path/to/missing/file"); - assertEquals( - MtlsProvider.MtlsEndpointUsagePolicy.AUTO, mtlsProvider.getMtlsEndpointUsagePolicy()); - } - - @Test - void testUseMtlsEndpointNever() { - MtlsProvider mtlsProvider = - new MtlsProvider( - name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "never" : "false", - new TestProcessProvider(0), - "/path/to/missing/file"); - assertEquals( - MtlsProvider.MtlsEndpointUsagePolicy.NEVER, mtlsProvider.getMtlsEndpointUsagePolicy()); - } - - @Test - void testUseMtlsClientCertificateTrue() { - MtlsProvider mtlsProvider = - new MtlsProvider( - name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "true", - new TestProcessProvider(0), - "/path/to/missing/file"); - assertTrue(mtlsProvider.useMtlsClientCertificate()); - } - - @Test - void testUseMtlsClientCertificateFalse() { - MtlsProvider mtlsProvider = - new MtlsProvider( - name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "auto" : "false", - new TestProcessProvider(0), - "/path/to/missing/file"); - assertFalse(mtlsProvider.useMtlsClientCertificate()); - } - - @Test - void testGetKeyStore() throws IOException { - MtlsProvider mtlsProvider = - new MtlsProvider( - name -> name.equals("GOOGLE_API_USE_MTLS_ENDPOINT") ? "always" : "false", - new TestProcessProvider(0), - "/path/to/missing/file"); - assertNull(mtlsProvider.getKeyStore()); - } - - @Test - void testGetKeyStoreNonZeroExitCode() - throws IOException, InterruptedException, GeneralSecurityException { - InputStream metadata = - this.getClass() - .getClassLoader() - .getResourceAsStream("com/google/api/gax/rpc/mtls/mtlsCertAndKey.pem"); - IOException actual = - assertThrows( - IOException.class, - () -> MtlsProvider.getKeyStore(metadata, new TestProcessProvider(1))); - assertTrue( - actual.getMessage().contains("Cert provider command failed with exit code: 1"), - "expected to fail with nonzero exit code"); - } - - @Test - void testExtractCertificateProviderCommand() throws IOException { - InputStream inputStream = - this.getClass() - .getClassLoader() - .getResourceAsStream("com/google/api/gax/rpc/mtls/mtls_context_aware_metadata.json"); - List command = MtlsProvider.extractCertificateProviderCommand(inputStream); - assertEquals(2, command.size()); - assertEquals("some_binary", command.get(0)); - assertEquals("some_argument", command.get(1)); - } - - @Test - void testRunCertificateProviderCommandSuccess() throws IOException, InterruptedException { - Process certCommandProcess = new TestCertProviderCommandProcess(0, false); - int exitValue = MtlsProvider.runCertificateProviderCommand(certCommandProcess, 100); - assertEquals(0, exitValue); - } - - @Test - void testRunCertificateProviderCommandTimeout() throws InterruptedException { - Process certCommandProcess = new TestCertProviderCommandProcess(0, true); - IOException actual = - assertThrows( - IOException.class, - () -> MtlsProvider.runCertificateProviderCommand(certCommandProcess, 100)); - assertTrue( - actual.getMessage().contains("cert provider command timed out"), - "expected to fail with timeout"); - } -} diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeMtlsProvider.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeMtlsProvider.java index e5f5c3a91a..abe374dac6 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeMtlsProvider.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeMtlsProvider.java @@ -32,42 +32,24 @@ import com.google.api.client.util.SecurityUtils; import com.google.api.core.InternalApi; -import com.google.api.gax.rpc.mtls.MtlsProvider; +import com.google.auth.mtls.MtlsProvider; import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; import java.security.KeyStore; @InternalApi("for testing") -public class FakeMtlsProvider extends MtlsProvider { - private boolean useClientCertificate; - private MtlsEndpointUsagePolicy mtlsEndpointUsagePolicy; +public class FakeMtlsProvider implements MtlsProvider { private KeyStore keyStore; private boolean throwExceptionForGetKeyStore; public FakeMtlsProvider( - boolean useClientCertificate, - MtlsEndpointUsagePolicy mtlsEndpointUsagePolicy, - KeyStore keystore, - String keyStorePassword, - boolean throwExceptionForGetKeyStore) { + KeyStore keystore, String keyStorePassword, boolean throwExceptionForGetKeyStore) { super(); - this.useClientCertificate = useClientCertificate; - this.mtlsEndpointUsagePolicy = mtlsEndpointUsagePolicy; this.keyStore = keystore; this.throwExceptionForGetKeyStore = throwExceptionForGetKeyStore; } - @Override - public boolean useMtlsClientCertificate() { - return useClientCertificate; - } - - @Override - public MtlsEndpointUsagePolicy getMtlsEndpointUsagePolicy() { - return mtlsEndpointUsagePolicy; - } - @Override public KeyStore getKeyStore() throws IOException { if (throwExceptionForGetKeyStore) { @@ -76,6 +58,11 @@ public KeyStore getKeyStore() throws IOException { return keyStore; } + @Override + public boolean isAvailable() throws IOException { + return true; + } + public static KeyStore createTestMtlsKeyStore() throws IOException { try { InputStream certAndKey =