Skip to content

Commit a0c42a4

Browse files
foxxtrotneozwu
authored andcommitted
Allow ProjectId to be read from Service Account Configuration.
For Firebase, we are using the Service Account configuration file parsed by GoogleCredential to set many of the values needed. We wish to pull the ProjectId from the GoogleCredential, rather than requiring that developers supply it separately. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=121305912
1 parent ad19a36 commit a0c42a4

File tree

2 files changed

+80
-2
lines changed

2 files changed

+80
-2
lines changed

google-api-client/src/main/java/com/google/api/client/googleapis/auth/oauth2/GoogleCredential.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,11 @@ public static GoogleCredential fromStream(InputStream credentialStream, HttpTran
271271
*/
272272
private String serviceAccountId;
273273

274+
/**
275+
* Service account Project ID or {@code null} if not using the service account flow.
276+
*/
277+
private String serviceAccountProjectId;
278+
274279
/**
275280
* Collection of OAuth scopes to use with the service account flow or {@code null} if not
276281
* using the service account flow.
@@ -318,6 +323,7 @@ protected GoogleCredential(Builder builder) {
318323
&& builder.serviceAccountScopes == null && builder.serviceAccountUser == null);
319324
} else {
320325
serviceAccountId = Preconditions.checkNotNull(builder.serviceAccountId);
326+
serviceAccountProjectId = builder.serviceAccountProjectId;
321327
serviceAccountScopes = Collections.unmodifiableCollection(builder.serviceAccountScopes);
322328
serviceAccountPrivateKey = builder.serviceAccountPrivateKey;
323329
serviceAccountPrivateKeyId = builder.serviceAccountPrivateKeyId;
@@ -397,6 +403,13 @@ public final String getServiceAccountId() {
397403
return serviceAccountId;
398404
}
399405

406+
/**
407+
* Returns the service account Project ID or {@code null} if not using the service account flow.
408+
*/
409+
public final String getServiceAccountProjectId() {
410+
return serviceAccountProjectId;
411+
}
412+
400413
/**
401414
* Returns a collection of OAuth scopes to use with the service account flow or {@code null}
402415
* if not using the service account flow.
@@ -500,6 +513,9 @@ public static class Builder extends Credential.Builder {
500513
/** Id of the private key to use with the service account flow or {@code null} for none. */
501514
String serviceAccountPrivateKeyId;
502515

516+
/** Project Id associated with the Service Account */
517+
String serviceAccountProjectId;
518+
503519
/**
504520
* Email address of the user the application is trying to impersonate in the service account
505521
* flow or {@code null} for none.
@@ -582,6 +598,26 @@ public Builder setServiceAccountId(String serviceAccountId) {
582598
return this;
583599
}
584600

601+
/**
602+
* Returns the service account Project ID or {@code null} for none.
603+
*/
604+
public final String getServiceAccountProjectId() {
605+
return serviceAccountProjectId;
606+
}
607+
608+
/**
609+
* Sets the service account Project ID or {@code null} for none.
610+
*
611+
* <p>
612+
* Overriding is only supported for the purpose of calling the super implementation and changing
613+
* the return type, but nothing else.
614+
* </p>
615+
*/
616+
public Builder setServiceAccountProjectId(String serviceAccountProjectId) {
617+
this.serviceAccountProjectId = serviceAccountProjectId;
618+
return this;
619+
}
620+
585621
/**
586622
* Returns a collection of OAuth scopes to use with the service account flow or {@code null}
587623
* for none.
@@ -777,12 +813,15 @@ private static GoogleCredential fromStreamUser(GenericJson fileContents, HttpTra
777813
private static GoogleCredential fromStreamServiceAccount(GenericJson fileContents,
778814
HttpTransport transport, JsonFactory jsonFactory) throws IOException {
779815
String clientId = (String) fileContents.get("client_id");
816+
String projectId = (String) fileContents.get("project_id");
780817
String clientEmail = (String) fileContents.get("client_email");
781818
String privateKeyPem = (String) fileContents.get("private_key");
782819
String privateKeyId = (String) fileContents.get("private_key_id");
783-
if (clientId == null || clientEmail == null || privateKeyPem == null || privateKeyId == null) {
820+
if (clientId == null || projectId == null || clientEmail == null || privateKeyPem == null
821+
|| privateKeyId == null) {
784822
throw new IOException("Error reading service account credential from stream, "
785-
+ "expecting 'client_id', 'client_email', 'private_key' and 'private_key_id'.");
823+
+ "expecting 'client_id', 'project_id', 'client_email', 'private_key' and "
824+
+ "'private_key_id'.");
786825
}
787826

788827
PrivateKey privateKey = privateKeyFromPkcs8(privateKeyPem);

google-api-client/src/test/java/com/google/api/client/googleapis/auth/oauth2/GoogleCredentialTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ public void testFromStreamServiceAccount() throws IOException {
186186
"36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com";
187187
final String serviceAccountEmail =
188188
"36680232662-vrd7ji19qgchd0ah2csanun6bnr@developer.gserviceaccount.com";
189+
final String projectId = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr";
189190

190191
MockTokenServerTransport transport = new MockTokenServerTransport();
191192
transport.addServiceAccount(serviceAccountEmail, accessToken);
@@ -197,6 +198,7 @@ public void testFromStreamServiceAccount() throws IOException {
197198
serviceAccountContents.put("client_email", serviceAccountEmail);
198199
serviceAccountContents.put("private_key", SA_KEY_TEXT);
199200
serviceAccountContents.put("private_key_id", SA_KEY_ID);
201+
serviceAccountContents.put("project_id", projectId);
200202
serviceAccountContents.put("type", GoogleCredential.SERVICE_ACCOUNT_FILE_TYPE);
201203
String json = serviceAccountContents.toPrettyString();
202204
InputStream serviceAccountStream = new ByteArrayInputStream(json.getBytes());
@@ -216,6 +218,7 @@ public void testFromStreamServiceAccountAlternateTokenUri() throws IOException {
216218
"36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com";
217219
final String serviceAccountEmail =
218220
"36680232662-vrd7ji19qgchd0ah2csanun6bnr@developer.gserviceaccount.com";
221+
final String projectId = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr";
219222

220223
final String tokenServerUrl = "http://another.auth.com/token";
221224
MockTokenServerTransport transport = new MockTokenServerTransport(tokenServerUrl);
@@ -228,6 +231,7 @@ public void testFromStreamServiceAccountAlternateTokenUri() throws IOException {
228231
serviceAccountContents.put("client_email", serviceAccountEmail);
229232
serviceAccountContents.put("private_key", SA_KEY_TEXT);
230233
serviceAccountContents.put("private_key_id", SA_KEY_ID);
234+
serviceAccountContents.put("project_id", projectId);
231235
serviceAccountContents.put("type", GoogleCredential.SERVICE_ACCOUNT_FILE_TYPE);
232236
serviceAccountContents.put("token_uri", tokenServerUrl);
233237
String json = serviceAccountContents.toPrettyString();
@@ -247,6 +251,7 @@ public void testFromStreamServiceAccountAlternateTokenUri() throws IOException {
247251
public void testFromStreamServiceAccountMissingClientIdThrows() throws IOException {
248252
final String serviceAccountEmail =
249253
"36680232662-vrd7ji19qgchd0ah2csanun6bnr@developer.gserviceaccount.com";
254+
final String projectId = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr";
250255

251256
MockHttpTransport transport = new MockTokenServerTransport();
252257

@@ -256,6 +261,7 @@ public void testFromStreamServiceAccountMissingClientIdThrows() throws IOExcepti
256261
serviceAccountContents.put("client_email", serviceAccountEmail);
257262
serviceAccountContents.put("private_key", SA_KEY_TEXT);
258263
serviceAccountContents.put("private_key_id", SA_KEY_ID);
264+
serviceAccountContents.put("project_id", projectId);
259265
serviceAccountContents.put("type", GoogleCredential.SERVICE_ACCOUNT_FILE_TYPE);
260266
String json = serviceAccountContents.toPrettyString();
261267
InputStream serviceAccountStream = new ByteArrayInputStream(json.getBytes());
@@ -271,6 +277,7 @@ public void testFromStreamServiceAccountMissingClientIdThrows() throws IOExcepti
271277
public void testFromStreamServiceAccountMissingClientEmailThrows() throws IOException {
272278
final String serviceAccountId =
273279
"36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com";
280+
final String projectId = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr";
274281

275282
MockHttpTransport transport = new MockTokenServerTransport();
276283

@@ -280,6 +287,7 @@ public void testFromStreamServiceAccountMissingClientEmailThrows() throws IOExce
280287
serviceAccountContents.put("client_id", serviceAccountId);
281288
serviceAccountContents.put("private_key", SA_KEY_TEXT);
282289
serviceAccountContents.put("private_key_id", SA_KEY_ID);
290+
serviceAccountContents.put("project_id", projectId);
283291
serviceAccountContents.put("type", GoogleCredential.SERVICE_ACCOUNT_FILE_TYPE);
284292
String json = serviceAccountContents.toPrettyString();
285293
InputStream serviceAccountStream = new ByteArrayInputStream(json.getBytes());
@@ -297,6 +305,7 @@ public void testFromStreamServiceAccountMissingPrivateKeyThrows() throws IOExcep
297305
"36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com";
298306
final String serviceAccountEmail =
299307
"36680232662-vrd7ji19qgchd0ah2csanun6bnr@developer.gserviceaccount.com";
308+
final String projectId = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr";
300309

301310
MockHttpTransport transport = new MockTokenServerTransport();
302311

@@ -306,6 +315,7 @@ public void testFromStreamServiceAccountMissingPrivateKeyThrows() throws IOExcep
306315
serviceAccountContents.put("client_id", serviceAccountId);
307316
serviceAccountContents.put("client_email", serviceAccountEmail);
308317
serviceAccountContents.put("private_key_id", SA_KEY_ID);
318+
serviceAccountContents.put("project_id", projectId);
309319
serviceAccountContents.put("type", GoogleCredential.SERVICE_ACCOUNT_FILE_TYPE);
310320
String json = serviceAccountContents.toPrettyString();
311321
InputStream serviceAccountStream = new ByteArrayInputStream(json.getBytes());
@@ -323,6 +333,7 @@ public void testFromStreamServiceAccountMissingPrivateKeyIdThrows() throws IOExc
323333
"36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com";
324334
final String serviceAccountEmail =
325335
"36680232662-vrd7ji19qgchd0ah2csanun6bnr@developer.gserviceaccount.com";
336+
final String projectId = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr";
326337

327338
MockHttpTransport transport = new MockTokenServerTransport();
328339

@@ -332,6 +343,7 @@ public void testFromStreamServiceAccountMissingPrivateKeyIdThrows() throws IOExc
332343
serviceAccountContents.put("client_id", serviceAccountId);
333344
serviceAccountContents.put("client_email", serviceAccountEmail);
334345
serviceAccountContents.put("private_key", SA_KEY_TEXT);
346+
serviceAccountContents.put("project_id", projectId);
335347
serviceAccountContents.put("type", GoogleCredential.SERVICE_ACCOUNT_FILE_TYPE);
336348
String json = serviceAccountContents.toPrettyString();
337349
InputStream serviceAccountStream = new ByteArrayInputStream(json.getBytes());
@@ -344,6 +356,33 @@ public void testFromStreamServiceAccountMissingPrivateKeyIdThrows() throws IOExc
344356
}
345357
}
346358

359+
public void testFromStreamServiceAccountMissingProjectIdThrows() throws IOException {
360+
final String serviceAccountId =
361+
"36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com";
362+
final String serviceAccountEmail =
363+
"36680232662-vrd7ji19qgchd0ah2csanun6bnr@developer.gserviceaccount.com";
364+
365+
MockHttpTransport transport = new MockTokenServerTransport();
366+
367+
// Write out user file
368+
GenericJson serviceAccountContents = new GenericJson();
369+
serviceAccountContents.setFactory(JSON_FACTORY);
370+
serviceAccountContents.put("client_id", serviceAccountId);
371+
serviceAccountContents.put("client_email", serviceAccountEmail);
372+
serviceAccountContents.put("private_key", SA_KEY_TEXT);
373+
serviceAccountContents.put("private_key_id", SA_KEY_ID);
374+
serviceAccountContents.put("type", GoogleCredential.SERVICE_ACCOUNT_FILE_TYPE);
375+
String json = serviceAccountContents.toPrettyString();
376+
InputStream serviceAccountStream = new ByteArrayInputStream(json.getBytes());
377+
378+
try {
379+
GoogleCredential.fromStream(serviceAccountStream, transport, JSON_FACTORY);
380+
fail();
381+
} catch (IOException expected) {
382+
assertTrue(expected.getMessage().contains("project_id"));
383+
}
384+
}
385+
347386
public void testFromStreamUser() throws IOException {
348387
final String accessToken = "1/MkSJoj1xsli0AccessToken_NKPY2";
349388
final String clientSecret = "jakuaL9YyieakhECKL2SwZcu";

0 commit comments

Comments
 (0)