Skip to content

Commit

Permalink
feat: support GDC-H Credentials (#1642)
Browse files Browse the repository at this point in the history
* chore: initial additions to handle GDC-H API audience

* chore: add unit tests for GDC-H

* chore: cleanup of logic

* chore: decompose tests into separate methods

* chore: fix clirr diff check

* chore: fmt:format

* chore: add support in `ClientSettings`

* chore: add showcase IT for GDCH credentials

* chore: comments

* chore: improve tests

* chore: add partial IT for testing context credential

* chore: recreate GdchCredentials with audience using convenience method

* chore: more readable api audience logic

* chore: no wildcard imports

* chore: javadoc for public methods

* chore: gdch test to use default null initialization

* chore: tear down for gdch IT

* chore: `assertThrows` for gdch ITs

* chore: mvn fmt:format

* test: remove context test

* docs: explain that audience will be overriden if set through client/stub settings

* test: test audience setting should modify initial credentials

* chore: clirr check

* chore: ignore gdch changes

* chore: format

* chore: default to endpoint if audience not provided

* test: refresh gdch creds to confirm audience works

* chore: fmt

* chore: fmt

* chore: better test names in ClientContextTest

* chore: better test names for showcase tests

* chore: simplify refresh verification logic

* chore: include outcome in gdch it test names

* chore: expand comments in GDCH ITs

* test: intercept mock transport to verify audience

* chore: fmt

* chore: move auth test-jar to shared dependencies

* chore: cleanup

* chore: use inferred version for auth library

* deps: update google-auth-java-library to 1.19.0

* choreL fmt ITGdch.java

* chore: import auth test-jar using common version variable

* chore: remove auth test-jar import from first-party-dependencies

* chore: add license headers to new files

* chore: revert google-auth-version to be obtained from main branch

* chore: correct showcase parent pom indentation

* chore: remove resource declaration for native test build
  • Loading branch information
diegomarquezp committed Jun 28, 2023
1 parent 41007a9 commit 26da0d3
Show file tree
Hide file tree
Showing 12 changed files with 602 additions and 1 deletion.
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
6 changes: 6 additions & 0 deletions gax-java/gax/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
<className>com/google/api/gax/paging/Page</className>
<method>* stream*(*)</method>
</difference>
<difference>
<!-- add gdchApiAudience to ClientContext -->
<differenceType>7013</differenceType>
<className>com/google/api/gax/rpc/*</className>
<method>* *Gdch*(*)</method>
</difference>
<difference>
<differenceType>7006</differenceType>
<className>com/google/api/gax/rpc/ServerStreamingCallSettings$Builder</className>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*/
package com.google.api.gax.rpc;

import com.google.api.client.util.Strings;
import com.google.api.core.ApiClock;
import com.google.api.core.BetaApi;
import com.google.api.core.NanoClock;
Expand All @@ -40,11 +41,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 +112,13 @@ public abstract class ClientContext {
@Nonnull
public abstract ApiTracerFactory getTracerFactory();

/**
* Gets the API audience used when creating a Client that uses {@link
* com.google.auth.oauth2.GdchCredentials}
*/
@Nullable
public abstract String getGdchApiAudience();

public static Builder newBuilder() {
return new AutoValue_ClientContext.Builder()
.setBackgroundResources(Collections.<BackgroundResource>emptyList())
Expand All @@ -119,7 +129,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 +178,30 @@ public static ClientContext create(StubSettings settings) throws IOException {

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

String settingsGdchApiAudience = settings.getGdchApiAudience();
if (credentials instanceof GdchCredentials) {
// 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 {
throw new IllegalArgumentException("Could not infer GDCH api audience from settings");
}

URI gdchAudienceUri;
try {
gdchAudienceUri = URI.create(audienceString);
} 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).createWithGdchAudience(gdchAudienceUri);
} else if (!Strings.isNullOrEmpty(settingsGdchApiAudience)) {
throw new IllegalArgumentException(
"GDC-H API audience can only be set when using GdchCredentials");
}

if (settings.getQuotaProjectId() != null && credentials != null) {
// If the quotaProjectId is set, wrap original credentials with correct quotaProjectId as
// QuotaProjectIdHidingCredentials.
Expand Down Expand Up @@ -325,6 +360,17 @@ 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);

/**
* Sets the API audience used by {@link com.google.auth.oauth2.GdchCredentials} It cannot be
* used if other type of {@link com.google.auth.Credentials} is used
*
* <p>If the provided credentials already contain an api audience, it will be overriden by this
* one
*
* @param gdchApiAudience the audience to be used - must be a valid URI string
*/
public abstract Builder setGdchApiAudience(String gdchApiAudience);

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

/** Gets the GDCH API audience that was previously set in this Builder */
public final String getGdchApiAudience() {
return stubSettings.getGdchApiAudience();
}

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

Expand Down Expand Up @@ -255,6 +261,18 @@ 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.
* If the provided credentials already have an api audience, then it will be overriden by this
* audience
*/
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 +340,12 @@ public Duration getWatchdogCheckInterval() {
return stubSettings.getStreamWatchdogCheckInterval();
}

/** Gets the GDCH API audience that was previously set in this Builder */
@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 +368,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,12 @@ public ApiTracerFactory getTracerFactory() {
return tracerFactory;
}

/** Gets the GDCH API audience to be used with {@link com.google.auth.oauth2.GdchCredentials} */
@Nullable
public final String getGdchApiAudience() {
return gdchApiAudience;
}

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

Expand All @@ -205,6 +214,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 +244,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 +279,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 +301,7 @@ protected Builder(ClientContext clientContext) {
this.streamWatchdogCheckInterval = clientContext.getStreamWatchdogCheckInterval();
this.tracerFactory = clientContext.getTracerFactory();
this.quotaProjectId = getQuotaProjectIdFromClientContext(clientContext);
this.gdchApiAudience = clientContext.getGdchApiAudience();
}
}

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

/**
* Sets the API audience used by {@link com.google.auth.oauth2.GdchCredentials} It cannot be
* used if other type of {@link com.google.auth.Credentials} is used. If the provided
* credentials already have an api audience set, then it will be overriden by this audience
*
* @param gdchApiAudience the audience to be used - must be a valid URI string
*/
public B setGdchApiAudience(String gdchApiAudience) {
this.gdchApiAudience = gdchApiAudience;
return self();
}

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

/** Gets the GDCH API audience that was previously set in this Builder */
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 +570,7 @@ public String toString() {
.add("streamWatchdogProvider", streamWatchdogProvider)
.add("streamWatchdogCheckInterval", streamWatchdogCheckInterval)
.add("tracerFactory", tracerFactory)
.add("gdchApiAudience", gdchApiAudience)
.toString();
}
}
Expand Down
Loading

0 comments on commit 26da0d3

Please sign in to comment.