diff --git a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java
index 15ce8947d..34e7f11ff 100644
--- a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java
+++ b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java
@@ -109,6 +109,68 @@ public class ComputeEngineCredentials extends GoogleCredentials
static final int MAX_COMPUTE_PING_TRIES = 3;
static final int COMPUTE_PING_CONNECTION_TIMEOUT_MS = 500;
+ /**
+ * Experimental Feature.
+ *
+ *
{@link GoogleAuthTransport} specifies how to authenticate to Google APIs.
+ *
+ *
Behavior of setting {@link GoogleAuthTransport} / {@link BindingEnforcement}:
+ *
+ *
MTLS-bound token where binding enforcement depends on IAM policy: MTLS / {}, {} /
+ * IAM_POLICY, MTLS / IAM_POLICY
+ *
+ *
MTLS-bound token where bindings are always enforced: {} / ON, MTLS / ON
+ *
+ *
DirectPath bound token: ALTS / {}
+ */
+ public enum GoogleAuthTransport {
+ // Authenticating to Google APIs via DirectPath
+ ALTS("alts"),
+ // Authenticating to Google APIs via GFE
+ MTLS("mtls");
+
+ private final String label;
+
+ private GoogleAuthTransport(String label) {
+ this.label = label;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+ }
+
+ /**
+ * Experimental Feature.
+ *
+ *
{@link BindingEnforcement} specifies how binding info in tokens will be enforced.
+ *
+ *
Behavior of setting {@link GoogleAuthTransport} / {@link BindingEnforcement}:
+ *
+ *
MTLS-bound token where binding enforcement depends on IAM policy: MTLS / {}, {} /
+ * IAM_POLICY, MTLS / IAM_POLICY
+ *
+ *
MTLS-bound token where bindings are always enforced: {} / ON, MTLS / ON
+ *
+ *
DirectPath bound token: ALTS / {}
+ */
+ public enum BindingEnforcement {
+ // Binding enforcement will always happen, irrespective of the IAM policy.
+ ON("on"),
+ // Binding enforcement will depend on IAM policy.
+ IAM_POLICY("iam-policy");
+
+ private final String label;
+
+ private BindingEnforcement(String label) {
+ this.label = label;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+ }
+
private static final String METADATA_FLAVOR = "Metadata-Flavor";
private static final String GOOGLE = "Google";
private static final String WINDOWS = "windows";
@@ -122,6 +184,9 @@ public class ComputeEngineCredentials extends GoogleCredentials
private final Collection scopes;
+ private final GoogleAuthTransport transport;
+ private final BindingEnforcement bindingEnforcement;
+
private transient HttpTransportFactory transportFactory;
private transient String serviceAccountEmail;
@@ -152,6 +217,8 @@ private ComputeEngineCredentials(ComputeEngineCredentials.Builder builder) {
scopeList.removeAll(Arrays.asList("", null));
this.scopes = ImmutableSet.copyOf(scopeList);
}
+ this.transport = builder.getGoogleAuthTransport();
+ this.bindingEnforcement = builder.getBindingEnforcement();
}
@Override
@@ -191,7 +258,10 @@ public final Collection getScopes() {
}
/**
- * If scopes is specified, add "?scopes=comma-separated-list-of-scopes" to the token url.
+ * If scopes is specified, add "?scopes=comma-separated-list-of-scopes" to the token url. If
+ * transport is specified, add "?transport=xyz" to the token url; xyz is one of "alts" or "mtls".
+ * If bindingEnforcement is specified, add "?binding-enforcement=xyz" to the token url; xyz is one
+ * of "iam-policy" or "on".
*
* @return token url with the given scopes
*/
@@ -200,6 +270,12 @@ String createTokenUrlWithScopes() {
if (!scopes.isEmpty()) {
tokenUrl.set("scopes", Joiner.on(',').join(scopes));
}
+ if (transport != null) {
+ tokenUrl.set("transport", transport.getLabel());
+ }
+ if (bindingEnforcement != null) {
+ tokenUrl.set("binding-enforcement", bindingEnforcement.getLabel());
+ }
return tokenUrl.toString();
}
@@ -643,6 +719,9 @@ public static class Builder extends GoogleCredentials.Builder {
private Collection scopes;
private Collection defaultScopes;
+ private GoogleAuthTransport transport;
+ private BindingEnforcement bindingEnforcement;
+
protected Builder() {
setRefreshMargin(COMPUTE_REFRESH_MARGIN);
setExpirationMargin(COMPUTE_EXPIRATION_MARGIN);
@@ -684,6 +763,28 @@ public Builder setQuotaProjectId(String quotaProjectId) {
return this;
}
+ /**
+ * Set the {@code GoogleAuthTransport} type.
+ *
+ * @param transport the transport type over which to authenticate to Google APIs
+ */
+ @CanIgnoreReturnValue
+ public Builder setGoogleAuthTransport(GoogleAuthTransport transport) {
+ this.transport = transport;
+ return this;
+ }
+
+ /**
+ * Set the {@code BindingEnforcement} type.
+ *
+ * @param bindingEnforcement the token binding enforcement policy.
+ */
+ @CanIgnoreReturnValue
+ public Builder setBindingEnforcement(BindingEnforcement bindingEnforcement) {
+ this.bindingEnforcement = bindingEnforcement;
+ return this;
+ }
+
public HttpTransportFactory getHttpTransportFactory() {
return transportFactory;
}
@@ -696,6 +797,24 @@ public Collection getDefaultScopes() {
return defaultScopes;
}
+ /**
+ * Get the {@code GoogleAuthTransport} type.
+ *
+ * @return the transport type over which to authenticate to Google APIs
+ */
+ public GoogleAuthTransport getGoogleAuthTransport() {
+ return transport;
+ }
+
+ /**
+ * Get the {@code BindingEnforcement} type.
+ *
+ * @return the token binding enforcement policy.
+ */
+ public BindingEnforcement getBindingEnforcement() {
+ return bindingEnforcement;
+ }
+
@Override
public ComputeEngineCredentials build() {
return new ComputeEngineCredentials(this);
diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java
index 10975d874..9f32d8277 100644
--- a/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java
+++ b/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java
@@ -190,6 +190,110 @@ public void buildTokenUrlWithScopes_defaultScopes() {
assertEquals("bar", scopes.toArray()[1]);
}
+ @Test
+ public void buildTokenUrl_nullTransport() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setGoogleAuthTransport(null)
+ .setBindingEnforcement(ComputeEngineCredentials.BindingEnforcement.ON)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?binding-enforcement=on", softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrl_nullBindingEnforcement() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setGoogleAuthTransport(ComputeEngineCredentials.GoogleAuthTransport.MTLS)
+ .setBindingEnforcement(null)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?transport=mtls", softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrl_nullTransport_nullBindingEnforcement() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setGoogleAuthTransport(null)
+ .setBindingEnforcement(null)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL, softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrlSoftMtlsBound_mtls_transport() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setGoogleAuthTransport(ComputeEngineCredentials.GoogleAuthTransport.MTLS)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?transport=mtls", softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrlSoftMtlsBound_iam_enforcement() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setBindingEnforcement(ComputeEngineCredentials.BindingEnforcement.IAM_POLICY)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?binding-enforcement=iam-policy", softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrlSoftMtlsBound_mtls_transport_iam_enforcement() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setGoogleAuthTransport(ComputeEngineCredentials.GoogleAuthTransport.MTLS)
+ .setBindingEnforcement(ComputeEngineCredentials.BindingEnforcement.IAM_POLICY)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?transport=mtls&binding-enforcement=iam-policy", softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrlHardMtlsBound_always_enforced() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setBindingEnforcement(ComputeEngineCredentials.BindingEnforcement.ON)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?binding-enforcement=on", softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrlHardMtlsBound_mtls_transport_always_enforced() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setGoogleAuthTransport(ComputeEngineCredentials.GoogleAuthTransport.MTLS)
+ .setBindingEnforcement(ComputeEngineCredentials.BindingEnforcement.ON)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?transport=mtls&binding-enforcement=on", softBoundTokenUrl);
+ }
+
+ @Test
+ public void buildTokenUrlHardDirectPathBound_alts_transport() {
+ ComputeEngineCredentials credentials =
+ ComputeEngineCredentials.newBuilder()
+ .setGoogleAuthTransport(ComputeEngineCredentials.GoogleAuthTransport.ALTS)
+ .build();
+ String softBoundTokenUrl = credentials.createTokenUrlWithScopes();
+
+ assertEquals(TOKEN_URL + "?transport=alts", softBoundTokenUrl);
+ }
+
@Test
public void buildScoped_scopesPresent() throws IOException {
ComputeEngineCredentials credentials =