From 4ddad12afee56070e55f154cf60ee317a909d7aa Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Tue, 12 Sep 2023 11:05:32 -0700 Subject: [PATCH 01/31] feat: first draft of tpc support, adding universe_domain field --- .../oauth2/ExternalAccountCredentials.java | 10 -- .../google/auth/oauth2/GoogleAuthUtils.java | 1 + .../google/auth/oauth2/GoogleCredentials.java | 104 +++++++++++++++++- .../auth/oauth2/ImpersonatedCredentials.java | 2 + .../oauth2/ServiceAccountCredentials.java | 36 +++--- .../ExternalAccountCredentialsTest.java | 5 +- 6 files changed, 121 insertions(+), 37 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index 85ac86b4b..90ab27f57 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -94,7 +94,6 @@ abstract static class CredentialSource implements java.io.Serializable { @Nullable private final String serviceAccountImpersonationUrl; @Nullable private final String clientId; @Nullable private final String clientSecret; - @Nullable private final String universeDomain; // This is used for Workforce Pools. It is passed to the Security Token Service during token // exchange in the `options` param and will be embedded in the token by the Security Token @@ -214,7 +213,6 @@ protected ExternalAccountCredentials( this.environmentProvider = environmentProvider == null ? SystemEnvironmentProvider.getInstance() : environmentProvider; this.workforcePoolUserProject = null; - this.universeDomain = null; this.serviceAccountImpersonationOptions = new ServiceAccountImpersonationOptions(new HashMap()); @@ -268,8 +266,6 @@ protected ExternalAccountCredentials(ExternalAccountCredentials.Builder builder) "The workforce_pool_user_project parameter should only be provided for a Workforce Pool configuration."); } - this.universeDomain = builder.universeDomain; - validateTokenUrl(tokenUrl); if (serviceAccountImpersonationUrl != null) { validateServiceAccountImpersonationInfoUrl(serviceAccountImpersonationUrl); @@ -591,11 +587,6 @@ public String getWorkforcePoolUserProject() { return workforcePoolUserProject; } - @Nullable - String getUniverseDomain() { - return universeDomain; - } - @Nullable public ServiceAccountImpersonationOptions getServiceAccountImpersonationOptions() { return serviceAccountImpersonationOptions; @@ -752,7 +743,6 @@ protected Builder(ExternalAccountCredentials credentials) { this.environmentProvider = credentials.environmentProvider; this.workforcePoolUserProject = credentials.workforcePoolUserProject; this.serviceAccountImpersonationOptions = credentials.serviceAccountImpersonationOptions; - this.universeDomain = credentials.universeDomain; this.metricsHandler = credentials.metricsHandler; } diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java b/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java index d82548a08..dbea4596f 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java @@ -38,6 +38,7 @@ * convenience methods such as a getter for well-known Application Default Credentials file path */ public class GoogleAuthUtils { + static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; /** * Gets the path to the well-known Application Default Credentials file location diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index d12632a32..b59e7fbbd 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -36,6 +36,7 @@ import com.google.api.client.json.JsonObjectParser; import com.google.api.client.util.Preconditions; import com.google.auth.http.HttpTransportFactory; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.io.InputStream; @@ -57,6 +58,7 @@ public class GoogleCredentials extends OAuth2Credentials implements QuotaProject static final String USER_FILE_TYPE = "authorized_user"; static final String SERVICE_ACCOUNT_FILE_TYPE = "service_account"; static final String GDCH_SERVICE_ACCOUNT_FILE_TYPE = "gdch_service_account"; + private final String universeDomain; protected final String quotaProjectId; @@ -169,6 +171,7 @@ public static GoogleCredentials fromStream( if (fileType == null) { throw new IOException("Error reading credentials from stream, 'type' field not specified."); } + if (USER_FILE_TYPE.equals(fileType)) { return UserCredentials.fromJson(fileContents, transportFactory); } @@ -185,14 +188,56 @@ public static GoogleCredentials fromStream( fileType)) { return ExternalAccountAuthorizedUserCredentials.fromJson(fileContents, transportFactory); } - if ("impersonated_service_account".equals(fileType)) { + if (ImpersonatedCredentials.IMPERSONATED_CREDENTIALS_FILE_TYPE.equals(fileType)) { return ImpersonatedCredentials.fromJson(fileContents, transportFactory); } throw new IOException( String.format( "Error reading credentials from stream, 'type' value '%s' not recognized." - + " Expecting '%s' or '%s'.", - fileType, USER_FILE_TYPE, SERVICE_ACCOUNT_FILE_TYPE)); + + " Valid values are '%s', '%s', '%s', '%s', '%s', 's'.", + fileType, + USER_FILE_TYPE, + SERVICE_ACCOUNT_FILE_TYPE, + GDCH_SERVICE_ACCOUNT_FILE_TYPE, + ExternalAccountCredentials.EXTERNAL_ACCOUNT_FILE_TYPE, + ExternalAccountAuthorizedUserCredentials.EXTERNAL_ACCOUNT_AUTHORIZED_USER_FILE_TYPE, + ImpersonatedCredentials.IMPERSONATED_CREDENTIALS_FILE_TYPE)); + } + + /** + * Returns an instance of GoogleCredentials defined by JSON + * + * To be used to parse common credentials fields + * + * @param json a map from the JSON representing the credentials. + * + * @return the credentials defined by the JSON. + * @throws IOException if the credential cannot be created from the JSON. + */ + @VisibleForTesting + static GoogleCredentials fromJson(Map json) throws IOException { + Builder credentialsBuilder = GoogleCredentials.newBuilder(); + + // parse fields that are common for all the types of GoogleCredentials + String universeDomain = (String) json.get("universe_domain"); + if (universeDomain != null + && universeDomain.trim().isEmpty() + && !universeDomain.equalsIgnoreCase(GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE)) { + credentialsBuilder.setUniverseDomain(universeDomain); + } + + return credentialsBuilder.build(); + } + + /** + * Creates a credential with the provided universe domain. + * + * @param universeDomain the universe domain to set on the credential. Empty or null value will + * result in the default universe domain 'googleapis.com' + * @return credential with the provided universe domain + */ + public GoogleCredentials createWithUniverseDomain(String universeDomain) { + return this.toBuilder().setUniverseDomain(universeDomain).build(); } /** @@ -205,6 +250,20 @@ public GoogleCredentials createWithQuotaProject(String quotaProject) { return this.toBuilder().setQuotaProjectId(quotaProject).build(); } + /** + * Returns the universe domain for the credential + * + * @return An explicit universe domain if it was explicitly provided, + * {@code GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE} otherwise. + */ + public String getUniverseDomain() { + if (this.universeDomain == null || universeDomain.trim().isEmpty()) { + return GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE; + } + + return this.universeDomain; + } + /** * Adds quota project ID to requestMetadata if present. * @@ -236,9 +295,19 @@ protected GoogleCredentials() { this(new Builder()); } + /** + * Constructor with explicit access token and quotaProjectId + * + * Deprecated, please use the builder constructor whenever possible + * + * @param accessToken initial or temporary access token + * @param quotaProjectId a quotaProjectId, a project id to be used for billing purposes + */ + @Deprecated protected GoogleCredentials(AccessToken accessToken, String quotaProjectId) { super(accessToken); this.quotaProjectId = quotaProjectId; + this.universeDomain = null; } /** @@ -250,19 +319,31 @@ public GoogleCredentials(AccessToken accessToken) { this(accessToken, null); } + /** + * Constructor with using builder + * All the fields comes explicitly from builder + * + * @param builder an instance of a builder + */ protected GoogleCredentials(Builder builder) { - this(builder.getAccessToken(), builder.getQuotaProjectId()); + super(builder.getAccessToken()); + this.quotaProjectId = builder.getQuotaProjectId(); + this.universeDomain = builder.getUniverseDomain(); } /** * Constructor with explicit access token and refresh times * + * Deprecated, please use the builder constructor whenever possible + * * @param accessToken initial or temporary access token */ + @Deprecated protected GoogleCredentials( AccessToken accessToken, Duration refreshMargin, Duration expirationMargin) { super(accessToken, refreshMargin, expirationMargin); this.quotaProjectId = null; + this.universeDomain = null; } public static Builder newBuilder() { @@ -347,12 +428,20 @@ public GoogleCredentials createDelegated(String user) { public static class Builder extends OAuth2Credentials.Builder { @Nullable protected String quotaProjectId; + @Nullable protected String universeDomain; protected Builder() {} protected Builder(GoogleCredentials credentials) { setAccessToken(credentials.getAccessToken()); this.quotaProjectId = credentials.quotaProjectId; + this.universeDomain = credentials.universeDomain; + } + + protected Builder(GoogleCredentials.Builder builder) { + setAccessToken(builder.getAccessToken()); + this.quotaProjectId = builder.quotaProjectId; + this.universeDomain = builder.universeDomain; } public GoogleCredentials build() { @@ -364,10 +453,17 @@ public Builder setQuotaProjectId(String quotaProjectId) { return this; } + public Builder setUniverseDomain(String universeDomain) { + this.universeDomain = universeDomain; + return this; + } + public String getQuotaProjectId() { return this.quotaProjectId; } + public String getUniverseDomain() { return this.universeDomain; } + @Override public Builder setAccessToken(AccessToken token) { super.setAccessToken(token); diff --git a/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java index f9b90b01b..8ca76b6a4 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java @@ -92,6 +92,8 @@ public class ImpersonatedCredentials extends GoogleCredentials implements ServiceAccountSigner, IdTokenProvider { + static final String IMPERSONATED_CREDENTIALS_FILE_TYPE = "impersonated_service_account"; + private static final long serialVersionUID = -2133257318957488431L; private static final String RFC3339 = "yyyy-MM-dd'T'HH:mm:ssX"; private static final int TWELVE_HOURS_IN_SECONDS = 43200; diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index c6c95a71c..728caa93a 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -184,8 +184,10 @@ static ServiceAccountCredentials fromJson( + "expecting 'client_id', 'client_email', 'private_key' and 'private_key_id'."); } + GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); + ServiceAccountCredentials.Builder builder = - ServiceAccountCredentials.newBuilder() + ServiceAccountCredentials.Builder(baseCredential.toBuilder()) .setClientId(clientId) .setClientEmail(clientEmail) .setPrivateKeyId(privateKeyId) @@ -462,26 +464,14 @@ public static ServiceAccountCredentials fromStream(InputStream credentialsStream */ public static ServiceAccountCredentials fromStream( InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException { - Preconditions.checkNotNull(credentialsStream); - Preconditions.checkNotNull(transportFactory); - - JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY; - JsonObjectParser parser = new JsonObjectParser(jsonFactory); - GenericJson fileContents = - parser.parseAndClose(credentialsStream, StandardCharsets.UTF_8, GenericJson.class); - - String fileType = (String) fileContents.get("type"); - if (fileType == null) { - throw new IOException("Error reading credentials from stream, 'type' field not specified."); - } - if (SERVICE_ACCOUNT_FILE_TYPE.equals(fileType)) { - return fromJson(fileContents, transportFactory); + ServiceAccountCredentials credential = + (ServiceAccountCredentials) GoogleCredentials.fromStream(credentialsStream, transportFactory); + if (credential == null) { + throw new IOException( + String.format( + "Error reading credentials from stream, ServiceAccountCredentials type is not recognized.")); } - throw new IOException( - String.format( - "Error reading credentials from stream, 'type' value '%s' not recognized." - + " Expecting '%s'.", - fileType, SERVICE_ACCOUNT_FILE_TYPE)); + return credential; } /** Returns whether the scopes are empty, meaning createScoped must be called before use. */ @@ -731,7 +721,7 @@ public byte[] sign(byte[] toSign) { /** * Returns a new JwtCredentials instance with modified claims. * - * @param newClaims new claims. Any unspecified claim fields will default to the the current + * @param newClaims new claims. Any unspecified claim fields will default to the current * values. * @return new credentials */ @@ -1005,6 +995,10 @@ protected Builder(ServiceAccountCredentials credentials) { this.defaultRetriesEnabled = credentials.defaultRetriesEnabled; } + protected Builder(GoogleCredentials.Builder superBuilder) { + super(superBuilder); + } + public Builder setClientId(String clientId) { this.clientId = clientId; return this; diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java index ec558cfa8..45daee8cd 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java @@ -66,6 +66,7 @@ public class ExternalAccountCredentialsTest extends BaseSerializationTest { private static final String STS_URL = "https://sts.googleapis.com"; + private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; private static final Map FILE_CREDENTIAL_SOURCE_MAP = new HashMap() { @@ -203,7 +204,7 @@ public void fromJson_identityPoolCredentialsWorkforce() { assertEquals("tokenInfoUrl", credential.getTokenInfoUrl()); assertEquals("userProject", credential.getWorkforcePoolUserProject()); assertNotNull(credential.getCredentialSource()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test @@ -225,7 +226,7 @@ public void fromJson_identityPoolCredentialsWithServiceAccountImpersonationOptio assertEquals("tokenInfoUrl", credential.getTokenInfoUrl()); assertNotNull(credential.getCredentialSource()); assertEquals(2800, credential.getServiceAccountImpersonationOptions().getLifetime()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test From c41f54279d387fa60a95c9870fa8055b9a1bc68b Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 12 Sep 2023 18:08:24 +0000 Subject: [PATCH 02/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../google/auth/oauth2/GoogleCredentials.java | 20 +++++++++---------- .../oauth2/ServiceAccountCredentials.java | 8 +++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index b59e7fbbd..a0505ac4d 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -207,10 +207,9 @@ public static GoogleCredentials fromStream( /** * Returns an instance of GoogleCredentials defined by JSON * - * To be used to parse common credentials fields + *

To be used to parse common credentials fields * * @param json a map from the JSON representing the credentials. - * * @return the credentials defined by the JSON. * @throws IOException if the credential cannot be created from the JSON. */ @@ -233,7 +232,7 @@ static GoogleCredentials fromJson(Map json) throws IOException { * Creates a credential with the provided universe domain. * * @param universeDomain the universe domain to set on the credential. Empty or null value will - * result in the default universe domain 'googleapis.com' + * result in the default universe domain 'googleapis.com' * @return credential with the provided universe domain */ public GoogleCredentials createWithUniverseDomain(String universeDomain) { @@ -253,8 +252,8 @@ public GoogleCredentials createWithQuotaProject(String quotaProject) { /** * Returns the universe domain for the credential * - * @return An explicit universe domain if it was explicitly provided, - * {@code GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE} otherwise. + * @return An explicit universe domain if it was explicitly provided, {@code + * GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE} otherwise. */ public String getUniverseDomain() { if (this.universeDomain == null || universeDomain.trim().isEmpty()) { @@ -298,7 +297,7 @@ protected GoogleCredentials() { /** * Constructor with explicit access token and quotaProjectId * - * Deprecated, please use the builder constructor whenever possible + *

Deprecated, please use the builder constructor whenever possible * * @param accessToken initial or temporary access token * @param quotaProjectId a quotaProjectId, a project id to be used for billing purposes @@ -320,8 +319,7 @@ public GoogleCredentials(AccessToken accessToken) { } /** - * Constructor with using builder - * All the fields comes explicitly from builder + * Constructor with using builder All the fields comes explicitly from builder * * @param builder an instance of a builder */ @@ -334,7 +332,7 @@ protected GoogleCredentials(Builder builder) { /** * Constructor with explicit access token and refresh times * - * Deprecated, please use the builder constructor whenever possible + *

Deprecated, please use the builder constructor whenever possible * * @param accessToken initial or temporary access token */ @@ -462,7 +460,9 @@ public String getQuotaProjectId() { return this.quotaProjectId; } - public String getUniverseDomain() { return this.universeDomain; } + public String getUniverseDomain() { + return this.universeDomain; + } @Override public Builder setAccessToken(AccessToken token) { diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index 728caa93a..effc8a67a 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -41,7 +41,6 @@ import com.google.api.client.http.HttpResponse; import com.google.api.client.http.HttpResponseException; import com.google.api.client.http.UrlEncodedContent; -import com.google.api.client.json.GenericJson; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.JsonObjectParser; import com.google.api.client.json.webtoken.JsonWebSignature; @@ -61,7 +60,6 @@ import java.io.ObjectInputStream; import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -465,7 +463,8 @@ public static ServiceAccountCredentials fromStream(InputStream credentialsStream public static ServiceAccountCredentials fromStream( InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException { ServiceAccountCredentials credential = - (ServiceAccountCredentials) GoogleCredentials.fromStream(credentialsStream, transportFactory); + (ServiceAccountCredentials) + GoogleCredentials.fromStream(credentialsStream, transportFactory); if (credential == null) { throw new IOException( String.format( @@ -721,8 +720,7 @@ public byte[] sign(byte[] toSign) { /** * Returns a new JwtCredentials instance with modified claims. * - * @param newClaims new claims. Any unspecified claim fields will default to the current - * values. + * @param newClaims new claims. Any unspecified claim fields will default to the current values. * @return new credentials */ @Override From 3957bd080b93b8af36584968942b8757922996fe Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Wed, 13 Sep 2023 05:23:11 -0700 Subject: [PATCH 03/31] Update oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java Co-authored-by: Leo <39062083+lsirac@users.noreply.github.com> --- oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index a0505ac4d..95ec95321 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -217,7 +217,7 @@ public static GoogleCredentials fromStream( static GoogleCredentials fromJson(Map json) throws IOException { Builder credentialsBuilder = GoogleCredentials.newBuilder(); - // parse fields that are common for all the types of GoogleCredentials + // Parse fields that are common for all the types of GoogleCredentials. String universeDomain = (String) json.get("universe_domain"); if (universeDomain != null && universeDomain.trim().isEmpty() From 41de188f711391f15ec4ecef425dc92e23a4f62e Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Wed, 13 Sep 2023 12:29:56 -0700 Subject: [PATCH 04/31] fix: adding tests --- .../google/auth/oauth2/GoogleCredentials.java | 4 +- .../oauth2/ServiceAccountCredentials.java | 14 ++-- .../auth/oauth2/GoogleCredentialsTest.java | 43 +++++++++++- .../oauth2/ServiceAccountCredentialsTest.java | 65 ++++++++++++++++--- 4 files changed, 106 insertions(+), 20 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 95ec95321..1d82e26ad 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -219,9 +219,7 @@ static GoogleCredentials fromJson(Map json) throws IOException { // Parse fields that are common for all the types of GoogleCredentials. String universeDomain = (String) json.get("universe_domain"); - if (universeDomain != null - && universeDomain.trim().isEmpty() - && !universeDomain.equalsIgnoreCase(GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE)) { + if (universeDomain != null && !universeDomain.trim().isEmpty()) { credentialsBuilder.setUniverseDomain(universeDomain); } diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index effc8a67a..aa64981a6 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -185,14 +185,15 @@ static ServiceAccountCredentials fromJson( GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); ServiceAccountCredentials.Builder builder = - ServiceAccountCredentials.Builder(baseCredential.toBuilder()) + ServiceAccountCredentials.newBuilder() .setClientId(clientId) .setClientEmail(clientEmail) .setPrivateKeyId(privateKeyId) .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServerUriFromCreds) .setProjectId(projectId) - .setQuotaProjectId(quotaProjectId); + .setQuotaProjectId(quotaProjectId) + .setUniverseDomain(baseCredential.getUniverseDomain()); return fromPkcs8(privateKeyPkcs8, builder); } @@ -993,10 +994,6 @@ protected Builder(ServiceAccountCredentials credentials) { this.defaultRetriesEnabled = credentials.defaultRetriesEnabled; } - protected Builder(GoogleCredentials.Builder superBuilder) { - super(superBuilder); - } - public Builder setClientId(String clientId) { this.clientId = clientId; return this; @@ -1074,6 +1071,11 @@ public Builder setDefaultRetriesEnabled(boolean defaultRetriesEnabled) { return this; } + public Builder setUniverseDomain(String universeDomain) { + this.universeDomain = universeDomain; + return this; + } + public String getClientId() { return clientId; } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index 80e28b3ec..c739b0c77 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -90,6 +90,8 @@ public class GoogleCredentialsTest extends BaseSerializationTest { Collections.unmodifiableCollection(Arrays.asList("scope1", "scope2")); private static final Collection DEFAULT_SCOPES = Collections.unmodifiableCollection(Arrays.asList("scope3")); + private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; + private static final String TPC_UNIVERSE = "foo.bar"; @Test public void getApplicationDefault_nullTransport_throws() throws IOException { @@ -124,7 +126,7 @@ public void fromStream_nullStream_throws() throws IOException { } @Test - public void fromStream_serviceAccount_providesToken() throws IOException { + public void fromStream_serviceAccount_noUniverse_providesToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); InputStream serviceAccountStream = @@ -135,6 +137,29 @@ public void fromStream_serviceAccount_providesToken() throws IOException { GoogleCredentials.fromStream(serviceAccountStream, transportFactory); assertNotNull(credentials); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + credentials = credentials.createScoped(SCOPES); + Map> metadata = credentials.getRequestMetadata(CALL_URI); + TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); + + credentials = credentials.createScoped(SCOPES, DEFAULT_SCOPES); + metadata = credentials.getRequestMetadata(CALL_URI); + TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); + } + + @Test + public void fromStream_serviceAccount_Universe_providesToken() throws IOException { + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + InputStream serviceAccountStream = + ServiceAccountCredentialsTest.writeServiceAccountStream( + SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, TPC_UNIVERSE); + + GoogleCredentials credentials = + GoogleCredentials.fromStream(serviceAccountStream, transportFactory); + + assertNotNull(credentials); + assertEquals(TPC_UNIVERSE, credentials.getUniverseDomain()); credentials = credentials.createScoped(SCOPES); Map> metadata = credentials.getRequestMetadata(CALL_URI); TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); @@ -563,6 +588,22 @@ public void createWithQuotaProject() { assertEquals(null, sameCredentials.getQuotaProjectId()); } + @Test + public void createWithUniverseDomain() { + final GoogleCredentials original = + new GoogleCredentials.Builder().setUniverseDomain("universe1").build(); + GoogleCredentials updated = original.createWithUniverseDomain("universe2"); + + assertEquals("universe1", original.getUniverseDomain()); + assertEquals("universe2", updated.getUniverseDomain()); + + GoogleCredentials withEmpty = original.createWithUniverseDomain(""); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, withEmpty.getUniverseDomain()); + + GoogleCredentials withNull = original.createWithUniverseDomain(null); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, withNull.getUniverseDomain()); + } + @Test public void serialize() throws IOException, ClassNotFoundException { final GoogleCredentials testCredentials = new GoogleCredentials.Builder().build(); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 6da93d409..b28618e1b 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -120,6 +120,8 @@ public class ServiceAccountCredentialsTest extends BaseSerializationTest { private static final int DEFAULT_LIFETIME_IN_SECONDS = 3600; private static final int INVALID_LIFETIME = 43210; private static final String JWT_ACCESS_PREFIX = "Bearer "; + private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; + private static final String TPC_UNIVERSE = "foo.bar"; private ServiceAccountCredentials.Builder createDefaultBuilder() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); @@ -192,6 +194,7 @@ public void createdScoped_clones() throws IOException { assertArrayEquals(newScopes.toArray(), newCredentials.getScopes().toArray()); assertEquals(USER, newCredentials.getServiceAccountUser()); assertEquals(PROJECT_ID, newCredentials.getProjectId()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, newCredentials.getUniverseDomain()); assertArrayEquals( SCOPES.toArray(), ((ServiceAccountCredentials) credentials).getScopes().toArray()); @@ -473,15 +476,25 @@ public void createScopedRequired_nonEmptyDefaultScopes() throws IOException { @Test public void fromJSON_getProjectId() throws IOException { - MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, null); ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromJson(json, transportFactory); + ServiceAccountCredentials.fromJson(json, new MockTokenServerTransportFactory()); assertEquals(PROJECT_ID, credentials.getProjectId()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + + @Test + public void fromJSON_Universe_getUniverseDomain() throws IOException { + GenericJson json = + writeServiceAccountJson( + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, TPC_UNIVERSE); + + ServiceAccountCredentials credentials = + ServiceAccountCredentials.fromJson(json, new MockTokenServerTransportFactory()); + assertEquals(TPC_UNIVERSE, credentials.getUniverseDomain()); } @Test @@ -490,7 +503,7 @@ public void fromJSON_getProjectIdNull() throws IOException { transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null, null); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null, null, null); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -503,7 +516,7 @@ public void fromJSON_hasAccessToken() throws IOException { transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, null); GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -519,7 +532,7 @@ public void fromJSON_tokenServerUri() throws IOException { transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, null); json.put("token_uri", tokenServerUri); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -532,7 +545,7 @@ public void fromJson_hasQuotaProjectId() throws IOException { transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, QUOTA_PROJECT); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, QUOTA_PROJECT, null); GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); credentials = credentials.createScoped(SCOPES); Map> metadata = credentials.getRequestMetadata(CALL_URI); @@ -583,6 +596,21 @@ public void getRequestMetadata_customTokenServer_hasAccessToken() throws IOExcep TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); } + @Test + public void getUniverseDomain_defaultUniverse() throws IOException { + final URI TOKEN_SERVER = URI.create("https://foo.com/bar"); + ServiceAccountCredentials credentials = + ServiceAccountCredentials.fromPkcs8( + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + new MockTokenServerTransportFactory(), + TOKEN_SERVER); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + @Test public void refreshAccessToken_refreshesToken() throws IOException { final String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2"; @@ -1613,7 +1641,8 @@ static GenericJson writeServiceAccountJson( String privateKeyPkcs8, String privateKeyId, String projectId, - String quotaProjectId) { + String quotaProjectId, + String universeDomain) { GenericJson json = new GenericJson(); if (clientId != null) { json.put("client_id", clientId); @@ -1633,6 +1662,9 @@ static GenericJson writeServiceAccountJson( if (quotaProjectId != null) { json.put("quota_project_id", quotaProjectId); } + if (universeDomain != null) { + json.put("universe_domain", universeDomain); + } json.put("type", GoogleCredentials.SERVICE_ACCOUNT_FILE_TYPE); return json; } @@ -1640,8 +1672,21 @@ static GenericJson writeServiceAccountJson( static InputStream writeServiceAccountStream( String clientId, String clientEmail, String privateKeyPkcs8, String privateKeyId) throws IOException { + return writeServiceAccountStream(clientId, clientEmail, privateKeyPkcs8, privateKeyId, null); + } + + static InputStream writeServiceAccountStream( + String clientId, String clientEmail, String privateKeyPkcs8, String privateKeyId, String universeDomain) + throws IOException { GenericJson json = - writeServiceAccountJson(clientId, clientEmail, privateKeyPkcs8, privateKeyId, null, null); + writeServiceAccountJson( + clientId, + clientEmail, + privateKeyPkcs8, + privateKeyId, + null, + null, + universeDomain); return TestUtils.jsonToInputStream(json); } From efe23b18d58381e2263fe25087d3fdf8b81bb296 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 13 Sep 2023 19:32:24 +0000 Subject: [PATCH 05/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../oauth2/ServiceAccountCredentialsTest.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index b28618e1b..7df87574f 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -490,7 +490,13 @@ public void fromJSON_getProjectId() throws IOException { public void fromJSON_Universe_getUniverseDomain() throws IOException { GenericJson json = writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, TPC_UNIVERSE); + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + PROJECT_ID, + null, + TPC_UNIVERSE); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, new MockTokenServerTransportFactory()); @@ -545,7 +551,13 @@ public void fromJson_hasQuotaProjectId() throws IOException { transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, QUOTA_PROJECT, null); + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + PROJECT_ID, + QUOTA_PROJECT, + null); GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); credentials = credentials.createScoped(SCOPES); Map> metadata = credentials.getRequestMetadata(CALL_URI); @@ -1676,17 +1688,15 @@ static InputStream writeServiceAccountStream( } static InputStream writeServiceAccountStream( - String clientId, String clientEmail, String privateKeyPkcs8, String privateKeyId, String universeDomain) + String clientId, + String clientEmail, + String privateKeyPkcs8, + String privateKeyId, + String universeDomain) throws IOException { GenericJson json = writeServiceAccountJson( - clientId, - clientEmail, - privateKeyPkcs8, - privateKeyId, - null, - null, - universeDomain); + clientId, clientEmail, privateKeyPkcs8, privateKeyId, null, null, universeDomain); return TestUtils.jsonToInputStream(json); } From 090674ffacaa6c215589342f67c66f17766d36ce Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Thu, 2 Nov 2023 00:52:14 -0700 Subject: [PATCH 06/31] fix: move universe_domain to very base Credential, tests cleanup --- .../java/com/google/auth/Credentials.java | 11 + .../google/auth/oauth2/GoogleAuthUtils.java | 1 - .../google/auth/oauth2/GoogleCredentials.java | 17 +- .../oauth2/ServiceAccountCredentials.java | 60 +- .../oauth2/ServiceAccountCredentialsTest.java | 535 +++++++++--------- 5 files changed, 345 insertions(+), 279 deletions(-) diff --git a/credentials/java/com/google/auth/Credentials.java b/credentials/java/com/google/auth/Credentials.java index 416de9d5a..3063dc2b0 100644 --- a/credentials/java/com/google/auth/Credentials.java +++ b/credentials/java/com/google/auth/Credentials.java @@ -43,6 +43,8 @@ public abstract class Credentials implements Serializable { private static final long serialVersionUID = 808575179767517313L; + public static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; + /** * A constant string name describing the authentication technology. * @@ -54,6 +56,15 @@ public abstract class Credentials implements Serializable { */ public abstract String getAuthenticationType(); + /** + * Returns the universe domain for the credential + * + * @return Return a default Google universe domain googleapis.com + */ + public String getUniverseDomain() { + return GOOGLE_DEFAULT_UNIVERSE; + } + /** * Get the current request metadata, refreshing tokens if required. * diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java b/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java index dbea4596f..d82548a08 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java @@ -38,7 +38,6 @@ * convenience methods such as a getter for well-known Application Default Credentials file path */ public class GoogleAuthUtils { - static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; /** * Gets the path to the well-known Application Default Credentials file location diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 1d82e26ad..c2cbece29 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -35,6 +35,7 @@ import com.google.api.client.json.JsonFactory; import com.google.api.client.json.JsonObjectParser; import com.google.api.client.util.Preconditions; +import com.google.auth.Credentials; import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; @@ -250,17 +251,27 @@ public GoogleCredentials createWithQuotaProject(String quotaProject) { /** * Returns the universe domain for the credential * - * @return An explicit universe domain if it was explicitly provided, {@code - * GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE} otherwise. + * @return An explicit universe domain if it was explicitly provided, invokes + * the super implementation otherwise. */ + @Override public String getUniverseDomain() { if (this.universeDomain == null || universeDomain.trim().isEmpty()) { - return GoogleAuthUtils.GOOGLE_DEFAULT_UNIVERSE; + return super.getUniverseDomain(); } return this.universeDomain; } + /** + * Checks if universe domain equals to {@link Credentials#GOOGLE_DEFAULT_UNIVERSE}. + * @return true if universeDomain equals to {@link Credentials#GOOGLE_DEFAULT_UNIVERSE}, + * false otherwise + */ + boolean isDefaultUniverseDomain() { + return getUniverseDomain() == Credentials.GOOGLE_DEFAULT_UNIVERSE; + } + /** * Adds quota project ID to requestMetadata if present. * diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index aa64981a6..debf2eec5 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -49,6 +49,7 @@ import com.google.api.client.util.GenericData; import com.google.api.client.util.Joiner; import com.google.api.client.util.Preconditions; +import com.google.auth.Credentials; import com.google.auth.RequestMetadataCallback; import com.google.auth.ServiceAccountSigner; import com.google.auth.http.HttpTransportFactory; @@ -480,6 +481,12 @@ public boolean createScopedRequired() { return scopes.isEmpty() && defaultScopes.isEmpty(); } + /** Returns true if credential is configured domain wide delegation */ + @VisibleForTesting + boolean isConfiguredForDomainWideDelegation() { + return serviceAccountUser != null && serviceAccountUser.length() > 0; + } + /** * Refreshes the OAuth2 access token by getting a new access token using a JSON Web Token (JWT). */ @@ -854,7 +861,7 @@ String createAssertionForIdToken( } /** - * Self signed JWT uses uri as audience, which should have the "https://{host}/" format. For + * Self-signed JWT uses uri as audience, which should have the "https://{host}/" format. For * instance, if the uri is "https://compute.googleapis.com/compute/v1/projects/", then this * function returns "https://compute.googleapis.com/". */ @@ -872,7 +879,7 @@ static URI getUriForSelfSignedJWT(URI uri) { @VisibleForTesting JwtCredentials createSelfSignedJwtCredentials(final URI uri) { - // Create a JwtCredentials for self signed JWT. See https://google.aip.dev/auth/4111. + // Create a JwtCredentials for self-signed JWT. See https://google.aip.dev/auth/4111. JwtClaims.Builder claimsBuilder = JwtClaims.newBuilder().setIssuer(clientEmail).setSubject(clientEmail); @@ -900,9 +907,12 @@ JwtCredentials createSelfSignedJwtCredentials(final URI uri) { @Override public void getRequestMetadata( final URI uri, Executor executor, final RequestMetadataCallback callback) { - if (useJwtAccessWithScope) { - // This will call getRequestMetadata(URI uri), which handles self signed JWT logic. - // Self signed JWT doesn't use network, so here we do a blocking call to improve + // For default universe Self-signed JWT could be explicitly disabled with + // {@code ServiceAccountCredentials.useJwtAccessWithScope} flag. + // If universe is non-default, it only supports self-signed JWT, and it is always allowed. + if (this.useJwtAccessWithScope || !isDefaultUniverseDomain()) { + // This will call getRequestMetadata(URI uri), which handles self-signed JWT logic. + // Self-signed JWT doesn't use network, so here we do a blocking call to improve // efficiency. executor will be ignored since it is intended for async operation. blockingGetToCallback(uri, callback); } else { @@ -920,17 +930,44 @@ public Map> getRequestMetadata(URI uri) throws IOException + " providing uri to getRequestMetadata."); } - // If scopes are provided but we cannot use self signed JWT, then use scopes to get access - // token. + if (isDefaultUniverseDomain()) { + return getRequestMetadataForGdu(uri); + } else { + return getRequestMetadataForNonGdu(uri); + } + } + + private Map> getRequestMetadataForGdu(URI uri) throws IOException { + // If scopes are provided, but we cannot use self-signed JWT or domain-wide delegation is + // configured then use scopes to get access token. if ((!createScopedRequired() && !useJwtAccessWithScope) - || (serviceAccountUser != null && serviceAccountUser.length() > 0)) { + || isConfiguredForDomainWideDelegation()) { return super.getRequestMetadata(uri); } - // If scopes are provided and self signed JWT can be used, use self signed JWT with scopes. - // Otherwise, use self signed JWT with uri as the audience. + return getRequestMetadataWithSelfSignedJwt(uri); + } + + private Map> getRequestMetadataForNonGdu(URI uri) throws IOException { + // Self Signed JWT is not supported for domain-wide delegation for non-GDU universes + if (isConfiguredForDomainWideDelegation()) { + throw new IOException( + String.format("Service Account user is configured for the credential. " + + "Domain-wide delegation is not supported in universes different than %s.", + Credentials.GOOGLE_DEFAULT_UNIVERSE)); + } + + return getRequestMetadataWithSelfSignedJwt(uri); + } + + /** Provide the access JWT for scopes if provided, for uri as aud otherwise */ + @VisibleForTesting + private Map> getRequestMetadataWithSelfSignedJwt(URI uri) + throws IOException { + // If scopes are provided and self-signed JWT can be used, use self-signed JWT with scopes. + // Otherwise, use self-signed JWT with uri as the audience. JwtCredentials jwtCredentials; - if (!createScopedRequired() && useJwtAccessWithScope) { + if (!createScopedRequired()) { // Create selfSignedJwtCredentialsWithScope when needed and reuse it for better performance. if (selfSignedJwtCredentialsWithScope == null) { selfSignedJwtCredentialsWithScope = createSelfSignedJwtCredentials(null); @@ -940,6 +977,7 @@ public Map> getRequestMetadata(URI uri) throws IOException // Create JWT credentials with the uri as audience. jwtCredentials = createSelfSignedJwtCredentials(uri); } + Map> requestMetadata = jwtCredentials.getRequestMetadata(null); return addQuotaProjectIdToRequestMetadata(quotaProjectId, requestMetadata); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 7df87574f..94e686ef9 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -121,20 +121,61 @@ public class ServiceAccountCredentialsTest extends BaseSerializationTest { private static final int INVALID_LIFETIME = 43210; private static final String JWT_ACCESS_PREFIX = "Bearer "; private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; - private static final String TPC_UNIVERSE = "foo.bar"; - private ServiceAccountCredentials.Builder createDefaultBuilder() throws IOException { - PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - return ServiceAccountCredentials.newBuilder() + private ServiceAccountCredentials.Builder createDefaultBuilderWithToken(String accessToken) throws IOException { + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, accessToken); + return createDefaultBuilder().setHttpTransportFactory(transportFactory); + } + + private ServiceAccountCredentials.Builder createDefaultBuilderWithScopes(Collection scopes) + throws IOException { + return createDefaultBuilder().setScopes(scopes); + } + + private ServiceAccountCredentials.Builder createDefaultBuilderWithKey(PrivateKey privateKey) { + ServiceAccountCredentials.Builder builder = ServiceAccountCredentials.newBuilder() .setClientId(CLIENT_ID) .setClientEmail(CLIENT_EMAIL) .setPrivateKey(privateKey) .setPrivateKeyId(PRIVATE_KEY_ID) - .setScopes(SCOPES) - .setServiceAccountUser(USER) - .setProjectId(PROJECT_ID); + .setProjectId(PROJECT_ID) + .setQuotaProjectId(QUOTA_PROJECT) + .setHttpTransportFactory(new MockHttpTransportFactory()); + + return builder; } + private ServiceAccountCredentials.Builder createDefaultBuilder() throws IOException { + PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); + return createDefaultBuilderWithKey(privateKey); + } + + // + // private ServiceAccountCredentials createServiceAccountWithToken(Collection scopes) + // throws IOException { + // MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + // transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); + // return createServiceAccountFromPkcs8(scopes, transportFactory); + // } + // + // private ServiceAccountCredentials createServiceAccountFromPkcs8(Collection scopes) + // throws IOException { + // return createServiceAccountFromPkcs8(scopes, new MockTokenServerTransportFactory()); + // } + // + // private ServiceAccountCredentials createServiceAccountFromPkcs8(Collection scopes, HttpTransportFactory transportFactory) + // throws IOException { + // return ServiceAccountCredentials.fromPkcs8( + // CLIENT_ID, + // CLIENT_EMAIL, + // PRIVATE_KEY_PKCS8, + // PRIVATE_KEY_ID, + // scopes, + // transportFactory, + // null); + // } + @Test public void setLifetime() throws IOException { ServiceAccountCredentials.Builder builder = createDefaultBuilder(); @@ -172,16 +213,11 @@ public void createWithCustomLifetime() throws IOException { @Test public void createdScoped_clones() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - GoogleCredentials credentials = - ServiceAccountCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientEmail(CLIENT_EMAIL) - .setPrivateKey(privateKey) - .setPrivateKeyId(PRIVATE_KEY_ID) - .setScopes(SCOPES) - .setServiceAccountUser(USER) - .setProjectId(PROJECT_ID) - .build(); + ServiceAccountCredentials credentials = createDefaultBuilderWithKey(privateKey) + .setServiceAccountUser(USER) + .setScopes(SCOPES) + .setProjectId(PROJECT_ID) + .build(); List newScopes = Arrays.asList("scope1", "scope2"); ServiceAccountCredentials newCredentials = @@ -203,17 +239,10 @@ public void createdScoped_clones() throws IOException { @Test public void createdDelegated_clones() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - ServiceAccountCredentials credentials = - ServiceAccountCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientEmail(CLIENT_EMAIL) - .setPrivateKey(privateKey) - .setPrivateKeyId(PRIVATE_KEY_ID) - .setScopes(SCOPES) - .setServiceAccountUser(USER) - .setProjectId(PROJECT_ID) - .setQuotaProjectId(QUOTA_PROJECT) - .build(); + ServiceAccountCredentials credentials = createDefaultBuilderWithKey(privateKey) + .setScopes(SCOPES) + .setServiceAccountUser(USER) + .build(); String newServiceAccountUser = "stranger@other.org"; ServiceAccountCredentials newCredentials = @@ -233,18 +262,9 @@ public void createdDelegated_clones() throws IOException { @Test public void createAssertion_correct() throws IOException { - PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); List scopes = Arrays.asList("scope1", "scope2"); - ServiceAccountCredentials credentials = - ServiceAccountCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientEmail(CLIENT_EMAIL) - .setPrivateKey(privateKey) - .setPrivateKeyId(PRIVATE_KEY_ID) - .setScopes(scopes) - .setServiceAccountUser(USER) - .setProjectId(PROJECT_ID) - .build(); + ServiceAccountCredentials.Builder builder = createDefaultBuilderWithScopes(scopes); + ServiceAccountCredentials credentials = builder.setServiceAccountUser(USER).build(); JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY; long currentTimeMillis = Clock.SYSTEM.currentTimeMillis(); @@ -262,17 +282,11 @@ public void createAssertion_correct() throws IOException { @Test public void createAssertion_defaultScopes_correct() throws IOException { - PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - List scopes = Arrays.asList("scope1", "scope2"); - ServiceAccountCredentials.Builder builder = - ServiceAccountCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientEmail(CLIENT_EMAIL) - .setPrivateKey(privateKey) - .setPrivateKeyId(PRIVATE_KEY_ID) - .setScopes(null, scopes) - .setServiceAccountUser(USER) - .setProjectId(PROJECT_ID); + List defaultScopes = Arrays.asList("scope1", "scope2"); + ServiceAccountCredentials.Builder builder = createDefaultBuilder(); + builder.setScopes(null, defaultScopes) + .setServiceAccountUser(USER); + assertEquals(2, builder.getDefaultScopes().size()); ServiceAccountCredentials credentials = builder.build(); @@ -287,7 +301,7 @@ public void createAssertion_defaultScopes_correct() throws IOException { assertEquals(currentTimeMillis / 1000, (long) payload.getIssuedAtTimeSeconds()); assertEquals(currentTimeMillis / 1000 + 3600, (long) payload.getExpirationTimeSeconds()); assertEquals(USER, payload.getSubject()); - assertEquals(Joiner.on(' ').join(scopes), payload.get("scope")); + assertEquals(Joiner.on(' ').join(defaultScopes), payload.get("scope")); } @Test @@ -305,13 +319,8 @@ public void createAssertion_custom_lifetime() throws IOException { @Test public void createAssertionForIdToken_correct() throws IOException { - PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - ServiceAccountCredentials credentials = - ServiceAccountCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientEmail(CLIENT_EMAIL) - .setPrivateKey(privateKey) + ServiceAccountCredentials credentials = createDefaultBuilder() .setPrivateKeyId(PRIVATE_KEY_ID) .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) @@ -334,7 +343,6 @@ public void createAssertionForIdToken_correct() throws IOException { @Test public void createAssertionForIdToken_custom_lifetime() throws IOException { - ServiceAccountCredentials credentials = createDefaultBuilder().setLifetime(4000).build(); JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY; @@ -350,7 +358,6 @@ public void createAssertionForIdToken_custom_lifetime() throws IOException { @Test public void createAssertionForIdToken_incorrect() throws IOException { - PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); ServiceAccountCredentials credentials = ServiceAccountCredentials.newBuilder() @@ -379,19 +386,12 @@ public void createAssertionForIdToken_incorrect() throws IOException { } @Test - public void createdScoped_enablesAccessTokens() throws IOException { - MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - GoogleCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - null, - transportFactory, - null); + public void createdScoped_withAud_noUniverse_jwtWithScopesDisabled_accessToken() throws IOException { + // TODO: this should not default to AUD and throw exception that scopes + // are provided, but cannot be used + GoogleCredentials credentials = createDefaultBuilderWithToken(ACCESS_TOKEN).build(); + // no aud, no scopes -> exception try { credentials.getRequestMetadata(null); fail("Should not be able to get token without scopes"); @@ -406,12 +406,62 @@ public void createdScoped_enablesAccessTokens() throws IOException { TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); } + @Test + public void createdScoped_withUniverse_selfSignedJwt() throws IOException { + GoogleCredentials credentials = createDefaultBuilder().build(); + credentials = credentials.createWithUniverseDomain("foo.bar"); + + try { + credentials.getRequestMetadata(null); + fail("Should not be able to get token without scopes"); + } catch (IOException e) { + assertTrue( + "expected to fail with exception", + e.getMessage().contains("Scopes and uri are not configured for service account")); + } + + GoogleCredentials scopedCredentials = credentials.createScoped("dummy.scope"); + Map> metadata = scopedCredentials.getRequestMetadata(null); + verifyJwtAccess(metadata, "dummy.scope"); + + // recreate to avoid jwt caching + scopedCredentials = credentials.createScoped("dummy.scope2"); + metadata = scopedCredentials.getRequestMetadata(CALL_URI); + verifyJwtAccess(metadata, "dummy.scope2"); + + // recreate to avoid jwt caching + scopedCredentials = credentials.createScoped(Collections.emptyList(), Arrays.asList("dummy.default.scope")); + metadata = scopedCredentials.getRequestMetadata(null); + verifyJwtAccess(metadata, "dummy.default.scope"); + + // recreate to avoid jwt caching + scopedCredentials = credentials.createScoped(Collections.emptyList(), Arrays.asList("dummy.default.scope2")); + metadata = scopedCredentials.getRequestMetadata(CALL_URI); + verifyJwtAccess(metadata, "dummy.default.scope2"); + } + + @Test + public void noScopes_withUniverse_selfSignedJwt() throws IOException { + GoogleCredentials credentials = createDefaultBuilder().build(); + credentials = credentials.createWithUniverseDomain("foo.bar"); + + try { + credentials.getRequestMetadata(null); + fail("Should not be able to get token without scopes"); + } catch (IOException e) { + assertTrue( + "expected to fail with exception", + e.getMessage().contains("Scopes and uri are not configured for service account")); + } + + Map> metadata = credentials.getRequestMetadata(CALL_URI); + assertNull(((ServiceAccountCredentials) credentials).getSelfSignedJwtCredentialsWithScope()); + verifyJwtAccess(metadata, null); + } + @Test public void createdScoped_defaultScopes() throws IOException { - final URI TOKEN_SERVER = URI.create("https://foo.com/bar"); MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - transportFactory.transport.setTokenServerUri(TOKEN_SERVER); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( @@ -428,7 +478,7 @@ public void createdScoped_defaultScopes() throws IOException { SCOPES, DEFAULT_SCOPES, transportFactory, - TOKEN_SERVER); + null); assertEquals(1, credentials.getDefaultScopes().size()); assertEquals("dummy.default.scope", credentials.getDefaultScopes().toArray()[0]); @@ -441,7 +491,7 @@ public void createdScoped_defaultScopes() throws IOException { SCOPES, DEFAULT_SCOPES, transportFactory, - TOKEN_SERVER, + null, "service_account_user"); assertEquals(1, credentials.getDefaultScopes().size()); assertEquals("dummy.default.scope", credentials.getDefaultScopes().toArray()[0]); @@ -477,8 +527,7 @@ public void createScopedRequired_nonEmptyDefaultScopes() throws IOException { @Test public void fromJSON_getProjectId() throws IOException { GenericJson json = - writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, null); + writeServiceAccountJson(PROJECT_ID, null, null); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, new MockTokenServerTransportFactory()); @@ -489,18 +538,11 @@ public void fromJSON_getProjectId() throws IOException { @Test public void fromJSON_Universe_getUniverseDomain() throws IOException { GenericJson json = - writeServiceAccountJson( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - PROJECT_ID, - null, - TPC_UNIVERSE); + writeServiceAccountJson(PROJECT_ID, null,"foo.bar"); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, new MockTokenServerTransportFactory()); - assertEquals(TPC_UNIVERSE, credentials.getUniverseDomain()); + assertEquals("foo.bar", credentials.getUniverseDomain()); } @Test @@ -508,8 +550,7 @@ public void fromJSON_getProjectIdNull() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = - writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null, null, null); + writeServiceAccountJson(null, null, null); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -521,8 +562,7 @@ public void fromJSON_hasAccessToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = - writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, null); + writeServiceAccountJson(PROJECT_ID, null, null); GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -531,14 +571,26 @@ public void fromJSON_hasAccessToken() throws IOException { TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); } + @Test + public void fromJSON_withUniverse_selfSignedJwt() throws IOException { + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); + GenericJson json = + writeServiceAccountJson(PROJECT_ID, null, "foo.bar"); + + GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); + + credentials = credentials.createScoped(SCOPES); + Map> metadata = credentials.getRequestMetadata(null); + verifyJwtAccess(metadata, "dummy.scope"); + } + @Test public void fromJSON_tokenServerUri() throws IOException { final String tokenServerUri = "https://foo.com/bar"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - GenericJson json = - writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null, null); + GenericJson json = writeServiceAccountJson(PROJECT_ID, null, null); json.put("token_uri", tokenServerUri); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -549,6 +601,7 @@ public void fromJSON_tokenServerUri() throws IOException { public void fromJson_hasQuotaProjectId() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); +<<<<<<< HEAD GenericJson json = writeServiceAccountJson( CLIENT_ID, @@ -558,6 +611,9 @@ public void fromJson_hasQuotaProjectId() throws IOException { PROJECT_ID, QUOTA_PROJECT, null); +======= + GenericJson json = writeServiceAccountJson(PROJECT_ID, QUOTA_PROJECT, null); +>>>>>>> 7959a6c (fix: move universe_domain to very base Credential, tests cleanup) GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); credentials = credentials.createScoped(SCOPES); Map> metadata = credentials.getRequestMetadata(CALL_URI); @@ -570,20 +626,10 @@ public void fromJson_hasQuotaProjectId() throws IOException { @Test public void getRequestMetadata_hasAccessToken() throws IOException { - MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - OAuth2Credentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); - + GoogleCredentials credentials = createDefaultBuilderWithToken(ACCESS_TOKEN) + .setScopes(SCOPES) + .build(); Map> metadata = credentials.getRequestMetadata(CALL_URI); - TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); } @@ -593,16 +639,11 @@ public void getRequestMetadata_customTokenServer_hasAccessToken() throws IOExcep MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); transportFactory.transport.setTokenServerUri(TOKEN_SERVER); - OAuth2Credentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - TOKEN_SERVER); - + OAuth2Credentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .setTokenServerUri(TOKEN_SERVER) + .build(); Map> metadata = credentials.getRequestMetadata(CALL_URI); TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); @@ -610,16 +651,7 @@ public void getRequestMetadata_customTokenServer_hasAccessToken() throws IOExcep @Test public void getUniverseDomain_defaultUniverse() throws IOException { - final URI TOKEN_SERVER = URI.create("https://foo.com/bar"); - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - new MockTokenServerTransportFactory(), - TOKEN_SERVER); + ServiceAccountCredentials credentials = createDefaultBuilder().build(); assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); } @@ -629,16 +661,10 @@ public void refreshAccessToken_refreshesToken() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); - + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -649,29 +675,23 @@ public void refreshAccessToken_refreshesToken() throws IOException { @Test public void refreshAccessToken_tokenExpiry() throws IOException { - final String tokenString = "1/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); credentials.clock = new FixedClock(0L); - transport.addServiceAccount(CLIENT_EMAIL, tokenString); AccessToken accessToken = credentials.refreshAccessToken(); - assertEquals(tokenString, accessToken.getTokenValue()); + assertEquals(ACCESS_TOKEN, accessToken.getTokenValue()); assertEquals(3600 * 1000L, accessToken.getExpirationTimeMillis().longValue()); // Test for large expires_in values (should not overflow). transport.setExpiresInSeconds(3600 * 1000); accessToken = credentials.refreshAccessToken(); - assertEquals(tokenString, accessToken.getTokenValue()); + assertEquals(ACCESS_TOKEN, accessToken.getTokenValue()); assertEquals(3600 * 1000 * 1000L, accessToken.getExpirationTimeMillis().longValue()); } @@ -681,15 +701,10 @@ public void refreshAccessToken_IOException_Retry() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build();; transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -706,15 +721,10 @@ public void refreshAccessToken_retriesServerErrors() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -733,15 +743,10 @@ public void refreshAccessToken_retriesTimeoutAndThrottled() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -760,16 +765,11 @@ public void refreshAccessToken_defaultRetriesDisabled() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null) - .createWithCustomRetryStrategy(false); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build() + .createWithCustomRetryStrategy(false); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -791,21 +791,15 @@ public void refreshAccessToken_defaultRetriesDisabled() throws IOException { @Test public void refreshAccessToken_maxRetries_maxDelay() throws IOException { - final String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); - transport.addServiceAccount(CLIENT_EMAIL, accessToken1); - TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); + TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), ACCESS_TOKEN); MockLowLevelHttpResponse response408 = new MockLowLevelHttpResponse().setStatusCode(408); MockLowLevelHttpResponse response429 = new MockLowLevelHttpResponse().setStatusCode(429); @@ -832,21 +826,15 @@ public void refreshAccessToken_maxRetries_maxDelay() throws IOException { @Test public void refreshAccessToken_RequestFailure_retried() throws IOException { - final String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); - transport.addServiceAccount(CLIENT_EMAIL, accessToken1); - TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); + TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), ACCESS_TOKEN); IOException error = new IOException("Invalid grant: Account not found"); MockLowLevelHttpResponse response503 = new MockLowLevelHttpResponse().setStatusCode(503); @@ -878,15 +866,10 @@ public void refreshAccessToken_4xx_5xx_NonRetryableFails() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -914,15 +897,10 @@ public void idTokenWithAudience_correct() throws IOException { String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -946,15 +924,10 @@ public void idTokenWithAudience_incorrect() throws IOException { String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -973,10 +946,7 @@ public void idTokenWithAudience_incorrect() throws IOException { @Test public void getScopes_nullReturnsEmpty() throws IOException { - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null); - + ServiceAccountCredentials credentials = createDefaultBuilder().build(); Collection scopes = credentials.getScopes(); assertNotNull(scopes); @@ -985,9 +955,7 @@ public void getScopes_nullReturnsEmpty() throws IOException { @Test public void getAccount_sameAs() throws IOException { - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null); + ServiceAccountCredentials credentials = createDefaultBuilder().build(); assertEquals(CLIENT_EMAIL, credentials.getAccount()); } @@ -995,13 +963,13 @@ public void getAccount_sameAs() throws IOException { public void sign_sameAs() throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { byte[] toSign = {0xD, 0xE, 0xA, 0xD}; - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null); + ServiceAccountCredentials credentials = createDefaultBuilder().build(); + byte[] signedBytes = credentials.sign(toSign); Signature signature = Signature.getInstance(OAuth2Utils.SIGNATURE_ALGORITHM); signature.initSign(credentials.getPrivateKey()); signature.update(toSign); + assertArrayEquals(signature.sign(), signedBytes); } @@ -1330,15 +1298,10 @@ public void getIdTokenWithAudience_badEmailError_issClaimTraced() throws IOExcep MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; transport.setError(new IOException("Invalid grant: Account not found")); - ServiceAccountCredentials credentials = - ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - null); + ServiceAccountCredentials credentials = createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build(); String targetAudience = "https://bar"; IdTokenCredentials tokenCredential = @@ -1397,7 +1360,7 @@ public void getUriForSelfSignedJWT_forStaticAudience_returnsURI() { } @Test - public void getRequestMetadataSetsQuotaProjectId() throws IOException { + public void getRequestMetadata_setsQuotaProjectId() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addClient(CLIENT_ID, "unused-client-secret"); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); @@ -1424,7 +1387,7 @@ public void getRequestMetadataSetsQuotaProjectId() throws IOException { } @Test - public void getRequestMetadataNoQuotaProjectId() throws IOException { + public void getRequestMetadata_noQuotaProjectId() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addClient(CLIENT_ID, "unused-client-secret"); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); @@ -1447,7 +1410,7 @@ public void getRequestMetadataNoQuotaProjectId() throws IOException { } @Test - public void getRequestMetadataWithCallback() throws IOException { + public void getRequestMetadata_withCallback() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addClient(CLIENT_ID, "unused-client-secret"); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); @@ -1460,7 +1423,6 @@ public void getRequestMetadataWithCallback() throws IOException { .setPrivateKey(privateKey) .setPrivateKeyId(PRIVATE_KEY_ID) .setScopes(SCOPES) - .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) .setQuotaProjectId("my-quota-project-id") .setHttpTransportFactory(transportFactory) @@ -1488,7 +1450,47 @@ public void onFailure(Throwable exception) { } @Test - public void getRequestMetadata_selfSignedJWT_withScopes() throws IOException { + public void getRequestMetadata_withScopes_withUniverseDomain_SelfSignedJwt() throws IOException { + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + transportFactory.transport.addClient(CLIENT_ID, "unused-client-secret"); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); + + PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); + GoogleCredentials credentials = + ServiceAccountCredentials.newBuilder() + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) + .setPrivateKey(privateKey) + .setPrivateKeyId(PRIVATE_KEY_ID) + .setScopes(SCOPES) + .setProjectId(PROJECT_ID) + .setHttpTransportFactory(transportFactory) + .setUniverseDomain("foo.bar") + .build(); + + final Map> plainMetadata = credentials.getRequestMetadata(); + final AtomicBoolean success = new AtomicBoolean(false); + credentials.getRequestMetadata( + null, + null, + new RequestMetadataCallback() { + @Override + public void onSuccess(Map> metadata) { + assertEquals(plainMetadata, metadata); + success.set(true); + } + + @Override + public void onFailure(Throwable exception) { + fail("Should not throw a failure."); + } + }); + + assertTrue("Should have run onSuccess() callback", success.get()); + } + + @Test + public void getRequestMetadata_withScopes_selfSignedJWT() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); GoogleCredentials credentials = ServiceAccountCredentials.newBuilder() @@ -1544,7 +1546,7 @@ public void refreshAccessToken_withDomainDelegation_selfSignedJWT_disabled() thr } @Test - public void getRequestMetadata_selfSignedJWT_withAudience() throws IOException { + public void getRequestMetadata_withAudience_selfSignedJWT() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); GoogleCredentials credentials = ServiceAccountCredentials.newBuilder() @@ -1562,7 +1564,7 @@ public void getRequestMetadata_selfSignedJWT_withAudience() throws IOException { } @Test - public void getRequestMetadata_selfSignedJWT_withDefaultScopes() throws IOException { + public void getRequestMetadata_withDefaultScopes_selfSignedJWT() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); GoogleCredentials credentials = ServiceAccountCredentials.newBuilder() @@ -1647,6 +1649,11 @@ private void verifyJwtAccess(Map> metadata, String expected assertEquals(PRIVATE_KEY_ID, signature.getHeader().getKeyId()); } + static GenericJson writeServiceAccountJson(String projectId, String quotaProjectId, String universeDomain) { + return writeServiceAccountJson( + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, projectId, quotaProjectId, universeDomain); + } + static GenericJson writeServiceAccountJson( String clientId, String clientEmail, From 3eb40478e00c56ad54780a270d9e6b1684bb3d96 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Thu, 2 Nov 2023 00:56:15 -0700 Subject: [PATCH 07/31] fix: resolve a conflict in tests --- .../auth/oauth2/ServiceAccountCredentialsTest.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 94e686ef9..021a7b820 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -601,21 +601,10 @@ public void fromJSON_tokenServerUri() throws IOException { public void fromJson_hasQuotaProjectId() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); -<<<<<<< HEAD - GenericJson json = - writeServiceAccountJson( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - PROJECT_ID, - QUOTA_PROJECT, - null); -======= GenericJson json = writeServiceAccountJson(PROJECT_ID, QUOTA_PROJECT, null); ->>>>>>> 7959a6c (fix: move universe_domain to very base Credential, tests cleanup) GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); credentials = credentials.createScoped(SCOPES); + Map> metadata = credentials.getRequestMetadata(CALL_URI); assertTrue(metadata.containsKey(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY)); From da7e1b75cd47e783951d204a24c8c42f7e114569 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Thu, 2 Nov 2023 07:58:26 +0000 Subject: [PATCH 08/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../google/auth/oauth2/GoogleCredentials.java | 9 +- .../oauth2/ServiceAccountCredentials.java | 3 +- .../oauth2/ServiceAccountCredentialsTest.java | 184 +++++++++--------- 3 files changed, 95 insertions(+), 101 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index c2cbece29..94fa4a879 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -251,8 +251,8 @@ public GoogleCredentials createWithQuotaProject(String quotaProject) { /** * Returns the universe domain for the credential * - * @return An explicit universe domain if it was explicitly provided, invokes - * the super implementation otherwise. + * @return An explicit universe domain if it was explicitly provided, invokes the super + * implementation otherwise. */ @Override public String getUniverseDomain() { @@ -265,8 +265,9 @@ public String getUniverseDomain() { /** * Checks if universe domain equals to {@link Credentials#GOOGLE_DEFAULT_UNIVERSE}. - * @return true if universeDomain equals to {@link Credentials#GOOGLE_DEFAULT_UNIVERSE}, - * false otherwise + * + * @return true if universeDomain equals to {@link Credentials#GOOGLE_DEFAULT_UNIVERSE}, false + * otherwise */ boolean isDefaultUniverseDomain() { return getUniverseDomain() == Credentials.GOOGLE_DEFAULT_UNIVERSE; diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index debf2eec5..0b2866fd8 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -952,7 +952,8 @@ private Map> getRequestMetadataForNonGdu(URI uri) throws IO // Self Signed JWT is not supported for domain-wide delegation for non-GDU universes if (isConfiguredForDomainWideDelegation()) { throw new IOException( - String.format("Service Account user is configured for the credential. " + String.format( + "Service Account user is configured for the credential. " + "Domain-wide delegation is not supported in universes different than %s.", Credentials.GOOGLE_DEFAULT_UNIVERSE)); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 021a7b820..5760714fa 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -122,26 +122,28 @@ public class ServiceAccountCredentialsTest extends BaseSerializationTest { private static final String JWT_ACCESS_PREFIX = "Bearer "; private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com"; - private ServiceAccountCredentials.Builder createDefaultBuilderWithToken(String accessToken) throws IOException { + private ServiceAccountCredentials.Builder createDefaultBuilderWithToken(String accessToken) + throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, accessToken); return createDefaultBuilder().setHttpTransportFactory(transportFactory); } - private ServiceAccountCredentials.Builder createDefaultBuilderWithScopes(Collection scopes) - throws IOException { + private ServiceAccountCredentials.Builder createDefaultBuilderWithScopes( + Collection scopes) throws IOException { return createDefaultBuilder().setScopes(scopes); } private ServiceAccountCredentials.Builder createDefaultBuilderWithKey(PrivateKey privateKey) { - ServiceAccountCredentials.Builder builder = ServiceAccountCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientEmail(CLIENT_EMAIL) - .setPrivateKey(privateKey) - .setPrivateKeyId(PRIVATE_KEY_ID) - .setProjectId(PROJECT_ID) - .setQuotaProjectId(QUOTA_PROJECT) - .setHttpTransportFactory(new MockHttpTransportFactory()); + ServiceAccountCredentials.Builder builder = + ServiceAccountCredentials.newBuilder() + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) + .setPrivateKey(privateKey) + .setPrivateKeyId(PRIVATE_KEY_ID) + .setProjectId(PROJECT_ID) + .setQuotaProjectId(QUOTA_PROJECT) + .setHttpTransportFactory(new MockHttpTransportFactory()); return builder; } @@ -164,7 +166,8 @@ private ServiceAccountCredentials.Builder createDefaultBuilder() throws IOExcept // return createServiceAccountFromPkcs8(scopes, new MockTokenServerTransportFactory()); // } // - // private ServiceAccountCredentials createServiceAccountFromPkcs8(Collection scopes, HttpTransportFactory transportFactory) + // private ServiceAccountCredentials createServiceAccountFromPkcs8(Collection scopes, + // HttpTransportFactory transportFactory) // throws IOException { // return ServiceAccountCredentials.fromPkcs8( // CLIENT_ID, @@ -213,11 +216,12 @@ public void createWithCustomLifetime() throws IOException { @Test public void createdScoped_clones() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - ServiceAccountCredentials credentials = createDefaultBuilderWithKey(privateKey) - .setServiceAccountUser(USER) - .setScopes(SCOPES) - .setProjectId(PROJECT_ID) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilderWithKey(privateKey) + .setServiceAccountUser(USER) + .setScopes(SCOPES) + .setProjectId(PROJECT_ID) + .build(); List newScopes = Arrays.asList("scope1", "scope2"); ServiceAccountCredentials newCredentials = @@ -239,10 +243,11 @@ public void createdScoped_clones() throws IOException { @Test public void createdDelegated_clones() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - ServiceAccountCredentials credentials = createDefaultBuilderWithKey(privateKey) - .setScopes(SCOPES) - .setServiceAccountUser(USER) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilderWithKey(privateKey) + .setScopes(SCOPES) + .setServiceAccountUser(USER) + .build(); String newServiceAccountUser = "stranger@other.org"; ServiceAccountCredentials newCredentials = @@ -284,8 +289,7 @@ public void createAssertion_correct() throws IOException { public void createAssertion_defaultScopes_correct() throws IOException { List defaultScopes = Arrays.asList("scope1", "scope2"); ServiceAccountCredentials.Builder builder = createDefaultBuilder(); - builder.setScopes(null, defaultScopes) - .setServiceAccountUser(USER); + builder.setScopes(null, defaultScopes).setServiceAccountUser(USER); assertEquals(2, builder.getDefaultScopes().size()); ServiceAccountCredentials credentials = builder.build(); @@ -320,7 +324,8 @@ public void createAssertion_custom_lifetime() throws IOException { @Test public void createAssertionForIdToken_correct() throws IOException { PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); - ServiceAccountCredentials credentials = createDefaultBuilder() + ServiceAccountCredentials credentials = + createDefaultBuilder() .setPrivateKeyId(PRIVATE_KEY_ID) .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) @@ -386,7 +391,8 @@ public void createAssertionForIdToken_incorrect() throws IOException { } @Test - public void createdScoped_withAud_noUniverse_jwtWithScopesDisabled_accessToken() throws IOException { + public void createdScoped_withAud_noUniverse_jwtWithScopesDisabled_accessToken() + throws IOException { // TODO: this should not default to AUD and throw exception that scopes // are provided, but cannot be used GoogleCredentials credentials = createDefaultBuilderWithToken(ACCESS_TOKEN).build(); @@ -430,12 +436,16 @@ public void createdScoped_withUniverse_selfSignedJwt() throws IOException { verifyJwtAccess(metadata, "dummy.scope2"); // recreate to avoid jwt caching - scopedCredentials = credentials.createScoped(Collections.emptyList(), Arrays.asList("dummy.default.scope")); + scopedCredentials = + credentials.createScoped( + Collections.emptyList(), Arrays.asList("dummy.default.scope")); metadata = scopedCredentials.getRequestMetadata(null); verifyJwtAccess(metadata, "dummy.default.scope"); // recreate to avoid jwt caching - scopedCredentials = credentials.createScoped(Collections.emptyList(), Arrays.asList("dummy.default.scope2")); + scopedCredentials = + credentials.createScoped( + Collections.emptyList(), Arrays.asList("dummy.default.scope2")); metadata = scopedCredentials.getRequestMetadata(CALL_URI); verifyJwtAccess(metadata, "dummy.default.scope2"); } @@ -526,8 +536,7 @@ public void createScopedRequired_nonEmptyDefaultScopes() throws IOException { @Test public void fromJSON_getProjectId() throws IOException { - GenericJson json = - writeServiceAccountJson(PROJECT_ID, null, null); + GenericJson json = writeServiceAccountJson(PROJECT_ID, null, null); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, new MockTokenServerTransportFactory()); @@ -537,8 +546,7 @@ public void fromJSON_getProjectId() throws IOException { @Test public void fromJSON_Universe_getUniverseDomain() throws IOException { - GenericJson json = - writeServiceAccountJson(PROJECT_ID, null,"foo.bar"); + GenericJson json = writeServiceAccountJson(PROJECT_ID, null, "foo.bar"); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, new MockTokenServerTransportFactory()); @@ -549,8 +557,7 @@ public void fromJSON_Universe_getUniverseDomain() throws IOException { public void fromJSON_getProjectIdNull() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - GenericJson json = - writeServiceAccountJson(null, null, null); + GenericJson json = writeServiceAccountJson(null, null, null); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -561,8 +568,7 @@ public void fromJSON_getProjectIdNull() throws IOException { public void fromJSON_hasAccessToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - GenericJson json = - writeServiceAccountJson(PROJECT_ID, null, null); + GenericJson json = writeServiceAccountJson(PROJECT_ID, null, null); GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -575,8 +581,7 @@ public void fromJSON_hasAccessToken() throws IOException { public void fromJSON_withUniverse_selfSignedJwt() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - GenericJson json = - writeServiceAccountJson(PROJECT_ID, null, "foo.bar"); + GenericJson json = writeServiceAccountJson(PROJECT_ID, null, "foo.bar"); GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -615,9 +620,8 @@ public void fromJson_hasQuotaProjectId() throws IOException { @Test public void getRequestMetadata_hasAccessToken() throws IOException { - GoogleCredentials credentials = createDefaultBuilderWithToken(ACCESS_TOKEN) - .setScopes(SCOPES) - .build(); + GoogleCredentials credentials = + createDefaultBuilderWithToken(ACCESS_TOKEN).setScopes(SCOPES).build(); Map> metadata = credentials.getRequestMetadata(CALL_URI); TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); } @@ -628,11 +632,12 @@ public void getRequestMetadata_customTokenServer_hasAccessToken() throws IOExcep MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); transportFactory.transport.setTokenServerUri(TOKEN_SERVER); - OAuth2Credentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .setTokenServerUri(TOKEN_SERVER) - .build(); + OAuth2Credentials credentials = + createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .setTokenServerUri(TOKEN_SERVER) + .build(); Map> metadata = credentials.getRequestMetadata(CALL_URI); TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); @@ -650,10 +655,8 @@ public void refreshAccessToken_refreshesToken() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -667,10 +670,8 @@ public void refreshAccessToken_tokenExpiry() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); credentials.clock = new FixedClock(0L); AccessToken accessToken = credentials.refreshAccessToken(); @@ -690,10 +691,9 @@ public void refreshAccessToken_IOException_Retry() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build();; + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); + ; transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -710,10 +710,8 @@ public void refreshAccessToken_retriesServerErrors() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -732,10 +730,8 @@ public void refreshAccessToken_retriesTimeoutAndThrottled() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -754,11 +750,12 @@ public void refreshAccessToken_defaultRetriesDisabled() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build() - .createWithCustomRetryStrategy(false); + ServiceAccountCredentials credentials = + createDefaultBuilder() + .setScopes(SCOPES) + .setHttpTransportFactory(transportFactory) + .build() + .createWithCustomRetryStrategy(false); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -782,10 +779,8 @@ public void refreshAccessToken_defaultRetriesDisabled() throws IOException { public void refreshAccessToken_maxRetries_maxDelay() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), ACCESS_TOKEN); @@ -817,10 +812,8 @@ public void refreshAccessToken_maxRetries_maxDelay() throws IOException { public void refreshAccessToken_RequestFailure_retried() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), ACCESS_TOKEN); @@ -855,10 +848,8 @@ public void refreshAccessToken_4xx_5xx_NonRetryableFails() throws IOException { final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -886,10 +877,8 @@ public void idTokenWithAudience_correct() throws IOException { String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -913,10 +902,8 @@ public void idTokenWithAudience_incorrect() throws IOException { String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); @@ -1287,10 +1274,8 @@ public void getIdTokenWithAudience_badEmailError_issClaimTraced() throws IOExcep MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); MockTokenServerTransport transport = transportFactory.transport; transport.setError(new IOException("Invalid grant: Account not found")); - ServiceAccountCredentials credentials = createDefaultBuilder() - .setScopes(SCOPES) - .setHttpTransportFactory(transportFactory) - .build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setScopes(SCOPES).setHttpTransportFactory(transportFactory).build(); String targetAudience = "https://bar"; IdTokenCredentials tokenCredential = @@ -1638,9 +1623,16 @@ private void verifyJwtAccess(Map> metadata, String expected assertEquals(PRIVATE_KEY_ID, signature.getHeader().getKeyId()); } - static GenericJson writeServiceAccountJson(String projectId, String quotaProjectId, String universeDomain) { + static GenericJson writeServiceAccountJson( + String projectId, String quotaProjectId, String universeDomain) { return writeServiceAccountJson( - CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, projectId, quotaProjectId, universeDomain); + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + projectId, + quotaProjectId, + universeDomain); } static GenericJson writeServiceAccountJson( From 35f79d09c5978ee44f5ec257675bede70b86fcbc Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Tue, 14 Nov 2023 03:15:17 -0800 Subject: [PATCH 09/31] feat: updates for ToString, hashCode and equals --- .../google/auth/oauth2/GoogleCredentials.java | 46 +++++++--- .../oauth2/ServiceAccountCredentials.java | 38 +++++---- .../oauth2/ServiceAccountCredentialsTest.java | 85 ++++++++++++++++--- 3 files changed, 129 insertions(+), 40 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 94fa4a879..7d91a33ac 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -38,6 +38,8 @@ import com.google.auth.Credentials; import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; +import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.io.InputStream; @@ -48,6 +50,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import javax.annotation.Nullable; /** Base type for credentials for authorizing calls to Google APIs using OAuth2. */ @@ -227,17 +230,6 @@ static GoogleCredentials fromJson(Map json) throws IOException { return credentialsBuilder.build(); } - /** - * Creates a credential with the provided universe domain. - * - * @param universeDomain the universe domain to set on the credential. Empty or null value will - * result in the default universe domain 'googleapis.com' - * @return credential with the provided universe domain - */ - public GoogleCredentials createWithUniverseDomain(String universeDomain) { - return this.toBuilder().setUniverseDomain(universeDomain).build(); - } - /** * Creates a credential with the provided quota project. * @@ -354,6 +346,38 @@ protected GoogleCredentials( this.universeDomain = null; } + /** + * A helper for overriding toString that allows inheritance of super class fields + * Extending classes can override this implementation and call super implementation and then + * add more fields. Same cannot be done with ToString() directly. + * @return an instance of the ToStringHelper that has all the relevant fields added + */ + protected ToStringHelper toStringHelper() { + return MoreObjects.toStringHelper(this).omitNullValues() + .add("quotaProjectId", quotaProjectId) + .add("universeDomain", getUniverseDomain()); + } + + @Override + public String toString() { + return toStringHelper().toString(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof GoogleCredentials)) { + return false; + } + GoogleCredentials other = (GoogleCredentials) obj; + return Objects.equals(this.getQuotaProjectId(), other.getQuotaProjectId()) + && Objects.equals(this.getUniverseDomain(), other.getUniverseDomain()); + } + + @Override + public int hashCode() { + return Objects.hash(getQuotaProjectId(), getUniverseDomain()); + } + public static Builder newBuilder() { return new Builder(); } diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index 0b2866fd8..907511d1c 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -55,6 +55,7 @@ import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; +import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.io.InputStream; @@ -754,28 +755,26 @@ public int hashCode() { tokenServerUri, scopes, defaultScopes, - quotaProjectId, lifetime, useJwtAccessWithScope, - defaultRetriesEnabled); + defaultRetriesEnabled, + super.hashCode()); } @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("clientId", clientId) - .add("clientEmail", clientEmail) - .add("privateKeyId", privateKeyId) - .add("transportFactoryClassName", transportFactoryClassName) - .add("tokenServerUri", tokenServerUri) - .add("scopes", scopes) - .add("defaultScopes", defaultScopes) - .add("serviceAccountUser", serviceAccountUser) - .add("quotaProjectId", quotaProjectId) - .add("lifetime", lifetime) - .add("useJwtAccessWithScope", useJwtAccessWithScope) - .add("defaultRetriesEnabled", defaultRetriesEnabled) - .toString(); + protected ToStringHelper toStringHelper() { + return super.toStringHelper() + .add("clientId", clientId) + .add("clientEmail", clientEmail) + .add("privateKeyId", privateKeyId) + .add("transportFactoryClassName", transportFactoryClassName) + .add("tokenServerUri", tokenServerUri) + .add("scopes", scopes) + .add("defaultScopes", defaultScopes) + .add("serviceAccountUser", serviceAccountUser) + .add("lifetime", lifetime) + .add("useJwtAccessWithScope", useJwtAccessWithScope) + .add("defaultRetriesEnabled", defaultRetriesEnabled); } @Override @@ -783,6 +782,10 @@ public boolean equals(Object obj) { if (!(obj instanceof ServiceAccountCredentials)) { return false; } + if (!super.equals(obj)) { + return false; + } + ServiceAccountCredentials other = (ServiceAccountCredentials) obj; return Objects.equals(this.clientId, other.clientId) && Objects.equals(this.clientEmail, other.clientEmail) @@ -792,7 +795,6 @@ public boolean equals(Object obj) { && Objects.equals(this.tokenServerUri, other.tokenServerUri) && Objects.equals(this.scopes, other.scopes) && Objects.equals(this.defaultScopes, other.defaultScopes) - && Objects.equals(this.quotaProjectId, other.quotaProjectId) && Objects.equals(this.lifetime, other.lifetime) && Objects.equals(this.useJwtAccessWithScope, other.useJwtAccessWithScope) && Objects.equals(this.defaultRetriesEnabled, other.defaultRetriesEnabled); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 5760714fa..2681df42e 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -51,6 +51,7 @@ import com.google.api.client.testing.http.MockLowLevelHttpResponse; import com.google.api.client.util.Clock; import com.google.api.client.util.Joiner; +import com.google.auth.Credentials; import com.google.auth.RequestMetadataCallback; import com.google.auth.TestUtils; import com.google.auth.http.AuthHttpConstants; @@ -414,8 +415,7 @@ public void createdScoped_withAud_noUniverse_jwtWithScopesDisabled_accessToken() @Test public void createdScoped_withUniverse_selfSignedJwt() throws IOException { - GoogleCredentials credentials = createDefaultBuilder().build(); - credentials = credentials.createWithUniverseDomain("foo.bar"); + GoogleCredentials credentials = createDefaultBuilder().setUniverseDomain("foo.bar").build(); try { credentials.getRequestMetadata(null); @@ -452,8 +452,7 @@ public void createdScoped_withUniverse_selfSignedJwt() throws IOException { @Test public void noScopes_withUniverse_selfSignedJwt() throws IOException { - GoogleCredentials credentials = createDefaultBuilder().build(); - credentials = credentials.createWithUniverseDomain("foo.bar"); + GoogleCredentials credentials = createDefaultBuilder().setUniverseDomain("foo.bar").build(); try { credentials.getRequestMetadata(null); @@ -1027,6 +1026,35 @@ public void equals_false_email() throws IOException { assertFalse(otherCredentials.equals(credentials)); } + @Test + public void equals_false_super() throws IOException { + final URI tokenServer1 = URI.create("https://foo1.com/bar"); + MockTokenServerTransportFactory serverTransportFactory = new MockTokenServerTransportFactory(); + OAuth2Credentials credentials = + ServiceAccountCredentials.fromPkcs8( + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + serverTransportFactory, + tokenServer1); + OAuth2Credentials otherCredentials = + ServiceAccountCredentials.fromPkcs8( + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + serverTransportFactory, + tokenServer1) + .toBuilder() + .setUniverseDomain("universe.com") + .build(); + assertFalse(credentials.equals(otherCredentials)); + assertFalse(otherCredentials.equals(credentials)); + } + @Test public void equals_false_keyId() throws IOException { final URI tokenServer1 = URI.create("https://foo1.com/bar"); @@ -1152,9 +1180,11 @@ public void toString_containsFields() throws IOException { OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8(PRIVATE_KEY_PKCS8, builder); String expectedToString = String.format( - "ServiceAccountCredentials{clientId=%s, clientEmail=%s, privateKeyId=%s, " - + "transportFactoryClassName=%s, tokenServerUri=%s, scopes=%s, defaultScopes=%s, serviceAccountUser=%s, " - + "quotaProjectId=%s, lifetime=3600, useJwtAccessWithScope=false, defaultRetriesEnabled=true}", + "ServiceAccountCredentials{quotaProjectId=%s, universeDomain=%s, clientId=%s, clientEmail=%s, " + + "privateKeyId=%s, transportFactoryClassName=%s, tokenServerUri=%s, scopes=%s, defaultScopes=%s, " + + "serviceAccountUser=%s, lifetime=3600, useJwtAccessWithScope=false, defaultRetriesEnabled=true}", + QUOTA_PROJECT, + Credentials.GOOGLE_DEFAULT_UNIVERSE, CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_ID, @@ -1162,8 +1192,7 @@ public void toString_containsFields() throws IOException { tokenServer, SCOPES, DEFAULT_SCOPES, - USER, - QUOTA_PROJECT); + USER); assertEquals(expectedToString, credentials.toString()); } @@ -1179,7 +1208,11 @@ public void hashCode_equals() throws IOException { PRIVATE_KEY_ID, SCOPES, transportFactory, - tokenServer); + tokenServer) + .createWithQuotaProject(QUOTA_PROJECT) + .toBuilder() + .setUniverseDomain("universe.com") + .build(); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( CLIENT_ID, @@ -1188,10 +1221,40 @@ public void hashCode_equals() throws IOException { PRIVATE_KEY_ID, SCOPES, transportFactory, - tokenServer); + tokenServer) + .createWithQuotaProject(QUOTA_PROJECT) + .toBuilder() + .setUniverseDomain("universe.com") + .build(); assertEquals(credentials.hashCode(), otherCredentials.hashCode()); } + @Test + public void hashCode_not_equals_quota() throws IOException { + final URI tokenServer = URI.create("https://foo.com/bar"); + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + OAuth2Credentials credentials = + ServiceAccountCredentials.fromPkcs8( + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + transportFactory, + tokenServer); + OAuth2Credentials otherCredentials = + ServiceAccountCredentials.fromPkcs8( + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + transportFactory, + tokenServer) + .createWithQuotaProject("some_quota"); + assertNotEquals(credentials.hashCode(), otherCredentials.hashCode()); + } + @Test public void serialize() throws IOException, ClassNotFoundException { final URI tokenServer = URI.create("https://foo.com/bar"); From 07491246b5204c6b059805f7ed53f4dbc8b67c86 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 14 Nov 2023 11:17:40 +0000 Subject: [PATCH 10/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../google/auth/oauth2/GoogleCredentials.java | 10 ++-- .../oauth2/ServiceAccountCredentials.java | 25 ++++----- .../oauth2/ServiceAccountCredentialsTest.java | 56 +++++++++---------- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 7d91a33ac..38bb45121 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -347,13 +347,15 @@ protected GoogleCredentials( } /** - * A helper for overriding toString that allows inheritance of super class fields - * Extending classes can override this implementation and call super implementation and then - * add more fields. Same cannot be done with ToString() directly. + * A helper for overriding toString that allows inheritance of super class fields Extending + * classes can override this implementation and call super implementation and then add more + * fields. Same cannot be done with ToString() directly. + * * @return an instance of the ToStringHelper that has all the relevant fields added */ protected ToStringHelper toStringHelper() { - return MoreObjects.toStringHelper(this).omitNullValues() + return MoreObjects.toStringHelper(this) + .omitNullValues() .add("quotaProjectId", quotaProjectId) .add("universeDomain", getUniverseDomain()); } diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index 907511d1c..5a82fd7e2 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -54,7 +54,6 @@ import com.google.auth.ServiceAccountSigner; import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.ImmutableSet; import java.io.IOException; @@ -763,18 +762,18 @@ public int hashCode() { @Override protected ToStringHelper toStringHelper() { - return super.toStringHelper() - .add("clientId", clientId) - .add("clientEmail", clientEmail) - .add("privateKeyId", privateKeyId) - .add("transportFactoryClassName", transportFactoryClassName) - .add("tokenServerUri", tokenServerUri) - .add("scopes", scopes) - .add("defaultScopes", defaultScopes) - .add("serviceAccountUser", serviceAccountUser) - .add("lifetime", lifetime) - .add("useJwtAccessWithScope", useJwtAccessWithScope) - .add("defaultRetriesEnabled", defaultRetriesEnabled); + return super.toStringHelper() + .add("clientId", clientId) + .add("clientEmail", clientEmail) + .add("privateKeyId", privateKeyId) + .add("transportFactoryClassName", transportFactoryClassName) + .add("tokenServerUri", tokenServerUri) + .add("scopes", scopes) + .add("defaultScopes", defaultScopes) + .add("serviceAccountUser", serviceAccountUser) + .add("lifetime", lifetime) + .add("useJwtAccessWithScope", useJwtAccessWithScope) + .add("defaultRetriesEnabled", defaultRetriesEnabled); } @Override diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 2681df42e..4ed07b015 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -1041,13 +1041,13 @@ public void equals_false_super() throws IOException { tokenServer1); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - serverTransportFactory, - tokenServer1) + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + serverTransportFactory, + tokenServer1) .toBuilder() .setUniverseDomain("universe.com") .build(); @@ -1202,26 +1202,26 @@ public void hashCode_equals() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - tokenServer) + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + transportFactory, + tokenServer) .createWithQuotaProject(QUOTA_PROJECT) .toBuilder() .setUniverseDomain("universe.com") .build(); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - tokenServer) + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + transportFactory, + tokenServer) .createWithQuotaProject(QUOTA_PROJECT) .toBuilder() .setUniverseDomain("universe.com") @@ -1244,13 +1244,13 @@ public void hashCode_not_equals_quota() throws IOException { tokenServer); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - CLIENT_ID, - CLIENT_EMAIL, - PRIVATE_KEY_PKCS8, - PRIVATE_KEY_ID, - SCOPES, - transportFactory, - tokenServer) + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, + SCOPES, + transportFactory, + tokenServer) .createWithQuotaProject("some_quota"); assertNotEquals(credentials.hashCode(), otherCredentials.hashCode()); } From 763f6b085fa0995c01c8d09fbb4364ae491b3cf6 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Tue, 14 Nov 2023 04:19:04 -0800 Subject: [PATCH 11/31] feat: refactor ExternalAccount to use base class universe domain, update tests --- .../oauth2/ExternalAccountCredentials.java | 12 ++--- .../ExternalAccountCredentialsTest.java | 46 ++++++++++--------- .../auth/oauth2/GoogleCredentialsTest.java | 8 ++-- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index 90ab27f57..1c64da30f 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -392,7 +392,7 @@ public static ExternalAccountCredentials fromStream( * @return the credentials defined by the JSON */ static ExternalAccountCredentials fromJson( - Map json, HttpTransportFactory transportFactory) { + Map json, HttpTransportFactory transportFactory) throws IOException { checkNotNull(json); checkNotNull(transportFactory); @@ -409,10 +409,11 @@ static ExternalAccountCredentials fromJson( String clientSecret = (String) json.get("client_secret"); String quotaProjectId = (String) json.get("quota_project_id"); String userProject = (String) json.get("workforce_pool_user_project"); - String universeDomain = (String) json.get("universe_domain"); Map impersonationOptionsMap = (Map) json.get("service_account_impersonation"); + GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); + if (impersonationOptionsMap == null) { impersonationOptionsMap = new HashMap(); } @@ -430,7 +431,7 @@ static ExternalAccountCredentials fromJson( .setClientId(clientId) .setClientSecret(clientSecret) .setServiceAccountImpersonationOptions(impersonationOptionsMap) - .setUniverseDomain(universeDomain) + .setUniverseDomain(baseCredential.getUniverseDomain()) .build(); } else if (isPluggableAuthCredential(credentialSourceMap)) { return PluggableAuthCredentials.newBuilder() @@ -446,7 +447,7 @@ static ExternalAccountCredentials fromJson( .setClientSecret(clientSecret) .setWorkforcePoolUserProject(userProject) .setServiceAccountImpersonationOptions(impersonationOptionsMap) - .setUniverseDomain(universeDomain) + .setUniverseDomain(baseCredential.getUniverseDomain()) .build(); } return IdentityPoolCredentials.newBuilder() @@ -462,7 +463,7 @@ static ExternalAccountCredentials fromJson( .setClientSecret(clientSecret) .setWorkforcePoolUserProject(userProject) .setServiceAccountImpersonationOptions(impersonationOptionsMap) - .setUniverseDomain(universeDomain) + .setUniverseDomain(baseCredential.getUniverseDomain()) .build(); } @@ -723,7 +724,6 @@ public abstract static class Builder extends GoogleCredentials.Builder { @Nullable protected Collection scopes; @Nullable protected String workforcePoolUserProject; @Nullable protected ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; - @Nullable protected String universeDomain; @Nullable protected ExternalAccountMetricsHandler metricsHandler; protected Builder() {} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java index 45daee8cd..8f8b919a1 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java @@ -173,7 +173,7 @@ public void fromStream_invalidWorkloadAudience_throws() throws IOException { } @Test - public void fromJson_identityPoolCredentialsWorkload() { + public void fromJson_identityPoolCredentialsWorkload() throws IOException { ExternalAccountCredentials credential = ExternalAccountCredentials.fromJson( buildJsonIdentityPoolCredential(), OAuth2Utils.HTTP_TRANSPORT_FACTORY); @@ -186,11 +186,11 @@ public void fromJson_identityPoolCredentialsWorkload() { assertEquals(STS_URL, credential.getTokenUrl()); assertEquals("tokenInfoUrl", credential.getTokenInfoUrl()); assertNotNull(credential.getCredentialSource()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test - public void fromJson_identityPoolCredentialsWorkforce() { + public void fromJson_identityPoolCredentialsWorkforce() throws IOException { ExternalAccountCredentials credential = ExternalAccountCredentials.fromJson( buildJsonIdentityPoolWorkforceCredential(), OAuth2Utils.HTTP_TRANSPORT_FACTORY); @@ -208,7 +208,8 @@ public void fromJson_identityPoolCredentialsWorkforce() { } @Test - public void fromJson_identityPoolCredentialsWithServiceAccountImpersonationOptions() { + public void fromJson_identityPoolCredentialsWithServiceAccountImpersonationOptions() + throws IOException { GenericJson identityPoolCredentialJson = buildJsonIdentityPoolCredential(); identityPoolCredentialJson.set( "service_account_impersonation", buildServiceAccountImpersonationOptions(2800)); @@ -230,7 +231,7 @@ public void fromJson_identityPoolCredentialsWithServiceAccountImpersonationOptio } @Test - public void fromJson_identityPoolCredentialsWithUniverseDomain() { + public void fromJson_identityPoolCredentialsWithUniverseDomain() throws IOException { GenericJson identityPoolCredentialJson = buildJsonIdentityPoolCredential(); identityPoolCredentialJson.set("universe_domain", "universeDomain"); @@ -261,7 +262,7 @@ public void fromJson_awsCredentials() throws IOException { assertEquals(STS_URL, credential.getTokenUrl()); assertEquals("tokenInfoUrl", credential.getTokenInfoUrl()); assertNotNull(credential.getCredentialSource()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test @@ -280,11 +281,11 @@ public void fromJson_awsCredentialsWithServiceAccountImpersonationOptions() thro assertEquals("tokenInfoUrl", credential.getTokenInfoUrl()); assertNotNull(credential.getCredentialSource()); assertEquals(2800, credential.getServiceAccountImpersonationOptions().getLifetime()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test - public void fromJson_awsCredentialsWithUniverseDomain() { + public void fromJson_awsCredentialsWithUniverseDomain() throws IOException { GenericJson awsCredentialJson = buildJsonAwsCredential(); awsCredentialJson.set("universe_domain", "universeDomain"); @@ -301,7 +302,7 @@ public void fromJson_awsCredentialsWithUniverseDomain() { } @Test - public void fromJson_pluggableAuthCredentials() { + public void fromJson_pluggableAuthCredentials() throws IOException { ExternalAccountCredentials credential = ExternalAccountCredentials.fromJson( buildJsonPluggableAuthCredential(), OAuth2Utils.HTTP_TRANSPORT_FACTORY); @@ -318,11 +319,11 @@ public void fromJson_pluggableAuthCredentials() { assertEquals("command", source.getCommand()); assertEquals(30000, source.getTimeoutMs()); // Default timeout is 30s. assertNull(source.getOutputFilePath()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test - public void fromJson_pluggableAuthCredentialsWorkforce() { + public void fromJson_pluggableAuthCredentialsWorkforce() throws IOException { ExternalAccountCredentials credential = ExternalAccountCredentials.fromJson( buildJsonPluggableAuthWorkforceCredential(), OAuth2Utils.HTTP_TRANSPORT_FACTORY); @@ -343,11 +344,11 @@ public void fromJson_pluggableAuthCredentialsWorkforce() { assertEquals("command", source.getCommand()); assertEquals(30000, source.getTimeoutMs()); // Default timeout is 30s. assertNull(source.getOutputFilePath()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test - public void fromJson_pluggableAuthCredentials_allExecutableOptionsSet() { + public void fromJson_pluggableAuthCredentials_allExecutableOptionsSet() throws IOException { GenericJson json = buildJsonPluggableAuthCredential(); Map credentialSourceMap = (Map) json.get("credential_source"); // Add optional params to the executable config (timeout, output file path). @@ -371,11 +372,12 @@ public void fromJson_pluggableAuthCredentials_allExecutableOptionsSet() { assertEquals("command", source.getCommand()); assertEquals("path/to/output/file", source.getOutputFilePath()); assertEquals(5000, source.getTimeoutMs()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test - public void fromJson_pluggableAuthCredentialsWithServiceAccountImpersonationOptions() { + public void fromJson_pluggableAuthCredentialsWithServiceAccountImpersonationOptions() + throws IOException { GenericJson pluggableAuthCredentialJson = buildJsonPluggableAuthCredential(); pluggableAuthCredentialJson.set( "service_account_impersonation", buildServiceAccountImpersonationOptions(2800)); @@ -397,11 +399,11 @@ public void fromJson_pluggableAuthCredentialsWithServiceAccountImpersonationOpti assertEquals("command", source.getCommand()); assertEquals(30000, source.getTimeoutMs()); // Default timeout is 30s. assertNull(source.getOutputFilePath()); - assertNull(credential.getUniverseDomain()); + assertEquals(GOOGLE_DEFAULT_UNIVERSE, credential.getUniverseDomain()); } @Test - public void fromJson_pluggableAuthCredentials_withUniverseDomain() { + public void fromJson_pluggableAuthCredentials_withUniverseDomain() throws IOException { GenericJson json = buildJsonPluggableAuthCredential(); json.set("universe_domain", "universeDomain"); @@ -431,7 +433,7 @@ public void fromJson_pluggableAuthCredentials_withUniverseDomain() { } @Test - public void fromJson_pluggableAuthCredentialsWithUniverseDomain() { + public void fromJson_pluggableAuthCredentialsWithUniverseDomain() throws IOException { GenericJson pluggableAuthCredentialJson = buildJsonPluggableAuthCredential(); pluggableAuthCredentialJson.set("universe_domain", "universeDomain"); @@ -455,7 +457,7 @@ public void fromJson_pluggableAuthCredentialsWithUniverseDomain() { } @Test - public void fromJson_nullJson_throws() { + public void fromJson_nullJson_throws() throws IOException { try { ExternalAccountCredentials.fromJson(/* json= */ null, OAuth2Utils.HTTP_TRANSPORT_FACTORY); fail("Exception should be thrown."); @@ -465,7 +467,7 @@ public void fromJson_nullJson_throws() { } @Test - public void fromJson_invalidServiceAccountImpersonationUrl_throws() { + public void fromJson_invalidServiceAccountImpersonationUrl_throws() throws IOException { GenericJson json = buildJsonIdentityPoolCredential(); json.put("service_account_impersonation_url", "https://iamcredentials.googleapis.com"); @@ -480,7 +482,7 @@ public void fromJson_invalidServiceAccountImpersonationUrl_throws() { } @Test - public void fromJson_nullTransport_throws() { + public void fromJson_nullTransport_throws() throws IOException { try { ExternalAccountCredentials.fromJson( new HashMap(), /* transportFactory= */ null); @@ -491,7 +493,7 @@ public void fromJson_nullTransport_throws() { } @Test - public void fromJson_invalidWorkforceAudiences_throws() { + public void fromJson_invalidWorkforceAudiences_throws() throws IOException { List invalidAudiences = Arrays.asList( "//iam.googleapis.com/locations/global/workloadIdentityPools/pool/providers/provider", diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index c739b0c77..0b740034c 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -589,18 +589,18 @@ public void createWithQuotaProject() { } @Test - public void createWithUniverseDomain() { + public void buildWithUniverseDomain() { final GoogleCredentials original = new GoogleCredentials.Builder().setUniverseDomain("universe1").build(); - GoogleCredentials updated = original.createWithUniverseDomain("universe2"); + GoogleCredentials updated = original.toBuilder().setUniverseDomain("universe2").build(); assertEquals("universe1", original.getUniverseDomain()); assertEquals("universe2", updated.getUniverseDomain()); - GoogleCredentials withEmpty = original.createWithUniverseDomain(""); + GoogleCredentials withEmpty = original.toBuilder().setUniverseDomain("").build(); assertEquals(GOOGLE_DEFAULT_UNIVERSE, withEmpty.getUniverseDomain()); - GoogleCredentials withNull = original.createWithUniverseDomain(null); + GoogleCredentials withNull = original.toBuilder().setUniverseDomain(null).build(); assertEquals(GOOGLE_DEFAULT_UNIVERSE, withNull.getUniverseDomain()); } From 309312daea64c6928e59826bc37dcfae361d5fab Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Sun, 19 Nov 2023 23:03:00 -0800 Subject: [PATCH 12/31] fix: test fixes --- ...lAccountAuthorizedUserCredentialsTest.java | 6 ++-- .../auth/oauth2/GoogleCredentialsTest.java | 8 ++---- .../auth/oauth2/UserCredentialsTest.java | 28 ------------------- 3 files changed, 5 insertions(+), 37 deletions(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java index 2fb89dfdc..bc74a0cef 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java @@ -985,9 +985,9 @@ public void equals_differentAccessToken() { ExternalAccountAuthorizedUserCredentials secondCredentials = credentials.toBuilder().setAccessToken(new AccessToken("different", new Date())).build(); - assertNotEquals(secondCredentials, credentials); - assertNotEquals(credentials, secondCredentials); - assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); + // credentials objects are still interchangeable even if access_tokens instances are different + assertEquals(secondCredentials, credentials); + assertEquals(credentials.hashCode(), secondCredentials.hashCode()); } @Test diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index 0b740034c..71382a3b7 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -148,7 +148,7 @@ public void fromStream_serviceAccount_noUniverse_providesToken() throws IOExcept } @Test - public void fromStream_serviceAccount_Universe_providesToken() throws IOException { + public void fromStream_serviceAccount_Universe_noToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); InputStream serviceAccountStream = @@ -162,11 +162,7 @@ public void fromStream_serviceAccount_Universe_providesToken() throws IOExceptio assertEquals(TPC_UNIVERSE, credentials.getUniverseDomain()); credentials = credentials.createScoped(SCOPES); Map> metadata = credentials.getRequestMetadata(CALL_URI); - TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); - - credentials = credentials.createScoped(SCOPES, DEFAULT_SCOPES); - metadata = credentials.getRequestMetadata(CALL_URI); - TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); + assertNotNull(((ServiceAccountCredentials) credentials).getSelfSignedJwtCredentialsWithScope()); } @Test diff --git a/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java index a5c666936..6f793204c 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java @@ -342,34 +342,6 @@ public void equals_false_refreshToken() throws IOException { assertFalse(otherCredentials.equals(credentials)); } - @Test - public void equals_false_accessToken() throws IOException { - final URI tokenServer1 = URI.create("https://foo1.com/bar"); - AccessToken accessToken = new AccessToken(ACCESS_TOKEN, null); - AccessToken otherAccessToken = new AccessToken("otherAccessToken", null); - MockHttpTransportFactory httpTransportFactory = new MockHttpTransportFactory(); - UserCredentials credentials = - UserCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientSecret(CLIENT_SECRET) - .setRefreshToken(REFRESH_TOKEN) - .setAccessToken(accessToken) - .setHttpTransportFactory(httpTransportFactory) - .setTokenServerUri(tokenServer1) - .build(); - UserCredentials otherCredentials = - UserCredentials.newBuilder() - .setClientId(CLIENT_ID) - .setClientSecret(CLIENT_SECRET) - .setRefreshToken(REFRESH_TOKEN) - .setAccessToken(otherAccessToken) - .setHttpTransportFactory(httpTransportFactory) - .setTokenServerUri(tokenServer1) - .build(); - assertFalse(credentials.equals(otherCredentials)); - assertFalse(otherCredentials.equals(credentials)); - } - @Test public void equals_false_transportFactory() throws IOException { final URI tokenServer1 = URI.create("https://foo1.com/bar"); From c63ed36e1bfd032fb21a061d68d736938eb3446d Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Mon, 20 Nov 2023 02:22:54 -0800 Subject: [PATCH 13/31] fix: javadoc updates and other nits --- .../java/com/google/auth/Credentials.java | 4 +- .../google/auth/oauth2/GoogleCredentials.java | 25 ++++++----- ...lAccountAuthorizedUserCredentialsTest.java | 2 +- .../oauth2/ServiceAccountCredentialsTest.java | 45 +++++-------------- 4 files changed, 28 insertions(+), 48 deletions(-) diff --git a/credentials/java/com/google/auth/Credentials.java b/credentials/java/com/google/auth/Credentials.java index 3063dc2b0..1287da79c 100644 --- a/credentials/java/com/google/auth/Credentials.java +++ b/credentials/java/com/google/auth/Credentials.java @@ -57,9 +57,9 @@ public abstract class Credentials implements Serializable { public abstract String getAuthenticationType(); /** - * Returns the universe domain for the credential + * Returns the universe domain for the credential. * - * @return Return a default Google universe domain googleapis.com + * @return a default Google universe domain googleapis.com */ public String getUniverseDomain() { return GOOGLE_DEFAULT_UNIVERSE; diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 38bb45121..580aef40b 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -209,9 +209,9 @@ public static GoogleCredentials fromStream( } /** - * Returns an instance of GoogleCredentials defined by JSON + * Returns an instance of GoogleCredentials defined by JSON. * - *

To be used to parse common credentials fields + *

To be used to parse common credentials fields. * * @param json a map from the JSON representing the credentials. * @return the credentials defined by the JSON. @@ -232,6 +232,7 @@ static GoogleCredentials fromJson(Map json) throws IOException { /** * Creates a credential with the provided quota project. + * Expected format is: some-domain.xyz * * @param quotaProject the quota project to set on the credential * @return credential with the provided quota project @@ -241,7 +242,7 @@ public GoogleCredentials createWithQuotaProject(String quotaProject) { } /** - * Returns the universe domain for the credential + * Gets the universe domain for the credential. * * @return An explicit universe domain if it was explicitly provided, invokes the super * implementation otherwise. @@ -297,9 +298,9 @@ protected GoogleCredentials() { } /** - * Constructor with explicit access token and quotaProjectId + * Constructor with an explicit access token and quotaProjectId. * - *

Deprecated, please use the builder constructor whenever possible + *

Deprecated, please use the builder constructor whenever possible. * * @param accessToken initial or temporary access token * @param quotaProjectId a quotaProjectId, a project id to be used for billing purposes @@ -321,7 +322,7 @@ public GoogleCredentials(AccessToken accessToken) { } /** - * Constructor with using builder All the fields comes explicitly from builder + * Constructor with using builder All the fields comes explicitly from builder. * * @param builder an instance of a builder */ @@ -332,9 +333,9 @@ protected GoogleCredentials(Builder builder) { } /** - * Constructor with explicit access token and refresh times + * Constructor with explicit access token and refresh times. * - *

Deprecated, please use the builder constructor whenever possible + *

Deprecated, please use the builder constructor whenever possible. * * @param accessToken initial or temporary access token */ @@ -347,11 +348,11 @@ protected GoogleCredentials( } /** - * A helper for overriding toString that allows inheritance of super class fields Extending - * classes can override this implementation and call super implementation and then add more - * fields. Same cannot be done with ToString() directly. + * A helper for overriding the toString() method. This allows inheritance of super class fields. + * Extending classes can override this implementation and call super implementation and add more + * fields. Same cannot be done with overriding the toString() directly. * - * @return an instance of the ToStringHelper that has all the relevant fields added + * @return an instance of the ToStringHelper that has public fields added */ protected ToStringHelper toStringHelper() { return MoreObjects.toStringHelper(this) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java index bc74a0cef..a5a2733a6 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java @@ -985,7 +985,7 @@ public void equals_differentAccessToken() { ExternalAccountAuthorizedUserCredentials secondCredentials = credentials.toBuilder().setAccessToken(new AccessToken("different", new Date())).build(); - // credentials objects are still interchangeable even if access_tokens instances are different + // Even if access token are different, credentials objects are still interchangeable. assertEquals(secondCredentials, credentials); assertEquals(credentials.hashCode(), secondCredentials.hashCode()); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 4ed07b015..5d0f31548 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -58,8 +58,10 @@ import com.google.auth.http.HttpTransportFactory; import com.google.common.collect.ImmutableSet; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.ObjectOutputStream; import java.net.URI; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -154,32 +156,6 @@ private ServiceAccountCredentials.Builder createDefaultBuilder() throws IOExcept return createDefaultBuilderWithKey(privateKey); } - // - // private ServiceAccountCredentials createServiceAccountWithToken(Collection scopes) - // throws IOException { - // MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - // transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); - // return createServiceAccountFromPkcs8(scopes, transportFactory); - // } - // - // private ServiceAccountCredentials createServiceAccountFromPkcs8(Collection scopes) - // throws IOException { - // return createServiceAccountFromPkcs8(scopes, new MockTokenServerTransportFactory()); - // } - // - // private ServiceAccountCredentials createServiceAccountFromPkcs8(Collection scopes, - // HttpTransportFactory transportFactory) - // throws IOException { - // return ServiceAccountCredentials.fromPkcs8( - // CLIENT_ID, - // CLIENT_EMAIL, - // PRIVATE_KEY_PKCS8, - // PRIVATE_KEY_ID, - // scopes, - // transportFactory, - // null); - // } - @Test public void setLifetime() throws IOException { ServiceAccountCredentials.Builder builder = createDefaultBuilder(); @@ -221,7 +197,6 @@ public void createdScoped_clones() throws IOException { createDefaultBuilderWithKey(privateKey) .setServiceAccountUser(USER) .setScopes(SCOPES) - .setProjectId(PROJECT_ID) .build(); List newScopes = Arrays.asList("scope1", "scope2"); @@ -394,11 +369,9 @@ public void createAssertionForIdToken_incorrect() throws IOException { @Test public void createdScoped_withAud_noUniverse_jwtWithScopesDisabled_accessToken() throws IOException { - // TODO: this should not default to AUD and throw exception that scopes - // are provided, but cannot be used GoogleCredentials credentials = createDefaultBuilderWithToken(ACCESS_TOKEN).build(); - // no aud, no scopes -> exception + // No aud, no scopes gives an exception. try { credentials.getRequestMetadata(null); fail("Should not be able to get token without scopes"); @@ -430,19 +403,19 @@ public void createdScoped_withUniverse_selfSignedJwt() throws IOException { Map> metadata = scopedCredentials.getRequestMetadata(null); verifyJwtAccess(metadata, "dummy.scope"); - // recreate to avoid jwt caching + // Recreate to avoid jwt caching. scopedCredentials = credentials.createScoped("dummy.scope2"); metadata = scopedCredentials.getRequestMetadata(CALL_URI); verifyJwtAccess(metadata, "dummy.scope2"); - // recreate to avoid jwt caching + // Recreate to avoid jwt caching. scopedCredentials = credentials.createScoped( Collections.emptyList(), Arrays.asList("dummy.default.scope")); metadata = scopedCredentials.getRequestMetadata(null); verifyJwtAccess(metadata, "dummy.default.scope"); - // recreate to avoid jwt caching + // Recreate to avoid jwt caching. scopedCredentials = credentials.createScoped( Collections.emptyList(), Arrays.asList("dummy.default.scope2")); @@ -1268,6 +1241,12 @@ public void serialize() throws IOException, ClassNotFoundException { SCOPES, transportFactory, tokenServer); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (ObjectOutputStream output = new ObjectOutputStream(bytes)) { + output.writeObject(credentials); + String s = output.toString(); + } ServiceAccountCredentials deserializedCredentials = serializeAndDeserialize(credentials); assertEquals(credentials, deserializedCredentials); assertEquals(credentials.hashCode(), deserializedCredentials.hashCode()); From 3b46e384b54713d65113dc56da26dcf4bc3a1a45 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Mon, 20 Nov 2023 10:25:05 +0000 Subject: [PATCH 14/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 580aef40b..6ca592ff1 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -231,8 +231,7 @@ static GoogleCredentials fromJson(Map json) throws IOException { } /** - * Creates a credential with the provided quota project. - * Expected format is: some-domain.xyz + * Creates a credential with the provided quota project. Expected format is: some-domain.xyz * * @param quotaProject the quota project to set on the credential * @return credential with the provided quota project From 482603f3aee9bb7400e68e8af10af858cec10d2d Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Fri, 24 Nov 2023 19:01:20 -0800 Subject: [PATCH 15/31] fix: universe comparison fix, restoring the original univerDeomain field for ExternalAccount builder --- .../com/google/auth/oauth2/ExternalAccountCredentials.java | 2 ++ .../java/com/google/auth/oauth2/GoogleCredentials.java | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index ff0ae8cdf..b241d8fce 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -726,6 +726,7 @@ public abstract static class Builder extends GoogleCredentials.Builder { @Nullable protected Collection scopes; @Nullable protected String workforcePoolUserProject; @Nullable protected ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; + @Nullable protected String universeDomain; @Nullable protected ExternalAccountMetricsHandler metricsHandler; protected Builder() {} @@ -745,6 +746,7 @@ protected Builder(ExternalAccountCredentials credentials) { this.environmentProvider = credentials.environmentProvider; this.workforcePoolUserProject = credentials.workforcePoolUserProject; this.serviceAccountImpersonationOptions = credentials.serviceAccountImpersonationOptions; + this.universeDomain = credentials.getUniverseDomain(); this.metricsHandler = credentials.metricsHandler; } diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 4efee05f5..f67877207 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -245,7 +245,7 @@ public GoogleCredentials createWithQuotaProject(String quotaProject) { * Gets the universe domain for the credential. * * @return An explicit universe domain if it was explicitly provided, invokes the super - * implementation otherwise. + * implementation otherwise */ @Override public String getUniverseDomain() { @@ -263,7 +263,7 @@ public String getUniverseDomain() { * otherwise */ boolean isDefaultUniverseDomain() { - return getUniverseDomain() == Credentials.GOOGLE_DEFAULT_UNIVERSE; + return getUniverseDomain().equals(Credentials.GOOGLE_DEFAULT_UNIVERSE); } /** From 0c21a72b62a3943f44da36f7343bf5ee8efc713d Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Wed, 29 Nov 2023 02:42:53 -0800 Subject: [PATCH 16/31] fix: deprecating a duplicate universeDomain field --- .../com/google/auth/oauth2/ExternalAccountCredentials.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index b241d8fce..86f6d03e2 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -726,7 +726,9 @@ public abstract static class Builder extends GoogleCredentials.Builder { @Nullable protected Collection scopes; @Nullable protected String workforcePoolUserProject; @Nullable protected ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; - @Nullable protected String universeDomain; + @Nullable + @Deprecated + protected String universeDomain; @Nullable protected ExternalAccountMetricsHandler metricsHandler; protected Builder() {} @@ -920,8 +922,10 @@ public Builder setServiceAccountImpersonationOptions(Map options * @return this {@code Builder} object */ @CanIgnoreReturnValue + @Override public Builder setUniverseDomain(String universeDomain) { this.universeDomain = universeDomain; + super.setUniverseDomain(universeDomain); return this; } From 4b21ca23be934b16e2d4c6041f76b2dbf9e001ff Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Wed, 29 Nov 2023 03:59:16 -0800 Subject: [PATCH 17/31] fix: restore the original behavior of equals and hashcode for UserCredentials and EAAU --- ...ernalAccountAuthorizedUserCredentials.java | 2 ++ .../google/auth/oauth2/UserCredentials.java | 6 ++++ ...lAccountAuthorizedUserCredentialsTest.java | 6 ++-- .../auth/oauth2/UserCredentialsTest.java | 30 +++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentials.java index 0f87464bd..e713f7452 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentials.java @@ -245,6 +245,7 @@ public static Builder newBuilder() { public int hashCode() { return Objects.hash( super.hashCode(), + getAccessToken(), clientId, clientSecret, refreshToken, @@ -281,6 +282,7 @@ public boolean equals(Object obj) { ExternalAccountAuthorizedUserCredentials credentials = (ExternalAccountAuthorizedUserCredentials) obj; return super.equals(credentials) + && Objects.equals(this.getAccessToken(), credentials.getAccessToken()) && Objects.equals(this.clientId, credentials.clientId) && Objects.equals(this.clientSecret, credentials.clientSecret) && Objects.equals(this.refreshToken, credentials.refreshToken) diff --git a/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java b/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java index abc040f25..d4358d93b 100644 --- a/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java @@ -319,8 +319,12 @@ public void save(String filePath) throws IOException { @Override public int hashCode() { + // We include access token explicitly here for backwards compatibility. + // For the rest of the credentials we don't include it because Credentials are + // equivalent with different valid active tokens if main and parent fields are equal. return Objects.hash( super.hashCode(), + getAccessToken(), clientId, clientSecret, refreshToken, @@ -347,8 +351,10 @@ public boolean equals(Object obj) { if (!(obj instanceof UserCredentials)) { return false; } + UserCredentials other = (UserCredentials) obj; return super.equals(other) + && Objects.equals(this.getAccessToken(), other.getAccessToken()) && Objects.equals(this.clientId, other.clientId) && Objects.equals(this.clientSecret, other.clientSecret) && Objects.equals(this.refreshToken, other.refreshToken) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java index a5a2733a6..2fb89dfdc 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java @@ -985,9 +985,9 @@ public void equals_differentAccessToken() { ExternalAccountAuthorizedUserCredentials secondCredentials = credentials.toBuilder().setAccessToken(new AccessToken("different", new Date())).build(); - // Even if access token are different, credentials objects are still interchangeable. - assertEquals(secondCredentials, credentials); - assertEquals(credentials.hashCode(), secondCredentials.hashCode()); + assertNotEquals(secondCredentials, credentials); + assertNotEquals(credentials, secondCredentials); + assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); } @Test diff --git a/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java index 6f793204c..7fc0a256f 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java @@ -33,6 +33,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; @@ -342,6 +343,35 @@ public void equals_false_refreshToken() throws IOException { assertFalse(otherCredentials.equals(credentials)); } + @Test + public void equals_false_accessToken() throws IOException { + final URI tokenServer1 = URI.create("https://foo1.com/bar"); + AccessToken accessToken = new AccessToken(ACCESS_TOKEN, null); + AccessToken otherAccessToken = new AccessToken("otherAccessToken", null); + MockHttpTransportFactory httpTransportFactory = new MockHttpTransportFactory(); + UserCredentials credentials = + UserCredentials.newBuilder() + .setClientId(CLIENT_ID) + .setClientSecret(CLIENT_SECRET) + .setRefreshToken(REFRESH_TOKEN) + .setAccessToken(accessToken) + .setHttpTransportFactory(httpTransportFactory) + .setTokenServerUri(tokenServer1) + .build(); + UserCredentials otherCredentials = + UserCredentials.newBuilder() + .setClientId(CLIENT_ID) + .setClientSecret(CLIENT_SECRET) + .setRefreshToken(REFRESH_TOKEN) + .setAccessToken(otherAccessToken) + .setHttpTransportFactory(httpTransportFactory) + .setTokenServerUri(tokenServer1) + .build(); + assertFalse(credentials.equals(otherCredentials)); + assertFalse(otherCredentials.equals(credentials)); + assertNotEquals(credentials.hashCode(), otherAccessToken.hashCode()); + } + @Test public void equals_false_transportFactory() throws IOException { final URI tokenServer1 = URI.create("https://foo1.com/bar"); From bab1ccc5e6d502a6528e83c965ca582f86a038e8 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Wed, 29 Nov 2023 12:01:28 +0000 Subject: [PATCH 18/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../com/google/auth/oauth2/ExternalAccountCredentials.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index 86f6d03e2..d5e8bd0d7 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -726,9 +726,7 @@ public abstract static class Builder extends GoogleCredentials.Builder { @Nullable protected Collection scopes; @Nullable protected String workforcePoolUserProject; @Nullable protected ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; - @Nullable - @Deprecated - protected String universeDomain; + @Nullable @Deprecated protected String universeDomain; @Nullable protected ExternalAccountMetricsHandler metricsHandler; protected Builder() {} From de8c4008a21031ddfad228e3719008087d5f10a3 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Thu, 7 Dec 2023 06:26:05 -0800 Subject: [PATCH 19/31] fix: comments addressed --- .../oauth2/ExternalAccountCredentials.java | 5 +++-- .../oauth2/ServiceAccountCredentials.java | 19 ++++++++++++------- .../oauth2/ServiceAccountCredentialsTest.java | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index d5e8bd0d7..cb04b557d 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -415,6 +415,7 @@ static ExternalAccountCredentials fromJson( (Map) json.get("service_account_impersonation"); GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); + String universeDomain = baseCredential.getUniverseDomain(); if (impersonationOptionsMap == null) { impersonationOptionsMap = new HashMap(); @@ -449,7 +450,7 @@ static ExternalAccountCredentials fromJson( .setClientSecret(clientSecret) .setWorkforcePoolUserProject(userProject) .setServiceAccountImpersonationOptions(impersonationOptionsMap) - .setUniverseDomain(baseCredential.getUniverseDomain()) + .setUniverseDomain(universeDomain) .build(); } return IdentityPoolCredentials.newBuilder() @@ -465,7 +466,7 @@ static ExternalAccountCredentials fromJson( .setClientSecret(clientSecret) .setWorkforcePoolUserProject(userProject) .setServiceAccountImpersonationOptions(impersonationOptionsMap) - .setUniverseDomain(baseCredential.getUniverseDomain()) + .setUniverseDomain(universeDomain) .build(); } diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index 23c279de3..f16eb1689 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -184,8 +184,6 @@ static ServiceAccountCredentials fromJson( + "expecting 'client_id', 'client_email', 'private_key' and 'private_key_id'."); } - GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); - ServiceAccountCredentials.Builder builder = ServiceAccountCredentials.newBuilder() .setClientId(clientId) @@ -194,8 +192,10 @@ static ServiceAccountCredentials fromJson( .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServerUriFromCreds) .setProjectId(projectId) - .setQuotaProjectId(quotaProjectId) - .setUniverseDomain(baseCredential.getUniverseDomain()); + .setQuotaProjectId(quotaProjectId); + + GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); + builder.setUniverseDomain(baseCredential.getUniverseDomain()); return fromPkcs8(privateKeyPkcs8, builder); } @@ -641,9 +641,10 @@ public ServiceAccountCredentials createWithCustomLifetime(int lifetime) { } /** - * Clones the service account with a new useJwtAccessWithScope value. + * Clones the service account with a new useJwtAccessWithScope value. This flag will be ignored + * if universeDomain field is different from {@link Credentials.GOOGLE_DEFAULT_UNIVERSE}. * - * @param useJwtAccessWithScope whether self signed JWT with scopes should be used + * @param useJwtAccessWithScope whether self-signed JWT with scopes should be used * @return the cloned service account credentials with the given useJwtAccessWithScope */ public ServiceAccountCredentials createWithUseJwtAccessWithScope(boolean useJwtAccessWithScope) { @@ -1115,6 +1116,10 @@ public Builder setLifetime(int lifetime) { return this; } + /** + * Sets the useJwtAccessWithScope flag. This flag will be ignored if universeDomain field + * is different from {@link Credentials.GOOGLE_DEFAULT_UNIVERSE}. + */ @CanIgnoreReturnValue public Builder setUseJwtAccessWithScope(boolean useJwtAccessWithScope) { this.useJwtAccessWithScope = useJwtAccessWithScope; @@ -1128,7 +1133,7 @@ public Builder setDefaultRetriesEnabled(boolean defaultRetriesEnabled) { } public Builder setUniverseDomain(String universeDomain) { - this.universeDomain = universeDomain; + super.universeDomain = universeDomain; return this; } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 5d0f31548..f8e9151bc 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -388,7 +388,7 @@ public void createdScoped_withAud_noUniverse_jwtWithScopesDisabled_accessToken() @Test public void createdScoped_withUniverse_selfSignedJwt() throws IOException { - GoogleCredentials credentials = createDefaultBuilder().setUniverseDomain("foo.bar").build(); + ServiceAccountCredentials credentials = createDefaultBuilder().setUniverseDomain("foo.bar").build(); try { credentials.getRequestMetadata(null); From 9659e40f30ff56ff98670fd38e52b32bbb815fa7 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Thu, 7 Dec 2023 14:28:24 +0000 Subject: [PATCH 20/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../com/google/auth/oauth2/ServiceAccountCredentials.java | 8 ++++---- .../google/auth/oauth2/ServiceAccountCredentialsTest.java | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index f16eb1689..2a7c6cc44 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -641,8 +641,8 @@ public ServiceAccountCredentials createWithCustomLifetime(int lifetime) { } /** - * Clones the service account with a new useJwtAccessWithScope value. This flag will be ignored - * if universeDomain field is different from {@link Credentials.GOOGLE_DEFAULT_UNIVERSE}. + * Clones the service account with a new useJwtAccessWithScope value. This flag will be ignored if + * universeDomain field is different from {@link Credentials.GOOGLE_DEFAULT_UNIVERSE}. * * @param useJwtAccessWithScope whether self-signed JWT with scopes should be used * @return the cloned service account credentials with the given useJwtAccessWithScope @@ -1117,8 +1117,8 @@ public Builder setLifetime(int lifetime) { } /** - * Sets the useJwtAccessWithScope flag. This flag will be ignored if universeDomain field - * is different from {@link Credentials.GOOGLE_DEFAULT_UNIVERSE}. + * Sets the useJwtAccessWithScope flag. This flag will be ignored if universeDomain field is + * different from {@link Credentials.GOOGLE_DEFAULT_UNIVERSE}. */ @CanIgnoreReturnValue public Builder setUseJwtAccessWithScope(boolean useJwtAccessWithScope) { diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index f8e9151bc..174db6e76 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -388,7 +388,8 @@ public void createdScoped_withAud_noUniverse_jwtWithScopesDisabled_accessToken() @Test public void createdScoped_withUniverse_selfSignedJwt() throws IOException { - ServiceAccountCredentials credentials = createDefaultBuilder().setUniverseDomain("foo.bar").build(); + ServiceAccountCredentials credentials = + createDefaultBuilder().setUniverseDomain("foo.bar").build(); try { credentials.getRequestMetadata(null); From 1bc4d3f628999e5478613ca441f633674130f362 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Fri, 8 Dec 2023 05:18:10 -0800 Subject: [PATCH 21/31] fix: docs update for Credentials.java Co-authored-by: Leo <39062083+lsirac@users.noreply.github.com> --- credentials/java/com/google/auth/Credentials.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/credentials/java/com/google/auth/Credentials.java b/credentials/java/com/google/auth/Credentials.java index 1287da79c..de88f83cc 100644 --- a/credentials/java/com/google/auth/Credentials.java +++ b/credentials/java/com/google/auth/Credentials.java @@ -59,7 +59,7 @@ public abstract class Credentials implements Serializable { /** * Returns the universe domain for the credential. * - * @return a default Google universe domain googleapis.com + * @return the default Google universe domain googleapis.com */ public String getUniverseDomain() { return GOOGLE_DEFAULT_UNIVERSE; From c671f0d148a26eee3cd4fd6038443bef1b68cd21 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Fri, 8 Dec 2023 05:19:56 -0800 Subject: [PATCH 22/31] Update docs GoogleCredentials.java constructor Co-authored-by: Leo <39062083+lsirac@users.noreply.github.com> --- oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index f67877207..4d5ef27dd 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -333,7 +333,7 @@ protected GoogleCredentials(Builder builder) { } /** - * Constructor with explicit access token and refresh times. + * Constructor with explicit access token and refresh margins. * *

Deprecated, please use the builder constructor whenever possible. * From 64b9d0a6ba13a1b6fb663f374111733732e5b246 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Fri, 8 Dec 2023 05:38:12 -0800 Subject: [PATCH 23/31] fix: javadoc fixes --- .../com/google/auth/oauth2/GoogleCredentials.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 4d5ef27dd..069a2117d 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -232,7 +232,7 @@ static GoogleCredentials fromJson(Map json) throws IOException { } /** - * Creates a credential with the provided quota project. Expected format is: some-domain.xyz + * Creates a credential with the provided quota project. * * @param quotaProject the quota project to set on the credential * @return credential with the provided quota project @@ -300,7 +300,8 @@ protected GoogleCredentials() { /** * Constructor with an explicit access token and quotaProjectId. * - *

Deprecated, please use the builder constructor whenever possible. + *

Deprecated, please use the {@link GoogleCredentials#GoogleCredentials(Builder)} constructor + * whenever possible. * * @param accessToken initial or temporary access token * @param quotaProjectId a quotaProjectId, a project id to be used for billing purposes @@ -322,7 +323,8 @@ public GoogleCredentials(AccessToken accessToken) { } /** - * Constructor with using builder All the fields comes explicitly from builder. + * Constructor that relies on a {@link GoogleCredential.Builder} to + * provide all the necessary field values for initialization. * * @param builder an instance of a builder */ @@ -335,7 +337,8 @@ protected GoogleCredentials(Builder builder) { /** * Constructor with explicit access token and refresh margins. * - *

Deprecated, please use the builder constructor whenever possible. + *

Deprecated, please use the {@link GoogleCredentials#GoogleCredentials(Builder)} + * constructor whenever possible. * * @param accessToken initial or temporary access token */ From bc51410aafdcbbbcb47e08e9cf26f1a110556357 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Fri, 8 Dec 2023 13:41:12 +0000 Subject: [PATCH 24/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../java/com/google/auth/oauth2/GoogleCredentials.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 069a2117d..a2d39521a 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -323,8 +323,8 @@ public GoogleCredentials(AccessToken accessToken) { } /** - * Constructor that relies on a {@link GoogleCredential.Builder} to - * provide all the necessary field values for initialization. + * Constructor that relies on a {@link GoogleCredential.Builder} to provide all the necessary + * field values for initialization. * * @param builder an instance of a builder */ @@ -337,8 +337,8 @@ protected GoogleCredentials(Builder builder) { /** * Constructor with explicit access token and refresh margins. * - *

Deprecated, please use the {@link GoogleCredentials#GoogleCredentials(Builder)} - * constructor whenever possible. + *

Deprecated, please use the {@link GoogleCredentials#GoogleCredentials(Builder)} constructor + * whenever possible. * * @param accessToken initial or temporary access token */ From a4c4a09b39e9d3583e0a94720952461461542f84 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Tue, 12 Dec 2023 08:00:21 -0800 Subject: [PATCH 25/31] getUniverseDomain throws IOExcpetion, more tests --- .../java/com/google/auth/Credentials.java | 8 +- .../auth/oauth2/ComputeEngineCredentials.java | 6 ++ .../oauth2/ExternalAccountCredentials.java | 9 +- .../google/auth/oauth2/GoogleCredentials.java | 25 +++-- .../auth/oauth2/AwsCredentialsTest.java | 2 +- .../ExternalAccountCredentialsTest.java | 2 +- .../auth/oauth2/GoogleCredentialsTest.java | 101 +++++++++++++++++- .../oauth2/IdentityPoolCredentialsTest.java | 2 +- .../oauth2/PluggableAuthCredentialsTest.java | 2 +- 9 files changed, 138 insertions(+), 19 deletions(-) diff --git a/credentials/java/com/google/auth/Credentials.java b/credentials/java/com/google/auth/Credentials.java index de88f83cc..413391058 100644 --- a/credentials/java/com/google/auth/Credentials.java +++ b/credentials/java/com/google/auth/Credentials.java @@ -59,9 +59,13 @@ public abstract class Credentials implements Serializable { /** * Returns the universe domain for the credential. * - * @return the default Google universe domain googleapis.com + * @return a universe domain value in the format some-domain.xyz. By default, returns the Google + * universe domain googleapis.com. + * @throws IOException extending classes might have to do remote calls to determine the universe + * domain. The exception should implement {@link Retryable} and {@code isRetryable()} will return + * true if the operation may be retried. */ - public String getUniverseDomain() { + public String getUniverseDomain() throws IOException { return GOOGLE_DEFAULT_UNIVERSE; } diff --git a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java index 735860d86..24f71c2c2 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java @@ -41,6 +41,7 @@ import com.google.api.client.http.HttpStatusCodes; import com.google.api.client.json.JsonObjectParser; import com.google.api.client.util.GenericData; +import com.google.auth.Credentials; import com.google.auth.ServiceAccountSigner; import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; @@ -179,6 +180,11 @@ public final Collection getScopes() { return scopes; } + @Override + public String getUniverseDomain() throws IOException { + return Credentials.GOOGLE_DEFAULT_UNIVERSE; + } + /** * If scopes is specified, add "?scopes=comma-separated-list-of-scopes" to the token url. * diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index cb04b557d..54273310e 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -36,6 +36,7 @@ import com.google.api.client.http.HttpHeaders; import com.google.api.client.json.GenericJson; import com.google.api.client.json.JsonObjectParser; +import com.google.auth.Credentials; import com.google.auth.RequestMetadataCallback; import com.google.auth.http.HttpTransportFactory; import com.google.common.base.MoreObjects; @@ -747,8 +748,14 @@ protected Builder(ExternalAccountCredentials credentials) { this.environmentProvider = credentials.environmentProvider; this.workforcePoolUserProject = credentials.workforcePoolUserProject; this.serviceAccountImpersonationOptions = credentials.serviceAccountImpersonationOptions; - this.universeDomain = credentials.getUniverseDomain(); this.metricsHandler = credentials.metricsHandler; + try { + universeDomain = credentials.getUniverseDomain(); + } + catch (IOException ex) { + throw new RuntimeException("Unexpected exception while getting universe domain", ex); + } + this.universeDomain = universeDomain; } /** diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index a2d39521a..2e24566c5 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -77,7 +77,10 @@ public class GoogleCredentials extends OAuth2Credentials implements QuotaProject * @return the credentials instance */ public static GoogleCredentials create(AccessToken accessToken) { - return GoogleCredentials.newBuilder().setAccessToken(accessToken).build(); + return GoogleCredentials.newBuilder() + .setAccessToken(accessToken) + .setUniverseDomain(Credentials.GOOGLE_DEFAULT_UNIVERSE) + .build(); } /** @@ -248,11 +251,7 @@ public GoogleCredentials createWithQuotaProject(String quotaProject) { * implementation otherwise */ @Override - public String getUniverseDomain() { - if (this.universeDomain == null || universeDomain.trim().isEmpty()) { - return super.getUniverseDomain(); - } - + public String getUniverseDomain() throws IOException { return this.universeDomain; } @@ -263,7 +262,7 @@ public String getUniverseDomain() { * otherwise */ boolean isDefaultUniverseDomain() { - return getUniverseDomain().equals(Credentials.GOOGLE_DEFAULT_UNIVERSE); + return this.universeDomain.equals(Credentials.GOOGLE_DEFAULT_UNIVERSE); } /** @@ -360,8 +359,8 @@ protected GoogleCredentials( protected ToStringHelper toStringHelper() { return MoreObjects.toStringHelper(this) .omitNullValues() - .add("quotaProjectId", quotaProjectId) - .add("universeDomain", getUniverseDomain()); + .add("quotaProjectId", this.quotaProjectId) + .add("universeDomain", this.universeDomain); } @Override @@ -376,12 +375,12 @@ public boolean equals(Object obj) { } GoogleCredentials other = (GoogleCredentials) obj; return Objects.equals(this.getQuotaProjectId(), other.getQuotaProjectId()) - && Objects.equals(this.getUniverseDomain(), other.getUniverseDomain()); + && Objects.equals(this.universeDomain, other.universeDomain); } @Override public int hashCode() { - return Objects.hash(getQuotaProjectId(), getUniverseDomain()); + return Objects.hash(getQuotaProjectId(), this.universeDomain); } public static Builder newBuilder() { @@ -502,6 +501,10 @@ public String getQuotaProjectId() { } public String getUniverseDomain() { + if (this.universeDomain == null || this.universeDomain.trim().isEmpty()) { + return Credentials.GOOGLE_DEFAULT_UNIVERSE; + } + return this.universeDomain; } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java index b6e73fcce..6a70e3138 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java @@ -760,7 +760,7 @@ public void getAwsRegion_metadataServer() throws IOException { } @Test - public void createdScoped_clonedCredentialWithAddedScopes() { + public void createdScoped_clonedCredentialWithAddedScopes() throws IOException { AwsCredentials credentials = (AwsCredentials) AwsCredentials.newBuilder(AWS_CREDENTIAL) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java index f5b5b3621..372cb5380 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java @@ -524,7 +524,7 @@ public void fromJson_invalidWorkforceAudiences_throws() throws IOException { } @Test - public void constructor_builder() { + public void constructor_builder() throws IOException { HashMap credentialSource = new HashMap<>(); credentialSource.put("file", "file"); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index 71382a3b7..3dbbff78b 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -34,6 +34,7 @@ import static org.junit.Assert.*; import com.google.api.client.util.Clock; +import com.google.auth.Credentials; import com.google.auth.TestUtils; import com.google.auth.http.HttpTransportFactory; import com.google.auth.oauth2.ExternalAccountAuthorizedUserCredentialsTest.MockExternalAccountAuthorizedUserCredentialsTransportFactory; @@ -223,6 +224,7 @@ public void fromStream_gdchServiceAccount_correct() throws IOException { GDCH_SA_SERVICE_IDENTITY_NAME, ((GdchCredentials) credentials).getServiceIdentityName()); assertEquals(GDCH_SA_TOKEN_SERVER_URI, ((GdchCredentials) credentials).getTokenServerUri()); assertEquals(GDCH_SA_CA_CERT_PATH, ((GdchCredentials) credentials).getCaCertPath()); + assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); assertNull(((GdchCredentials) credentials).getApiAudience()); credentials = ((GdchCredentials) credentials).createWithGdchAudience(GDCH_API_AUDIENCE); @@ -376,6 +378,18 @@ public void fromStream_user_providesToken() throws IOException { TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); } + @Test + public void fromStream_user_defaultUniverse() throws IOException { + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + InputStream userStream = + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, null); + + GoogleCredentials credentials = GoogleCredentials.fromStream(userStream, transportFactory); + + assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + @Test public void fromStream_userNoClientId_throws() throws IOException { InputStream userStream = @@ -421,6 +435,23 @@ public void fromStream_identityPoolCredentials_providesToken() throws IOExceptio TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken()); } + @Test + public void fromStream_identityPoolCredentials_defaultUniverse() throws IOException { + MockExternalAccountCredentialsTransportFactory transportFactory = + new MockExternalAccountCredentialsTransportFactory(); + InputStream identityPoolCredentialStream = + IdentityPoolCredentialsTest.writeIdentityPoolCredentialsStream( + transportFactory.transport.getStsUrl(), + transportFactory.transport.getMetadataUrl(), + /* serviceAccountImpersonationUrl= */ null, + /* serviceAccountImpersonationOptionsMap= */ null); + + GoogleCredentials credentials = + GoogleCredentials.fromStream(identityPoolCredentialStream, transportFactory); + + assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + @Test public void fromStream_awsCredentials_providesToken() throws IOException { MockExternalAccountCredentialsTransportFactory transportFactory = @@ -441,6 +472,23 @@ public void fromStream_awsCredentials_providesToken() throws IOException { TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken()); } + @Test + public void fromStream_awsCredentials_defaultUniverse() throws IOException { + MockExternalAccountCredentialsTransportFactory transportFactory = + new MockExternalAccountCredentialsTransportFactory(); + + InputStream awsCredentialStream = + AwsCredentialsTest.writeAwsCredentialsStream( + transportFactory.transport.getStsUrl(), + transportFactory.transport.getAwsRegionUrl(), + transportFactory.transport.getAwsCredentialsUrl()); + + GoogleCredentials credentials = + GoogleCredentials.fromStream(awsCredentialStream, transportFactory); + + assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + @Test public void fromStream_pluggableAuthCredentials_providesToken() throws IOException { MockExternalAccountCredentialsTransportFactory transportFactory = @@ -464,6 +512,19 @@ public void fromStream_pluggableAuthCredentials_providesToken() throws IOExcepti TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken()); } + @Test + public void fromStream_pluggableAuthCredentials_defaultUniverse() throws IOException { + MockExternalAccountCredentialsTransportFactory transportFactory = + new MockExternalAccountCredentialsTransportFactory(); + + InputStream stream = + PluggableAuthCredentialsTest.writeCredentialsStream(transportFactory.transport.getStsUrl()); + + GoogleCredentials credentials = GoogleCredentials.fromStream(stream, transportFactory); + + assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + @Test public void fromStream_externalAccountAuthorizedUserCredentials_providesToken() throws IOException { @@ -479,6 +540,20 @@ public void fromStream_externalAccountAuthorizedUserCredentials_providesToken() TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken()); } + @Test + public void fromStream_externalAccountAuthorizedUserCredentials_defaultUniverse() + throws IOException { + MockExternalAccountAuthorizedUserCredentialsTransportFactory transportFactory = + new MockExternalAccountAuthorizedUserCredentialsTransportFactory(); + InputStream stream = + TestUtils.jsonToInputStream( + ExternalAccountAuthorizedUserCredentialsTest.buildJsonCredentials()); + + GoogleCredentials credentials = GoogleCredentials.fromStream(stream, transportFactory); + + assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + @Test public void fromStream_Impersonation_providesToken_WithQuotaProject() throws IOException { MockTokenServerTransportFactory transportFactoryForSource = @@ -515,6 +590,30 @@ public void fromStream_Impersonation_providesToken_WithQuotaProject() throws IOE assertEquals(ImpersonatedCredentialsTest.QUOTA_PROJECT_ID, headerValues.get(0)); } + @Test + public void fromStream_Impersonation_defaultUniverse() throws IOException { + MockTokenServerTransportFactory transportFactoryForSource = + new MockTokenServerTransportFactory(); + transportFactoryForSource.transport.addServiceAccount( + ImpersonatedCredentialsTest.SA_CLIENT_EMAIL, ImpersonatedCredentialsTest.ACCESS_TOKEN); + + MockIAMCredentialsServiceTransportFactory transportFactory = + new MockIAMCredentialsServiceTransportFactory(); + + InputStream impersonationCredentialsStream = + ImpersonatedCredentialsTest.writeImpersonationCredentialsStream( + ImpersonatedCredentialsTest.IMPERSONATION_URL, + ImpersonatedCredentialsTest.DELEGATES, + ImpersonatedCredentialsTest.QUOTA_PROJECT_ID); + + ImpersonatedCredentials credentials = + (ImpersonatedCredentials) + GoogleCredentials.fromStream(impersonationCredentialsStream, transportFactoryForSource); + credentials.setTransportFactory(transportFactory); + + assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); + } + @Test public void fromStream_Impersonation_providesToken_WithoutQuotaProject() throws IOException { MockTokenServerTransportFactory transportFactoryForSource = @@ -585,7 +684,7 @@ public void createWithQuotaProject() { } @Test - public void buildWithUniverseDomain() { + public void buildWithUniverseDomain() throws IOException { final GoogleCredentials original = new GoogleCredentials.Builder().setUniverseDomain("universe1").build(); GoogleCredentials updated = original.toBuilder().setUniverseDomain("universe2").build(); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java index 387430d42..7bb64ab1e 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java @@ -94,7 +94,7 @@ public HttpTransport create() { } @Test - public void createdScoped_clonedCredentialWithAddedScopes() { + public void createdScoped_clonedCredentialWithAddedScopes() throws IOException { IdentityPoolCredentials credentials = (IdentityPoolCredentials) IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java index 395fe6cd6..3ffa2c24f 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java @@ -437,7 +437,7 @@ public void builder_allFields() { } @Test - public void createdScoped_clonedCredentialWithAddedScopes() { + public void createdScoped_clonedCredentialWithAddedScopes() throws IOException { PluggableAuthCredentials credentials = (PluggableAuthCredentials) PluggableAuthCredentials.newBuilder(CREDENTIAL) From 439b48696fdcf9c026762fdd85ea5ffe2089672c Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 12 Dec 2023 16:02:34 +0000 Subject: [PATCH 26/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- credentials/java/com/google/auth/Credentials.java | 6 +++--- .../com/google/auth/oauth2/ComputeEngineCredentials.java | 2 +- .../com/google/auth/oauth2/ExternalAccountCredentials.java | 4 +--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/credentials/java/com/google/auth/Credentials.java b/credentials/java/com/google/auth/Credentials.java index 413391058..ae38166f8 100644 --- a/credentials/java/com/google/auth/Credentials.java +++ b/credentials/java/com/google/auth/Credentials.java @@ -60,10 +60,10 @@ public abstract class Credentials implements Serializable { * Returns the universe domain for the credential. * * @return a universe domain value in the format some-domain.xyz. By default, returns the Google - * universe domain googleapis.com. + * universe domain googleapis.com. * @throws IOException extending classes might have to do remote calls to determine the universe - * domain. The exception should implement {@link Retryable} and {@code isRetryable()} will return - * true if the operation may be retried. + * domain. The exception should implement {@link Retryable} and {@code isRetryable()} will + * return true if the operation may be retried. */ public String getUniverseDomain() throws IOException { return GOOGLE_DEFAULT_UNIVERSE; diff --git a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java index 24f71c2c2..8434794f6 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java @@ -182,7 +182,7 @@ public final Collection getScopes() { @Override public String getUniverseDomain() throws IOException { - return Credentials.GOOGLE_DEFAULT_UNIVERSE; + return Credentials.GOOGLE_DEFAULT_UNIVERSE; } /** diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index 54273310e..e20737659 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -36,7 +36,6 @@ import com.google.api.client.http.HttpHeaders; import com.google.api.client.json.GenericJson; import com.google.api.client.json.JsonObjectParser; -import com.google.auth.Credentials; import com.google.auth.RequestMetadataCallback; import com.google.auth.http.HttpTransportFactory; import com.google.common.base.MoreObjects; @@ -751,8 +750,7 @@ protected Builder(ExternalAccountCredentials credentials) { this.metricsHandler = credentials.metricsHandler; try { universeDomain = credentials.getUniverseDomain(); - } - catch (IOException ex) { + } catch (IOException ex) { throw new RuntimeException("Unexpected exception while getting universe domain", ex); } this.universeDomain = universeDomain; From 69c966e34a4c7e326e5798d94edca1d65ddbb440 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Tue, 12 Dec 2023 08:28:05 -0800 Subject: [PATCH 27/31] fix: universeDomain from deprecated constructors --- .../java/com/google/auth/oauth2/GoogleCredentials.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 2e24566c5..7a936b306 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -227,9 +227,7 @@ static GoogleCredentials fromJson(Map json) throws IOException { // Parse fields that are common for all the types of GoogleCredentials. String universeDomain = (String) json.get("universe_domain"); - if (universeDomain != null && !universeDomain.trim().isEmpty()) { - credentialsBuilder.setUniverseDomain(universeDomain); - } + credentialsBuilder.setUniverseDomain(universeDomain); return credentialsBuilder.build(); } @@ -309,7 +307,7 @@ protected GoogleCredentials() { protected GoogleCredentials(AccessToken accessToken, String quotaProjectId) { super(accessToken); this.quotaProjectId = quotaProjectId; - this.universeDomain = null; + this.universeDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE; } /** @@ -346,7 +344,7 @@ protected GoogleCredentials( AccessToken accessToken, Duration refreshMargin, Duration expirationMargin) { super(accessToken, refreshMargin, expirationMargin); this.quotaProjectId = null; - this.universeDomain = null; + this.universeDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE; } /** From 18e1429464b9ad0f94aacb61d9ba501f5c7a339e Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Thu, 14 Dec 2023 05:17:21 -0800 Subject: [PATCH 28/31] fix: revert common json parsing, other comments addressed --- .../java/com/google/auth/Credentials.java | 5 +- .../auth/oauth2/ComputeEngineCredentials.java | 5 -- .../oauth2/ExternalAccountCredentials.java | 11 ++--- .../google/auth/oauth2/GoogleCredentials.java | 39 +++++----------- .../oauth2/ServiceAccountCredentials.java | 7 ++- .../auth/oauth2/GoogleCredentialsTest.java | 46 +++++++++++++++++-- 6 files changed, 62 insertions(+), 51 deletions(-) diff --git a/credentials/java/com/google/auth/Credentials.java b/credentials/java/com/google/auth/Credentials.java index ae38166f8..493b970ad 100644 --- a/credentials/java/com/google/auth/Credentials.java +++ b/credentials/java/com/google/auth/Credentials.java @@ -57,12 +57,13 @@ public abstract class Credentials implements Serializable { public abstract String getAuthenticationType(); /** - * Returns the universe domain for the credential. + * Gets the universe domain for the credential in a blocking manner, refreshing tokens if + * required. * * @return a universe domain value in the format some-domain.xyz. By default, returns the Google * universe domain googleapis.com. * @throws IOException extending classes might have to do remote calls to determine the universe - * domain. The exception should implement {@link Retryable} and {@code isRetryable()} will + * domain. The exception must implement {@link Retryable} and {@code isRetryable()} will * return true if the operation may be retried. */ public String getUniverseDomain() throws IOException { diff --git a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java index 8434794f6..04d890081 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java @@ -180,11 +180,6 @@ public final Collection getScopes() { return scopes; } - @Override - public String getUniverseDomain() throws IOException { - return Credentials.GOOGLE_DEFAULT_UNIVERSE; - } - /** * If scopes is specified, add "?scopes=comma-separated-list-of-scopes" to the token url. * diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index e20737659..0e1c71ea4 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -413,9 +413,7 @@ static ExternalAccountCredentials fromJson( String userProject = (String) json.get("workforce_pool_user_project"); Map impersonationOptionsMap = (Map) json.get("service_account_impersonation"); - - GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); - String universeDomain = baseCredential.getUniverseDomain(); + String universeDomain = (String) json.get("universe_domain"); if (impersonationOptionsMap == null) { impersonationOptionsMap = new HashMap(); @@ -434,7 +432,7 @@ static ExternalAccountCredentials fromJson( .setClientId(clientId) .setClientSecret(clientSecret) .setServiceAccountImpersonationOptions(impersonationOptionsMap) - .setUniverseDomain(baseCredential.getUniverseDomain()) + .setUniverseDomain(universeDomain) .build(); } else if (isPluggableAuthCredential(credentialSourceMap)) { return PluggableAuthCredentials.newBuilder() @@ -749,11 +747,10 @@ protected Builder(ExternalAccountCredentials credentials) { this.serviceAccountImpersonationOptions = credentials.serviceAccountImpersonationOptions; this.metricsHandler = credentials.metricsHandler; try { - universeDomain = credentials.getUniverseDomain(); + this.universeDomain = credentials.getUniverseDomain(); } catch (IOException ex) { throw new RuntimeException("Unexpected exception while getting universe domain", ex); } - this.universeDomain = universeDomain; } /** @@ -928,8 +925,8 @@ public Builder setServiceAccountImpersonationOptions(Map options @CanIgnoreReturnValue @Override public Builder setUniverseDomain(String universeDomain) { - this.universeDomain = universeDomain; super.setUniverseDomain(universeDomain); + this.universeDomain = universeDomain; return this; } diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 7a936b306..3039f64c9 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -63,6 +63,7 @@ public class GoogleCredentials extends OAuth2Credentials implements QuotaProject static final String USER_FILE_TYPE = "authorized_user"; static final String SERVICE_ACCOUNT_FILE_TYPE = "service_account"; static final String GDCH_SERVICE_ACCOUNT_FILE_TYPE = "gdch_service_account"; + private final String universeDomain; protected final String quotaProjectId; @@ -202,7 +203,7 @@ public static GoogleCredentials fromStream( throw new IOException( String.format( "Error reading credentials from stream, 'type' value '%s' not recognized." - + " Valid values are '%s', '%s', '%s', '%s', '%s', 's'.", + + " Valid values are '%s', '%s', '%s', '%s', '%s', '%s'.", fileType, USER_FILE_TYPE, SERVICE_ACCOUNT_FILE_TYPE, @@ -212,26 +213,6 @@ public static GoogleCredentials fromStream( ImpersonatedCredentials.IMPERSONATED_CREDENTIALS_FILE_TYPE)); } - /** - * Returns an instance of GoogleCredentials defined by JSON. - * - *

To be used to parse common credentials fields. - * - * @param json a map from the JSON representing the credentials. - * @return the credentials defined by the JSON. - * @throws IOException if the credential cannot be created from the JSON. - */ - @VisibleForTesting - static GoogleCredentials fromJson(Map json) throws IOException { - Builder credentialsBuilder = GoogleCredentials.newBuilder(); - - // Parse fields that are common for all the types of GoogleCredentials. - String universeDomain = (String) json.get("universe_domain"); - credentialsBuilder.setUniverseDomain(universeDomain); - - return credentialsBuilder.build(); - } - /** * Creates a credential with the provided quota project. * @@ -315,6 +296,7 @@ protected GoogleCredentials(AccessToken accessToken, String quotaProjectId) { * * @param accessToken initial or temporary access token */ + @Deprecated public GoogleCredentials(AccessToken accessToken) { this(accessToken, null); } @@ -328,7 +310,12 @@ public GoogleCredentials(AccessToken accessToken) { protected GoogleCredentials(Builder builder) { super(builder.getAccessToken()); this.quotaProjectId = builder.getQuotaProjectId(); - this.universeDomain = builder.getUniverseDomain(); + + if (builder.universeDomain == null || builder.universeDomain.trim().isEmpty()) { + this.universeDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE; + } else { + this.universeDomain = builder.getUniverseDomain(); + } } /** @@ -372,13 +359,13 @@ public boolean equals(Object obj) { return false; } GoogleCredentials other = (GoogleCredentials) obj; - return Objects.equals(this.getQuotaProjectId(), other.getQuotaProjectId()) + return Objects.equals(this.quotaProjectId, other.quotaProjectId) && Objects.equals(this.universeDomain, other.universeDomain); } @Override public int hashCode() { - return Objects.hash(getQuotaProjectId(), this.universeDomain); + return Objects.hash(this.quotaProjectId, this.universeDomain); } public static Builder newBuilder() { @@ -499,10 +486,6 @@ public String getQuotaProjectId() { } public String getUniverseDomain() { - if (this.universeDomain == null || this.universeDomain.trim().isEmpty()) { - return Credentials.GOOGLE_DEFAULT_UNIVERSE; - } - return this.universeDomain; } diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index 2a7c6cc44..69361e00c 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -166,6 +166,7 @@ static ServiceAccountCredentials fromJson( String projectId = (String) json.get("project_id"); String tokenServerUriStringFromCreds = (String) json.get("token_uri"); String quotaProjectId = (String) json.get("quota_project_id"); + String universeDomain = (String) json.get("universe_domain"); URI tokenServerUriFromCreds = null; try { if (tokenServerUriStringFromCreds != null) { @@ -192,10 +193,8 @@ static ServiceAccountCredentials fromJson( .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServerUriFromCreds) .setProjectId(projectId) - .setQuotaProjectId(quotaProjectId); - - GoogleCredentials baseCredential = GoogleCredentials.fromJson(json); - builder.setUniverseDomain(baseCredential.getUniverseDomain()); + .setQuotaProjectId(quotaProjectId) + .setUniverseDomain(universeDomain); return fromPkcs8(privateKeyPkcs8, builder); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index 3dbbff78b..f4997e34b 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -33,6 +33,7 @@ import static org.junit.Assert.*; +import com.google.api.client.json.GenericJson; import com.google.api.client.util.Clock; import com.google.auth.Credentials; import com.google.auth.TestUtils; @@ -50,6 +51,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.MissingFormatArgumentException; import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.junit.runner.RunWith; @@ -104,6 +106,24 @@ public void getApplicationDefault_nullTransport_throws() throws IOException { } } + @Test + public void fromStream_unknownType_throws() throws IOException { + MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); + GenericJson json = new GenericJson(); + json.put("type", "unsupported_credential"); + InputStream stream = TestUtils.jsonToInputStream(json); + try { + GoogleCredentials.fromStream(stream, transportFactory); + fail("Should throw if type is unknown."); + } catch (IOException expected) { + String expectedError = "Error reading credentials from stream, 'type' value " + + "'unsupported_credential' not recognized. Valid values are 'authorized_user', " + + "'service_account', 'gdch_service_account', 'external_account', " + + "'external_account_authorized_user', 'impersonated_service_account'."; + assertTrue(expected.getMessage().contains(expectedError)); + } + } + @Test public void fromStream_nullTransport_throws() throws IOException { InputStream stream = new ByteArrayInputStream("foo".getBytes()); @@ -115,6 +135,22 @@ public void fromStream_nullTransport_throws() throws IOException { } } + @Test + public void fromStream_noType_throws() throws IOException { + MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); + GenericJson json = ServiceAccountCredentialsTest + .writeServiceAccountJson("project_id", QUOTA_PROJECT, "universe"); + json.remove("type"); + InputStream stream = TestUtils.jsonToInputStream(json); + try { + GoogleCredentials.fromStream(stream, transportFactory); + fail("Should throw if type is unknown."); + } catch (IOException expected) { + String expectedError = "Error reading credentials from stream, 'type' field not specified."; + assertEquals(expectedError, expected.getMessage()); + } + } + @Test public void fromStream_nullStream_throws() throws IOException { MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); @@ -363,7 +399,7 @@ public void fromStream_gdchServiceAccountInvalidCaCertPath_throws() throws IOExc } @Test - public void fromStream_user_providesToken() throws IOException { + public void fromStream_userCredentials_providesToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addClient(USER_CLIENT_ID, USER_CLIENT_SECRET); transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN); @@ -379,7 +415,7 @@ public void fromStream_user_providesToken() throws IOException { } @Test - public void fromStream_user_defaultUniverse() throws IOException { + public void fromStream_userCredentials_defaultUniverse() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); InputStream userStream = UserCredentialsTest.writeUserStream( @@ -391,7 +427,7 @@ public void fromStream_user_defaultUniverse() throws IOException { } @Test - public void fromStream_userNoClientId_throws() throws IOException { + public void fromStream_userCredentials_NoClientId_throws() throws IOException { InputStream userStream = UserCredentialsTest.writeUserStream(null, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); @@ -399,7 +435,7 @@ public void fromStream_userNoClientId_throws() throws IOException { } @Test - public void fromStream_userNoClientSecret_throws() throws IOException { + public void fromStream_userCredentials_NoClientSecret_throws() throws IOException { InputStream userStream = UserCredentialsTest.writeUserStream(USER_CLIENT_ID, null, REFRESH_TOKEN, QUOTA_PROJECT); @@ -407,7 +443,7 @@ public void fromStream_userNoClientSecret_throws() throws IOException { } @Test - public void fromStream_userNoRefreshToken_throws() throws IOException { + public void fromStream_userCredentials_NoRefreshToken_throws() throws IOException { InputStream userStream = UserCredentialsTest.writeUserStream( USER_CLIENT_ID, USER_CLIENT_SECRET, null, QUOTA_PROJECT); From 8c21b7e4720eabe80b988aee25b9480e4032b314 Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Thu, 14 Dec 2023 13:19:52 +0000 Subject: [PATCH 29/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../auth/oauth2/ComputeEngineCredentials.java | 1 - .../com/google/auth/oauth2/GoogleCredentials.java | 1 - .../google/auth/oauth2/GoogleCredentialsTest.java | 15 ++++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java index 04d890081..735860d86 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java @@ -41,7 +41,6 @@ import com.google.api.client.http.HttpStatusCodes; import com.google.api.client.json.JsonObjectParser; import com.google.api.client.util.GenericData; -import com.google.auth.Credentials; import com.google.auth.ServiceAccountSigner; import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 3039f64c9..531c43e1b 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -37,7 +37,6 @@ import com.google.api.client.util.Preconditions; import com.google.auth.Credentials; import com.google.auth.http.HttpTransportFactory; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.ImmutableList; diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index f4997e34b..df1ba9216 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -51,7 +51,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.MissingFormatArgumentException; import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.junit.runner.RunWith; @@ -116,10 +115,11 @@ public void fromStream_unknownType_throws() throws IOException { GoogleCredentials.fromStream(stream, transportFactory); fail("Should throw if type is unknown."); } catch (IOException expected) { - String expectedError = "Error reading credentials from stream, 'type' value " - + "'unsupported_credential' not recognized. Valid values are 'authorized_user', " - + "'service_account', 'gdch_service_account', 'external_account', " - + "'external_account_authorized_user', 'impersonated_service_account'."; + String expectedError = + "Error reading credentials from stream, 'type' value " + + "'unsupported_credential' not recognized. Valid values are 'authorized_user', " + + "'service_account', 'gdch_service_account', 'external_account', " + + "'external_account_authorized_user', 'impersonated_service_account'."; assertTrue(expected.getMessage().contains(expectedError)); } } @@ -138,8 +138,9 @@ public void fromStream_nullTransport_throws() throws IOException { @Test public void fromStream_noType_throws() throws IOException { MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); - GenericJson json = ServiceAccountCredentialsTest - .writeServiceAccountJson("project_id", QUOTA_PROJECT, "universe"); + GenericJson json = + ServiceAccountCredentialsTest.writeServiceAccountJson( + "project_id", QUOTA_PROJECT, "universe"); json.remove("type"); InputStream stream = TestUtils.jsonToInputStream(json); try { From eceba5af23f320e49c691d58bf22a6de809e1185 Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Tue, 19 Dec 2023 04:23:22 -0800 Subject: [PATCH 30/31] fix: few nits addressed --- .../auth/oauth2/ExternalAccountCredentials.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index 0e1c71ea4..105250623 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -394,7 +394,7 @@ public static ExternalAccountCredentials fromStream( */ @SuppressWarnings("unchecked") static ExternalAccountCredentials fromJson( - Map json, HttpTransportFactory transportFactory) throws IOException { + Map json, HttpTransportFactory transportFactory) { checkNotNull(json); checkNotNull(transportFactory); @@ -411,9 +411,9 @@ static ExternalAccountCredentials fromJson( String clientSecret = (String) json.get("client_secret"); String quotaProjectId = (String) json.get("quota_project_id"); String userProject = (String) json.get("workforce_pool_user_project"); + String universeDomain = (String) json.get("universe_domain"); Map impersonationOptionsMap = (Map) json.get("service_account_impersonation"); - String universeDomain = (String) json.get("universe_domain"); if (impersonationOptionsMap == null) { impersonationOptionsMap = new HashMap(); @@ -725,7 +725,12 @@ public abstract static class Builder extends GoogleCredentials.Builder { @Nullable protected Collection scopes; @Nullable protected String workforcePoolUserProject; @Nullable protected ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; + + /* The field is not being used and value not set. Superseded by the same field in the + {@link GoogleCredential.Builder}. + */ @Nullable @Deprecated protected String universeDomain; + @Nullable protected ExternalAccountMetricsHandler metricsHandler; protected Builder() {} @@ -746,11 +751,6 @@ protected Builder(ExternalAccountCredentials credentials) { this.workforcePoolUserProject = credentials.workforcePoolUserProject; this.serviceAccountImpersonationOptions = credentials.serviceAccountImpersonationOptions; this.metricsHandler = credentials.metricsHandler; - try { - this.universeDomain = credentials.getUniverseDomain(); - } catch (IOException ex) { - throw new RuntimeException("Unexpected exception while getting universe domain", ex); - } } /** @@ -926,7 +926,6 @@ public Builder setServiceAccountImpersonationOptions(Map options @Override public Builder setUniverseDomain(String universeDomain) { super.setUniverseDomain(universeDomain); - this.universeDomain = universeDomain; return this; } From bfbd4fc2e1f3111523d6819f87c482ef363a086e Mon Sep 17 00:00:00 2001 From: Owl Bot Date: Tue, 19 Dec 2023 12:25:47 +0000 Subject: [PATCH 31/31] =?UTF-8?q?=F0=9F=A6=89=20Updates=20from=20OwlBot=20?= =?UTF-8?q?post-processor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --- .../com/google/auth/oauth2/ExternalAccountCredentials.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index 105250623..bccd943eb 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -727,8 +727,8 @@ public abstract static class Builder extends GoogleCredentials.Builder { @Nullable protected ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; /* The field is not being used and value not set. Superseded by the same field in the - {@link GoogleCredential.Builder}. - */ + {@link GoogleCredential.Builder}. + */ @Nullable @Deprecated protected String universeDomain; @Nullable protected ExternalAccountMetricsHandler metricsHandler;