Skip to content

Commit b951fa6

Browse files
committed
Handle optional fields with null JSON value gracefully
1 parent 4507cf9 commit b951fa6

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.google.api.client.http.HttpHeaders;
3737
import com.google.api.client.json.GenericJson;
3838
import com.google.api.client.json.JsonObjectParser;
39+
import com.google.api.client.util.Data;
3940
import com.google.auth.RequestMetadataCallback;
4041
import com.google.auth.http.HttpTransportFactory;
4142
import com.google.common.base.MoreObjects;
@@ -418,15 +419,15 @@ static ExternalAccountCredentials fromJson(
418419
Map<String, Object> credentialSourceMap = (Map<String, Object>) json.get("credential_source");
419420

420421
// Optional params.
421-
String serviceAccountImpersonationUrl = (String) json.get("service_account_impersonation_url");
422-
String tokenInfoUrl = (String) json.get("token_info_url");
423-
String clientId = (String) json.get("client_id");
424-
String clientSecret = (String) json.get("client_secret");
425-
String quotaProjectId = (String) json.get("quota_project_id");
426-
String userProject = (String) json.get("workforce_pool_user_project");
427-
String universeDomain = (String) json.get("universe_domain");
422+
String serviceAccountImpersonationUrl = getOptional(json, "service_account_impersonation_url", String.class);
423+
String tokenInfoUrl = getOptional(json, "token_info_url", String.class);
424+
String clientId = getOptional(json, "client_id", String.class);
425+
String clientSecret = getOptional(json, "client_secret", String.class);
426+
String quotaProjectId = getOptional(json, "quota_project_id", String.class);
427+
String userProject = getOptional(json, "workforce_pool_user_project", String.class);
428+
String universeDomain = getOptional(json, "universe_domain", String.class);
428429
Map<String, Object> impersonationOptionsMap =
429-
(Map<String, Object>) json.get("service_account_impersonation");
430+
getOptional(json, "service_account_impersonation", Map.class);
430431

431432
if (impersonationOptionsMap == null) {
432433
impersonationOptionsMap = new HashMap<String, Object>();
@@ -481,6 +482,14 @@ static ExternalAccountCredentials fromJson(
481482
.build();
482483
}
483484

485+
private static <T> T getOptional(Map<String, Object> json, String fieldName, Class<T> clazz) {
486+
Object value = json.get(fieldName);
487+
if (value == null || Data.isNull(value)) {
488+
return null;
489+
}
490+
return clazz.cast(value);
491+
}
492+
484493
private static boolean isPluggableAuthCredential(Map<String, Object> credentialSource) {
485494
// Pluggable Auth is enabled via a nested executable field in the credential source.
486495
return credentialSource.containsKey(EXECUTABLE_SOURCE_KEY);

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,19 @@ public void fromStream_nullTransport_throws() throws IOException {
148148
}
149149
}
150150

151+
@Test
152+
public void fromStream_nullOptionalField() throws IOException {
153+
ExternalAccountCredentials credentials = ExternalAccountCredentials.fromStream(
154+
new ByteArrayInputStream(("{" +
155+
"\"service_account_impersonation_url\": null," +
156+
//required
157+
"\"audience\": \"audience\"," +
158+
"\"subject_token_type\": \"subjectTokenType\"," +
159+
"\"credential_source\": {\"file\":\"file\"}" +
160+
"}").getBytes()));
161+
assertNull(credentials.getServiceAccountImpersonationUrl());
162+
}
163+
151164
@Test
152165
public void fromStream_nullStream_throws() throws IOException {
153166
try {

0 commit comments

Comments
 (0)