Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: multi universe support, adding universe_domain field #1282

Merged
merged 36 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4ddad12
feat: first draft of tpc support, adding universe_domain field
TimurSadykov Sep 12, 2023
c41f542
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Sep 12, 2023
3957bd0
Update oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
TimurSadykov Sep 13, 2023
41de188
fix: adding tests
TimurSadykov Sep 13, 2023
efe23b1
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Sep 13, 2023
090674f
fix: move universe_domain to very base Credential, tests cleanup
TimurSadykov Nov 2, 2023
3eb4047
fix: resolve a conflict in tests
TimurSadykov Nov 2, 2023
da7e1b7
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Nov 2, 2023
72e4dd0
Merge branch 'main' into tpc-stage1
TimurSadykov Nov 2, 2023
c192155
Merge branch 'main' into tpc-stage1
TimurSadykov Nov 14, 2023
35f79d0
feat: updates for ToString, hashCode and equals
TimurSadykov Nov 14, 2023
0749124
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Nov 14, 2023
763f6b0
feat: refactor ExternalAccount to use base class universe domain, upd…
TimurSadykov Nov 14, 2023
309312d
fix: test fixes
TimurSadykov Nov 20, 2023
c63ed36
fix: javadoc updates and other nits
TimurSadykov Nov 20, 2023
3b46e38
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Nov 20, 2023
bc2360f
Merge remote-tracking branch 'origin/main' into tpc-stage1
TimurSadykov Nov 24, 2023
482603f
fix: universe comparison fix, restoring the original univerDeomain fi…
TimurSadykov Nov 25, 2023
0c21a72
fix: deprecating a duplicate universeDomain field
TimurSadykov Nov 29, 2023
4b21ca2
fix: restore the original behavior of equals and hashcode for UserCre…
TimurSadykov Nov 29, 2023
bab1ccc
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Nov 29, 2023
a009715
Merge branch 'main' into tpc-stage1
lsirac Dec 7, 2023
de8c400
fix: comments addressed
TimurSadykov Dec 7, 2023
9659e40
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Dec 7, 2023
1bc4d3f
fix: docs update for Credentials.java
TimurSadykov Dec 8, 2023
c671f0d
Update docs GoogleCredentials.java constructor
TimurSadykov Dec 8, 2023
64b9d0a
fix: javadoc fixes
TimurSadykov Dec 8, 2023
bc51410
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Dec 8, 2023
a4c4a09
getUniverseDomain throws IOExcpetion, more tests
TimurSadykov Dec 12, 2023
439b486
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Dec 12, 2023
69c966e
fix: universeDomain from deprecated constructors
TimurSadykov Dec 12, 2023
18e1429
fix: revert common json parsing, other comments addressed
TimurSadykov Dec 14, 2023
8c21b7e
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Dec 14, 2023
eceba5a
fix: few nits addressed
TimurSadykov Dec 19, 2023
bfbd4fc
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Dec 19, 2023
6a3b81c
Merge branch 'main' into tpc-stage1
lsirac Dec 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions credentials/java/com/google/auth/Credentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -180,11 +179,6 @@ public final Collection<String> 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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,7 @@ static ExternalAccountCredentials fromJson(
String userProject = (String) json.get("workforce_pool_user_project");
Map<String, Object> impersonationOptionsMap =
(Map<String, Object>) json.get("service_account_impersonation");

GoogleCredentials baseCredential = GoogleCredentials.fromJson(json);
String universeDomain = baseCredential.getUniverseDomain();
String universeDomain = (String) json.get("universe_domain");
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved

if (impersonationOptionsMap == null) {
impersonationOptionsMap = new HashMap<String, Object>();
Expand All @@ -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()
Expand Down Expand Up @@ -749,11 +747,10 @@ protected Builder(ExternalAccountCredentials credentials) {
this.serviceAccountImpersonationOptions = credentials.serviceAccountImpersonationOptions;
this.metricsHandler = credentials.metricsHandler;
try {
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved
universeDomain = credentials.getUniverseDomain();
this.universeDomain = credentials.getUniverseDomain();
} catch (IOException ex) {
throw new RuntimeException("Unexpected exception while getting universe domain", ex);
}
this.universeDomain = universeDomain;
}

/**
Expand Down Expand Up @@ -928,8 +925,8 @@ public Builder setServiceAccountImpersonationOptions(Map<String, Object> options
@CanIgnoreReturnValue
@Override
public Builder setUniverseDomain(String universeDomain) {
this.universeDomain = universeDomain;
super.setUniverseDomain(universeDomain);
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved
this.universeDomain = universeDomain;
return this;
}

Expand Down
40 changes: 11 additions & 29 deletions oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -63,6 +62,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;
Expand Down Expand Up @@ -202,7 +202,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,
Expand All @@ -212,26 +212,6 @@ public static GoogleCredentials fromStream(
ImpersonatedCredentials.IMPERSONATED_CREDENTIALS_FILE_TYPE));
}

/**
* Returns an instance of GoogleCredentials defined by JSON.
*
* <p>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<String, Object> 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.
*
Expand Down Expand Up @@ -315,6 +295,7 @@ protected GoogleCredentials(AccessToken accessToken, String quotaProjectId) {
*
* @param accessToken initial or temporary access token
*/
@Deprecated
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved
public GoogleCredentials(AccessToken accessToken) {
this(accessToken, null);
}
Expand All @@ -328,7 +309,12 @@ public GoogleCredentials(AccessToken accessToken) {
protected GoogleCredentials(Builder builder) {
super(builder.getAccessToken());
this.quotaProjectId = builder.getQuotaProjectId();
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved
this.universeDomain = builder.getUniverseDomain();

if (builder.universeDomain == null || builder.universeDomain.trim().isEmpty()) {
TimurSadykov marked this conversation as resolved.
Show resolved Hide resolved
this.universeDomain = Credentials.GOOGLE_DEFAULT_UNIVERSE;
} else {
this.universeDomain = builder.getUniverseDomain();
}
}

/**
Expand Down Expand Up @@ -372,13 +358,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() {
Expand Down Expand Up @@ -499,10 +485,6 @@ public String getQuotaProjectId() {
}

public String getUniverseDomain() {
if (this.universeDomain == null || this.universeDomain.trim().isEmpty()) {
return Credentials.GOOGLE_DEFAULT_UNIVERSE;
}

return this.universeDomain;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -104,6 +105,25 @@ 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());
Expand All @@ -115,6 +135,23 @@ 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();
Expand Down Expand Up @@ -363,7 +400,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);
Expand All @@ -379,7 +416,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(
Expand All @@ -391,23 +428,23 @@ 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);

testFromStreamException(userStream, "client_id");
}

@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);

testFromStreamException(userStream, "client_secret");
}

@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);
Expand Down