From ed39c34693783460fc03effb47e7027914cfb5bc Mon Sep 17 00:00:00 2001 From: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com> Date: Mon, 16 Aug 2021 10:31:11 -0700 Subject: [PATCH] feat: add UseJwtAccessWithScope to GoogleCredentialsProvider (#1420) --- dependencies.properties | 2 +- .../gax/core/GoogleCredentialsProvider.java | 21 +++++++- .../core/GoogleCredentialsProviderTest.java | 52 ++++++++++++++----- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/dependencies.properties b/dependencies.properties index 605cfd362..f7249050c 100644 --- a/dependencies.properties +++ b/dependencies.properties @@ -34,7 +34,7 @@ version.io_grpc=1.37.0 # 2) Replace all characters which are neither alphabetic nor digits with the underscore ('_') character maven.com_google_api_grpc_proto_google_common_protos=com.google.api.grpc:proto-google-common-protos:2.0.1 maven.com_google_api_grpc_grpc_google_common_protos=com.google.api.grpc:grpc-google-common-protos:2.0.1 -maven.com_google_auth_google_auth_library_oauth2_http=com.google.auth:google-auth-library-oauth2-http:0.24.0 +maven.com_google_auth_google_auth_library_oauth2_http=com.google.auth:google-auth-library-oauth2-http:0.27.0 maven.com_google_auth_google_auth_library_credentials=com.google.auth:google-auth-library-credentials:1.0.0 maven.io_opencensus_opencensus_api=io.opencensus:opencensus-api:0.28.0 maven.io_opencensus_opencensus_contrib_grpc_metrics=io.opencensus:opencensus-contrib-grpc-metrics:0.28.0 diff --git a/gax/src/main/java/com/google/api/gax/core/GoogleCredentialsProvider.java b/gax/src/main/java/com/google/api/gax/core/GoogleCredentialsProvider.java index ddba0331d..56642ecde 100644 --- a/gax/src/main/java/com/google/api/gax/core/GoogleCredentialsProvider.java +++ b/gax/src/main/java/com/google/api/gax/core/GoogleCredentialsProvider.java @@ -56,6 +56,9 @@ public abstract class GoogleCredentialsProvider implements CredentialsProvider { @BetaApi public abstract List getJwtEnabledScopes(); + @BetaApi + public abstract boolean getUseJwtAccessWithScope(); + @VisibleForTesting @Nullable abstract GoogleCredentials getOAuth2Credentials(); @@ -91,12 +94,19 @@ public Credentials getCredentials() throws IOException { if (credentials.createScopedRequired()) { credentials = credentials.createScoped(getScopesToApply()); } + + if (getUseJwtAccessWithScope() && credentials instanceof ServiceAccountCredentials) { + // See https://google.aip.dev/auth/4111 for self signed JWT. + ServiceAccountCredentials serviceAccount = (ServiceAccountCredentials) credentials; + return serviceAccount.createWithUseJwtAccessWithScope(true); + } return credentials; } public static Builder newBuilder() { return new AutoValue_GoogleCredentialsProvider.Builder() - .setJwtEnabledScopes(ImmutableList.of()); + .setJwtEnabledScopes(ImmutableList.of()) + .setUseJwtAccessWithScope(false); } public abstract Builder toBuilder(); @@ -134,9 +144,18 @@ public abstract static class Builder { @BetaApi public abstract List getJwtEnabledScopes(); + /** Whether self signed JWT with scopes should be used for service account credentials. */ + @BetaApi + public abstract Builder setUseJwtAccessWithScope(boolean val); + + /** The UseJwtAccessWithScope value previously provided. */ + @BetaApi + public abstract boolean getUseJwtAccessWithScope(); + public GoogleCredentialsProvider build() { setScopesToApply(ImmutableList.copyOf(getScopesToApply())); setJwtEnabledScopes(ImmutableList.copyOf(getJwtEnabledScopes())); + setUseJwtAccessWithScope(getUseJwtAccessWithScope()); return autoBuild(); } diff --git a/gax/src/test/java/com/google/api/gax/core/GoogleCredentialsProviderTest.java b/gax/src/test/java/com/google/api/gax/core/GoogleCredentialsProviderTest.java index e3fc32d1d..9cea58f6a 100644 --- a/gax/src/test/java/com/google/api/gax/core/GoogleCredentialsProviderTest.java +++ b/gax/src/test/java/com/google/api/gax/core/GoogleCredentialsProviderTest.java @@ -30,6 +30,7 @@ package com.google.api.gax.core; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertTrue; import com.google.auth.Credentials; import com.google.auth.oauth2.ServiceAccountCredentials; @@ -43,15 +44,18 @@ @RunWith(JUnit4.class) public class GoogleCredentialsProviderTest { + ServiceAccountCredentials CreateServiceAccountCredentials() { + return ServiceAccountCredentials.newBuilder() + .setClientId("fake-client-id") + .setClientEmail("fake@example.com") + .setPrivateKeyId("fake-private-key") + .setPrivateKey(Mockito.mock(PrivateKey.class)) + .build(); + } + @Test public void serviceAccountReplacedWithJwtTokens() throws Exception { - ServiceAccountCredentials serviceAccountCredentials = - ServiceAccountCredentials.newBuilder() - .setClientId("fake-client-id") - .setClientEmail("fake@example.com") - .setPrivateKeyId("fake-private-key") - .setPrivateKey(Mockito.mock(PrivateKey.class)) - .build(); + ServiceAccountCredentials serviceAccountCredentials = CreateServiceAccountCredentials(); GoogleCredentialsProvider provider = GoogleCredentialsProvider.newBuilder() @@ -71,13 +75,7 @@ public void serviceAccountReplacedWithJwtTokens() throws Exception { @Test public void noJwtWithoutScopeMatch() throws Exception { - ServiceAccountCredentials serviceAccountCredentials = - ServiceAccountCredentials.newBuilder() - .setClientId("fake-client-id") - .setClientEmail("fake@example.com") - .setPrivateKeyId("fake-private-key") - .setPrivateKey(Mockito.mock(PrivateKey.class)) - .build(); + ServiceAccountCredentials serviceAccountCredentials = CreateServiceAccountCredentials(); GoogleCredentialsProvider provider = GoogleCredentialsProvider.newBuilder() @@ -100,4 +98,30 @@ public void noJwtWithoutScopeMatch() throws Exception { .isEqualTo(serviceAccountCredentials.getPrivateKey()); assertThat(serviceAccountCredentials2.getScopes()).containsExactly("scope1", "scope2"); } + + @Test + public void useJwtAccessWithScope() throws Exception { + ServiceAccountCredentials serviceAccountCredentials = CreateServiceAccountCredentials(); + + GoogleCredentialsProvider provider = + GoogleCredentialsProvider.newBuilder() + .setScopesToApply(ImmutableList.of("scope1", "scope2")) + .setOAuth2Credentials(serviceAccountCredentials) + .setUseJwtAccessWithScope(true) + .build(); + + Credentials credentials = provider.getCredentials(); + assertThat(credentials).isInstanceOf(ServiceAccountCredentials.class); + + ServiceAccountCredentials serviceAccountCredentials2 = (ServiceAccountCredentials) credentials; + assertThat(serviceAccountCredentials2.getClientId()) + .isEqualTo(serviceAccountCredentials.getClientId()); + assertThat(serviceAccountCredentials2.getClientEmail()) + .isEqualTo(serviceAccountCredentials.getClientEmail()); + assertThat(serviceAccountCredentials2.getPrivateKeyId()) + .isEqualTo(serviceAccountCredentials.getPrivateKeyId()); + assertThat(serviceAccountCredentials2.getPrivateKey()) + .isEqualTo(serviceAccountCredentials.getPrivateKey()); + assertTrue(serviceAccountCredentials2.getUseJwtAccessWithScope()); + } }