Skip to content

Commit

Permalink
fix: move universe_domain to very base Credential, tests cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
TimurSadykov committed Nov 2, 2023
1 parent efe23b1 commit 090674f
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 279 deletions.
11 changes: 11 additions & 0 deletions credentials/java/com/google/auth/Credentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 14 additions & 3 deletions oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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).
*/
Expand Down Expand Up @@ -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/".
*/
Expand All @@ -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);

Expand Down Expand Up @@ -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 {
Expand All @@ -920,17 +930,44 @@ public Map<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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);
Expand All @@ -940,6 +977,7 @@ public Map<String, List<String>> getRequestMetadata(URI uri) throws IOException
// Create JWT credentials with the uri as audience.
jwtCredentials = createSelfSignedJwtCredentials(uri);
}

Map<String, List<String>> requestMetadata = jwtCredentials.getRequestMetadata(null);
return addQuotaProjectIdToRequestMetadata(quotaProjectId, requestMetadata);
}
Expand Down
Loading

0 comments on commit 090674f

Please sign in to comment.