Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: support GDC-H Credentials #1642

Merged
merged 54 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
80f7327
chore: initial additions to handle GDC-H API audience
diegomarquezp Apr 14, 2023
110f043
chore: add unit tests for GDC-H
diegomarquezp Apr 20, 2023
7385189
chore: cleanup of logic
diegomarquezp May 3, 2023
032af75
chore: decompose tests into separate methods
diegomarquezp May 3, 2023
6cc7f6b
chore: fix clirr diff check
diegomarquezp May 3, 2023
78df0fd
chore: fmt:format
diegomarquezp May 3, 2023
f5b9d99
chore: add support in `ClientSettings`
diegomarquezp May 17, 2023
5f149db
Merge remote-tracking branch 'origin/main' into gdc-h
diegomarquezp May 18, 2023
bbde736
chore: add showcase IT for GDCH credentials
diegomarquezp May 18, 2023
8fb9ced
chore: comments
diegomarquezp May 18, 2023
ea4a03c
chore: improve tests
diegomarquezp May 18, 2023
ea05922
chore: add partial IT for testing context credential
diegomarquezp May 23, 2023
5cbf2b2
chore: recreate GdchCredentials with audience using convenience method
diegomarquezp May 24, 2023
40f21a5
chore: more readable api audience logic
diegomarquezp May 24, 2023
27cb7c7
chore: no wildcard imports
diegomarquezp May 24, 2023
bd44dd1
chore: javadoc for public methods
diegomarquezp May 24, 2023
c5cac43
chore: gdch test to use default null initialization
diegomarquezp May 24, 2023
f1b5cbf
chore: tear down for gdch IT
diegomarquezp May 24, 2023
5e2af11
chore: `assertThrows` for gdch ITs
diegomarquezp May 24, 2023
a3a0f4b
chore: mvn fmt:format
diegomarquezp May 24, 2023
ef540ad
test: remove context test
diegomarquezp May 25, 2023
d1b7b92
docs: explain that audience will be overriden if set through client/s…
diegomarquezp May 25, 2023
ce57a76
test: test audience setting should modify initial credentials
diegomarquezp May 26, 2023
524712a
Merge branch 'main' into gdc-h
diegomarquezp May 26, 2023
33e95ec
chore: clirr check
diegomarquezp May 26, 2023
44e5369
Merge branch 'gdc-h' of https://github.com/googleapis/gapic-generator…
diegomarquezp May 26, 2023
32e175f
chore: ignore gdch changes
diegomarquezp May 26, 2023
f3c2a0a
chore: format
diegomarquezp May 26, 2023
a297a16
chore: default to endpoint if audience not provided
diegomarquezp Jun 14, 2023
1e5cac4
test: refresh gdch creds to confirm audience works
diegomarquezp Jun 20, 2023
80f1821
Merge branch 'main' into gdc-h
diegomarquezp Jun 21, 2023
1875523
chore: fmt
diegomarquezp Jun 21, 2023
f38a76b
Merge remote-tracking branch 'origin/gdc-h' into gdc-h
diegomarquezp Jun 21, 2023
3360925
chore: fmt
diegomarquezp Jun 21, 2023
1608cc2
chore: better test names in ClientContextTest
diegomarquezp Jun 21, 2023
6f9f4c5
chore: better test names for showcase tests
diegomarquezp Jun 21, 2023
cdfc1ac
chore: simplify refresh verification logic
diegomarquezp Jun 22, 2023
434ee7a
chore: include outcome in gdch it test names
diegomarquezp Jun 22, 2023
f255d09
chore: expand comments in GDCH ITs
diegomarquezp Jun 22, 2023
59b9c26
Merge remote-tracking branch 'origin/main' into gdc-h
diegomarquezp Jun 22, 2023
c42a160
test: intercept mock transport to verify audience
diegomarquezp Jun 23, 2023
0fe4c6b
chore: fmt
diegomarquezp Jun 23, 2023
1c69890
chore: move auth test-jar to shared dependencies
diegomarquezp Jun 23, 2023
a2e6c90
chore: cleanup
diegomarquezp Jun 23, 2023
d6ce65c
chore: use inferred version for auth library
diegomarquezp Jun 27, 2023
60828fe
deps: update google-auth-java-library to 1.19.0
diegomarquezp Jun 28, 2023
e30dabb
choreL fmt ITGdch.java
diegomarquezp Jun 28, 2023
ad0f3ba
chore: import auth test-jar using common version variable
diegomarquezp Jun 28, 2023
4f819b7
chore: remove auth test-jar import from first-party-dependencies
diegomarquezp Jun 28, 2023
95a3568
chore: add license headers to new files
diegomarquezp Jun 28, 2023
5e84582
chore: revert google-auth-version to be obtained from main branch
diegomarquezp Jun 28, 2023
7e7979a
Merge remote-tracking branch 'origin/main' into gdc-h
diegomarquezp Jun 28, 2023
596ff9b
chore: correct showcase parent pom indentation
diegomarquezp Jun 28, 2023
f08dffc
chore: remove resource declaration for native test build
diegomarquezp Jun 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gax-java/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ target

# IntelliJ
.idea
.ijwb
*.iml
out

Expand Down
12 changes: 12 additions & 0 deletions gax-java/gax/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,16 @@
<className>com/google/api/gax/paging/Page</className>
<method>* stream*(*)</method>
</difference>
<difference>
<!-- add gdchApiAudience to ClientContext and StubSettings -->
<differenceType>7012</differenceType>
<className>com/google/api/gax/rpc/ClientContext</className>
<method>* gdch*(*)</method>
</difference>
<difference>
<!-- add gdchApiAudience to ClientContext and StubSettings -->
<differenceType>7012</differenceType>
<className>com/google/api/gax/rpc/StubSettings</className>
<method>* gdch*(*)</method>
</difference>
</differences>
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@
import com.google.api.gax.tracing.ApiTracerFactory;
import com.google.api.gax.tracing.BaseApiTracerFactory;
import com.google.auth.Credentials;
import com.google.auth.oauth2.GdchCredentials;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -109,6 +111,9 @@ public abstract class ClientContext {
@Nonnull
public abstract ApiTracerFactory getTracerFactory();

@Nullable
public abstract String getGdchApiAudience();

public static Builder newBuilder() {
return new AutoValue_ClientContext.Builder()
.setBackgroundResources(Collections.<BackgroundResource>emptyList())
Expand All @@ -119,7 +124,8 @@ public static Builder newBuilder() {
.setStreamWatchdog(null)
.setStreamWatchdogCheckInterval(Duration.ZERO)
.setTracerFactory(BaseApiTracerFactory.getInstance())
.setQuotaProjectId(null);
.setQuotaProjectId(null)
.setGdchApiAudience(null);
}

public abstract Builder toBuilder();
Expand Down Expand Up @@ -167,6 +173,23 @@ public static ClientContext create(StubSettings settings) throws IOException {

Credentials credentials = settings.getCredentialsProvider().getCredentials();

String gdhcApiAudience = settings.getGdchApiAudience();
diegomarquezp marked this conversation as resolved.
Show resolved Hide resolved
if (gdhcApiAudience != null && credentials instanceof GdchCredentials) {
diegomarquezp marked this conversation as resolved.
Show resolved Hide resolved
// We recompute the GdchCredentials with the audience
URI gdchAudienceUri;
try {
gdchAudienceUri = URI.create(gdhcApiAudience);
} catch (IllegalArgumentException ex) { // thrown when passing a malformed uri string
throw new IllegalArgumentException("The GDC-H API audience string is not a valid URI", ex);
}
credentials =
((GdchCredentials) credentials).toBuilder().setGdchAudience(gdchAudienceUri).build();
diegomarquezp marked this conversation as resolved.
Show resolved Hide resolved
} else if (gdhcApiAudience != null) {
// We have audience set for non-gdch credentials - this is not allowed
throw new IllegalArgumentException(
"GDC-H API audience can only be set when using GdchCredentials");
}

if (settings.getQuotaProjectId() != null) {
// If the quotaProjectId is set, wrap original credentials with correct quotaProjectId as
// QuotaProjectIdHidingCredentials.
Expand Down Expand Up @@ -325,6 +348,8 @@ public abstract static class Builder {
@BetaApi("The surface for tracing is not stable yet and may change in the future.")
public abstract Builder setTracerFactory(ApiTracerFactory tracerFactory);

public abstract Builder setGdchApiAudience(String credentialsApiAudience);
diegomarquezp marked this conversation as resolved.
Show resolved Hide resolved

public abstract ClientContext build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ public final Duration getWatchdogCheckInterval() {
return stubSettings.getStreamWatchdogCheckInterval();
}

public final String getGdchApiAudience() {
return stubSettings.getGdchApiAudience();
}

public String toString() {
return MoreObjects.toStringHelper(this)
.add("executorProvider", getExecutorProvider())
Expand All @@ -124,6 +128,7 @@ public String toString() {
.add("quotaProjectId", getQuotaProjectId())
.add("watchdogProvider", getWatchdogProvider())
.add("watchdogCheckInterval", getWatchdogCheckInterval())
.add("gdchApiAudience", getGdchApiAudience())
.toString();
}

Expand Down Expand Up @@ -255,6 +260,16 @@ public B setWatchdogCheckInterval(@Nullable Duration checkInterval) {
return self();
}

/**
* Sets the GDC-H api audience. This is intended only to be used with {@link
* com.google.auth.oauth2.GdchCredentials} If this field is set and other type of {@link
* com.google.auth.Credentials} is used then an {@link IllegalArgumentException} will be thrown
*/
public B setGdchApiAudience(@Nullable String gdchApiAudience) {
stubSettings.setGdchApiAudience(gdchApiAudience);
return self();
}

/**
* Gets the ExecutorProvider that was previously set on this Builder. This ExecutorProvider is
* to use for running asynchronous API call logic (such as retries and long-running operations),
Expand Down Expand Up @@ -322,6 +337,11 @@ public Duration getWatchdogCheckInterval() {
return stubSettings.getStreamWatchdogCheckInterval();
}

@Nullable
public String getGdchApiAudience() {
return stubSettings.getGdchApiAudience();
}

/** Applies the given settings updater function to the given method settings builders. */
protected static void applyToAllUnaryMethods(
Iterable<UnaryCallSettings.Builder<?, ?>> methodSettingsBuilders,
Expand All @@ -344,6 +364,7 @@ public String toString() {
.add("quotaProjectId", getQuotaProjectId())
.add("watchdogProvider", getWatchdogProvider())
.add("watchdogCheckInterval", getWatchdogCheckInterval())
.add("gdchApiAudience", getGdchApiAudience())
.toString();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public abstract class StubSettings<SettingsT extends StubSettings<SettingsT>> {
private final String endpoint;
private final String mtlsEndpoint;
private final String quotaProjectId;
@Nullable private final String gdchApiAudience;
@Nullable private final WatchdogProvider streamWatchdogProvider;
@Nonnull private final Duration streamWatchdogCheckInterval;
@Nonnull private final ApiTracerFactory tracerFactory;
Expand Down Expand Up @@ -103,6 +104,7 @@ protected StubSettings(Builder builder) {
this.streamWatchdogCheckInterval = builder.streamWatchdogCheckInterval;
this.tracerFactory = builder.tracerFactory;
this.deprecatedExecutorProviderSet = builder.deprecatedExecutorProviderSet;
this.gdchApiAudience = builder.gdchApiAudience;
}

/** @deprecated Please use {@link #getBackgroundExecutorProvider()}. */
Expand Down Expand Up @@ -172,6 +174,11 @@ public ApiTracerFactory getTracerFactory() {
return tracerFactory;
}

@Nullable
public final String getGdchApiAudience() {
return gdchApiAudience;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
Expand All @@ -188,6 +195,7 @@ public String toString() {
.add("streamWatchdogProvider", streamWatchdogProvider)
.add("streamWatchdogCheckInterval", streamWatchdogCheckInterval)
.add("tracerFactory", tracerFactory)
.add("gdchApiAudience", gdchApiAudience)
.toString();
}

Expand All @@ -205,6 +213,7 @@ public abstract static class Builder<
private String endpoint;
private String mtlsEndpoint;
private String quotaProjectId;
@Nullable private String gdchApiAudience;
@Nullable private WatchdogProvider streamWatchdogProvider;
@Nonnull private Duration streamWatchdogCheckInterval;
@Nonnull private ApiTracerFactory tracerFactory;
Expand Down Expand Up @@ -234,6 +243,7 @@ protected Builder(StubSettings settings) {
this.streamWatchdogCheckInterval = settings.streamWatchdogCheckInterval;
this.tracerFactory = settings.tracerFactory;
this.deprecatedExecutorProviderSet = settings.deprecatedExecutorProviderSet;
this.gdchApiAudience = settings.gdchApiAudience;
}

/** Get Quota Project ID from Client Context * */
Expand Down Expand Up @@ -268,6 +278,7 @@ protected Builder(ClientContext clientContext) {
this.streamWatchdogCheckInterval = Duration.ofSeconds(10);
this.tracerFactory = BaseApiTracerFactory.getInstance();
this.deprecatedExecutorProviderSet = false;
this.gdchApiAudience = null;
} else {
ExecutorProvider fixedExecutorProvider =
FixedExecutorProvider.create(clientContext.getExecutor());
Expand All @@ -289,6 +300,7 @@ protected Builder(ClientContext clientContext) {
this.streamWatchdogCheckInterval = clientContext.getStreamWatchdogCheckInterval();
this.tracerFactory = clientContext.getTracerFactory();
this.quotaProjectId = getQuotaProjectIdFromClientContext(clientContext);
this.gdchApiAudience = clientContext.getGdchApiAudience();
blakeli0 marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -435,6 +447,11 @@ public B setStreamWatchdogCheckInterval(@Nonnull Duration checkInterval) {
return self();
}

public B setGdchApiAudience(String gdchApiAudience) {
diegomarquezp marked this conversation as resolved.
Show resolved Hide resolved
this.gdchApiAudience = gdchApiAudience;
return self();
}

/**
* Configures the {@link ApiTracerFactory} that will be used to generate traces.
*
Expand Down Expand Up @@ -513,6 +530,10 @@ public ApiTracerFactory getTracerFactory() {
return tracerFactory;
}

public String getGdchApiAudience() {
return gdchApiAudience;
}

/** Applies the given settings updater function to the given method settings builders. */
protected static void applyToAllUnaryMethods(
Iterable<UnaryCallSettings.Builder<?, ?>> methodSettingsBuilders,
Expand Down Expand Up @@ -540,6 +561,7 @@ public String toString() {
.add("streamWatchdogProvider", streamWatchdogProvider)
.add("streamWatchdogCheckInterval", streamWatchdogCheckInterval)
.add("tracerFactory", tracerFactory)
.add("gdchApiAudience", gdchApiAudience)
.toString();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,7 @@
package com.google.api.gax.rpc;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
diegomarquezp marked this conversation as resolved.
Show resolved Hide resolved

import com.google.api.core.ApiClock;
import com.google.api.gax.core.BackgroundResource;
Expand All @@ -49,10 +46,13 @@
import com.google.api.gax.rpc.testing.FakeStubSettings;
import com.google.api.gax.rpc.testing.FakeTransportChannel;
import com.google.auth.Credentials;
import com.google.auth.oauth2.ComputeEngineCredentials;
import com.google.auth.oauth2.GdchCredentials;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.collect.ImmutableMap;
import com.google.common.truth.Truth;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -769,4 +769,85 @@ public void testExecutorSettings() throws Exception {
transportChannel = (FakeTransportChannel) context.getTransportChannel();
assertThat(transportChannel.getExecutor()).isSameInstanceAs(executorProvider.getExecutor());
}

private Credentials getMockGdchCredentials() {
Credentials creds = Mockito.mock(GdchCredentials.class);

// GdchCredentials builder is mocked to accept a well-formed uri
GdchCredentials.Builder gdchCredsBuilder = Mockito.mock(GdchCredentials.Builder.class);
Mockito.when(gdchCredsBuilder.setGdchAudience(Mockito.any(URI.class)))
.thenReturn(gdchCredsBuilder);
Mockito.when(gdchCredsBuilder.build()).thenReturn((GdchCredentials) creds);
Mockito.when(((GdchCredentials) creds).toBuilder()).thenReturn(gdchCredsBuilder);
return creds;
}

private TransportChannelProvider getFakeTransportChannelProvider() {
return new FakeTransportProvider(
FakeTransportChannel.create(new FakeChannel()), null, true, null, null);
}

@Test
public void testGDCHCredentialsNoAudience() throws IOException {}

@Test
public void testGdchCredentialNoAudience_correct() throws IOException {
diegomarquezp marked this conversation as resolved.
Show resolved Hide resolved
TransportChannelProvider transportChannelProvider = getFakeTransportChannelProvider();
Credentials creds = getMockGdchCredentials();

// it should correctly create a client context with gdch creds and null audience
CredentialsProvider provider = FixedCredentialsProvider.create(creds);
StubSettings settings = new FakeStubSettings.Builder().setGdchApiAudience(null).build();
FakeClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings);
clientSettingsBuilder.setCredentialsProvider(provider);
clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider);
// should not throw
ClientContext context = ClientContext.create(clientSettingsBuilder.build());
assertThat(context.getCredentials()).isInstanceOf(GdchCredentials.class);
assertNull(context.getGdchApiAudience());
}

@Test
public void testGdchCredentialInvalidAudience_throws() throws IOException {
TransportChannelProvider transportChannelProvider = getFakeTransportChannelProvider();
Credentials creds = getMockGdchCredentials();
CredentialsProvider provider = FixedCredentialsProvider.create(creds);

// it should throw if both apiAudience and GDC-H creds are set but apiAudience is not a valid
// uri
StubSettings settings =
new FakeStubSettings.Builder().setGdchApiAudience("$invalid-uri:").build();
ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings);
clientSettingsBuilder.setCredentialsProvider(provider);
clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider);
final ClientSettings withGdchCredentialsAndMalformedApiAudience = clientSettingsBuilder.build();
// should throw
String exMessage =
assertThrows(
IllegalArgumentException.class,
() -> ClientContext.create(withGdchCredentialsAndMalformedApiAudience))
.getMessage();
assertThat(exMessage).contains("The GDC-H API audience string is not a valid URI");
}

@Test
public void testNonGdchCredentialAnyAudience_throws() throws IOException {
TransportChannelProvider transportChannelProvider = getFakeTransportChannelProvider();

// it should throw if apiAudience is set but not using GDC-H creds
StubSettings settings =
new FakeStubSettings.Builder().setGdchApiAudience("audience:test").build();
Credentials creds = Mockito.mock(ComputeEngineCredentials.class);
CredentialsProvider provider = FixedCredentialsProvider.create(creds);
ClientSettings.Builder clientSettingsBuilder = new FakeClientSettings.Builder(settings);
clientSettingsBuilder.setCredentialsProvider(provider);
clientSettingsBuilder.setTransportChannelProvider(transportChannelProvider);
final ClientSettings withComputeCredentials = clientSettingsBuilder.build();
// should throw
String exMessage =
assertThrows(
IllegalArgumentException.class, () -> ClientContext.create(withComputeCredentials))
.getMessage();
assertThat(exMessage).contains("GDC-H API audience can only be set when using GdchCredentials");
}
}
Loading