Skip to content

Commit 77e84a9

Browse files
authored
fix(auth): handle missing APPDATA on Windows gracefully (#13471)
Other languages (such as Python and Node.js) handle missing HOME or APPDATA directories by falling back gracefully or failing with a structured Error/Exception. This change brings Java into parity by ensuring an orderly IOException is thrown instead of an opaque NullPointerException when APPDATA is null. Fixes #12565
1 parent a5ba606 commit 77e84a9

3 files changed

Lines changed: 29 additions & 5 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ private final GoogleCredentials getDefaultCredentialsUnsynchronized(
239239
return credentials;
240240
}
241241

242-
private final File getWellKnownCredentialsFile() {
242+
private final File getWellKnownCredentialsFile() throws IOException {
243243
return GoogleAuthUtils.getWellKnownCredentialsFile(this);
244244
}
245245

google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/GoogleAuthUtils.java

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

3434
import java.io.File;
35+
import java.io.IOException;
3536

3637
/**
3738
* This public class provides shared utilities for common OAuth2 utils or ADC. It also exposes
@@ -45,7 +46,7 @@ public class GoogleAuthUtils {
4546
* @return the path to the well-known Application Default Credentials file location
4647
*/
4748
public static final String getWellKnownCredentialsPath() {
48-
return getWellKnownCredentialsFile(DefaultCredentialsProvider.DEFAULT).getAbsolutePath();
49+
return getWellKnownCredentialsPath(DefaultCredentialsProvider.DEFAULT);
4950
}
5051

5152
/**
@@ -54,7 +55,11 @@ public static final String getWellKnownCredentialsPath() {
5455
* @return the path to the well-known Application Default Credentials file location
5556
*/
5657
static final String getWellKnownCredentialsPath(DefaultCredentialsProvider provider) {
57-
return getWellKnownCredentialsFile(provider).getAbsolutePath();
58+
try {
59+
return getWellKnownCredentialsFile(provider).getAbsolutePath();
60+
} catch (IOException e) {
61+
throw new RuntimeException(e);
62+
}
5863
}
5964

6065
/**
@@ -64,13 +69,18 @@ static final String getWellKnownCredentialsPath(DefaultCredentialsProvider provi
6469
* purposes)
6570
* @return the well-known Application Default Credentials file
6671
*/
67-
static final File getWellKnownCredentialsFile(DefaultCredentialsProvider provider) {
72+
static final File getWellKnownCredentialsFile(DefaultCredentialsProvider provider)
73+
throws IOException {
6874
File cloudConfigPath;
6975
String envPath = provider.getEnv("CLOUDSDK_CONFIG");
7076
if (envPath != null) {
7177
cloudConfigPath = new File(envPath);
7278
} else if (provider.getOsName().indexOf("windows") >= 0) {
73-
File appDataPath = new File(provider.getEnv("APPDATA"));
79+
String appData = provider.getEnv("APPDATA");
80+
if (appData == null) {
81+
throw new IOException(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS);
82+
}
83+
File appDataPath = new File(appData);
7484
cloudConfigPath = new File(appDataPath, provider.CLOUDSDK_CONFIG_DIRECTORY);
7585
} else {
7686
File configPath = new File(provider.getProperty("user.home", ""), ".config");

google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/DefaultCredentialsProviderTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,20 @@ void getDefaultCredentials_noCredentials_throws() {
115115
assertEquals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS, message);
116116
}
117117

118+
@Test
119+
void getDefaultCredentials_windowsMissingAppData_throws() {
120+
// When APPDATA is unset on Windows, the ADC resolution should fail gracefully
121+
// with a structured missing credentials exception, rather than crashing with an NPE.
122+
MockHttpTransportFactory transportFactory = new MockHttpTransportFactory();
123+
TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider();
124+
testProvider.setProperty("os.name", "windows");
125+
testProvider.setEnv("APPDATA", null);
126+
127+
IOException e =
128+
assertThrows(IOException.class, () -> testProvider.getDefaultCredentials(transportFactory));
129+
assertEquals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS, e.getMessage());
130+
}
131+
118132
@Test
119133
void getDefaultCredentials_noCredentialsSandbox_throwsNonSecurity() {
120134
MockHttpTransportFactory transportFactory = new MockHttpTransportFactory();

0 commit comments

Comments
 (0)