Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
dc5b79c
fix: allow for ES algorithm in GdchCredentials
diegomarquezp Mar 4, 2026
0c5e423
test: partially adapt tests
diegomarquezp Mar 4, 2026
5851b3e
test: finish adjusting tests
diegomarquezp Mar 4, 2026
258ac9d
chore: format
diegomarquezp Mar 4, 2026
e8511bb
fix: restore credential name
diegomarquezp Mar 4, 2026
a4d0f93
docs: restore license
diegomarquezp Mar 4, 2026
e3d5302
fix: restore removed code
diegomarquezp Mar 4, 2026
e6635c6
test: increase coverage
diegomarquezp Mar 5, 2026
cc49dba
test(gdch): parameterize test
diegomarquezp Mar 10, 2026
f58f593
test: remove unused var
diegomarquezp Mar 10, 2026
42f2662
chore: remove unused throw clause
diegomarquezp Mar 10, 2026
91a3751
test: parameterize more
diegomarquezp Mar 10, 2026
b83a511
fix: remove unused parameter
diegomarquezp Mar 10, 2026
625741e
fix: make variables final as intended
diegomarquezp Mar 10, 2026
1e0a7c3
fix: remove unused throw clause
diegomarquezp Mar 10, 2026
24cd25d
fix: remove unused throw clause
diegomarquezp Mar 10, 2026
027a242
fix: make OAuth2Credentials clock package private for production code
diegomarquezp Mar 10, 2026
a8b459b
fix: use non deprecated base 64 encoder
diegomarquezp Mar 10, 2026
4e8af24
test: parameterize flagged tests
diegomarquezp Mar 10, 2026
f257a81
chore: format
diegomarquezp Mar 10, 2026
c523df2
test: fix assertion
diegomarquezp Mar 10, 2026
ed026a4
build: remove unused dependency
diegomarquezp Mar 10, 2026
1528e76
test: run linux gce only on linux envs
diegomarquezp Mar 10, 2026
7300e59
fix: sonarqube flags (use java.util.Base64)
diegomarquezp Mar 10, 2026
382d8ae
fix: improve error message template
diegomarquezp Mar 16, 2026
c348ee1
fix: keep overload of "with audience" that takes an URI
diegomarquezp Mar 16, 2026
6323455
fix: restore public getter of getApiAudience
diegomarquezp Mar 16, 2026
1aa7715
docs: add javadoc for signing logic
diegomarquezp Mar 17, 2026
4f69872
test: test private signature and decode methods
diegomarquezp Mar 18, 2026
f4b53ee
fix: add null and empty check for audience string
diegomarquezp Mar 18, 2026
b3085a2
docs: add javadoc for audience getters
diegomarquezp Mar 18, 2026
39ef931
fix: use enum for possible algorithms
diegomarquezp Mar 18, 2026
3003076
fix: use obsolete javadoc instead of @deprecated
diegomarquezp Mar 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
294 changes: 258 additions & 36 deletions oauth2_http/java/com/google/auth/oauth2/GdchCredentials.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public class OAuth2Credentials extends Credentials {
// Change listeners are not serialized
private transient List<CredentialsChangedListener> changeListeners;
// Until we expose this to the users it can remain transient and non-serializable
@VisibleForTesting transient Clock clock = Clock.SYSTEM;
transient Clock clock = Clock.SYSTEM;

/**
* Returns the credentials instance from the given access token.
Expand Down
22 changes: 20 additions & 2 deletions oauth2_http/java/com/google/auth/oauth2/OAuth2Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.PemReader;
import com.google.api.client.util.PemReader.Section;
import com.google.api.client.util.SecurityUtils;
import com.google.auth.http.AuthHttpConstants;
import com.google.auth.http.HttpTransportFactory;
import com.google.common.base.Strings;
Expand Down Expand Up @@ -80,6 +79,11 @@
*/
public class OAuth2Utils {

public enum Pkcs8Algorithm {
RSA,
EC
}
Comment on lines +82 to +85
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that OAuth2Utils and GdchCredentials classes are in the same package, can we make these enums and methods package-private?


static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

public static final String TOKEN_TYPE_ACCESS_TOKEN =
Expand Down Expand Up @@ -267,6 +271,20 @@ static Map<String, Object> validateMap(Map<String, Object> map, String key, Stri
* key creation.
*/
public static PrivateKey privateKeyFromPkcs8(String privateKeyPkcs8) throws IOException {
return privateKeyFromPkcs8(privateKeyPkcs8, Pkcs8Algorithm.RSA);
}

/**
* Converts a PKCS#8 string to a private key of the specified algorithm.
*
* @param privateKeyPkcs8 the PKCS#8 string.
* @param algorithm the algorithm of the private key.
* @return the private key.
* @throws IOException if the PKCS#8 data is invalid or if an unexpected exception occurs during
* key creation.
*/
public static PrivateKey privateKeyFromPkcs8(String privateKeyPkcs8, Pkcs8Algorithm algorithm)
throws IOException {
Reader reader = new StringReader(privateKeyPkcs8);
Section section = PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY");
if (section == null) {
Expand All @@ -276,7 +294,7 @@ public static PrivateKey privateKeyFromPkcs8(String privateKeyPkcs8) throws IOEx
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
Exception unexpectedException;
try {
KeyFactory keyFactory = SecurityUtils.getRsaKeyFactory();
KeyFactory keyFactory = KeyFactory.getInstance(algorithm.toString());
return keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException exception) {
unexpectedException = exception;
Expand Down
20 changes: 20 additions & 0 deletions oauth2_http/javatests/com/google/auth/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,26 @@ public static Map<String, String> parseQuery(String query) throws IOException {
return map;
}

/**
* Parses the request body as either JSON or a query string.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: query string is part of the URL, right? This seems to be doing two separate things. Can we separate the logic for this into two methods:

  1. parseQuery
  2. parseJson()

*
* @param content The request body content.
* @return A map of the parsed parameters.
* @throws IOException If the content cannot be parsed.
*/
public static Map<String, String> parseBody(String content) throws IOException {
if (content != null && content.trim().startsWith("{")) {
GenericJson json = JSON_FACTORY.fromString(content, GenericJson.class);
Map<String, String> map = new HashMap<>();
for (Map.Entry<String, Object> entry : json.entrySet()) {
Object value = entry.getValue();
map.put(entry.getKey(), value == null ? null : value.toString());
}
return map;
}
return parseQuery(content);
}

public static String errorJson(String message) throws IOException {
GenericJson errorResponse = new GenericJson();
errorResponse.setFactory(JSON_FACTORY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.LowLevelHttpRequest;
Expand Down Expand Up @@ -94,7 +95,7 @@ class DefaultCredentialsProviderTest {
private static final String GDCH_SA_CA_CERT_FILE_NAME = "cert.pem";
private static final String GDCH_SA_CA_CERT_PATH =
GdchCredentialsTest.class.getClassLoader().getResource(GDCH_SA_CA_CERT_FILE_NAME).getPath();
private static final URI GDCH_SA_API_AUDIENCE = URI.create("https://gdch-api-audience");
private static final String GDCH_SA_API_AUDIENCE = "https://gdch-api-audience";
private static final Collection<String> SCOPES = Collections.singletonList("dummy.scope");
private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo");
private static final String QUOTA_PROJECT = "sample-quota-project-id";
Expand Down Expand Up @@ -180,48 +181,36 @@ void getDefaultCredentials_noCredentials_singleGceTestRequest() {
}

@Test
void getDefaultCredentials_noCredentials_linuxNotGce() throws IOException {
TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider();
testProvider.setProperty("os.name", "Linux");
String productFilePath = SMBIOS_PATH_LINUX;
InputStream productStream = new ByteArrayInputStream("test".getBytes());
testProvider.addFile(productFilePath, productStream);

assertFalse(ComputeEngineCredentials.checkStaticGceDetection(testProvider));
void getDefaultCredentials_noCredentials_linuxNotGce() {
checkStaticGceDetection("Linux", "test", false);
}

@Test
void getDefaultCredentials_static_linux() throws IOException {
TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider();
testProvider.setProperty("os.name", "Linux");
String productFilePath = SMBIOS_PATH_LINUX;
File productFile = new File(productFilePath);
InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes());
testProvider.addFile(productFile.getAbsolutePath(), productStream);

assertTrue(ComputeEngineCredentials.checkStaticGceDetection(testProvider));
void getDefaultCredentials_static_linux() {
checkStaticGceDetection("Linux", "Googlekdjsfhg", true);
}

@Test
void getDefaultCredentials_static_windows_configuredAsLinux_notGce() throws IOException {
TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider();
testProvider.setProperty("os.name", "windows");
String productFilePath = SMBIOS_PATH_LINUX;
InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes());
testProvider.addFile(productFilePath, productStream);

assertFalse(ComputeEngineCredentials.checkStaticGceDetection(testProvider));
void getDefaultCredentials_static_windows_configuredAsLinux_notGce() {
checkStaticGceDetection("windows", "Googlekdjsfhg", false);
}

@Test
void getDefaultCredentials_static_unsupportedPlatform_notGce() throws IOException {
void getDefaultCredentials_static_unsupportedPlatform_notGce() {
checkStaticGceDetection("macos", "Googlekdjsfhg", false);
}

private void checkStaticGceDetection(String osName, String productContent, boolean expected) {
assumeTrue(
System.getProperty("os.name").toLowerCase().startsWith("linux"),
"This test only runs on Linux.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but I don't think this is the behavior we want. IIUC, this looks like it will only run the test on Linux environments (e.g. our if our CI or local was linux). The original tests was mocking the environment and testing it so that it would mock the os.name value regardless of the CI or local OS.

TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider();
testProvider.setProperty("os.name", "macos");
testProvider.setProperty("os.name", osName);
String productFilePath = SMBIOS_PATH_LINUX;
InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes());
InputStream productStream = new ByteArrayInputStream(productContent.getBytes());
testProvider.addFile(productFilePath, productStream);

assertFalse(ComputeEngineCredentials.checkStaticGceDetection(testProvider));
assertEquals(expected, ComputeEngineCredentials.checkStaticGceDetection(testProvider));
}

@Test
Expand Down
Loading
Loading