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: Introduce Environment Variable for Quota Project Id #1082

Merged
merged 23 commits into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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: 5 additions & 0 deletions .kokoro/nightly/integration.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ env_vars: {
key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES"
value: "1"
}

env_vars: {
key: "GOOGLE_CLOUD_QUOTA_PROJECT"
value: "gcloud-devel"
}
5 changes: 5 additions & 0 deletions .kokoro/presubmit/integration.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,8 @@ env_vars: {
key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES"
value: "1"
}

env_vars: {
key: "GOOGLE_CLOUD_QUOTA_PROJECT"
value: "gcloud-devel"
}
9 changes: 9 additions & 0 deletions oauth2_http/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- see http://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
<differences>
<difference>
<differenceType>6001</differenceType>
<className>com/google/auth/oauth2/ExternalAccountCredentials/Builder</className>
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
<field>quotaProjectId</field>
</difference>
</differences>
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,11 @@
* overriding the state and environment for testing purposes.
*/
class DefaultCredentialsProvider {

static final DefaultCredentialsProvider DEFAULT = new DefaultCredentialsProvider();
static final String CREDENTIAL_ENV_VAR = "GOOGLE_APPLICATION_CREDENTIALS";
static final String QUOTA_PROJECT_ENV_VAR = "GOOGLE_CLOUD_QUOTA_PROJECT";

static final String WELL_KNOWN_CREDENTIALS_FILE = "application_default_credentials.json";
static final String CLOUDSDK_CONFIG_DIRECTORY = "gcloud";
static final String HELP_PERMALINK =
Expand Down Expand Up @@ -214,6 +217,14 @@ private final GoogleCredentials getDefaultCredentialsUnsynchronized(
credentials = tryGetComputeCredentials(transportFactory);
}

if (credentials != null) {
String quotaFromEnv = getEnv(QUOTA_PROJECT_ENV_VAR);

if (quotaFromEnv != null && quotaFromEnv.trim().length() > 0) {
credentials = credentials.createWithQuotaProject(quotaFromEnv);
}
}

return credentials;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@
* <p>Handles initializing external credentials, calls to the Security Token Service, and service
* account impersonation.
*/
public abstract class ExternalAccountCredentials extends GoogleCredentials
implements QuotaProjectIdProvider {
public abstract class ExternalAccountCredentials extends GoogleCredentials {

/** Base credential source class. Dictates the retrieval method of the external credential. */
abstract static class CredentialSource {
Expand All @@ -91,7 +90,6 @@ abstract static class CredentialSource {

@Nullable private final String tokenInfoUrl;
@Nullable private final String serviceAccountImpersonationUrl;
@Nullable private final String quotaProjectId;
@Nullable private final String clientId;
@Nullable private final String clientSecret;

Expand Down Expand Up @@ -194,6 +192,7 @@ protected ExternalAccountCredentials(
@Nullable String clientSecret,
@Nullable Collection<String> scopes,
@Nullable EnvironmentProvider environmentProvider) {
super(null, quotaProjectId);
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
this.transportFactory =
MoreObjects.firstNonNull(
transportFactory,
Expand All @@ -205,7 +204,6 @@ protected ExternalAccountCredentials(
this.credentialSource = checkNotNull(credentialSource);
this.tokenInfoUrl = tokenInfoUrl;
this.serviceAccountImpersonationUrl = serviceAccountImpersonationUrl;
this.quotaProjectId = quotaProjectId;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.scopes =
Expand All @@ -231,6 +229,7 @@ protected ExternalAccountCredentials(
* @param builder the {@code Builder} object used to construct the credentials.
*/
protected ExternalAccountCredentials(ExternalAccountCredentials.Builder builder) {
super(null, builder.getQuotaProjectId());
this.transportFactory =
MoreObjects.firstNonNull(
builder.transportFactory,
Expand All @@ -242,7 +241,6 @@ protected ExternalAccountCredentials(ExternalAccountCredentials.Builder builder)
this.credentialSource = checkNotNull(builder.credentialSource);
this.tokenInfoUrl = builder.tokenInfoUrl;
this.serviceAccountImpersonationUrl = builder.serviceAccountImpersonationUrl;
this.quotaProjectId = builder.quotaProjectId;
this.clientId = builder.clientId;
this.clientSecret = builder.clientSecret;
this.scopes =
Expand Down Expand Up @@ -721,7 +719,6 @@ public abstract static class Builder extends GoogleCredentials.Builder {
protected HttpTransportFactory transportFactory;

@Nullable protected String serviceAccountImpersonationUrl;
@Nullable protected String quotaProjectId;
@Nullable protected String clientId;
@Nullable protected String clientSecret;
@Nullable protected Collection<String> scopes;
Expand All @@ -731,14 +728,14 @@ public abstract static class Builder extends GoogleCredentials.Builder {
protected Builder() {}

protected Builder(ExternalAccountCredentials credentials) {
super(credentials);
this.transportFactory = credentials.transportFactory;
this.audience = credentials.audience;
this.subjectTokenType = credentials.subjectTokenType;
this.tokenUrl = credentials.tokenUrl;
this.tokenInfoUrl = credentials.tokenInfoUrl;
this.serviceAccountImpersonationUrl = credentials.serviceAccountImpersonationUrl;
this.credentialSource = credentials.credentialSource;
this.quotaProjectId = credentials.quotaProjectId;
this.clientId = credentials.clientId;
this.clientSecret = credentials.clientSecret;
this.scopes = credentials.scopes;
Expand Down Expand Up @@ -836,7 +833,7 @@ public Builder setTokenInfoUrl(String tokenInfoUrl) {
* @return this {@code Builder} object
*/
public Builder setQuotaProjectId(String quotaProjectId) {
this.quotaProjectId = quotaProjectId;
super.setQuotaProjectId(quotaProjectId);
return this;
}

Expand Down
61 changes: 57 additions & 4 deletions oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,19 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

/** Base type for credentials for authorizing calls to Google APIs using OAuth2. */
public class GoogleCredentials extends OAuth2Credentials {
public class GoogleCredentials extends OAuth2Credentials implements QuotaProjectIdProvider {

private static final long serialVersionUID = -1522852442442473691L;

static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project";
static final String USER_FILE_TYPE = "authorized_user";
static final String SERVICE_ACCOUNT_FILE_TYPE = "service_account";

protected final String quotaProjectId;
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved

private static final DefaultCredentialsProvider defaultCredentialsProvider =
new DefaultCredentialsProvider();

Expand Down Expand Up @@ -184,6 +187,20 @@ public static GoogleCredentials fromStream(
fileType, USER_FILE_TYPE, SERVICE_ACCOUNT_FILE_TYPE));
}

/**
* Creates a credential with quota project from environment if present
*
* @param environmentProvider a provider used to get environment values
* @return credential with quota project from envoronment
*/
public GoogleCredentials createWithQuotaProject(String quotaProject) {
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
if (quotaProject == null) {
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
return this;
}

return this.toBuilder().setQuotaProjectId(quotaProject).build();
}

/**
* Adds quota project ID to requestMetadata if present.
*
Expand All @@ -200,9 +217,23 @@ static Map<String, List<String>> addQuotaProjectIdToRequestMetadata(
return Collections.unmodifiableMap(newRequestMetadata);
}

@Override
protected Map<String, List<String>> getAdditionalHeaders() {
Map<String, List<String>> headers = super.getAdditionalHeaders();
if (quotaProjectId != null) {
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
return addQuotaProjectIdToRequestMetadata(this.quotaProjectId, headers);
}
return headers;
}

/** Default constructor. */
protected GoogleCredentials() {
this(null);
this(new Builder());
}

protected GoogleCredentials(AccessToken accessToken, String quotaProjectId) {
super(accessToken);
this.quotaProjectId = quotaProjectId;
}

/**
Expand All @@ -211,7 +242,12 @@ protected GoogleCredentials() {
* @param accessToken initial or temporary access token
*/
public GoogleCredentials(AccessToken accessToken) {
super(accessToken);
this(accessToken, null);
}

public GoogleCredentials(Builder builder) {
chingor13 marked this conversation as resolved.
Show resolved Hide resolved
super(builder.getAccessToken());
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
this.quotaProjectId = builder.getQuotaProjectId();
}

/**
Expand All @@ -222,6 +258,7 @@ public GoogleCredentials(AccessToken accessToken) {
protected GoogleCredentials(
AccessToken accessToken, Duration refreshMargin, Duration expirationMargin) {
super(accessToken, refreshMargin, expirationMargin);
this.quotaProjectId = null;
}

public static Builder newBuilder() {
Expand All @@ -232,6 +269,10 @@ public Builder toBuilder() {
return new Builder(this);
}

public String getQuotaProjectId() {
sai-sunder-s marked this conversation as resolved.
Show resolved Hide resolved
return this.quotaProjectId;
}

/**
* Indicates whether the credentials require scopes to be specified via a call to {@link
* GoogleCredentials#createScoped} before use.
Expand Down Expand Up @@ -300,14 +341,26 @@ public GoogleCredentials createDelegated(String user) {
}

public static class Builder extends OAuth2Credentials.Builder {
@Nullable protected String quotaProjectId;

protected Builder() {}

protected Builder(GoogleCredentials credentials) {
setAccessToken(credentials.getAccessToken());
this.quotaProjectId = credentials.quotaProjectId;
}

public GoogleCredentials build() {
return new GoogleCredentials(getAccessToken());
return new GoogleCredentials(this);
}

public Builder setQuotaProjectId(String quotaProjectId) {
this.quotaProjectId = quotaProjectId;
return this;
}

public String getQuotaProjectId() {
return this.quotaProjectId;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
* </pre>
*/
public class ImpersonatedCredentials extends GoogleCredentials
implements ServiceAccountSigner, IdTokenProvider, QuotaProjectIdProvider {
implements ServiceAccountSigner, IdTokenProvider {

private static final long serialVersionUID = -2133257318957488431L;
private static final String RFC3339 = "yyyy-MM-dd'T'HH:mm:ssX";
Expand All @@ -105,7 +105,6 @@ public class ImpersonatedCredentials extends GoogleCredentials
private List<String> delegates;
private List<String> scopes;
private int lifetime;
private String quotaProjectId;
private String iamEndpointOverride;
private final String transportFactoryClassName;

Expand Down Expand Up @@ -451,16 +450,8 @@ public ImpersonatedCredentials createWithCustomCalendar(Calendar calendar) {
.build();
}

@Override
protected Map<String, List<String>> getAdditionalHeaders() {
Map<String, List<String>> headers = super.getAdditionalHeaders();
if (quotaProjectId != null) {
return addQuotaProjectIdToRequestMetadata(quotaProjectId, headers);
}
return headers;
}

private ImpersonatedCredentials(Builder builder) {
super(builder);
this.sourceCredentials = builder.getSourceCredentials();
this.targetPrincipal = builder.getTargetPrincipal();
this.delegates = builder.getDelegates();
Expand All @@ -470,7 +461,6 @@ private ImpersonatedCredentials(Builder builder) {
firstNonNull(
builder.getHttpTransportFactory(),
getFromServiceLoader(HttpTransportFactory.class, OAuth2Utils.HTTP_TRANSPORT_FACTORY));
this.quotaProjectId = builder.quotaProjectId;
this.iamEndpointOverride = builder.iamEndpointOverride;
this.transportFactoryClassName = this.transportFactory.getClass().getName();
this.calendar = builder.getCalendar();
Expand Down Expand Up @@ -628,7 +618,6 @@ public static class Builder extends GoogleCredentials.Builder {
private List<String> scopes;
private int lifetime = DEFAULT_LIFETIME_IN_SECONDS;
private HttpTransportFactory transportFactory;
private String quotaProjectId;
private String iamEndpointOverride;
private Calendar calendar = Calendar.getInstance();

Expand Down Expand Up @@ -694,7 +683,7 @@ public HttpTransportFactory getHttpTransportFactory() {
}

public Builder setQuotaProjectId(String quotaProjectId) {
this.quotaProjectId = quotaProjectId;
super.setQuotaProjectId(quotaProjectId);
return this;
}

Expand Down
Loading