Skip to content

Commit 046ec89

Browse files
committed
feat: Introduce per-credential specific load methods
1 parent 84fc566 commit 046ec89

10 files changed

+192
-60
lines changed

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

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
package com.google.auth.oauth2;
3333

3434
import static com.google.auth.oauth2.OAuth2Utils.JSON_FACTORY;
35-
import static com.google.common.base.Preconditions.checkNotNull;
3635

3736
import com.google.api.client.http.GenericUrl;
3837
import com.google.api.client.http.HttpHeaders;
@@ -140,7 +139,6 @@ private ExternalAccountAuthorizedUserCredentials(Builder builder) {
140139
*/
141140
public static ExternalAccountAuthorizedUserCredentials fromStream(InputStream credentialsStream)
142141
throws IOException {
143-
checkNotNull(credentialsStream);
144142
return fromStream(credentialsStream, OAuth2Utils.HTTP_TRANSPORT_FACTORY);
145143
}
146144

@@ -162,17 +160,26 @@ public static ExternalAccountAuthorizedUserCredentials fromStream(InputStream cr
162160
*/
163161
public static ExternalAccountAuthorizedUserCredentials fromStream(
164162
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
165-
checkNotNull(credentialsStream);
166-
checkNotNull(transportFactory);
167-
168-
JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY);
169-
GenericJson fileContents =
170-
parser.parseAndClose(credentialsStream, StandardCharsets.UTF_8, GenericJson.class);
171-
try {
172-
return fromJson(fileContents, transportFactory);
173-
} catch (ClassCastException | IllegalArgumentException e) {
174-
throw new CredentialFormatException("Invalid input stream provided.", e);
163+
GenericJson fileContents = parseJsonInputStream(credentialsStream, transportFactory);
164+
String fileType = (String) fileContents.get("type");
165+
if (fileType == null) {
166+
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
167+
}
168+
if (fileType.equals(
169+
GoogleCredentialsInfo.EXTERNAL_ACCOUNT_AUTHORIZED_USER_CREDENTIALS.getFileType())) {
170+
try {
171+
return fromJson(fileContents, transportFactory);
172+
} catch (ClassCastException | IllegalArgumentException e) {
173+
throw new CredentialFormatException("Invalid input stream provided.", e);
174+
}
175175
}
176+
177+
throw new IOException(
178+
String.format(
179+
"Error reading credentials from stream, 'type' value '%s' not recognized."
180+
+ " Expecting '%s'.",
181+
fileType,
182+
GoogleCredentialsInfo.EXTERNAL_ACCOUNT_AUTHORIZED_USER_CREDENTIALS.getFileType()));
176183
}
177184

178185
@Override

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
import com.google.api.client.http.HttpHeaders;
3737
import com.google.api.client.json.GenericJson;
38-
import com.google.api.client.json.JsonObjectParser;
3938
import com.google.api.client.util.Data;
4039
import com.google.auth.RequestMetadataCallback;
4140
import com.google.auth.http.HttpTransportFactory;
@@ -46,7 +45,6 @@
4645
import java.io.ObjectInputStream;
4746
import java.math.BigDecimal;
4847
import java.net.URI;
49-
import java.nio.charset.StandardCharsets;
5048
import java.util.ArrayList;
5149
import java.util.Collection;
5250
import java.util.Collections;
@@ -387,17 +385,24 @@ public static ExternalAccountCredentials fromStream(InputStream credentialsStrea
387385
*/
388386
public static ExternalAccountCredentials fromStream(
389387
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
390-
checkNotNull(credentialsStream);
391-
checkNotNull(transportFactory);
392-
393-
JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY);
394-
GenericJson fileContents =
395-
parser.parseAndClose(credentialsStream, StandardCharsets.UTF_8, GenericJson.class);
396-
try {
397-
return fromJson(fileContents, transportFactory);
398-
} catch (ClassCastException | IllegalArgumentException e) {
399-
throw new CredentialFormatException("An invalid input stream was provided.", e);
388+
GenericJson fileContents = parseJsonInputStream(credentialsStream, transportFactory);
389+
String fileType = (String) fileContents.get("type");
390+
if (fileType == null) {
391+
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
400392
}
393+
if (fileType.equals(GoogleCredentialsInfo.EXTERNAL_ACCOUNT_CREDENTIALS.getFileType())) {
394+
try {
395+
return fromJson(fileContents, transportFactory);
396+
} catch (ClassCastException | IllegalArgumentException e) {
397+
throw new CredentialFormatException("An invalid input stream was provided.", e);
398+
}
399+
}
400+
401+
throw new IOException(
402+
String.format(
403+
"Error reading credentials from stream, 'type' value '%s' not recognized."
404+
+ " Expecting '%s'.",
405+
fileType, GoogleCredentialsInfo.EXTERNAL_ACCOUNT_CREDENTIALS.getFileType()));
401406
}
402407

403408
/**
@@ -417,9 +422,6 @@ public static ExternalAccountCredentials fromStream(
417422
@SuppressWarnings("unchecked")
418423
static ExternalAccountCredentials fromJson(
419424
Map<String, Object> json, HttpTransportFactory transportFactory) {
420-
checkNotNull(json);
421-
checkNotNull(transportFactory);
422-
423425
String audience = (String) json.get("audience");
424426
String subjectTokenType = (String) json.get("subject_token_type");
425427
String tokenUrl = (String) json.get("token_url");

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.google.api.client.http.HttpTransport;
4040
import com.google.api.client.http.UrlEncodedContent;
4141
import com.google.api.client.http.javanet.NetHttpTransport;
42+
import com.google.api.client.json.GenericJson;
4243
import com.google.api.client.json.JsonFactory;
4344
import com.google.api.client.json.JsonObjectParser;
4445
import com.google.api.client.json.webtoken.JsonWebSignature;
@@ -99,6 +100,60 @@ public class GdchCredentials extends GoogleCredentials {
99100
this.name = GoogleCredentialsInfo.GDCH_CREDENTIALS.getCredentialName();
100101
}
101102

103+
/**
104+
* Returns credentials defined by a GDCHCredential key file in JSON format from the Google
105+
* Developers Console.
106+
*
107+
* <p>Important: If you accept a credential configuration (credential JSON/File/Stream) from an
108+
* external source for authentication to Google Cloud Platform, you must validate it before
109+
* providing it to any Google API or library. Providing an unvalidated credential configuration to
110+
* Google APIs can compromise the security of your systems and data. For more information, refer
111+
* to {@see <a
112+
* href="https://cloud.google.com/docs/authentication/external/externally-sourced-credentials">documentation</a>}.
113+
*
114+
* @param credentialsStream the stream with the credential definition.
115+
* @return the credential defined by the credentialsStream.
116+
* @throws IOException if the credential cannot be created from the stream.
117+
*/
118+
public static GdchCredentials fromStream(InputStream credentialsStream) throws IOException {
119+
return fromStream(credentialsStream, OAuth2Utils.HTTP_TRANSPORT_FACTORY);
120+
}
121+
122+
/**
123+
* Returns credentials defined by a GDCHCredential key file in JSON format from the Google
124+
* Developers Console.
125+
*
126+
* <p>Important: If you accept a credential configuration (credential JSON/File/Stream) from an
127+
* external source for authentication to Google Cloud Platform, you must validate it before
128+
* providing it to any Google API or library. Providing an unvalidated credential configuration to
129+
* Google APIs can compromise the security of your systems and data. For more information, refer
130+
* to {@see <a
131+
* href="https://cloud.google.com/docs/authentication/external/externally-sourced-credentials">documentation</a>}.
132+
*
133+
* @param credentialsStream the stream with the credential definition.
134+
* @param transportFactory HTTP transport factory, creates the transport used to get access
135+
* tokens.
136+
* @return the credential defined by the credentialsStream.
137+
* @throws IOException if the credential cannot be created from the stream.
138+
*/
139+
public static GdchCredentials fromStream(
140+
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
141+
GenericJson fileContents = parseJsonInputStream(credentialsStream, transportFactory);
142+
String fileType = (String) fileContents.get("type");
143+
if (fileType == null) {
144+
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
145+
}
146+
if (fileType.equals(GoogleCredentialsInfo.GDCH_CREDENTIALS.getFileType())) {
147+
return fromJson(fileContents, transportFactory);
148+
}
149+
150+
throw new IOException(
151+
String.format(
152+
"Error reading credentials from stream, 'type' value '%s' not recognized."
153+
+ " Expecting '%s'.",
154+
fileType, GoogleCredentialsInfo.GDCH_CREDENTIALS.getFileType()));
155+
}
156+
102157
/**
103158
* Create GDCH service account credentials defined by JSON.
104159
*

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,16 @@ public static GoogleCredentials fromStream(InputStream credentialsStream) throws
235235
return fromStream(credentialsStream, OAuth2Utils.HTTP_TRANSPORT_FACTORY);
236236
}
237237

238+
static GenericJson parseJsonInputStream(
239+
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
240+
Preconditions.checkNotNull(credentialsStream);
241+
Preconditions.checkNotNull(transportFactory);
242+
243+
JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY;
244+
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
245+
return parser.parseAndClose(credentialsStream, StandardCharsets.UTF_8, GenericJson.class);
246+
}
247+
238248
/**
239249
* This method is obsolete because of a potential security risk. Use the credential specific load
240250
* method instead
@@ -276,14 +286,7 @@ public static GoogleCredentials fromStream(InputStream credentialsStream) throws
276286
"This method is obsolete because of a potential security risk. Use the credential specific load method instead")
277287
public static GoogleCredentials fromStream(
278288
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
279-
Preconditions.checkNotNull(credentialsStream);
280-
Preconditions.checkNotNull(transportFactory);
281-
282-
JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY;
283-
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
284-
GenericJson fileContents =
285-
parser.parseAndClose(credentialsStream, StandardCharsets.UTF_8, GenericJson.class);
286-
289+
GenericJson fileContents = parseJsonInputStream(credentialsStream, transportFactory);
287290
String fileType = (String) fileContents.get("type");
288291
if (fileType == null) {
289292
throw new IOException("Error reading credentials from stream, 'type' field not specified.");

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

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.google.api.client.http.HttpResponse;
4242
import com.google.api.client.http.HttpTransport;
4343
import com.google.api.client.http.json.JsonHttpContent;
44+
import com.google.api.client.json.GenericJson;
4445
import com.google.api.client.json.JsonObjectParser;
4546
import com.google.api.client.util.GenericData;
4647
import com.google.auth.CredentialTypeForMetrics;
@@ -55,6 +56,7 @@
5556
import com.google.common.collect.ImmutableMap;
5657
import com.google.errorprone.annotations.CanIgnoreReturnValue;
5758
import java.io.IOException;
59+
import java.io.InputStream;
5860
import java.io.ObjectInputStream;
5961
import java.text.DateFormat;
6062
import java.text.ParseException;
@@ -360,6 +362,61 @@ public byte[] sign(byte[] toSign) {
360362
}
361363
}
362364

365+
/**
366+
* Returns credentials defined by a ImpersonatedCredential key file in JSON format from the Google
367+
* Developers Console.
368+
*
369+
* <p>Important: If you accept a credential configuration (credential JSON/File/Stream) from an
370+
* external source for authentication to Google Cloud Platform, you must validate it before
371+
* providing it to any Google API or library. Providing an unvalidated credential configuration to
372+
* Google APIs can compromise the security of your systems and data. For more information, refer
373+
* to {@see <a
374+
* href="https://cloud.google.com/docs/authentication/external/externally-sourced-credentials">documentation</a>}.
375+
*
376+
* @param credentialsStream the stream with the credential definition.
377+
* @return the credential defined by the credentialsStream.
378+
* @throws IOException if the credential cannot be created from the stream.
379+
*/
380+
public static ImpersonatedCredentials fromStream(InputStream credentialsStream)
381+
throws IOException {
382+
return fromStream(credentialsStream, OAuth2Utils.HTTP_TRANSPORT_FACTORY);
383+
}
384+
385+
/**
386+
* Returns credentials defined by a ImpersonatedCredential key file in JSON format from the Google
387+
* Developers Console.
388+
*
389+
* <p>Important: If you accept a credential configuration (credential JSON/File/Stream) from an
390+
* external source for authentication to Google Cloud Platform, you must validate it before
391+
* providing it to any Google API or library. Providing an unvalidated credential configuration to
392+
* Google APIs can compromise the security of your systems and data. For more information, refer
393+
* to {@see <a
394+
* href="https://cloud.google.com/docs/authentication/external/externally-sourced-credentials">documentation</a>}.
395+
*
396+
* @param credentialsStream the stream with the credential definition.
397+
* @param transportFactory HTTP transport factory, creates the transport used to get access
398+
* tokens.
399+
* @return the credential defined by the credentialsStream.
400+
* @throws IOException if the credential cannot be created from the stream.
401+
*/
402+
public static ImpersonatedCredentials fromStream(
403+
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
404+
GenericJson fileContents = parseJsonInputStream(credentialsStream, transportFactory);
405+
String fileType = (String) fileContents.get("type");
406+
if (fileType == null) {
407+
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
408+
}
409+
if (fileType.equals(GoogleCredentialsInfo.IMPERSONATED_CREDENTIALS.getFileType())) {
410+
return fromJson(fileContents, transportFactory);
411+
}
412+
413+
throw new IOException(
414+
String.format(
415+
"Error reading credentials from stream, 'type' value '%s' not recognized."
416+
+ " Expecting '%s'.",
417+
fileType, GoogleCredentialsInfo.IMPERSONATED_CREDENTIALS.getFileType()));
418+
}
419+
363420
/**
364421
* Returns impersonation account credentials defined by JSON using the format generated by gCloud.
365422
* The source credentials in the JSON should be either user account credentials or service account
@@ -380,7 +437,6 @@ public byte[] sign(byte[] toSign) {
380437
@SuppressWarnings("unchecked")
381438
static ImpersonatedCredentials fromJson(
382439
Map<String, Object> json, HttpTransportFactory transportFactory) throws IOException {
383-
384440
checkNotNull(json);
385441
checkNotNull(transportFactory);
386442

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.google.api.client.http.HttpResponse;
4444
import com.google.api.client.http.HttpResponseException;
4545
import com.google.api.client.http.UrlEncodedContent;
46+
import com.google.api.client.json.GenericJson;
4647
import com.google.api.client.json.JsonFactory;
4748
import com.google.api.client.json.JsonObjectParser;
4849
import com.google.api.client.json.webtoken.JsonWebSignature;
@@ -485,14 +486,20 @@ public static ServiceAccountCredentials fromStream(InputStream credentialsStream
485486
*/
486487
public static ServiceAccountCredentials fromStream(
487488
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
488-
ServiceAccountCredentials credential =
489-
(ServiceAccountCredentials)
490-
GoogleCredentials.fromStream(credentialsStream, transportFactory);
491-
if (credential == null) {
492-
throw new IOException(
493-
"Error reading credentials from stream, ServiceAccountCredentials type is not recognized.");
489+
GenericJson fileContents = parseJsonInputStream(credentialsStream, transportFactory);
490+
String fileType = (String) fileContents.get("type");
491+
if (fileType == null) {
492+
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
493+
}
494+
if (fileType.equals(GoogleCredentialsInfo.SERVICE_ACCOUNT_CREDENTIALS.getFileType())) {
495+
return fromJson(fileContents, transportFactory);
494496
}
495-
return credential;
497+
498+
throw new IOException(
499+
String.format(
500+
"Error reading credentials from stream, 'type' value '%s' not recognized."
501+
+ " Expecting '%s'.",
502+
fileType, GoogleCredentialsInfo.SERVICE_ACCOUNT_CREDENTIALS.getFileType()));
496503
}
497504

498505
/** Returns whether the scopes are empty, meaning createScoped must be called before use. */

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import com.google.api.client.http.HttpResponseException;
4242
import com.google.api.client.http.UrlEncodedContent;
4343
import com.google.api.client.json.GenericJson;
44-
import com.google.api.client.json.JsonFactory;
4544
import com.google.api.client.json.JsonObjectParser;
4645
import com.google.api.client.util.GenericData;
4746
import com.google.api.client.util.Preconditions;
@@ -173,19 +172,12 @@ public static UserCredentials fromStream(InputStream credentialsStream) throws I
173172
*/
174173
public static UserCredentials fromStream(
175174
InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException {
176-
Preconditions.checkNotNull(credentialsStream);
177-
Preconditions.checkNotNull(transportFactory);
178-
179-
JsonFactory jsonFactory = JSON_FACTORY;
180-
JsonObjectParser parser = new JsonObjectParser(jsonFactory);
181-
GenericJson fileContents =
182-
parser.parseAndClose(credentialsStream, StandardCharsets.UTF_8, GenericJson.class);
183-
175+
GenericJson fileContents = parseJsonInputStream(credentialsStream, transportFactory);
184176
String fileType = (String) fileContents.get("type");
185177
if (fileType == null) {
186178
throw new IOException("Error reading credentials from stream, 'type' field not specified.");
187179
}
188-
if (GoogleCredentialsInfo.USER_CREDENTIALS.getFileType().equals(fileType)) {
180+
if (fileType.equals(GoogleCredentialsInfo.USER_CREDENTIALS.getFileType())) {
189181
return fromJson(fileContents, transportFactory);
190182
}
191183
throw new IOException(

oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,8 @@ public void fromStream_allFields() throws IOException {
542542
@Test
543543
public void fromStream_minimumRequiredFieldsForRefresh() throws IOException {
544544
GenericJson json = new GenericJson();
545+
json.put(
546+
"type", GoogleCredentialsInfo.EXTERNAL_ACCOUNT_AUTHORIZED_USER_CREDENTIALS.getFileType());
545547
json.put("client_id", CLIENT_ID);
546548
json.put("client_secret", CLIENT_SECRET);
547549
json.put("refresh_token", REFRESH_TOKEN);
@@ -565,6 +567,8 @@ public void fromStream_minimumRequiredFieldsForRefresh() throws IOException {
565567
public void fromStream_accessTokenOnly_notSupported() throws IOException {
566568
GenericJson json = new GenericJson();
567569
json.put("access_token", ACCESS_TOKEN);
570+
json.put(
571+
"type", GoogleCredentialsInfo.EXTERNAL_ACCOUNT_AUTHORIZED_USER_CREDENTIALS.getFileType());
568572
try {
569573
ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json));
570574
fail("Should not be able to continue without exception.");

0 commit comments

Comments
 (0)