From cc39e0b87019e084ec5adb1318564bad2e846f06 Mon Sep 17 00:00:00 2001 From: anish k Date: Fri, 24 Apr 2026 00:53:43 +0000 Subject: [PATCH 1/2] fix(auth): handle null APPDATA environment variable in GoogleAuthUtils.getWellKnownCredentialsFile In `GoogleAuthUtils.getWellKnownCredentialsFile()`, on Windows systems where `CLOUDSDK_CONFIG` is unset, the code calls `provider.getEnv("APPDATA")` and passes the result directly to `new File(String)`. When `APPDATA` is not present in the environment, `getEnv()` returns `null`, and `new File(null)` immediately throws a raw `NullPointerException` with no useful context. Signed-off-by: anish k --- .../google/auth/oauth2/GoogleAuthUtils.java | 11 ++++++++++- .../auth/oauth2/GoogleAuthUtilsTest.java | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java index d82548a082fd..aab851c80f16 100644 --- a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java +++ b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java @@ -32,6 +32,8 @@ package com.google.auth.oauth2; import java.io.File; +import java.io.FileNotFoundException; +import java.io.UncheckedIOException; /** * This public class provides shared utilities for common OAuth2 utils or ADC. It also exposes @@ -70,7 +72,14 @@ static final File getWellKnownCredentialsFile(DefaultCredentialsProvider provide if (envPath != null) { cloudConfigPath = new File(envPath); } else if (provider.getOsName().indexOf("windows") >= 0) { - File appDataPath = new File(provider.getEnv("APPDATA")); + String appDataEnv = provider.getEnv("APPDATA"); + if (appDataEnv == null) { + throw new UncheckedIOException( + new FileNotFoundException( + "APPDATA environment variable is not set; cannot locate the well-known" + + " credentials file on Windows.")); + } + File appDataPath = new File(appDataEnv); cloudConfigPath = new File(appDataPath, provider.CLOUDSDK_CONFIG_DIRECTORY); } else { File configPath = new File(provider.getProperty("user.home", ""), ".config"); diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java index de7077ef6277..4ced1118d7ad 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java @@ -33,12 +33,31 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; +import java.io.FileNotFoundException; +import java.io.UncheckedIOException; import org.junit.jupiter.api.Test; class GoogleAuthUtilsTest { + @Test + void getWellKnownCredentialsFile_windows_nullAppData_throwsUncheckedIOException() { + DefaultCredentialsProviderTest.TestDefaultCredentialsProvider provider = + new DefaultCredentialsProviderTest.TestDefaultCredentialsProvider(); + provider.setProperty("os.name", "windows"); + // APPDATA is intentionally not set, so getEnv("APPDATA") returns null + + UncheckedIOException thrown = + assertThrows( + UncheckedIOException.class, + () -> GoogleAuthUtils.getWellKnownCredentialsFile(provider)); + assertTrue(thrown.getCause() instanceof FileNotFoundException); + assertTrue(thrown.getCause().getMessage().contains("APPDATA")); + } + @Test void getWellKnownCredentialsPath_correct() { DefaultCredentialsProvider provider = From a5ed2408c87e51d4d015f70e8e36d09e8a0e5adf Mon Sep 17 00:00:00 2001 From: anish k Date: Fri, 24 Apr 2026 01:50:33 +0000 Subject: [PATCH 2/2] address review feedback: extend APPDATA check to reject empty/blank strings, add tests Signed-off-by: anish k --- .../google/auth/oauth2/GoogleAuthUtils.java | 4 +-- .../auth/oauth2/GoogleAuthUtilsTest.java | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java index aab851c80f16..59e2766928fd 100644 --- a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java +++ b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java @@ -73,10 +73,10 @@ static final File getWellKnownCredentialsFile(DefaultCredentialsProvider provide cloudConfigPath = new File(envPath); } else if (provider.getOsName().indexOf("windows") >= 0) { String appDataEnv = provider.getEnv("APPDATA"); - if (appDataEnv == null) { + if (appDataEnv == null || appDataEnv.trim().isEmpty()) { throw new UncheckedIOException( new FileNotFoundException( - "APPDATA environment variable is not set; cannot locate the well-known" + "APPDATA environment variable is not set or empty; cannot locate the well-known" + " credentials file on Windows.")); } File appDataPath = new File(appDataEnv); diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java index 4ced1118d7ad..d756cc9e4f77 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleAuthUtilsTest.java @@ -56,6 +56,39 @@ void getWellKnownCredentialsFile_windows_nullAppData_throwsUncheckedIOException( () -> GoogleAuthUtils.getWellKnownCredentialsFile(provider)); assertTrue(thrown.getCause() instanceof FileNotFoundException); assertTrue(thrown.getCause().getMessage().contains("APPDATA")); + assertTrue(thrown.getCause().getMessage().contains("not set or empty")); + } + + @Test + void getWellKnownCredentialsFile_windows_emptyAppData_throwsUncheckedIOException() { + DefaultCredentialsProviderTest.TestDefaultCredentialsProvider provider = + new DefaultCredentialsProviderTest.TestDefaultCredentialsProvider(); + provider.setProperty("os.name", "windows"); + provider.setEnv("APPDATA", ""); + + UncheckedIOException thrown = + assertThrows( + UncheckedIOException.class, + () -> GoogleAuthUtils.getWellKnownCredentialsFile(provider)); + assertTrue(thrown.getCause() instanceof FileNotFoundException); + assertTrue(thrown.getCause().getMessage().contains("APPDATA")); + assertTrue(thrown.getCause().getMessage().contains("not set or empty")); + } + + @Test + void getWellKnownCredentialsFile_windows_blankAppData_throwsUncheckedIOException() { + DefaultCredentialsProviderTest.TestDefaultCredentialsProvider provider = + new DefaultCredentialsProviderTest.TestDefaultCredentialsProvider(); + provider.setProperty("os.name", "windows"); + provider.setEnv("APPDATA", " "); + + UncheckedIOException thrown = + assertThrows( + UncheckedIOException.class, + () -> GoogleAuthUtils.getWellKnownCredentialsFile(provider)); + assertTrue(thrown.getCause() instanceof FileNotFoundException); + assertTrue(thrown.getCause().getMessage().contains("APPDATA")); + assertTrue(thrown.getCause().getMessage().contains("not set or empty")); } @Test