Skip to content

Commit 040acef

Browse files
authored
feat: Introduce Environment Variable for Quota Project Id (#1082)
* feat: Introduce Environment Variable for Quota Project Id * add back constructr * move env logic to GoogleCredentials * static to non-static * EnvironmentProvider in builder * move env logic back to adc * null check * add functional test * Adding env var to cfg * Adding env var to cfg * clean up cfgs * clirr exemption and builder constructor * lint * update classname * clean up * formatting * updating tests * fix fn test * copyright 2022 * add back a FT * allow null quota project * update javadoc * nits
1 parent 517e450 commit 040acef

12 files changed

+221
-117
lines changed

.kokoro/nightly/integration.cfg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,8 @@ env_vars: {
4545
key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES"
4646
value: "1"
4747
}
48+
49+
env_vars: {
50+
key: "GOOGLE_CLOUD_QUOTA_PROJECT"
51+
value: "gcloud-devel"
52+
}

.kokoro/presubmit/integration.cfg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,8 @@ env_vars: {
4141
key: "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES"
4242
value: "1"
4343
}
44+
45+
env_vars: {
46+
key: "GOOGLE_CLOUD_QUOTA_PROJECT"
47+
value: "gcloud-devel"
48+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!-- see http://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
3+
<differences>
4+
<difference>
5+
<differenceType>6001</differenceType>
6+
<className>com/google/auth/oauth2/ExternalAccountCredentials$Builder</className>
7+
<field>quotaProjectId</field>
8+
</difference>
9+
</differences>

oauth2_http/java/com/google/auth/oauth2/DefaultCredentialsProvider.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@
5353
* overriding the state and environment for testing purposes.
5454
*/
5555
class DefaultCredentialsProvider {
56+
5657
static final DefaultCredentialsProvider DEFAULT = new DefaultCredentialsProvider();
5758
static final String CREDENTIAL_ENV_VAR = "GOOGLE_APPLICATION_CREDENTIALS";
59+
static final String QUOTA_PROJECT_ENV_VAR = "GOOGLE_CLOUD_QUOTA_PROJECT";
60+
5861
static final String WELL_KNOWN_CREDENTIALS_FILE = "application_default_credentials.json";
5962
static final String CLOUDSDK_CONFIG_DIRECTORY = "gcloud";
6063
static final String HELP_PERMALINK =
@@ -214,6 +217,14 @@ private final GoogleCredentials getDefaultCredentialsUnsynchronized(
214217
credentials = tryGetComputeCredentials(transportFactory);
215218
}
216219

220+
if (credentials != null) {
221+
String quotaFromEnv = getEnv(QUOTA_PROJECT_ENV_VAR);
222+
223+
if (quotaFromEnv != null && quotaFromEnv.trim().length() > 0) {
224+
credentials = credentials.createWithQuotaProject(quotaFromEnv);
225+
}
226+
}
227+
217228
return credentials;
218229
}
219230

oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@
6464
* <p>Handles initializing external credentials, calls to the Security Token Service, and service
6565
* account impersonation.
6666
*/
67-
public abstract class ExternalAccountCredentials extends GoogleCredentials
68-
implements QuotaProjectIdProvider {
67+
public abstract class ExternalAccountCredentials extends GoogleCredentials {
6968

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

9291
@Nullable private final String tokenInfoUrl;
9392
@Nullable private final String serviceAccountImpersonationUrl;
94-
@Nullable private final String quotaProjectId;
9593
@Nullable private final String clientId;
9694
@Nullable private final String clientSecret;
9795

@@ -194,6 +192,7 @@ protected ExternalAccountCredentials(
194192
@Nullable String clientSecret,
195193
@Nullable Collection<String> scopes,
196194
@Nullable EnvironmentProvider environmentProvider) {
195+
super(/* accessToken= */ null, quotaProjectId);
197196
this.transportFactory =
198197
MoreObjects.firstNonNull(
199198
transportFactory,
@@ -205,7 +204,6 @@ protected ExternalAccountCredentials(
205204
this.credentialSource = checkNotNull(credentialSource);
206205
this.tokenInfoUrl = tokenInfoUrl;
207206
this.serviceAccountImpersonationUrl = serviceAccountImpersonationUrl;
208-
this.quotaProjectId = quotaProjectId;
209207
this.clientId = clientId;
210208
this.clientSecret = clientSecret;
211209
this.scopes =
@@ -231,6 +229,7 @@ protected ExternalAccountCredentials(
231229
* @param builder the {@code Builder} object used to construct the credentials.
232230
*/
233231
protected ExternalAccountCredentials(ExternalAccountCredentials.Builder builder) {
232+
super(builder);
234233
this.transportFactory =
235234
MoreObjects.firstNonNull(
236235
builder.transportFactory,
@@ -242,7 +241,6 @@ protected ExternalAccountCredentials(ExternalAccountCredentials.Builder builder)
242241
this.credentialSource = checkNotNull(builder.credentialSource);
243242
this.tokenInfoUrl = builder.tokenInfoUrl;
244243
this.serviceAccountImpersonationUrl = builder.serviceAccountImpersonationUrl;
245-
this.quotaProjectId = builder.quotaProjectId;
246244
this.clientId = builder.clientId;
247245
this.clientSecret = builder.clientSecret;
248246
this.scopes =
@@ -550,12 +548,6 @@ public String getServiceAccountEmail() {
550548
return ImpersonatedCredentials.extractTargetPrincipal(serviceAccountImpersonationUrl);
551549
}
552550

553-
@Override
554-
@Nullable
555-
public String getQuotaProjectId() {
556-
return quotaProjectId;
557-
}
558-
559551
@Nullable
560552
public String getClientId() {
561553
return clientId;
@@ -721,7 +713,6 @@ public abstract static class Builder extends GoogleCredentials.Builder {
721713
protected HttpTransportFactory transportFactory;
722714

723715
@Nullable protected String serviceAccountImpersonationUrl;
724-
@Nullable protected String quotaProjectId;
725716
@Nullable protected String clientId;
726717
@Nullable protected String clientSecret;
727718
@Nullable protected Collection<String> scopes;
@@ -731,14 +722,14 @@ public abstract static class Builder extends GoogleCredentials.Builder {
731722
protected Builder() {}
732723

733724
protected Builder(ExternalAccountCredentials credentials) {
725+
super(credentials);
734726
this.transportFactory = credentials.transportFactory;
735727
this.audience = credentials.audience;
736728
this.subjectTokenType = credentials.subjectTokenType;
737729
this.tokenUrl = credentials.tokenUrl;
738730
this.tokenInfoUrl = credentials.tokenInfoUrl;
739731
this.serviceAccountImpersonationUrl = credentials.serviceAccountImpersonationUrl;
740732
this.credentialSource = credentials.credentialSource;
741-
this.quotaProjectId = credentials.quotaProjectId;
742733
this.clientId = credentials.clientId;
743734
this.clientSecret = credentials.clientSecret;
744735
this.scopes = credentials.scopes;
@@ -836,7 +827,7 @@ public Builder setTokenInfoUrl(String tokenInfoUrl) {
836827
* @return this {@code Builder} object
837828
*/
838829
public Builder setQuotaProjectId(String quotaProjectId) {
839-
this.quotaProjectId = quotaProjectId;
830+
super.setQuotaProjectId(quotaProjectId);
840831
return this;
841832
}
842833

oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,19 @@
4646
import java.util.HashMap;
4747
import java.util.List;
4848
import java.util.Map;
49+
import javax.annotation.Nullable;
4950

5051
/** Base type for credentials for authorizing calls to Google APIs using OAuth2. */
51-
public class GoogleCredentials extends OAuth2Credentials {
52+
public class GoogleCredentials extends OAuth2Credentials implements QuotaProjectIdProvider {
5253

5354
private static final long serialVersionUID = -1522852442442473691L;
5455

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

60+
protected final String quotaProjectId;
61+
5962
private static final DefaultCredentialsProvider defaultCredentialsProvider =
6063
new DefaultCredentialsProvider();
6164

@@ -184,6 +187,16 @@ public static GoogleCredentials fromStream(
184187
fileType, USER_FILE_TYPE, SERVICE_ACCOUNT_FILE_TYPE));
185188
}
186189

190+
/**
191+
* Creates a credential with the provided quota project.
192+
*
193+
* @param quotaProject the quota project to set on the credential
194+
* @return credential with the provided quota project
195+
*/
196+
public GoogleCredentials createWithQuotaProject(String quotaProject) {
197+
return this.toBuilder().setQuotaProjectId(quotaProject).build();
198+
}
199+
187200
/**
188201
* Adds quota project ID to requestMetadata if present.
189202
*
@@ -200,9 +213,24 @@ static Map<String, List<String>> addQuotaProjectIdToRequestMetadata(
200213
return Collections.unmodifiableMap(newRequestMetadata);
201214
}
202215

216+
@Override
217+
protected Map<String, List<String>> getAdditionalHeaders() {
218+
Map<String, List<String>> headers = super.getAdditionalHeaders();
219+
String quotaProjectId = this.getQuotaProjectId();
220+
if (quotaProjectId != null) {
221+
return addQuotaProjectIdToRequestMetadata(quotaProjectId, headers);
222+
}
223+
return headers;
224+
}
225+
203226
/** Default constructor. */
204227
protected GoogleCredentials() {
205-
this(null);
228+
this(new Builder());
229+
}
230+
231+
protected GoogleCredentials(AccessToken accessToken, String quotaProjectId) {
232+
super(accessToken);
233+
this.quotaProjectId = quotaProjectId;
206234
}
207235

208236
/**
@@ -211,7 +239,11 @@ protected GoogleCredentials() {
211239
* @param accessToken initial or temporary access token
212240
*/
213241
public GoogleCredentials(AccessToken accessToken) {
214-
super(accessToken);
242+
this(accessToken, null);
243+
}
244+
245+
protected GoogleCredentials(Builder builder) {
246+
this(builder.getAccessToken(), builder.getQuotaProjectId());
215247
}
216248

217249
/**
@@ -222,6 +254,7 @@ public GoogleCredentials(AccessToken accessToken) {
222254
protected GoogleCredentials(
223255
AccessToken accessToken, Duration refreshMargin, Duration expirationMargin) {
224256
super(accessToken, refreshMargin, expirationMargin);
257+
this.quotaProjectId = null;
225258
}
226259

227260
public static Builder newBuilder() {
@@ -232,6 +265,11 @@ public Builder toBuilder() {
232265
return new Builder(this);
233266
}
234267

268+
@Override
269+
public String getQuotaProjectId() {
270+
return this.quotaProjectId;
271+
}
272+
235273
/**
236274
* Indicates whether the credentials require scopes to be specified via a call to {@link
237275
* GoogleCredentials#createScoped} before use.
@@ -300,14 +338,26 @@ public GoogleCredentials createDelegated(String user) {
300338
}
301339

302340
public static class Builder extends OAuth2Credentials.Builder {
341+
@Nullable protected String quotaProjectId;
342+
303343
protected Builder() {}
304344

305345
protected Builder(GoogleCredentials credentials) {
306346
setAccessToken(credentials.getAccessToken());
347+
this.quotaProjectId = credentials.quotaProjectId;
307348
}
308349

309350
public GoogleCredentials build() {
310-
return new GoogleCredentials(getAccessToken());
351+
return new GoogleCredentials(this);
352+
}
353+
354+
public Builder setQuotaProjectId(String quotaProjectId) {
355+
this.quotaProjectId = quotaProjectId;
356+
return this;
357+
}
358+
359+
public String getQuotaProjectId() {
360+
return this.quotaProjectId;
311361
}
312362

313363
@Override

oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
* </pre>
9090
*/
9191
public class ImpersonatedCredentials extends GoogleCredentials
92-
implements ServiceAccountSigner, IdTokenProvider, QuotaProjectIdProvider {
92+
implements ServiceAccountSigner, IdTokenProvider {
9393

9494
private static final long serialVersionUID = -2133257318957488431L;
9595
private static final String RFC3339 = "yyyy-MM-dd'T'HH:mm:ssX";
@@ -105,7 +105,6 @@ public class ImpersonatedCredentials extends GoogleCredentials
105105
private List<String> delegates;
106106
private List<String> scopes;
107107
private int lifetime;
108-
private String quotaProjectId;
109108
private String iamEndpointOverride;
110109
private final String transportFactoryClassName;
111110

@@ -304,11 +303,6 @@ public String getAccount() {
304303
return this.targetPrincipal;
305304
}
306305

307-
@Override
308-
public String getQuotaProjectId() {
309-
return this.quotaProjectId;
310-
}
311-
312306
@VisibleForTesting
313307
String getIamEndpointOverride() {
314308
return this.iamEndpointOverride;
@@ -451,16 +445,8 @@ public ImpersonatedCredentials createWithCustomCalendar(Calendar calendar) {
451445
.build();
452446
}
453447

454-
@Override
455-
protected Map<String, List<String>> getAdditionalHeaders() {
456-
Map<String, List<String>> headers = super.getAdditionalHeaders();
457-
if (quotaProjectId != null) {
458-
return addQuotaProjectIdToRequestMetadata(quotaProjectId, headers);
459-
}
460-
return headers;
461-
}
462-
463448
private ImpersonatedCredentials(Builder builder) {
449+
super(builder);
464450
this.sourceCredentials = builder.getSourceCredentials();
465451
this.targetPrincipal = builder.getTargetPrincipal();
466452
this.delegates = builder.getDelegates();
@@ -470,7 +456,6 @@ private ImpersonatedCredentials(Builder builder) {
470456
firstNonNull(
471457
builder.getHttpTransportFactory(),
472458
getFromServiceLoader(HttpTransportFactory.class, OAuth2Utils.HTTP_TRANSPORT_FACTORY));
473-
this.quotaProjectId = builder.quotaProjectId;
474459
this.iamEndpointOverride = builder.iamEndpointOverride;
475460
this.transportFactoryClassName = this.transportFactory.getClass().getName();
476461
this.calendar = builder.getCalendar();
@@ -628,7 +613,6 @@ public static class Builder extends GoogleCredentials.Builder {
628613
private List<String> scopes;
629614
private int lifetime = DEFAULT_LIFETIME_IN_SECONDS;
630615
private HttpTransportFactory transportFactory;
631-
private String quotaProjectId;
632616
private String iamEndpointOverride;
633617
private Calendar calendar = Calendar.getInstance();
634618

@@ -694,7 +678,7 @@ public HttpTransportFactory getHttpTransportFactory() {
694678
}
695679

696680
public Builder setQuotaProjectId(String quotaProjectId) {
697-
this.quotaProjectId = quotaProjectId;
681+
super.setQuotaProjectId(quotaProjectId);
698682
return this;
699683
}
700684

0 commit comments

Comments
 (0)